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

来源:互联网 发布:学吉他软件下载 编辑:程序博客网 时间:2024/05/02 08:30

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

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
原创粉丝点击