代码之家  ›  专栏  ›  技术社区  ›  Mayur Tolani

如何避免ArrayIndexOutOfbounds异常?

  •  1
  • Mayur Tolani  · 技术社区  · 8 年前

    我正在尝试使用堆栈求解中缀表达式,我的程序似乎会抛出一个 ArrayIndexOutOfBoundsException .

    你能指导我如何解决代码中的错误吗?

    程序类

    public class CS6084BTolani {
    
        public static String evaluateInfix(String exps)
        {
            exps = exps.replaceAll(" ", "");//removing white spaces
            System.out.println(exps);
    
            StackADT<Double> values = new StackADT<Double>(exps.length());//Stack for Operands
            StackADT<String> ops = new StackADT<String>(exps.length());//for operators
    
    
            StringTokenizer tokens = new StringTokenizer(exps, "()^*/+-", true);//to seperate all the operands and operators 
    
            while(tokens.hasMoreTokens())
            {
                String tkn = tokens.nextToken();
    
                if(tkn.equals("(")) 
                {
                    ops.push(tkn);
                    System.out.println("ADDING to ops : "+ops.peek());
                } 
                else if(tkn.matches("\\d+\\.\\d+")||tkn.matches("\\d+"))
                {
    
                    values.push(Double.valueOf(tkn));
                    System.out.println("ADDING to values : "+values.peek());
                }
                else if (tkn.equals("^") || tkn.equals("*") || tkn.equals("/") || tkn.equals("+") || tkn.equals("-"))
                {
                    while (!ops.isEmpty() && hasPrecedence(tkn, ops.peek()))
                      values.push(applyOp(ops.pop(), values.pop(), values.pop()));
                  System.out.println("ADDING to values: "+values.peek());
    
                    // Push current token to 'ops'.
                    ops.push(tkn);
                    System.out.println("ADDING to ops: "+ops.peek());
                }
                else if(tkn.equals(")"))
                {
                    while (!(ops.peek()).equals("("))
                    {
                      values.push(applyOp(ops.pop(), values.pop(), values.pop()));
                      System.out.println("ADDING to values: "+values.peek());
                    }
                    ops.pop();
                }
    
    
            }
    
            while (!ops.isEmpty())
                values.push(applyOp(ops.pop(), values.pop(), values.pop()));
    
            // Top of 'values' contains result, return it
            return String.valueOf(values.pop());
        }
    
        public static boolean hasPrecedence(String op1, String op2)
        {
            if (op2 == "(" || op2 == "(")
                return false;
            if ( (op1 == "^" ) && (op2 == "+" || op2 == "-"))
                return false;
            if ( (op1 == "^" ) && (op2 == "*" || op2 == "/"))
                return false;
            if ( (op1 == "*" || op1 == "/") && (op2 == "+" || op2 == "-"))
                return false;
            else
                return true;
        }
    
        public static double applyOp(String op, double b, double a)
        {
            switch (op)
            {
            case "^":
                return Math.pow(a,b);
            case "+":
                return a + b;
            case "-":
                return a - b;
            case "*":
                return a * b;
            case "/":
                if (b == 0)
                    throw new
                    UnsupportedOperationException("Cannot divide by zero");
                return a / b;
            }
            return 0;
        }
    
        public static void main(String a[]) throws Exception
        {
            //Input ip = new Input("inputData4B.txt");
            String expOne = "(100.0 + 2.3)";//ip.getFirstString();
            System.out.println("Answer: "+evaluateInfix(expOne));
            //String expTwo = ip.getSecondString();
            //System.out.println("Answer: "+evaluateInfix(expTwo));
            //String expThree = ip.getThirdString();
            //System.out.println("Answer: "+evaluateInfix(expThree));
            //String expFour = ip.getFourthString();
            //System.out.println("Answer: "+evaluateInfix(expFour));
        }
    }
    

    堆栈类

    class StackADT<T extends Object> {
    
        private int stackSize;
        private T[] stackArr;
        private int top;
    
    
        public StackADT(int size) 
        {
            stackSize = size;
            stackArr = (T[]) new Object[stackSize];
            top = -1;
        }
        public void push(T element){
    
            stackArr[++top] = element;
        }
        public T pop()  
        {
            if(isEmpty())
            {
                System.out.println("Stack is isEmpty.");
            }
            T element = stackArr[top--];
            return element;
        }
        public T peek() 
        {
            return stackArr[top];
        }
    
        public boolean isEmpty() 
        {
            return (top == -1);
        }    
    }
    

    跑步时它是这样的:

    java CS6084BTolani
    
    (100.0+2.3)
    
    
    ADDING to ops : (
    
    ADDING to values : 100.0
    
    Stack is isEmpty.
    
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
    
    at StackADT.pop(CS6084BTolani.java:139)
    
    at CS6084BTolani.evaluateInfix(CS6084BTolani.java:38)
    
    at CS6084BTolani.main(CS6084BTolani.java:102)
    
    2 回复  |  直到 8 年前
        1
  •  0
  •   Sergey Vyacheslavovich Brunov prodigitalson    8 年前

    分析

    尝试使用标记顺序计算表达式。 下次什么时候 operation token 可用,则 operation 正在应用,但没有检查 value stack size大于或等于弹出值之前执行(解释)操作所需的值的数量。这就是为什么最后打印的消息是 Stack is isEmpty. .

    一般说明

    该算法是中缀表达式求值算法。

    如果目标是学习如何设计算法,那么尝试自己设计。 否则,使用其描述学习算法,例如,从 this source .

    在更新当前实现之前,请尝试了解它有什么问题:将其与设计或描述的版本进行比较。之后,如果需要大量更改,请更新实现或创建新的实现。

    解决方案

    目前,我发现操作优先级处理有问题。请考虑以下操作处理:

    else if (tkn.equals("^") || tkn.equals("*") || tkn.equals("/") || tkn.equals("+") || tkn.equals("-")) {
        if (!ops.isEmpty() && !hasPrecedence(tkn, ops.peek())) {
            values.push(applyOp(ops.pop(), values.pop(), values.pop()));
            System.out.println("ADDING to values: " + values.peek());
        }
        else {
            // Push current token to 'ops'.
            ops.push(tkn);
            System.out.println("ADDING to ops: " + ops.peek());
        }
    }
    
        2
  •  0
  •   John D    8 年前

    这不是一个答案,而是一个使程序更容易调试的建议-它不适合于注释:)

    else if (tkn.equals("^") || tkn.equals("*") || tkn.equals("/") || tkn.equals("+") || tkn.equals("-"))
        {
            while (!ops.isEmpty() && hasPrecedence(tkn, ops.peek())) {
              values.push(applyOp(ops.pop(), values.pop(), values.pop()));
              System.out.println("ADDING calculations to values: "+values.peek());
            }