zoukankan      html  css  js  c++  java
  • 栈的应用---括号的匹配和算术表达式的计算

      括号的匹配,就是给你一个表达式,比如a {b [c (d  + e) / 2  - f  ]  + 1}, 看看里面的括号是否匹配。怎么看呢?从左到右扫描表达式,遇到左括号{[(,就把它存起来,遇到其它字符,则忽略,遇到右括号时,把前面刚加进去的左括号取出来,看是否匹配。如果匹配,就继续向下走,如果不匹配,就是不匹配了。存什么地方呢?假设存数组。拿a {b [c (d  + e) / 2  - f  ]  + 1} 举例一下,从a开始,向后扫描,a是字符,忽略; { 是左括号,放到数组0位置;b是字符,忽略;[左括号,放到数组1位置;c是字符,忽略;(左括号,放到数组2的位置;d+e都是字符,忽略;)是右字符,这时就要从数组中拿出字符了,拿出哪一个呢?很显然,是拿出位置2中的元素(,匹配吗?()匹配,那继续向下走,同时把2位置处的元素删除;/2-f都是字符,忽略;]右括号,继续从数组中拿出括号,这时要拿位置1处的元素,[,[]匹配,继续向下走,同时把1位置处的元素删除;+1都是字符,忽略;}右括号,继续从数组中拿出括号,这时要拿位置0处的元素{,{}匹配,表达式没有剩下字符了,整个表达式是匹配的。匹配过程中,可以看到左括号添加和取出,顺序是相反的,添加的时候是0,1,2,取出的时候,是2,1,0. 这不就是栈吗?重新描述一下表达式的匹配过程,遇到左括号,push()进栈,遇到右括号,pop()出栈,看pop()出来的元素是否和右括号匹配。

       {([都是左括号,push进栈;)是右括号,pop(), (出栈,()匹配;继续 ,]是右括号,pop(),[出栈,[]匹配;继续,}右括号,pop(),{出栈,{}匹配成功;整个表达式也成功了。

      再看几个不匹配的表达式,比如{ [ ( ] ) },

       { [ (依次入栈,碰到],pop(), (出栈,(] 不匹配。再看一个 [ ( ) ] },

     

        [ (依次入栈,碰到), pop(), (出栈,() 匹配;碰到],pop(), [出栈,[]匹配;碰到},此时,栈为空,不能再pop()了,也就是没有左括号和}匹配。再看{ [ ( ) ],

      { [ (依次入栈,) ]依次出栈,都匹配,但是栈中还剩余一个{,也就是没有右括号和它匹配。

       经过上面的分析,括号匹配的实现也有点清晰了。创建一个栈,从左右向扫描表达式,就是循环遍历表达式,遇到左括号,调用push()方法入栈,遇到右括号,要先判断栈是否为空,如果为空,那肯定没有对应的左括号,也就不匹配,直接return,不用再循环了。如果栈不为空,调用pop()方法,弹出一个左括号,看是否匹配,如果不匹配,也是return,不用再循环了,如果匹配,再继续循环。如果循环完成了,也是匹配的,但还要判断栈是否为空,如果为空,整个表达式就是匹配的,如果栈不为空,整个表达式是不匹配的。

      创建栈,可以使用自己的实现,也可以使用Java提供的LinkedList类,LinkedList实现了栈的API

    package dataStructuresAndAbstractions.stack;
    
    import java.util.LinkedList;
    
    public class BalanceChecker {
        public static boolean checkBalance(String expression){
            LinkedList<Character> openDelimiterStack = new LinkedList<>();
    
            int charCount = expression.length();
            boolean isBanlanced = true;
            int index = 0;
            char nextChar = ' ';
    
            while (isBanlanced && (index < charCount)){
                nextChar = expression.charAt(index);
                switch (nextChar){
    
                    case '(':
                    case '{':
                    case '[':
                        openDelimiterStack.push(nextChar);
                        break;
    
                    case ')':
                    case ']':
                    case '}':
                        if(openDelimiterStack.isEmpty()){
                            isBanlanced= false;
                        } else {
                            char delimiter = openDelimiterStack.pop();
                            isBanlanced = isPaired(delimiter, nextChar);
                        }
                        break;
                }
                index++;
            }
    
    
            if (!openDelimiterStack.isEmpty()){
                isBanlanced = false;
            }
    
            return isBanlanced;
    
        }
    
        private static boolean isPaired(char open, char close){
            return (open == '(' && close == ')') ||
                    (open == '[' && close == ']') ||
                    (open == '{' && close == '}');
        }
    
        public static void main(String[] args) {
            String expression = "a {b [c (d + e)/2 - f] + 1}";
            boolean isBalanced = BalanceChecker.checkBalance(expression);
            if (isBalanced)
                System.out.println(expression + " is balanced");
            else System.out.println(expression + " is not balanced");
        }
    }

      计算带有括号的算术表达式,比如"(1+((2+3)*(4*5)))", 实现的思路是,先创建两个栈,一个是存放操作数字符,一个存放操作符字符,再从左到右循环遍历字符串,忽略左括号,遇到数字,压入到数字字符栈中,遇到操作符,压入到操作符栈中,遇到右括号,弹出一个操作符和两个操作数进行计算,计算完成后,再压入到数字字符栈中,循环完毕,数字栈中只有一个数,这个数就是表达式的计算结果。忽略(,1压入操作数栈,+压入操作符栈。忽略((,2压入操作数栈,+压入操作符栈,3压入操作数栈。

       此时遇到了右扩号,弹出2,3,和+,执行3+2,把结果5压入数字栈

       继续向下走,*入操作符栈,忽略(,4压入操作数栈,*压入操作符栈,5压入操作数栈)))

       遇到了右扩号,弹出5,4,和*,计算4*5,得出20放入操作数栈中

       向下走,还是右括号,弹出20,5,和*,把20*5的结果100,放入到操作数栈中

      还剩最后一个右括号,再把100,1和+弹出,把结果101放到操作数栈中,

       至此,表达式遍历完毕,操作符数栈中,只剩下一个数字,这个数字,就是表达式的计算结果。

    import java.util.LinkedList;
    
    public class StackEvaluate {
        public static void main(String[] args) {
            LinkedList<String> ops = new LinkedList<>();
            LinkedList<Double> vals = new LinkedList<>();
            String expression = "(1+((2+3)*(4*5)))";
    
            for (int i = 0; i < expression.length(); i++) {
                String s = expression.charAt(i) + "";
                if (s.equals("(")) {
                    ;
                } else if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {
                    ops.push(s);
                } else if (s.equals(")")) {
                    String op = ops.pop();
                    double v = vals.pop();
    
                    if (op.equals("+")) {
                        v = vals.pop() + v;
                    } else if (op.equals("-")) {
                        v = vals.pop() - v;
                    } else if (op.equals("*")) {
                        v = vals.pop() * v;
                    } else if (op.equals("/")) {
                        v = vals.pop();
                    }
    
                    vals.push(v);
                } else {
                    vals.push(Double.parseDouble(s));
                }
            }
    
            System.out.println(vals.pop());
        }
    }
  • 相关阅读:
    5个最佳WordPress通知栏插件
    最新lombok插件和IDEA2020.1不兼容,Plugin "Lombok" is incompatible (until build 193.SNAPSHOT < IU-201.6668....
    nuxt中localstorage的替代方案
    nuxt或者vue,axios中如何发送多个请求
    wordpress nginx详细环境配置安装命令和相关问题解决
    [no_perms] Private mode enable, only admin can publish this module
    vue bootstrap中modal对话框不显示遮挡打不开
    vue监听当前页面的地址变化/路由变化
    来看看JDK13的81个新特性和API
    Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test java.lang.IllegalStateException
  • 原文地址:https://www.cnblogs.com/SamWeb/p/15427353.html
Copyright © 2011-2022 走看看