You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

中缀转后缀算法问题: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方法逻辑完全错误

  1. 笔误导致分支失效:方法内的else if(p_op1 < p_op1)是低级错误,应该是p_op1 < p_op2,这个错误导致该分支永远无法进入。
  2. 返回值逻辑完全颠倒:需求是当栈顶运算符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("/");
}

额外优化建议

  1. 表达式拆分逻辑隐患:原split方法依赖简单正则拆分,遇到多位数、负数时会出错,建议改用更可靠的正则:Pattern.compile("(?<=[-+*/])|(?=[-+*/])")分割运算符与数字。
  2. Operand判断逻辑不可靠:postfix方法中用i%2 == 0判断数字的逻辑,一旦表达式拆分出错就会失效,建议直接用正则匹配\\d+来判断当前字符串是否为数字。

修复后,输入3+2*4-3将得到期望的输出[3, 2, 4, *, +, 3, -]。

内容的提问来源于stack exchange,提问作者IamTufa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:45:33