中缀表达式求解器的空堆栈异常



因此,该程序假设从GUI中获取语法正确的中缀表达式,其中包含整数操作数和四个算术运算符(+-*/)并显示结果。在括号中输入表达式时遇到问题。

例如,此表达式

5+3-2 

将返回 6,但括号中的表达式相同

(5+3-2)

返回空堆栈异常。

我已经尝试尽可能仔细地完成此操作,但我知道有用。编译器在第三个 while 循环中指出错误,这表明我的最佳猜测是堆栈 valueStack 当时没有两个值,但我似乎无法弄清楚原因。谁能帮我弄清楚我做错了什么?

   public String infix(String expression)
   {
      expression=expression.replaceAll("[tn ]", "");
      String operator = "*/+-";
      int value1, value2;
      char ch;
      StringTokenizer tokenizer = new StringTokenizer(expression, operator, true); 
      Stack<Integer> valueStack = new Stack<Integer>();
      Stack<Character> operatorStack = new Stack<Character>();
      while(tokenizer.hasMoreTokens())
      {
         String token = tokenizer.nextToken();
         if(isInteger(token) == true)
            valueStack.push(Integer.parseInt(token));
         else if(token.charAt(0) == '(')
            operatorStack.push(token.charAt(0));
         else if(token.charAt(0) == ')')
            while(operatorStack.peek() != '(')
            {
               value1 = valueStack.pop();
               value2 = valueStack.pop();
               valueStack.push(solver(value1, value2, operatorStack.pop()));
               operatorStack.pop();
            }
         else if(token.charAt(0) == '+' || token.charAt(0) == '-' || token.charAt(0) == '*' || token.charAt(0) == '/')
         {
            while(!operatorStack.isEmpty() && precedence(token.charAt(0)) <= precedence(operatorStack.peek()))
            {
               value1 = valueStack.pop(); 
               value2 = valueStack.pop(); //empty stack error starts here
               valueStack.push(solver(value1, value2, operatorStack.pop()));
            }
            operatorStack.push(token.charAt(0));
         }
      }
      while(!operatorStack.isEmpty())
      {
         value1 = valueStack.pop();
         value2 = valueStack.pop();
         ch = operatorStack.pop();
         valueStack.push(solver(value1, value2, ch));
      }

      String result = Integer.toString(valueStack.pop());
      return result;     
   }  //End of infix
   public static boolean isInteger(String s)
   {
      try
      { 
         Integer.parseInt(s);
      } 
      catch(NumberFormatException e)
      {
         return false; 
      } 
      catch(NullPointerException e) 
      {
         return false;
      }
      return true;
   } // end of isInteger
   public int solver( int value1, int value2, char operator)
   {
      try
      {
         if(operator == '*')
            return value2 * value1;
         else if(operator == '/')
            return value2 / value1;
         else if(operator == '+')
            return value2 + value1;
         else if(operator == '-')
            return value2 - value1;
         else
            return 0;
      }
      catch(ArithmeticException e )
      {
         JOptionPane.showMessageDialog(null, "Division by Zero");
      }
      return 0;
   } // end of solver
   public int precedence(char op)
   {
      if(op == '+' || op == '-')
         return 1;
      else if(op == '*' || op == '/')
         return 2;
      else
         return 0;
   }   // end of precedence

首先,我只修复了用括号括起来的表达式崩溃的错误。对不起,我没有测试其他东西。

有一些问题(我在调试的代码中包含注释)但本质上你假设你在某个点上有一个堆栈上有 2 个值,而实际上你只有一个。这是因为您输入的第一个数字从未被打开,因为它附加了一个"("。第一个标记是"(5"而不是"(",所以它从来没有达到5,反正这里是代码哈哈

import java.util.*;
import javax.swing.JOptionPane;
public class Calc {
    public String infix(String expression)
    {
        expression=expression.replaceAll("[tn ]", "");
        String operator = "(*/+-)"; // I added (,) see line 20 for why ...
        int value1, value2;
        char ch;
        StringTokenizer tokenizer = new StringTokenizer(expression, operator, true); 
        Stack<Integer> valueStack = new Stack<Integer>();
        Stack<Character> operatorStack = new Stack<Character>();
        while(tokenizer.hasMoreTokens())
        {
            String token = tokenizer.nextToken();
            // the token here was "(5" when really it should be 5, therefore 5 doesn't get put on the value stack, which has consequences
            // see line 37 ...
            if(isInteger(token) == true)
                valueStack.push(Integer.parseInt(token));
            else if(token.charAt(0) == '(')
                operatorStack.push(token.charAt(0));
            else if(token.charAt(0) == ')')
                while(operatorStack.peek() != '(') // also need to check if the stack is empty here ...
                {
                    value1 = valueStack.pop();
                    value2 = valueStack.pop();
                    valueStack.push(solver(value1, value2, operatorStack.pop()));
                    operatorStack.pop();
                    // also need to check if the stack is empty here ...
                    if (operatorStack.isEmpty())
                        break;
                }
            else if(token.charAt(0) == '+' || token.charAt(0) == '-' || token.charAt(0) == '*' || token.charAt(0) == '/')
            {
                while(!operatorStack.isEmpty() && precedence(token.charAt(0)) <= precedence(operatorStack.peek()))
                {   // the bug happens because there is only one value [3] on the valueStack, and here you assume there are 2 (should be 3,5)
                    value1 = valueStack.pop(); 
                    value2 = valueStack.pop(); //empty stack error starts here
                    valueStack.push(solver(value1, value2, operatorStack.pop()));
                }
                operatorStack.push(token.charAt(0));
            }
        }
        while(!operatorStack.isEmpty())
        {
            value1 = valueStack.pop();
            value2 = valueStack.pop();
            ch = operatorStack.pop();
            valueStack.push(solver(value1, value2, ch));
        }

        String result = Integer.toString(valueStack.pop());
        return result;     
    }  //End of infix
    public static boolean isInteger(String s)
    {
        try
        { 
            Integer.parseInt(s);
        } 
        catch(NumberFormatException e)
        {
            return false; 
        } 
        catch(NullPointerException e) 
        {
            return false;
        }
        return true;
    } // end of isInteger
    public int solver( int value1, int value2, char operator)
    {
        try
        {
            if(operator == '*')
                return value2 * value1;
            else if(operator == '/')
                return value2 / value1;
            else if(operator == '+')
                return value2 + value1;
            else if(operator == '-')
                return value2 - value1;
            else
                return 0;
        }
        catch(ArithmeticException e )
        {
            JOptionPane.showMessageDialog(null, "Division by Zero");
        }
        return 0;
    } // end of solver
    public int precedence(char op)
    {
        if(op == '+' || op == '-')
            return 1;
        else if(op == '*' || op == '/')
            return 2;
        else
            return 0;
    }   // end of precedence

