数据结构(6)--逆波兰计算器的运用

在很多情况下,我们都会认为我们的数据结构比较偏向底层开发,偏向C语言,但是实际上很多情况下,我们的JAVA等高级语言都会在平时的算法中使用到的数据结构,那么我就跟大家在这里使用一下.至于逆波兰表示法又称后缀表示法,在我们的计算机计算的时候,计算机是很机械化的,他没法灵巧运用人的灵活.比如说(5-1)*6+1这么一个数学题,现在的小学生我估计三年级都会了,不然还怎么玩LOL,对吧.
但是如果我们对代码不作处理,计算器怎么可能知道计算的是5-1先还是乘法优先,所以我们就需要用到逆波兰表示法,正好逆波兰表示法又是基于栈来实现的.那么今天我们就来灵活应用,起码别人问到,我们都可以灵活回答,对吧.

     public class Test {

           //方法:使用链式堆栈,设计一个算法计算表达式
            public static void expCaculate(LinkStack stack) throws Exception {
                char ch; //扫描每次输入的字符。
                int x1, x2, b = 0; //x1,x2:两个操作数 ,b字符的ASCII码
                System.out.println("输入后缀表达式并以#符号结束:");
                while ((ch = (char) (b = System.in.read())) != '#') {
                    //如果是数字,说明是操作数则压入堆栈
                    if (Character.isDigit(ch)) {
                        stack.push(new Integer(Character.toString(ch)));
                    }
                    //如果不是数字,说明是运算符
                    else {
                        x2 = ((Integer) stack.pop()).intValue();
                        x1 = ((Integer) stack.pop()).intValue();
                        switch (ch) {
                            case '+':
                                x1 += x2;
                                break;
                            case '-':
                                x1 -= x2;
                                break;
                            case '*':
                                x1 *= x2;
                                break;
                            case '/':
                                if (x2 == 0) {
                                    throw new Exception("分母不能为零!");
                                } else {
                                    x1 /= x2;
                                }
                                break;
                        }
                        stack.push(new Integer(x1));
                    }
                }
                System.out.println("后缀表达式计算结果是:" + stack.getTop());
            }

            public static void main(String[] args) throws Exception {
                LinkStack stack = new LinkStack();
                //(2+3)*(3-1)/2=5的后缀表达式为:23+31-*2/
                //方法:键盘输入后缀表达式,输出的得到计算结果
                Test.expCaculate(stack);

            }

中缀转后缀表达式

当然,在日常生活中,我们基本上是不会使用后缀表达式的,但是上面的方法却是要我们输入后缀表达式.所以,我们正确的思路是:
中缀表达式—>后缀表达式–>逆波兰表达式
那么我们就区分下这么几种表达式:

  • 中缀表达式:运算符放在两个运算对象中间,如:(2+1)*3。我们从小做数学题时,一直使用的就是中缀表达式。
  • 后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则),如:21 + 3 。又比如3+(6-4/2)*5=23的后缀表达式为:3642/-5+#(#符号为结束符)
  • 前缀表达式:同后缀表达式一样,不包含括号,运算符放在两个运算对象的前面,如:* + 2 1 3 。前缀表达式和后缀表达式其实是差不多的,只不过符号位置不同而已,前缀表达式不是很常见。

    当然对于这个表达式的转换是比较难懂的,所以大家一定要不停去思考.

代码:

 public class InfixToSuffix {
         /**
         * 中缀表达式转后缀表达式 只处理了+,-,*,/和括号,没有处理负号及其它运算符,也没对前缀表达式验证。
         * 如要处理负号,可对表达式进行预转义处理,当下面条件成立时,将负号换成单目运算符"!" infix.charAt[i]=='-'&&(
         * i==0||infix.charAt[i-1]=='(')
         * 3*6/4+3
         * 3+6-4           3 6 + 4 -
         * 3+(6-4/2)*5    3 6 4 2 / - 5 * +
         */
        //方法:中缀表达式转成后缀表达式
        /**
         * 1. 这里使用了JAVA提供的Stack栈对象
         * 2. 遍历字符串,然后根据需求,遇到什么出栈,遇到什么不出栈,这里这个可以作为一个工具类
         * 
         * @param infix
         * @return
         */
        public static String infixToSuffix(String infix) {
            Stack stack = new Stack();
            String suffix = "";//前缀字符串
            int length = infix.length();
            for (int i = 0; i < length; i++) {//遍历字符串
                Character temp;
                char c = infix.charAt(i); //判断字节对象
                switch (c) {
                    // 忽略空格
                    case ' ':
                        break;
                    // 碰到'(',push到栈
                    case '(': //符号进栈
                        stack.push(c); 
                        break;
                    // 碰到'+''-',将栈中所有运算符弹出,送到输出队列中
                    case '+':
                    case '-':
                        while (stack.size() != 0) {
                            temp = stack.pop(); //就是+ -已经是最低了
                            if (temp == '(') {  //假如遇到(就进站内)
                                stack.push('(');
                                break;
                            }
                            suffix += " " + temp; //拼接
                        }
                        stack.push(c); 
                        suffix += " ";
                        break;
                    // 碰到'*''/',将栈中所有乘除运算符弹出,送到输出队列中
                    case '*':
                    case '/':
                        while (stack.size() != 0) {
                            temp = stack.pop();
                            if (temp == '(' || temp == '+' || temp == '-') {
                                stack.push(temp);  
                                break;
                            } else {
                                suffix += " " + temp;
                            }
                        }
                        stack.push(c);
                        suffix += " ";
                        break;
                    // 碰到右括号,将靠近栈顶的第一个左括号上面的运算符全部依次弹出,送至输出队列后,再丢弃左括号
                    case ')':
                        while (stack.size() != 0) {
                            temp = stack.pop();
                            if (temp == '(') //遇到左括号就停止
                                break;
                            else
                                suffix += " " + temp;
                        }
                        // suffix += " ";
                        break;
                    //如果是数字,直接送至输出序列
                    default:
                        suffix += c;
                }
            }

            //如果栈不为空,把剩余的运算符依次弹出,送至输出序列。
            while (stack.size() != 0) {
                suffix += " " + stack.pop();
            }
            return suffix;
        }

        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
             String str = "1+(2-3)*4+10/5";
            //调用方法:中缀表达式转成后缀表达式
                System.out.println(InfixToSuffix.infixToSuffix(str));
        }

    }

你可能感兴趣的:(Java)