• 数据结构 栈解析 算法表达式


    1 本文目标

    分析用堆栈解析算术表达式的基本方法。给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式。

    2 中缀表达式和后缀表达式

    中缀表达式就是通常所说的算术表达式,比如(1+2)*3-4。

    后缀表达式是指通过解析后,运算符在运算数之后的表达式,比如上式解析成后缀表达式就是12+3*4-。这种表达式可以直接利用栈来求解。

    3 运算符的优先级

    优先级 运算符
    1 括号()
    2 负号-
    3 乘方**
    4 乘*,除/,求余%
    5 加+,减-
    6 小于<,小于等于<=,大于>,大于等于>=
    7 等于==,不等于!=
    8 逻辑与&&
    9 逻辑或||


    大致的规律是,一元运算符 > 二元运算符 > 多元运算符。

    4 利用堆栈解析算术表达式的过程

    中缀表达式翻译成后缀表达式的方法如下:

    (1)从右向左依次取得数据ch。

    (2)如果ch是操作数,直接输出。

    (3)如果ch是运算符(含左右括号),则:
          a:如果ch = '(',放入堆栈。
          b:如果ch = ')',依次输出堆栈中的运算符,直到遇到'('为止。
          c:如果ch不是')'或者'(',那么就和堆栈顶点位置的运算符top做优先级比较。
              1:如果ch优先级比top高,那么将ch放入堆栈。
              2:如果ch优先级低于或者等于top,那么输出top,然后将ch放入堆栈。

    (4)如果表达式已经读取完成,而堆栈中还有运算符时,依次由顶端输出。

    如果我们有表达式(A-B)*C+D-E/F,要翻译成后缀表达式,并且把后缀表达式存储在一个名叫output的字符串中,可以用下面的步骤。

    (1)读取'(',压入堆栈,output为空
    (2)读取A,是运算数,直接输出到output字符串,output = A
    (3)读取'-',此时栈里面只有一个'(',因此将'-'压入栈,output = A
    (4)读取B,是运算数,直接输出到output字符串,output = AB
    (5)读取')',这时候依次输出栈里面的运算符'-',然后就是'(',直接弹出,output = AB-
    (6)读取'*',是运算符,由于此时栈为空,因此直接压入栈,output = AB-
    (7)读取C,是运算数,直接输出到output字符串,output = AB-C
    (8)读取'+',是运算符,它的优先级比'*'低,那么弹出'*',压入'+",output = AB-C*
    (9)读取D,是运算数,直接输出到output字符串,output = AB-C*D
    (10)读取'-',是运算符,和'+'的优先级一样,因此弹出'+',然后压入'-',output = AB-C*D+
    (11)读取E,是运算数,直接输出到output字符串,output = AB-C*D+E
    (12)读取'/',是运算符,比'-'的优先级高,因此压入栈,output = AB-C*D+E
    (13)读取F,是运算数,直接输出到output字符串,output = AB-C*D+EF
    (14)原始字符串已经读取完毕,将栈里面剩余的运算符依次弹出,output = AB-C*D+EF/-

    5 计算算术表达式

    当有了后缀表达式以后,运算表达式的值就非常容易了。可以按照下面的流程来计算。

    (1)从左向右扫描表达式,一个取出一个数据data
    (2)如果data是操作数,就压入堆栈
    (3)如果data是操作符,就从堆栈中弹出此操作符需要用到的数据的个数,进行运算,然后把结果压入堆栈
    (4)如果数据处理完毕,堆栈中最后剩余的数据就是最终结果。

    比如我们要处理一个后缀表达式1234+*+65/-,那么具体的步骤如下。

    (1)首先1,2,3,4都是操作数,将它们都压入堆栈
    (2)取得'+',为运算符,弹出数据3,4,得到结果7,然后将7压入堆栈
    (3)取得'*',为运算符,弹出数据7,2,得到数据14,然后将14压入堆栈
    (4)取得'+',为运算符,弹出数据14,1,得到结果15,然后将15压入堆栈
    (5)6,5都是数据,都压入堆栈
    (6)取得'/',为运算符,弹出数据6,5,得到结果1.2,然后将1.2压入堆栈
    (7)取得'-',为运算符,弹出数据15,1.2,得到数据13.8,这就是最后的运算结果

    代码:

    public class EvaluateExpression {
        
        public static void main(String [] args) {
            Scanner input = new Scanner(System.in);
            String expression = input.nextLine();
            expression = EvaluateExpression.insertBlanks(expression);
            
            int result = evaluateExpression(expression);
            System.out.println(result);
        }
        
        
        public static int evaluateExpression(String expression) {
            
            Stack<Integer> operandStack = new Stack<>();
            
            Stack<Character> operatorStack = new Stack<>();
            
            
            String [] tokens = expression.split(" ");
            
            for(int i=0; i<tokens.length; i++) {
                if(tokens[i].length() == 0) {
                    continue;
                }else if(tokens[i].equals("+") || tokens[i].equals("-")) {
                    while(!operatorStack.isEmpty() && 
                            (operandStack.peek() == '*' ||
                            operandStack.peek() == '-' || 
                            operandStack.peek() == '/' ||
                            operandStack.peek() == '+')
                            ) {
                        processAnOperator(operandStack, operatorStack);
                    }
                    operatorStack.push(tokens[i].charAt(0));
                }else if(tokens[i].equals("/") || tokens[i].equals("*")) {
                    while(!operatorStack.isEmpty() && (operatorStack.peek() == '/' 
                            || operatorStack.peek() == '*')) {
                        processAnOperator(operandStack, operatorStack);
                    }
                    operatorStack.push(tokens[i].charAt(0));
                }else if(tokens[i].trim().equals("(")) {
                    operatorStack.push('(');
                }else if(tokens[i].trim().equals(")")) {
                    while(operatorStack.peek() != '(') {
                        processAnOperator(operandStack, operatorStack);
                    }
                    operatorStack.pop(); // 出栈 ‘(’
                }else {
                    operandStack.push(new Integer(tokens[i]));
                }
                
            }
            while(!operatorStack.isEmpty()) {
                processAnOperator(operandStack, operatorStack);
            }
            return operandStack.pop();
        }
        
        
        
        public static void processAnOperator(Stack<Integer> operandStack,Stack<Character> operatorStack) {
             char op = operatorStack.pop();
             int op1 = operandStack.pop();
             int op2 = operandStack.pop();
             
             if(op == '+') {
                 operandStack.push(op1 + op2);
             }else if(op == '-') {
                 operandStack.push(op2 - op1);
             }else if(op == '*'){
                 operandStack.push(op2 * op1);
             }else if(op == '/') {
                 operandStack.push(op2 / op1);
             }
             
        }
        
        
        
        public static String insertBlanks(String s) {
            StringBuilder result = new StringBuilder();
        
            for(int i=0; i<s.length(); i++) {
                if(s.charAt(i) == '(' || s.charAt(i) == ')'
                        || s.charAt(i) == '+' || s.charAt(i) == '-' 
                        || s.charAt(i) == '/' || s.charAt(i) == '*') {
                    result.append(' ');
                    result.append(s.charAt(i));
                    result.append(' ');
                    
                }else {
                    result.append(s.charAt(i));
            
                }
                
            }
            return result.toString();
        }
    }
  • 相关阅读:
    SC Alibaba20211102 Nacos 微服务框架结构 SerivceImplOrder <OpenFeign> SerivceImplMember 群
    SC Alibaba20211030 Nacos 微服务框架结构 SerivceImplOrder <OpenFeign> SerivceImplMember
    SC Alibaba20211028 Nacos 微服务框架结构 SerivceImplMember
    SC Alibaba20211022 Nacos 负载均衡 rest|feign(ribbon) ----@loadbalancer
    springboot启动多个实例
    SC Alibaba20211019 Nacos 手写LoadBalancer LoadBalancerClient
    SC Alibaba20211018 Nacos discoveryCient-restTemplate调用
    SC Alibaba20211017 Nacos 命令 测试服务、配置功能 postman
    mysql性能测试(SQL_CALC_FOUND_ROWS)
    GIS相关的一些常用操作(持续记录...)
  • 原文地址:https://www.cnblogs.com/zquan/p/9368653.html
Copyright © 2020-2023  润新知