    public static void main (String [] args) {
        Calc c = new Calc();
        System.out.println(c.infix("(5+2-1)")); // heyy it works now :)
    }
}

只是一个快速编辑,上面的代码仍然会为这样的表达式(5+(3+2))即嵌套括号抛出异常,所以我也为此添加了一个快速(可能不是很漂亮)修复:

import java.util.*;
import javax.swing.JOptionPane;
public class Calc {
    public String infix(String expression)
    {
        expression=expression.replaceAll("[tn ]", "");
        String operator = "(*/+-)"; // I added (,) see line 20 for why ...
        int value1, value2;
        char ch;
        StringTokenizer tokenizer = new StringTokenizer(expression, operator, true); 
        Stack<Integer> valueStack = new Stack<Integer>();
        Stack<Character> operatorStack = new Stack<Character>();
        // added this in:
        boolean stopParsingBrackets = false;
        while(tokenizer.hasMoreTokens())
        {
            String token = tokenizer.nextToken();
            // the token here was "(5" when really it should be 5, therefore 5 doesn't get put on the value stack, which has consequences
            // see line 37 ...
            if(isInteger(token) == true)
                valueStack.push(Integer.parseInt(token));
            else if(token.charAt(0) == '(' && stopParsingBrackets)
                operatorStack.push(token.charAt(0));
            else if(token.charAt(0) == ')' && stopParsingBrackets)
                while(operatorStack.peek() != '(') // also need to check if the stack is empty here ...
                {
                    value1 = valueStack.pop();
                    value2 = valueStack.pop();
                    valueStack.push(solver(value1, value2, operatorStack.pop()));
                    operatorStack.pop();
                    // also need to check if the stack is empty here ...
                    if (operatorStack.isEmpty()) {
                        stopParsingBrackets = true;
                    }
                }
            else if(token.charAt(0) == '+' || token.charAt(0) == '-' || token.charAt(0) == '*' || token.charAt(0) == '/')
            {
                while(!operatorStack.isEmpty() && precedence(token.charAt(0)) <= precedence(operatorStack.peek()))
                {   // the bug happens because there is only one value [3] on the valueStack, and here you assume there are 2 (should be 3,5)
                    value1 = valueStack.pop(); 
                    value2 = valueStack.pop(); //empty stack error starts here
                    valueStack.push(solver(value1, value2, operatorStack.pop()));
                }
                operatorStack.push(token.charAt(0));
            }
        }
        while(!operatorStack.isEmpty())
        {
            value1 = valueStack.pop();
            value2 = valueStack.pop();
            ch = operatorStack.pop();
            valueStack.push(solver(value1, value2, ch));
        }

        String result = Integer.toString(valueStack.pop());
        return result;     
    }  //End of infix
    public static boolean isInteger(String s)
    {
        try
        { 
            Integer.parseInt(s);
        } 
        catch(NumberFormatException e)
        {
            return false; 
        } 
        catch(NullPointerException e) 
        {
            return false;
        }
        return true;
    } // end of isInteger
    public int solver( int value1, int value2, char operator)
    {
        try
        {
            if(operator == '*')
                return value2 * value1;
            else if(operator == '/')
                return value2 / value1;
            else if(operator == '+')
                return value2 + value1;
            else if(operator == '-')
                return value2 - value1;
            else
                return 0;
        }
        catch(ArithmeticException e )
        {
            JOptionPane.showMessageDialog(null, "Division by Zero");
        }
        return 0;
    } // end of solver
    public int precedence(char op)
    {
        if(op == '+' || op == '-')
            return 1;
        else if(op == '*' || op == '/')
            return 2;
        else
            return 0;
    }   // end of precedence

    public static void main (String [] args) {
        Calc c = new Calc();
        System.out.println(c.infix("(5+(2-1+2))")); // heyy it works now :)
    }
}

最新更新