使用堆栈将缺少左括号的表达式补全并计算其值

问题描述:输入一个缺少左括号的表达式,打印出其补全括号的中序表达式,并计算表达式的值。例如给定表达式:

1+2) * 3-4) * 5-6)))

得到输出:

((1+2) * ((3-4) * (5-6)))

计算得到其值为3
问题分析:计算表达式的问题通常使用堆栈。有的算法中利用操作符的优先级以及复杂的记录过程,其实只要利用好堆栈的特性,任何多余的操作都是完全没有必要的。这里首先考虑计算出表达式的值的问题,以此思路推及补全表达式的问题。
由于所计算的表达式是由数字和操作符构成的,因而解析表达式的时候需要使用两个堆栈分别存放数字和操作符。将表达式分别入栈,每当遇到右括号时出栈计算子表达式,将结果再次入栈参与下一次的计算。

public class Test1{

    public static boolean isNumber(char s) {
        return (48<=s&&s<=57)?true:false;
    }   
    public static boolean isOpr(char s) {
        return (s=='+'||s=='-'||s=='*'||s=='/')?true:false;
    }

    public static void main(String[] args) {
        In in=new In("D:\\expression.txt");
        String string=in.readAll();
        char[] word=string.toCharArray();       
        ListStack<Character> oprStack=new ListStack<>();// 数字
        ListStack<Integer> numStack=new ListStack<>();// 操作符        
        for (int i = 0; i < word.length; i++) {
            if (isNumber(word[i])) {// 数字
                numStack.push(word[i]-48);
            }else if (isOpr(word[i])) {// 操作符
                oprStack.push(word[i]);
            }else if (word[i]==')') {
                // 遇到右括号的时候计算子表达式
                int right=numStack.pop();
                int left=numStack.pop();
                char opr=oprStack.pop();
                int result=0;
                switch (opr) {
                case '+':
                    result=left+right;
                    break;
                case '-':
                    result=left-right;
                    break;
                case '*':
                    result=left*right;
                    break;
                case '/':
                    result=left/right;
                    break;
                default:
                    break;
                }
                // 最后将子表达式的结果入栈参与下次计算
                numStack.push(result);
            }
        }
        // 程序最后操作符的堆栈为空,数字的堆栈中就是最后的计算结果
        System.out.println(numStack.pop());
    }
}

可见整个算法是非常简单的。接着要将表达式的左括号补全,应该如何做呢?首先会想到要去找插入左括号的位置,而左括号又取决于右括号的迭代层次,因此要想通过记录位置的方法来解决此问题不是很容易。
而通过分析计算表达式的值的问题,我们可以得到启发:通过将子表达式的结果逐层代入父表达式,就可以利用堆栈非常简单的解决问题,从而有以下解决方案。

public class Test2{
    public static void main(String[] args) {
        In in=new In("D:\\expression.txt");
        String string=in.readAll();
        String[] strings =string.split("");
        Stack<String> exprStack=new Stack<>();
        for (int i = 0; i < strings.length; i++) {
            // 将表达式内容全部入栈
            if (!strings[i].equals(")")) {
                exprStack.push(strings[i]);
            }else {
                // 在遇到右括号的时候将子表达式用一个String对象表示并入栈以代入父表达式
                String right=exprStack.pop();
                String opr=exprStack.pop();
                String left=exprStack.pop();
                String expr="("+left+opr+right+")";// 补全左右括号
                exprStack.push(expr);
            }
        }
        System.out.println(exprStack.pop());
    }
}

上述算法关键在于将子表达式用一个String对象表示,就如同一个计算的结果,入栈后代入父表达式。
总结:将子表达式用一个结果表示,逐层代入父表达式,可以利用堆栈处理表达式的补全问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值