1.平衡符号
  编译器需要检查代码的语法错误,但是常常由于缺少一个符号(如一楼一个花括号或者注释起始符)引起编译器上百行的诊断,而真正的错误并没有找出(在这一点上java编译器还是比较可靠的,但不是所有编译器)。在这种情况下一个有用的工具就是检查符号是否有效。于是每一个左花括号,左方括号以及左圆括号必然有右括号与其对应(比如{[]}是合法的,但是{[}]是错误的)。显然为此编写一个大型程序去校验是不值得的,事实上检验这些事情是很容易的,我们就圆括号、方括号和花括号进行一次校验,我们这个简单的算法用到一个栈

class Check {

        // 用一个Map来装需要成对的符号
        private HashMap<Character, Character> mappings;

        // 初始化映射,方便之后读取使用
        public Check() {
            this.mappings = new HashMap<Character, Character>();
            this.mappings.put(')', '(');
            this.mappings.put('}', '{');
            this.mappings.put(']', '[');
        }

        public boolean isValid(String s) {

            // 初始化一个栈
            Stack<Character> stack = new Stack<Character>();

            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);

                // 判断当前字符是否为一个右括号
                if (this.mappings.containsKey(c)) {

                    // 元素出栈,若为空则设置为"#"
                    char topElement = stack.empty() ? '#' : stack.pop();

                    //如果括号不能组成对则返回false
                    if (topElement != this.mappings.get(c)) {
                        return false;
                    }
                } else {
                    // 如果为一个做括号则元素入栈
                    stack.push(c);
                }
            }

            // 如果元素为空,则校验为true
            return stack.isEmpty();
        }
    }

2.后缀表达式
  假设这么一个场景:我们在外购物,一些货物会有折扣,我们在使用计算器计算各个物品价格为4.99,5.99,6.99的花费,商品会有9折的折扣。那么输入这些数据的自然方式将是:

4.99+5.99+6.99*0.9=

随着计算器的不同,这个结果或者是所要的答案16.173(顺序执行),或者是科学答案17.271。最简单的计算器都会给出第一个答案,但是许多先进的计算器是知道乘法的优先级高于加法的。

另外一种情况, 如果我们的折扣只适用于4.99和6.99的商品,那么计算顺序为:

4.990.9+5.99+6.990.9=

将在科学计算器中给出正确答案16.772,而在简单计算器上给出错误答案15.724。科学计算器一般包含括号,因此我们总能通过加括号的方式得到正确的答案,但是使用简单计算器需要我们记住中间的结果。

这例典型的计算顺序可以是将4.99和0.9相乘记为A1,然后将5.99与A1相加,再将结果存入A1;我们再将6.99与0.9相乘记为A2,最后将A1和A2相加并把结果存入A1。这样我们可以将这种操作顺序书写如下:

4.99 0.9 * 5.99 + 6.99 0.9 * +

这个记法叫做后缀(postfix)或是逆波兰(reverse Polish)记法,其求值过程就是上述过程,计算这个问题最简单的方法是使用一个栈当见到数时就把它推入栈,在遇到运算符时就将该符号作用于从栈中弹出的两个数上,再将结果推入栈中。下面模拟一下计算6 5 2 3 + 8 * + 3 + *的过程。
  在这里插入图片描述
  计算一个后缀表达式花费的时间是O(N),因为对输入中的每个元素处理都由栈操作组成,花费时间为常数,这样计算的优点是没有必要知道任何优先的规则。这里介绍了后缀表达式顺便再简介一下前缀表达式和中缀表达式,前缀表达式使用非常少,指的是将符号写在适用数字之前比如1-(2+3)的前缀表达式为- 1 + 2 3,将表达式从右往左直接入栈出栈即可。中缀表达式就是我们正规的运算表达式,需要了解的是中缀和后缀的转换。

我们可以用栈将一个标准形式的表达式(中缀表达式)转换成后缀表达式。假设表达式合法为:

a + b * c ( d * e + f ) * g

先说一下思路,计算从一个空的栈开始,当读到一个操作数时,立即把它放到输出中,已经见到过但尚未放到输出的操作符推入栈中。当遇到左括号时也推入栈,如果遇到一个右括号,那么就将栈元素弹出并写在输出中直到遇到一个对应的左括号,但是这个左括号只被弹出并不输出。如果见到其他符号(+,*,(),那么我们从栈中弹出元素直到发现优先级更低的元素为止。这里需要注意:如果处理一个左括号(时,+的优先级最低,而(的优先级最高。当弹栈的工作结束后我们再将操作符压入栈中。最后,如果读到输入的末尾,我们将栈元素弹出直到变为空栈,将符号写在输出中。

在这里插入图片描述

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.nextLine();
        ArrayList<Character> outPut = new ArrayList<>();
        Stack<Character> characters = new Stack<>();
        HashMap<Character, Integer> map = new HashMap<>();
        map.put('+',1);
        map.put('*',2);
        //如果入栈的是‘+’栈顶是‘*’,则‘*’出栈,‘+’再入栈,栈顶为‘+’则出栈,再入栈。遍历判断
        // 如果入栈的是‘*’,栈顶为‘*’则出栈,再入栈,如果栈顶为‘(’,直接入栈。遍历判断
        // 如果符号的是‘(’,直接入栈。
        //如果符号是‘)’,则元素依次出栈,直到栈顶元素为‘(’,‘(’出栈结束。
        //如果是其它符号,直接进入数组。
        //当遍历完字符串时,元素出栈。
        int length = s.length();
//        for (int i=0;i<s.length();i++){//这种方式当数据量多的时候消耗时间更多!//详细参考这篇博客https://www.trinea.cn/android/arraylist-linkedlist-loop-performance/
            for (int i=0;i<length;i++){
                char c = s.charAt(i);
            if (c=='+'||c=='*'){
                if (characters.isEmpty()||characters.peek()=='('){//"||"只要满足第一个条件,后面的条件就不再判断,而|要对所有的条件进行判断。
                    characters.push(c);
                }else if (map.get(c)<=map.get(characters.peek())){//前者的优先级比后者小或相等
                    while (!characters.isEmpty()&&map.get(characters.peek())!=null&&map.get(c)<=map.get(characters.peek())){
                        Character pop = characters.pop();
                        outPut.add(pop);
                    }
                    characters.push(c);
                } else {//前者比后者大
                    characters.push(c);
                }
            }else if (c=='('){
                characters.push(c);
            }else if (c==')'){
                while (characters.peek()!='('){
                    Character pop = characters.pop();
                    outPut.add(pop);
                }
                //‘(’出去
                characters.pop();
            }else {
                //其它数字
                outPut.add(c);
            }
        }
        while (!characters.isEmpty()){
                outPut.add(characters.pop());
        }
        for (int i=0;i<outPut.size();i++){
            System.out.print(outPut.get(i));
        }
    }

输入:a+bc+(de+f)g
输出:abc
+def+g

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值