中缀转后缀算法问题:while语句未按预期触发
问题描述
我正在实现一个将用户输入的数学中缀表达式转换为后缀表达式的Java程序,后续用于表达式求值,但在postfix方法中遇到问题:
代码中的while循环语句while(!ope.empty()&& HasHigherPrecedence(ope.peek(), this.exp[i]))未按预期触发。例如当栈顶运算符为*、当前运算符为-时,*优先级更高且栈非空,理论上应触发循环,但实际未执行。
已排查其他部分未发现错误,耗时1.5小时仍无法解决,期望得到的后缀表达式输出为[3, 2, 4, *, +, 3, -]。
相关代码
private Scanner sc = new Scanner(System.in); private String expression; private String exp[]; private ArrayList<String> post_fix = new ArrayList<>(); Stack<String> ope = new Stack<String>(); public Model() { expression = sc.nextLine(); } public void split() { //splitting the entered expression to array of operators alone and array of the numbers then create Arraylist to combine the operators and numbers together as if it is a string expression but as an array String num[]= this.expression.split("[/+/*/-]"); String preop[]= this.expression.split("[0-9]+");// this will give [empty, operator, operator...] therefore we will create another array to fill in the ops excluding empty ArrayList<String> op = new ArrayList<>();//I used arraylist because easier for(int i = 1; i<preop.length;i++) { op.add(preop[i]); } //putting the operands and the operators together in the same array ArrayList<String> exp = new ArrayList<>(); for(int i = 0; i <num.length;i++) { exp.add(num[i]); } int count = 0; for(int i = 0; i <op.size();i++) { //fill the arraylist with numbers then add the operators to it by using number (index of the operator +1 +count) exp.add(i+1+count, op.get(i)); //This is why arraylist was used in order to let values to be placed in between count++; //i+1+count is used because index of the operator is in between two numbers meaning it is after the first index in num array so i+1 and because array keeps increasing, we do +count for the other operators to be placed in } this.exp = new String[exp.size()]; // we change the arraylist exp to instance array for faster operations later on System.out.print("Test to check if expression is converted into array as intented: "); for(int i = 0; i<this.exp.length;i++) { this.exp[i] = exp.get(i); System.out.print(this.exp[i]); } System.out.println(); } public void postfix() { for(int i = 0; i < exp.length; i++) { if(i%2 == 0)//since operands are observed to always have even index in the array { post_fix.add(exp[i]); System.out.println(post_fix); } else { boolean x = !ope.empty(); System.out.println("Test of !ope.empty: " + x); while(!ope.empty()&& HasHigherPrecedence(ope.peek(), this.exp[i])) { post_fix.add(ope.peek()); ope.pop(); } ope.push(exp[i]); System.out.println("stack_top: "+ ope.peek()); } } while(!ope.empty()) { post_fix.add(ope.peek()); ope.pop(); } System.out.println("Output: "+post_fix); } public String getPost_fix() { String temp = ""; for(int i =0; i < exp.length;i++) { temp = temp + post_fix.get(i); } return temp; } public double evaluate() { return 0; } private boolean HasHigherPrecedence(String op1, String op2) { //op1 is operator 1 at the top of the stack thus associativity highest int a_op1 = 1; int a_op2 = 0; int p_op1 = 0; int p_op2= 0; //the precedence will be measured with numbers String operators[]= {"","+","-","*","/"}; int precedence[] = {0,1,1,2,2}; //the reason for blank operator and 0 precedence is because the stack initially will be empty for(int i = 0; i< operators.length;i++) { if(op1.equals(operators[i])) { p_op1=precedence[i]; } } for(int i = 0; i< operators.length;i++) { if(op2.equals(operators[i])) { p_op2=precedence[i]; } } boolean higher_ornot = false; if(p_op1 > p_op2) { higher_ornot = false; } else if(p_op1 < p_op1) { higher_ornot = true; } else if(p_op1== p_op2) { System.out.println(op1+": "+p_op1); System.out.println(op2+": "+p_op2); higher_ornot = false; //since associativity of op1 will be higher --> thus higher precedence } return higher_ornot; } }
当前程序输出
Test to check if expression is converted into array as intented: 3+2*4-3 [3] Test of !ope.empty: false stack_top: + [3, 2] Test of !ope.empty: true stack_top: * [3, 2, 4] Test of !ope.empty: true stack_top: - Output: [3, 2, 4, +, *, -]
问题原因及修复方案
核心问题:HasHigherPrecedence方法逻辑完全错误
- 笔误导致分支失效:方法内的
else if(p_op1 < p_op1)是低级错误,应该是p_op1 < p_op2,这个错误导致该分支永远无法进入。 - 返回值逻辑完全颠倒:需求是当栈顶运算符
op1优先级高于/等于当前运算符op2时,触发循环弹出栈顶,但当前代码:- 当
p_op1 > p_op2(比如op1=*,op2=-)时返回false,直接阻止循环执行; - 正确逻辑应为:
op1优先级大于等于op2时返回true,让循环触发。
- 当
修复后的HasHigherPrecedence方法
private boolean HasHigherPrecedence(String op1, String op2) { int p_op1 = 0; int p_op2 = 0; String operators[] = {"", "+", "-", "*", "/"}; int precedence[] = {0, 1, 1, 2, 2}; // 合并循环,减少冗余代码 for (int i = 0; i < operators.length; i++) { if (op1.equals(operators[i])) { p_op1 = precedence[i]; } if (op2.equals(operators[i])) { p_op2 = precedence[i]; } } // 左结合运算符:优先级相同则栈顶运算符先出栈 return p_op1 > p_op2 || (p_op1 == p_op2 && isLeftAssociative(op1)); } // 补充左结合判断(加减乘除均为左结合) private boolean isLeftAssociative(String op) { return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/"); }
额外优化建议
- 表达式拆分逻辑隐患:原
split方法依赖简单正则拆分,遇到多位数、负数时会出错,建议改用更可靠的正则:Pattern.compile("(?<=[-+*/])|(?=[-+*/])")分割运算符与数字。 - Operand判断逻辑不可靠:
postfix方法中用i%2 == 0判断数字的逻辑,一旦表达式拆分出错就会失效,建议直接用正则匹配\\d+来判断当前字符串是否为数字。
修复后,输入3+2*4-3将得到期望的输出[3, 2, 4, *, +, 3, -]。
内容的提问来源于stack exchange,提问作者IamTufa
相关产品推荐
相关产品推荐

