zoukankan      html  css  js  c++  java
  • 使用栈实现解析算术表达式

    目的

      1. 使用栈将中缀表达式转换成后缀表达式

      2. 使用后缀表达式求算术值


    注意:

      因为是简单实践,所以代码逻辑已经简化,比如只能对个位数的加减乘除进行解析、没有设异常处理等


    一:需要实现一个栈

    这个没什么好说的,只是一个结构很简单的栈

     1 public class Stack {
     2 
     3     private int maxSize;
     4     private int top;
     5     private Object[] stackArr;
     6 
     7     public Stack(int maxSize) {
     8         this.maxSize = maxSize;
     9         stackArr = new Object[maxSize];
    10         top = -1;
    11     }
    12 
    13     public void push(Object i){
    14         stackArr[++top] = i;
    15     }
    16 
    17     public Object pop(){
    18         return stackArr[top--];
    19     }
    20 
    21     public Object peek(){
    22         return stackArr[top];
    23     }
    24 
    25     public Object peekN(int n) {
    26         return stackArr[n];
    27     }
    28 
    29     public boolean isEmpty(){
    30         return (top == -1);
    31     }
    32 
    33     public boolean isFull(){
    34         return (top == maxSize-1);
    35     }
    36 
    37     public int size(){
    38         return top+1;
    39     }
    40 
    41     public void dispaly(String s) {
    42         System.out.print(s + "		" + "Stack {bottom-->top}: ");
    43         for (int i = 0; i < size(); i++) {
    44             System.out.print(peekN(i) + "	");
    45         }
    46         System.out.println();
    47     }
    48 }
    View Code

     二:将中缀表达式转换成后缀表达式

    这里需要处理的操作符有:"+"、"-"、 "*"、 "/"、 "(" 、")"

    需要关注的有四点:

    (1)操作符的优先级:  "( )"    >    "* /"    >    "+ -"

    (2)同级操作符的操作顺序是无所谓的,只要操作数顺序不变即可

    (3)遇到高优先级操作时,栈的压栈和出栈的实现

    (4)栈存的是操作符

      1 public class InfixToPostfix {
      2 
      3     private Stack stack;
      4     private String input;
      5     private StringBuilder output;
      6     /**
      7      * 加减类型
      8      */
      9     private static final int ADD_SUB_TYPE = 1;
     10     /**
     11      * 乘除类型
     12      */
     13     private static final int MUL_DIV_TYPE = 2;
     14 
     15     public InfixToPostfix(String input) {
     16         this.input = input;
     17         stack = new Stack(input.length());
     18         output = new StringBuilder();
     19     }
     20 
     21     public String doTransform() {
     22         String[] split = input.split("");
     23         for (int i = 0; i < split.length; i++) {
     24             stack.dispaly("FOR		" + split[i]);
     25             switch (split[i]) {
     26                 case "+":
     27                 case "-":
     28                     // 对"+"、"-"操作符进行处理
     29                     manageOperator(split[i], ADD_SUB_TYPE);
     30                     break;
     31                 case "*":
     32                 case "/":
     33                     // 对"*"、"/"操作符进行处理
     34                     manageOperator(split[i], MUL_DIV_TYPE);
     35                     break;
     36                 case "(":
     37                     // 左括号表示下一个计算块拥有更高一级优先级,直接入栈即可
     38                     stack.push(split[i]);
     39                     break;
     40                 case ")":
     41                     // 对")"操作符进行处理
     42                     manageParen(split[i]);
     43                     break;
     44                 default:
     45                     // 拼接输出结果
     46                     output.append(split[i]);
     47                     break;
     48             }
     49         }
     50         // 将栈内剩余的元素全部出栈
     51         while (!stack.isEmpty()) {
     52             stack.dispaly("WHILE	");
     53             String pop = (String) stack.pop();
     54             output.append(pop);
     55         }
     56         stack.dispaly("END		");
     57         return output.toString();
     58     }
     59 
     60     /**
     61      * 对右括号操作符进行处理
     62      * @param rightParen
     63      */
     64     private void manageParen(String rightParen) {
     65         // 取出当前栈顶元素
     66         while (!stack.isEmpty()) {
     67             String top = (String) stack.pop();
     68             // 有两种情况:
     69             // 1. 取出的是 "(",说明被括号括起来的计算块已经结束,直接break掉循环即可。
     70             // 2. 取出来的是其他操作符(+-*/),出栈并打印即可。这里不能break,因为操作符可能有多个,要一直出栈,直到取到 "("
     71             if (top.equals("(")) {
     72                 break;
     73             } else {
     74                 output.append(top);
     75             }
     76         }
     77     }
     78 
     79     /**
     80      * 对加减乘除操作符进行处理
     81      * @param operator
     82      * @param type
     83      */
     84     private void manageOperator(String operator, int type) {
     85         // 当栈不为空时,需要判断
     86         while (!stack.isEmpty()) {
     87             // 先取出栈顶元素
     88             String top = (String) stack.pop();
     89             // 此时,有两种情况:
     90             // 1. 取出的是 "(" 左括号,说明此时正在进行更高优先级的计算(也就是括号内的计算),所以需要把出栈 "(" 重新入栈,并break掉循环。最后将传过来的的操作符入栈。
     91             // 2. 取出的是其他操作符(+-*/),需要进行优先级判断。
     92             //      2.1 取出操作符优先级比读取的(即传过来的)高,说明应该执行上一个计算块,所以要将取出的操作符出栈并打印,break掉循环。最后将传过来的的操作符入栈。
     93             //      2.2 取出操作符优先级比读取的(即传过来的)低或者相等,说明应该或可以先执行下一个计算块,所以要将取出的操作符重新入栈,并break掉循环。最后将传过来的的操作符入栈。
     94             if (top.equals("(")) {
     95                 stack.push(top);
     96                 break;
     97             } else {
     98                 // 确定取出来的操作符的类型
     99                 int topType = 0;
    100                 if (top.equals("+") || top.equals("-")) {
    101                     // 类型为加减
    102                     topType = 1;
    103                 } else {
    104                     // 类型为乘除
    105                     topType = 2;
    106                 }
    107                 // 与传过来的类型比较
    108                 if (topType > type) {
    109                     output.append(top);
    110                 } else {
    111                     stack.push(top);
    112                     break;
    113                 }
    114             }
    115         }
    116         // 将传过来的操作符入栈
    117         stack.push(operator);
    118     }
    119 }
    View Code

    测试:

    1 @Test
    2 public void fun1(){
    3     // String input = "A+B-C";
    4     String input = "A*(B+C)-D/(E+F)";
    5     InfixToPostfix trans = new InfixToPostfix(input);
    6     String output = trans.doTransform();
    7     System.out.println("----------------------");
    8     System.out.println("后缀表达式为: " + output);
    9 }

    结果:

    FOR        A        Stack {bottom-->top}: 
    FOR        *        Stack {bottom-->top}: 
    FOR        (        Stack {bottom-->top}: *    
    FOR        B        Stack {bottom-->top}: *    (    
    FOR        +        Stack {bottom-->top}: *    (    
    FOR        C        Stack {bottom-->top}: *    (    +    
    FOR        )        Stack {bottom-->top}: *    (    +    
    FOR        -        Stack {bottom-->top}: *    
    FOR        D        Stack {bottom-->top}: -    
    FOR        /        Stack {bottom-->top}: -    
    FOR        (        Stack {bottom-->top}: -    /    
    FOR        E        Stack {bottom-->top}: -    /    (    
    FOR        +        Stack {bottom-->top}: -    /    (    
    FOR        F        Stack {bottom-->top}: -    /    (    +    
    FOR        )        Stack {bottom-->top}: -    /    (    +    
    WHILE            Stack {bottom-->top}: -    /    
    WHILE            Stack {bottom-->top}: -    
    END                Stack {bottom-->top}: 
    ----------------------
    后缀表达式为: ABC+*DEF+/-

     三:使用后缀表达式求算术值

    需要注意的是:

      栈存的是操作数,和上面的相反

     1 public class ParsePostfix {
     2 
     3     private Stack stack;
     4     private String input;
     5     private StringBuilder sb;
     6 
     7     public ParsePostfix(String input) {
     8         this.input = input;
     9         stack = new Stack(input.length());
    10         sb = new StringBuilder();
    11     }
    12 
    13     public int doParse(){
    14         for (int i = 0; i < input.length(); i++) {
    15             char c = input.charAt(i);
    16             // 两种情况:
    17             // 1. 传过来的是一个数字,直接压入栈
    18             // 2. 传过来的是一个操作符,那就取两个栈内元素,进行算术处理,并将结果压入栈
    19             if (c >= '0' && c <= '9') {
    20                 // 直接压入栈,需要转成int,网上找的,-'0' 即可
    21                 stack.push(c - '0');
    22             } else {
    23                 int result = 0;
    24                 // 取两个栈内元素,进行算术处理
    25                 int num1 = (int) stack.pop();
    26                 int num2 = (int) stack.pop();
    27                 switch (c) {
    28                     case '+':
    29                         result = num2 + num1;
    30                         break;
    31                     case '-':
    32                         result = num2 - num1;
    33                         break;
    34                     case '*':
    35                         result = num2 * num1;
    36                         break;
    37                     case '/':
    38                         result = num2 / num1;
    39                         break;
    40                 }
    41                 stack.push(result);
    42             }
    43         }
    44         int finalResult = (int) stack.pop();
    45         return finalResult;
    46     }
    47 }
    View Code

     测试:

    1 @Test
    2 public void fun2(){
    3     String input = "531-+";
    4     ParsePostfix pp = new ParsePostfix(input);
    5     int i = pp.doParse();
    6     System.out.println(i);
    7 }

    结果:

    7

     四:两者结合测试

     1 public static void main(String[] args) {
     2     String input = "5+3-5*8/2";
     3     InfixToPostfix trans = new InfixToPostfix(input);
     4     String output = trans.doTransform();
     5     System.out.println("----------------------");
     6     System.out.println("后缀表达式为: " + output);
     7     System.out.println("----------------------");
     8     ParsePostfix pp = new ParsePostfix(output);
     9     int result = pp.doParse();
    10     System.out.println("最终结果为: " + result);
    11 }

    结果:

    FOR        5        Stack {bottom-->top}: 
    FOR        +        Stack {bottom-->top}: 
    FOR        3        Stack {bottom-->top}: +    
    FOR        -        Stack {bottom-->top}: +    
    FOR        5        Stack {bottom-->top}: +    -    
    FOR        *        Stack {bottom-->top}: +    -    
    FOR        8        Stack {bottom-->top}: +    -    *    
    FOR        /        Stack {bottom-->top}: +    -    *    
    FOR        2        Stack {bottom-->top}: +    -    *    /    
    WHILE              Stack {bottom-->top}: +    -    *    /    
    WHILE              Stack {bottom-->top}: +    -    *    
    WHILE              Stack {bottom-->top}: +    -    
    WHILE              Stack {bottom-->top}: +    
    END                 Stack {bottom-->top}: 
    ----------------------
    后缀表达式为: 53582/*-+
    ----------------------
    最终结果为: -12

  • 相关阅读:
    第七周-学习进度条
    《梦断代码》阅读笔记01
    第六周-学习进度条
    构建之法阅读笔记03
    结对项目开发(石家庄地铁乘车系统)
    第五周-学习进度条
    第四周-学习进度条
    HDU--1272 小希的迷宫(并查集判环与联通)
    HDU--1856 More is better(简单带权并查集)
    HDU--3635 带权并查集
  • 原文地址:https://www.cnblogs.com/shadowdoor/p/9221139.html
Copyright © 2011-2022 走看看