Infix expression turn postfix notation (Java code implementation)

Postfix expression

Postfix expression called reverse Polish notation, which can be used in the evaluation process stack to secondary storage. E.g. postfix expression is desired value: 1 2 3 * 4 + 5 + -, the evaluation process is as follows:

  1. Traversal expression directly onto the stack when a numeral, the stack structure is as follows

    

  2. Then read the "+" operator, then the top element and a secondary stack pop operation performed with the operator performs operation 2 + 3, and 5 the result onto the stack, then the stack structure is as follows

    

 

    3. Continue to read 4, a digital push directly, when the stack structure is as follows

 

    

 

  4. Continue to read back, this time reading the operator "*", the sub-stack and the top element from the stack and calculates operator, i.e. 4 * 5 performed, then the result onto the stack 20 In this case the stack structure is as follows

    

  5. Continue to read back, this time to read operator "+", the sub-stack and the top element from the stack and calculates the operator, i.e., 1 + 20 performs, then the result onto the stack 21, At this time, the stack structure is as follows

    

 

  6. Continue to read back, this time to read the number 5, the direct digital push the stack structure is as follows

 

    

 

  7. Read the last one of the operator, once the top of the stack and the top element from the stack and calculates operator, i.e. execution 21-5 (Note that the order of twice the stack - top of the stack), then the result onto the stack 16 in this case the stack structure is as follows

 

    

 

  At this time, the top element is the result of the expression. (Note: For ease of understanding, where the stack pointer moves down, the top element removed directly, actual data corresponding to the location also exists, but not read by the stack pointer, waiting GC)

Postfix infix expression turn

Infix expression way as we humans can identify, and the postfix expression is the way the computer calculates (i.e., our process described above).

 

Conversion rules

  1) We use a stack store operator stack structure, with a result List structure storage postfix

  2) first reads the number, direct deposit in list

  3) When the read-to-left bracket "(", the direct push, when the operator is read, the two cases discussed

    When a stack is empty or operator stack operator priority less than the current operator precedence. (e.g., + and - lower than the priority and * /), directly onto the stack

    b.当运算符不为空时且栈顶操作符的优先级大于或等于当前运算符优先级时,循环执行出栈操作并加入list中,直到遇到优先级小于当前运算符的元素为止。循环执行完后再将当前运算符压栈。另外需要注意的是,只有遇到右括号时,左括号才出栈

  4) 当遇到右括号")"时,循环执行出栈操作并加入到list中,直到遇到左括号为止。并将左括号弹出,但不加入list中

  5) 表达式的值读取完后,将操作符栈中的所有元素弹出并加入到list中

  执行完上面步骤后,list中存储的顺序即为我们转换后的后缀表达式的结果

转换实例

  下面利用上面定义的转换规则,将表达式 1+((2+3)*4)-5 以图解的方式描述其转换过程

  1.首先定义一个存储操作符的栈 Stack<String> stack = new Stack<>() ,和一个存储最终后缀表达式的列表 List<String> list = new ArrayList<>()

  2.读取表达式,首先读取到数字 1 ,按照上述规则,直接添加至list中。此时stack和list结构如下

  

  3.然后读取到操作符 + ,此时stack为空,按照上述规则,直接入栈,此时stack和list结构如下

  

 

  4.接下来的两次读取都是左括号,按照我们的规则,左括号直接入栈,此时stack和list结构如下

 

  

 

  5.接着读取到数字2,按照我们的规则,数字直接加入list中,此时stack和list结构如下

 

  

 

  6.接着读取到操作符+,按照我们的规则,此时栈不为空且栈顶元素为左括号,而只有遇到右括号时,左括号才出栈,所以+运算符直接入栈,此时stack和list结构如下

 

  

 

  7. 接着读取到数字3,根据我们的规则,数字直接加入list中,此时stack和list结构如下

  

 

  8. 继续向后读取,读到到右括号 ")",按照我们的规则,执行stack出栈并加入list中操作,直到遇到左括号,并将左括号弹出,但不加入list中,此时stack和list结构如下

  

 

  9.接着读取到操作符 * ,按照我们的规则,此时栈顶元素为左括号,只需将操作符压栈即可,此时stack和list结构如下

 

  

 

  10.接下来读取到数字4,按照规则直接将数字加入list中即可,此时stack和list结构如下

 

  

 

  11.接下来读取到右括号")",按照我们的规则,执行stack出栈并加入list中操作,直到遇到左括号,并将左括号弹出,但不加入list中,此时stack和list结构如下

 

  

 

  12.继续向后读取,此时读取到操作符-,按照我们的规则,当栈不为空且当前优先级小于等于栈顶操作符优先级时,循环执行出栈并加入list操作。循环执行完再将当前操作符入栈

 

  

 

  13.读取最后一个元素为数字5,按照规则,直接加入list中即可。当表达式读取完后,依此弹出操作符栈中的所有元素,并加入list中,此时stack和list结构如下

 

  

 

  此时list中的顺序即为我们转换后的后缀表达式的顺序,即:1 2 3 + 4 * + 5 -

