栈的应用----括号匹配 与 逆波兰表达式求值

文章目录

  • 1 括号匹配问题
  • 2 逆波兰表达式求值问题
    • 1 中缀表达式
    • 2 逆波兰表达式(后缀表达式)
    • 3 逆波兰表达式求值

1 括号匹配问题

  1. 问题:给定一个字符串,里面可能包含"()"小括号,请编写程序检查该字符串中的小括号是否成对出现。

  2. 例如:(hello) 正确 ((hello)())正确 (hello))错误

  3. 问题分析:

    1. 需要匹对小括号成对出现,那我们只需要先把左括号全部存储起来,然后出现一个右括号,就匹配一个左括号,直到右括号没有了,且左括号的数量为0,则表示完全匹配成功。当然,若匹配不到左括号,那就是不合格。
  4. 具体实现:

    1. 我们可以先创建一个栈,依次读取字符串中每一个字符。
    2. 遇到左括号我们就存入栈中,其余字符不存入栈中。
    3. 遇到右括号就从栈中取出一个元素,并判断是否为左括号,如果是,则匹配成功,若不是则不匹配。
    4. 读取完字符串数据,判断栈中是否还有左括号,若还有则表示右括号少了即不匹配。
  5. 代码实现:

    /**
     * @author JIN
     * @description 括号匹配问题
     **/
    public class test {
           
        public static boolean isMatch(String str){
           
            Stack<String> stack = new Stack<>();
            for (int i = 0; i < str.length(); i++) {
           
                String s = Character.toString(str.charAt(i));
                if(s.equals("(")){
           
                    stack.push("s");
                }
                if(s.equals(")")){
           
                    String pop = stack.pop();
                    if(pop == null){
           
                        return false;
                    }
                }
            }
            if(stack.size() > 0){
           
                return false;
            }
            return true;
        }
    
        public static void main(String[] args) {
           
            String str = "(hello)(( world)";
            System.out.println(test.isMatch(str));
        }
    }
    

    下面是stack的代码(链表方式):
    这篇文章中 有用数组创建stack的,如果想用数组的朋友,可以去这里查看:
    https://blog.csdn.net/xueyijin/article/details/108035244

    import java.util.Iterator;
    
    /**
     * @author JIN
     * @description 栈
     **/
    public class Stack<T> implements Iterable<T>{
           
        //头节点
        private Node head;
        //栈内个数
        private int N;
    
        public Stack(){
           
            head = new Node(null,null);
            N = 0;
        }
    
        //判断是否为空
        public boolean isEmpty(){
           
            return N == 0;
        }
    
        //返回栈中个数
        public int size(){
           
            return N;
        }
    
        //入栈
        public void push(T t){
           
            //栈后进的元素是在前面,因此使用头插法。
            head.next = new Node(t,head.next);
            N++;
        }
        //出栈
        public T pop(){
           
            Node node = head.next;
            //安全性校验
            // 若没有这个校验,栈中若没有元素,即node == null
            //此时node.next将是空指针异常
            if(node == null){
           
                return null;
            }
            //把第一个元素取出,并让头节点指向第二个节点。
            head.next = node.next;
            N--;
            return node.data;
        }
    
        class Node{
           
            private T data;
            private Node next;
    
            public Node(T data, Node next){
           
                this.data = data;
                this.next = next;
            }
        }
    
        @Override
        public Iterator<T> iterator() {
           
            return new Iterator<T>() {
           
                private Node node = head;
    
                @Override
                public boolean hasNext() {
           
                    return node.next != null;
                }
    
                @Override
                public T next() {
           
                    node = node.next;
                    return node.data;
                }
            };
        }
    }
    
    

2 逆波兰表达式求值问题

1 中缀表达式

中缀表达式就是我们平常生活中使用的表达式,例如:1+3*2,2-(1+3)等等,中缀表达式的特点是:二元运算符总是置于两个操作数中间。

