4、栈、计算机计算实现、中缀表达式转化前缀表达式和后缀表达式(逆波兰数)

141 阅读2分钟
栈:先进后出的结构,像子弹上膛,Java中方法的调用以及递归调用都是栈的数据结构

1、中缀表达式转后缀表达式

计算机进行计算的时候一般都是通过栈的结构进行计算的,它不能像人一样识别中缀表达式(想4 + 5 * 6),他只能利用栈的结构进行转化计算,他先转化为后缀表达式(也叫做逆波兰数)。

image.png

==代码==

//中缀表达式转化为后缀表达式  
public static Collection<String> midToSuff(Collection<String> midExpression){  
    //栈保存运算符  
    //队列保存后缀表达式  
    /*  
    1、读取到数的时候加入队列  
    2、读取到运算符的时候  
        - 如果栈为null,直接入栈  
        - 栈不为空时候,和栈顶元素进行比较  
        - 比较优先级  
            优先级高的时候,直接进栈  
        - 优先级低的时候,进行讨论  
            - 入栈元素不为右括号  
                - 排除栈顶为左括号的情况,如果为栈顶左括号直接入栈  
                - 如果栈顶不为左括号,优先级进行比较,如果栈顶元素的优先及大于要入栈的运算符,栈顶元素弹出,入队列。继续循环比较  
            - 入栈元素为右括号  
                - 栈内符号出栈,直到遇见左括号,右括号不入栈,切左括号不入队列  
     */    Stack<String> operator = new Stack<>();  
    Queue<String> suff = new LinkedList<>();  
    midExpression.stream().forEach(o -> {  
        if (StrUtil.isNumeric(o)) {  
            suff.offer(o);  
        }else {  
            if (operator.isEmpty()) {  
                operator.push(o);  
            }else {  
                if (priorityOperator(o) > priorityOperator(operator.peek())){  
                    operator.push(o);  
                }else {  
                    if(priorityOperator(o) == -3){  
                        while (priorityOperator(operator.peek()) != 3){  
                            suff.offer(operator.pop());  
                        }  
                        operator.pop();  
                    }else {  
                        while (true){  
                            if (operator.isEmpty() || priorityOperator(operator.peek()) == 3 || priorityOperator(operator.peek()) < priorityOperator(o)) {  
                                operator.push(o);  
                                break;  
                            }else {  
                                suff.offer(operator.pop());  
                            }  
                        }  
                    }  
                }  
            }  
        }  
    });  
    while (!operator.isEmpty()) {  
        suff.offer(operator.pop());  
    }  
    return suff;  
}  
  
private static int priorityOperator(String c){  
    switch (c){  
        case "+":;  
        case "-":  
            return 1;  
        case "*":;  
        case "/":  
            return 2;  
        case "(":  
            return 3;  
        case ")":  
            return -3;  
    }  
    return 0;  
}

  1. 定义栈,利用栈的结构保存运算符
  2. 读取中缀表达式,如果遇到数字直接添加到队列(或者集合)
  3. 遇到运算符分该下情况
    1. 当运算符栈为空时直接添加入栈
    2. 运算符栈不为空的时候,待入栈元素和栈顶元素做比较运算符的优先级
      1. 当待入栈运算符优先级高于栈顶运算,直接入栈
      2. 待入栈元素运算符优先级低于栈顶元素,先判断特殊情况)的情况,如果待入栈元素是右括号,则运算符出栈,并进入队列,循环进行,直到栈顶元素为(的时候,退出循环,并把(弹出栈,但不进入队列。
      3. 如果不是特殊元素,及非)且待入栈元素小于栈顶元素,此时栈顶元素出栈并进入队列,待入栈元素继续和栈顶元素进行比较,直到栈顶元素的运算级别小于等于待入栈元素或者栈为null或者栈顶元素为(的时候,待入栈元素入栈。

2、计算

通过读取后缀表达式,经过栈工具的操作进行计算

image.png

public static Number calc(Collection<String> suffExpression){  
    Stack<BigDecimal> stack = new Stack<>();  
    suffExpression.stream().forEach(o -> {  
        if (StrUtil.isNumeric(o)) {  
            stack.push(new BigDecimal(o));  
        }else {  
            stack.push(calcEnum(stack.pop(),stack.pop(),o));  
        }  
    });  
    return stack.peek();  
}

  1. 读取后缀表达式,定义栈空间
  2. 读取到数字的时候入栈
  3. 读取到操作符的时候,弹出栈顶元素和次栈顶元素,并和操作符结合计算,并把结果入栈
  4. 重复操作,直到后缀表达式集合到末端。