转换代码

 1 private static List<String> parseToSuffixExpression(List<String> expressionList) {
 2         //创建一个栈用于保存操作符
 3         Stack<String> opStack = new Stack<>();
 4         //创建一个list用于保存后缀表达式
 5         List<String> suffixList = new ArrayList<>();
 6         for(String item : expressionList){
 7             //得到数或操作符
 8             if(isOperator(item)){
 9                 //是操作符 判断操作符栈是否为空
10                 if(opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())){
11                     //为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符直接压栈
12                     opStack.push(item);
13                 }else {
14                     //否则将栈中元素出栈如队,直到遇到大于当前操作符或者遇到左括号时
15                     while (!opStack.isEmpty() && !"(".equals(opStack.peek())){
16                         if(priority(item) <= priority(opStack.peek())){
17                             suffixList.add(opStack.pop());
18                         }
19                     }
20                     //当前操作符压栈
21                     opStack.push(item);
22                 }
23             }else if(isNumber(item)){
24                 //是数字则直接入队
25                 suffixList.add(item);
26             }else if("(".equals(item)){
27                 //是左括号,压栈
28                 opStack.push(item);
29             }else if(")".equals(item)){
30                 //是右括号 ,将栈中元素弹出入队,直到遇到左括号,左括号出栈,但不入队
31                 while (!opStack.isEmpty()){
32                     if("(".equals(opStack.peek())){
33                         opStack.pop();
34                         break;
35                     }else {
36                         suffixList.add(opStack.pop());
37                     }
38                 }
39             }else {
40                 throw new RuntimeException("有非法字符!");
41             }
42         }
43         //循环完毕,如果操作符栈中元素不为空,将栈中元素出栈入队
44         while (!opStack.isEmpty()){
45             suffixList.add(opStack.pop());
46         }
47         return suffixList;
48     }
49     /**
50      * 判断字符串是否为操作符
51      * @param op
52      * @return
53      */
54     public static boolean isOperator(String op){
55         return op.equals("+") || op.equals("-") || op.equals("*") || op.equals("/");
56     }
57 
58     /**
59      * 判断是否为数字
60      * @param num
61      * @return
62      */
63     public static boolean isNumber(String num){
64         return num.matches("\\d+");
65     }
66 
67     /**
68      * 获取操作符的优先级
69      * @param op
70      * @return
71      */
72     public static int priority(String op){
73         if(op.equals("*") || op.equals("/")){
74             return 1;
75         }else if(op.equals("+") || op.equals("-")){
76             return 0;
77         }
78         return -1;
79     }

 

  这里为了方便操作,将原中缀表达式字符串转换为list结构,转换list的代码如下

 1 /**
 2      * 将表达式转为list
 3      * @param expression
 4      * @return
 5      */
 6     private static List<String> expressionToList(String expression) {
 7         int index = 0;
 8         List<String> list = new ArrayList<>();
 9         do{
10             char ch = expression.charAt(index);
11             if(ch < 47 || ch > 58){
12                 //是操作符,直接添加至list中
13                 index ++ ;
14                 list.add(ch+"");
15             }else if(ch >= 47 && ch <= 58){
16                 //是数字,判断多位数的情况
17                 String str = "";
18                 while (index < expression.length() && expression.charAt(index) >=47 && expression.charAt(index) <= 58){
19                     str += expression.charAt(index);
20                     index ++;
21                 }
22                 list.add(str);
23             }
24         }while (index < expression.length());
25         return list;
26     }

  注:char类型本质为int类型,查看assic码表可知,0~9对应的char在 47~58之间,所以代码依此来判断是数字还是操作符。另外代码中有判断多位数情况,请注意

  下面展示测试代码

1 public static void main(String []args){
2 
3         String expression = "1+((2+3)*4)-5";
4         List<String> expressionList = expressionToList(expression);
5         System.out.println("expressionList="+expressionList);
6         //将中缀表达式转换为后缀表达式
7         List<String> suffixList = parseToSuffixExpression(expressionList);
8         System.out.println(suffixList);
9 }

  测试结果如下:

  与我们上述描述的结果相同,以上即为中缀表达式转换后缀表达式的过程及相关代码。另外附上根据后缀表达式求值的代码,感兴趣的可以参考

 1  /**
 2      * 根据后缀表达式list计算结果
 3      * @param list
 4      * @return
 5      */
 6     private static int calculate(List<String> list) {
 7         Stack<Integer> stack = new Stack<>();
 8         for(int i=0; i<list.size(); i++){
 9             String item = list.get(i);
10             if(item.matches("\\d+")){
11                 //是数字
12                 stack.push(Integer.parseInt(item));
13             }else {
14                 //是操作符,取出栈顶两个元素
15                 int num2 = stack.pop();
16                 int num1 = stack.pop();
17                 int res = 0;
18                 if(item.equals("+")){
19                     res = num1 + num2;
20                 }else if(item.equals("-")){
21                     res = num1 - num2;
22                 }else if(item.equals("*")){
23                     res = num1 * num2;
24                 }else if(item.equals("/")){
25                     res = num1 / num2;
26                 }else {
27                     throw new RuntimeException("运算符错误!");
28                 }
29                 stack.push(res);
30             }
31         }
32         return stack.pop();
33     }

  测试运算代码如下

 1 public static void main(String []args){
 2 
 3         String expression = "1+((2+3)*4)-5";
 4         List<String> expressionList = expressionToList(expression);
 5         System.out.println("中缀表达式转为list结构="+expressionList);
 6         //将中缀表达式转换为后缀表达式
 7         List<String> suffixList = parseToSuffixExpression(expressionList);
 8         System.out.println("对应的后缀表达式列表结构="+suffixList);
 9         //根据后缀表达式计算结果
10         int calculateResult = calculate(suffixList);
11         System.out.printf(expression+"=%d\n",calculateResult);
12 }

  计算结果如下

 

总结

  中缀表达式转后缀表达式的难点在于转换规则,当然这个规则是研究算法的人已经帮我们制定好的,我们只需要按照这个规则实现代码即可。如果上述代码有问题可在留言区回复,谢谢

 

Guess you like

Origin www.cnblogs.com/menglong1108/p/11619896.html