2 逆波兰表达式(后缀表达式)

  1. 后缀表达式:运算符总是放在跟它相关的操作数之后。
  2. 例子:
    中缀表达式 逆波兰表达式
    a+b ab+
    a+(b-c) abc-+
    a+(b-c)*d abc-d*+
    a*(b-c)+d abc-*d+
  3. 逆波兰表达式还是从左往右看,逆波兰只是把运算符两边的操作数统一放在左边。如:ab+ 等于 a+b
  4. 解释其他例子:
    1. abc-+ 从左边开始看,遇到第一个运算符 - ,则看左边两个操作数bc 即 b-c, 设 b-c = e, 即原来式子变成 ae+,遇到第二个运算符+,则看左边两个操作数 即 a + e, 即 a + (b - c)
    2. abc-d*+ 从左边开始看,遇到第一个运算符-,则看左边两个操作数bc 即 b-c, 设 b-c = e, 即原来式子变成 aed*+,遇到第二个运算符*,则看左边两个操作数 ed 为 e * d,即 (b - c)*d 设 (b - c)*d = f,即原来式子变成af+,遇到第三个运算符 +,则看左边两个操作数af 即 a + f 即a + (b-c)*d.
    3. abc-d+ 从左边开始看,遇到第一个运算符-,则看左边两个操作数bc 即 b-c, 设 b-c = e, 即原来式子变成aed+,遇到第二个运算符*,则看左边两个操作数 ae,为a * e 即 a*(b-c) 设 a*(b-c) = f,即原来式子变成 fd+,遇到第三个运算符 +,则看左边两个操作数fd 即 f + d 即 a*(b-c) + d

3 逆波兰表达式求值

  1. 问题:给定一个只包含加减乘除四种运算的逆波兰表达式的数组表示方式,求出该逆波兰表达式的结果。

  2. 如:给定 {“3”,“17”,“15”,“-”,”*“,”18“,”6“,”/“,”+"} 求其值为9.

  3. 思路:

    1. 若你理解上面怎么从逆波兰表达式还原成中缀表达式的话,你应该惊奇的发现,似乎上面的思路就是按照从左到右顺序查看内容, 遇到运算符,则往左边(回去)看两个操作数,得到表达式,并用一个变量来代替这个表达式,然后继续从左到右。
    2. 现在是要求逆波兰表达式,那么如:ab+, 就是要求a+b咯,现在你再看上面一点的思路,得到一个运算符,回去看两个操作数,得到表达式,不就是 得到一个运算符,回去看两个操作数,计算出结果,再放回去继续嘛。
    3. 因此我们考虑下栈的特点:扫描逆波兰表达式,遇到操作数就压入栈中,遇到一个运算符则取出两个数据,计算出结果再放入栈中,直到扫描完,最后在栈中的数据便是 最后的值。
  4. 代码(stack的代码如上):

    package suanfa;
    
    /**
     * @author JIN
     * @description 逆波兰表达式求值
     * @createTime 2020-08-16 15:01
     **/
    public class ReversePolishNotation {
           
        // reverse 相反的
        // polish 波兰人
        // notation 符号
    
        public static Integer caculate(String str[]){
           
            Stack<Integer> stack = new Stack<>();
            //两个操作数
            Integer o1,o2;
            for (int i = 0; i < str.length; i++) {
           
                //注:栈是先进后出,注意除法 跟 减法 谁在前面
                //即 是 s1 - s2, 还是 s2 - s1 两者有顺序之分
                String s = str[i];
                switch (s) {
           
                    case "+":
                        o2 = stack.pop();
                        o1 = stack.pop();
                        stack.push(o1 + o2);
                        break;
                    case "-":
                        o2 = stack.pop();
                        o1 = stack.pop();
                        stack.push(o1 - o2);
                        break;
                    case "*":
                        o2 = stack.pop();
                        o1 = stack.pop();
                        stack.push(o1 * o2);
                        break;
                    case "/":
                        o2 = stack.pop();
                        o1 = stack.pop();
                        stack.push(o1 / o2);
                        break;
                    default:
                        stack.push(Integer.parseInt(s));
                }
            }
            return stack.pop();
        }
    
        public static void main(String[] args) {
           
            String str[] = {
           "3","17","15","-","*","18","6","-","+"};
            System.out.println(caculate(str));
        }
    }
    
    

你可能感兴趣的:(数据结构,数据结构,java,栈)