中缀表达式转后缀表达式(Java代码实现)

后缀表达式求值

后缀表达式又叫逆波兰表达式,其求值过程可以用到栈来辅助存储。例如要求值的后缀表达式为:1 2 3 + 4 * + 5 -,则求值过程如下:

  1. 遍历表达式,遇到数字时直接入栈,栈结构如下

    

  2. 接着读到 “+”操作符,则将栈顶和次栈顶元素出栈与操作符进行运算,执行 2 + 3操作,并将结果5压入栈中,此时栈结构如下

    

3.  继续读到4,是数字则直接压栈,此时栈结构如下

    

  4. 继续向后读取,此时读取到操作符“*”,则将栈顶和次栈顶元素出栈与操作符进行运算,即执行 5 * 4 ,然后将结果20压入栈中,此时栈结构如下

    

  5. 继续向后读取,此时读到操作符“+”,则将栈顶和次栈顶元素出栈与操作符进行运算,即执行1 + 20,然后将结果21压入栈中,此时栈结构如下

    

  6. 继续向后读取,此时读到数字5,则直接将数字压栈,栈结构如下

    

  7. 读取到最后一个为操作符,将栈顶和次栈顶元素出栈与操作符进行运算,即执行 21- 5(注意顺序 次栈顶-栈顶),然后将结果16压入栈中,此时栈结构如下

    

  此时栈顶元素即为表达式的结果。(注:为方便理解,这里栈顶指针向下移动后,上面元素直接去掉了,实际情况数据还会存在对应位置,只是通过栈顶指针读取不到,等待GC)

中缀表达式转后缀表达式

中缀表达式为我们人类能识别的方式,而后缀表达式是计算机进行运算的方式(即我们上述的过程)。

转换规则

  1)我们使用一个stack栈结构存储操作符,用一个List结构存储后缀表达式结果

  2)首先读取到数字,直接存入list中

  3)当读取到左括号"("时,直接压栈,当读取到运算符时,分两种情况讨论

    a.当运算符栈为空或者栈顶操作符的优先级小于当前运算符优先级时(如+和-的优先级低于 * 和 /),直接入栈

    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 }

  计算结果如下

总结

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

原文地址:https://www.cnblogs.com/menglong1108/p/11619896.html

时间: 2024-12-11 20:42:55

中缀表达式转后缀表达式(Java代码实现)的相关文章

Java版 中缀表达式转换为后缀表达式并求结果

基础知识 平时我们所说的一个算术表达式,例如:9+(3-1)*3+10/2即为中缀表达式,然而计算机无法计算中缀表达式的值,这是因为计算机无法进行带有左右括号和运算符的优先级这种混合运算.后缀表达式(又称 逆波兰式)的使用解决了上述问题. 上述的算术表达式的后缀表达式为:9 3 1 - 3 * + 10 2 / + 算法思想 如何计算上述后缀表达式的结果呢? 答案:从左到右扫描上述后缀表达式,然后: 1. 遇到数字入栈 2. 遇到运算符 将栈顶的前两个元素出栈,然后计算结果,并将计算的结果入栈

java中缀表达式转后缀表达式

四则运算是栈的重要应用之一 中缀表达式转后缀表达式(逆波兰算法)过程 从左到右遍历中缀表达式 数字直接输出为后缀表达式一部分 如果是符号,则判断与栈顶元素的优先级 高于栈顶元素优先级直接入栈 低于或等于栈顶优先级栈顶元素出栈并输出为后缀表达式一部分(注意这里是递归比较栈顶元素的优先级并出栈),最后将当前元素入栈直到遍历完中缀表达式,最终输出后缀表达式 下面是自己的实现源码 package com.yhq.demospringboot; import org.apache.commons.lang

数据结构Java实现06----中缀表达式转换为后缀表达式

数据结构Java实现06----中缀表达式转换为后缀表达式 本文主要内容: 表达式的三种形式 中缀表达式与后缀表达式转换算法 一.表达式的三种形式: 中缀表达式:运算符放在两个运算对象中间,如:(2+1)*3.我们从小做数学题时,一直使用的就是中缀表达式. 后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则),如:2 1 + 3 *.又比如3+(6-4/2)*5=23的后缀表达式为:3642/-5*+# (#符号为结束符

栈的应用之中缀表达式转后缀表达式

1,中缀表达式的定义及为什么要将中缀表达式转换为后缀表达式? 中缀表达式(中缀记法) 中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间.中缀表达式是人们常用的算术表示方法. 虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值.对计算机来说,计算前缀或后缀表达式的值要比中缀表达式简单. 比如,计算机计算后缀表达式的过程如下----后缀表达式的计算机求值: 从左

数据结构中缀表达式转后缀表达式以及后缀转中缀表达式

最近一直在看数据结构这本书,我相信,对于每个程序员来说,数据结构都尤为重要.为什么要学,可以看看这位博友的认识http://blog.csdn.NET/sdkfjksf/article/details/54380659 直入主题:将中缀表达式转为后缀表达式 以及将后缀表达式转为前缀表达式的实现. 关于后缀转中缀,中缀转后缀的理论介绍,请先阅读其互转的理论知识,或者我转发的这篇文章,这里不再累赘,最好参考<数据结构与算法描述Java语言版>,接下来将会用java写. 一.首先,怎么实现中缀表达式

算数表达式求值(中缀表达式转后缀表达式并求值)

中缀表达式转后缀表达式的规则:1.遇到操作数:直接输出(添加到后缀表达式中)2.栈为空时,遇到运算符,直接入栈3.遇到左括号:将其入栈4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出.5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈(如果此时栈顶的运算符为"(",则将这个运算符也压入栈中)6.最终将栈中的元素依次出栈,输出 具体代码实现: 第一步:中缀表达式转后缀表达式 1 package data.st

中缀表达式转为后缀表达式

** * 中缀表达式转后缀表达式 * * 作用:将一长串计算表达式转换为计算机易于操作的字符序列,用于计算器的设计 *  * 参与转换运算符 * +-/*()^% * * * 使用StringBuilder来保存转换出的后缀表达式 * 使用栈来操作运算符 * * * 转换原则 * 1.上述字符中()没有优先级值,+-优先级值为1,/*%优先级值为2,^优先级值为3 * 2.对于一个待计算的表达式,从左向右逐个检查每个字符 * 3.遇到数字,直接append到StringBuilder * 4.遇

经典白话算法之中缀表达式和后缀表达式

一.后缀表达式求值 后缀表达式也叫逆波兰表达式,其求值过程可以用到栈来辅助存储. 假定待求值的后缀表达式为:6  5  2  3  + 8 * + 3  +  *,则其求值过程如下: (1)遍历表达式,遇到的数字首先放入栈中,依次读入6 5 2 3 此时栈如下所示: (2)接着读到"+",则从栈中弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中. (3)然后读到8(数字入栈),将其直接放入栈中. (4)读到"*",弹出8和5,执行8*5,并将结果40压入栈中

数据结构——栈——中缀表达式和后缀表达式

什么是中缀表达式,什么是后缀表达式 我们一般看见的多项式计算都是中缀表达式构成的:1+2*3+4/3 类似这种,为什么说是中缀呢?因为它的计算符号都是在两个数中间的. 那么自然而然的明白了后缀表达式是一种计算符号在两个数后面的. 如123*+43/+ 中缀表达式和后缀表达式有什么关系? 其实仔细你就会发现,上面给出的式子其实都是一样的,只是计算的顺序在后缀表达式中你看不懂而已. 因为我们习惯去看中缀表达式的计算. 其实他们之间是可以互相转换的.他们也可以表达同一个意思,同一个计算式子. 为什么会