【问题标题】:how to avoid ArrayIndexOutOfbounds Exception?如何避免 ArrayIndexOutOfbounds 异常?
【发布时间】:2017-02-10 03:32:20
【问题描述】:

我正在尝试使用堆栈解决中缀表达式,但我的程序似乎抛出了 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)

【问题讨论】:

  • 我看不到明显的原因,但看起来values.push(applyOp(ops.pop(), values.pop(), values.pop()));2.3 被推入值堆栈之前被调用。您可以使第二个 ADDING to values 打印语句与第一个不同,这样您就可以区分事件,并将其移动到 while 循环中。
  • @JohnD 对不起,我不明白你在说哪个 while 循环。能详细点吗?
  • 请看下面的“答案”

标签: java arrays exception stack infix-notation


【解决方案1】:

分析

这似乎是一个逻辑错误(概念错误?)。

尝试使用标记顺序评估表达式。 当下一个operation token 可用时,将应用operation,但不会检查value stack 的大小是否大于或等于在弹出值之前执行(解释)操作所需的值的数量。这就是为什么最后打印的消息是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());
    }
}

【讨论】:

  • 非常感谢!我一直在检查除优先级之外的所有其他内容。我已经浏览了您刚刚提供的链接,该链接实际上是我的教授的,他正在教我这门课。 tysm!
  • @MayurTolani,不客气!很高兴它有所帮助。惊人的巧合!
  • @MayurTolani,如果是这样,请考虑接受答案。
  • 非常感谢您的帮助。但代码给出了错误的答案。我想,出现了其他一些逻辑错误。正在评估中缀表达式,但它没有正确遵循顺序
  • yes 原来的问题已经解决了。我会把你的答案作为正确的答案,当我做对时,我会用正确的工作代码更新代码。
【解决方案2】:

这不是一个答案,而是一个让程序更容易调试的建议——它不适合评论:)

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());
        }

【讨论】:

  • 在到达这一点之前发现代码中断。该 Print 语句不会被执行。 @johnD
  • 看起来像是调试器的工作 - 单步执行每个语句!
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 2011-05-01
  • 1970-01-01
  • 2016-09-15
  • 2016-08-13
  • 2015-12-11
  • 2015-10-26
  • 2014-06-06
相关资源
最近更新 更多