李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
数据结构学习--中缀表达式转换为后缀表达式
Leefs
2020-01-30 AM
2507℃
0条
# 数据结构学习--中缀表达式转换为后缀表达式 ### 前言 大家看到,后缀表达式适合计算机进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将中缀表达式转成后缀表达式。 ### 步骤 ``` 1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2; 2. 从左至右扫描中缀表达式; 3. 遇到操作数时,将其压s2; 4. 遇到运算符时,比较其与s1栈顶运算符的优先级; 4.1 如果s1为空,或栈顶运算符为左括号"(",则直接将此运算符入栈; 4.2 否则,若优先级比栈顶运算符的高,也将运算符压入s1; 4.3 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较; 5. 遇到括号时: 5.1 如果是左括号"(",则直接压入s1 5.2 如果是右括号")",则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃 6. 重复步骤2至5,直到表达式的最右边 7. 将s1中剩余的运算符依次弹出并压入s2 8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式 ``` **举例说明:** **将中缀表达式**"1+((2+3) X 4)-5"转换为后缀表达式的过程如下 | 扫描到的元素 | s2(栈底->栈顶) | s1 (栈底->栈顶) | 说明 | | ------------ | ---------------------- | --------------- | ---------------------------------- | | 1 | 1 | 空 | 数字,直接入栈 | | + | 1 | + | s1为空,运算符直接入栈 | | ( | 1 | + ( | 左括号,直接入栈 | | ( | 1 | + ( ( | 同上 | | 2 | 1 2 | + ( ( | 数字 | | + | 1 2 | + ( ( + | s1栈顶为左括号,运算符直接入栈 | | 3 | 1 2 3 | + ( ( + | 数字 | | ) | 1 2 3 + | + ( | 右括号,弹出运算符直至遇到左括号 | | × | 1 2 3 + | + ( × | s1栈顶为左括号,运算符直接入栈 | | 4 | 1 2 3 + 4 | + ( × | 数字 | | ) | 1 2 3 + 4 × | + | 右括号,弹出运算符直至遇到左括号 | | - | 1 2 3 + 4 × + | - | -与+优先级相同,因此弹出+,再压入- | | 5 | 1 2 3 + 4 × + 5 | - | 数字 | | 到达最右端 | **1 2 3 + 4 × + 5 -** | 空 | s1中剩余的运算符 | **因此结果为** **"1 2 3 + 4 × + 5 –"** ### 代码实现中缀表达式转为后缀表达式 **思路分析** ![09.中缀表达式转后缀表达式01.png][1] **代码** ```java public class PolandNotation { public static void main(String[] args) { //完成将一个中缀表达式转成后缀表达式的功能 //说明 //1. 1+((2+3)×4)-5 => 转成 1 2 3 + 4 × + 5 – //2. 因为直接对str 进行操作,不方便,因此 先将 "1+((2+3)×4)-5" =》 中缀的表达式对应的List // 即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] //3. 将得到的中缀表达式对应的List => 后缀表达式对应的List // 即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] =》 ArrayList [1,2,3,+,4,*,+,5,–] String expression = "1+((2+3)*4)-5";//注意表达式 List
infixExpressionList = toInfixExpressionList(expression); System.out.println("中缀表达式对应的List=" + infixExpressionList); // ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] List
suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList); System.out.println("后缀表达式对应的List" + suffixExpreesionList); //ArrayList [1,2,3,+,4,*,+,5,–] System.out.printf("expression=%d", calculate(suffixExpreesionList)); // ? /*String suffixExpression="4 5 * 8 - 60 + 8 2 / +"; List
list = getListString(suffixExpression); int res = calculate(list); System.out.println("计算的结果是="+res);*/ } //即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] =》 ArrayList [1,2,3,+,4,*,+,5,–] //方法:将得到的中缀表达式对应的List => 后缀表达式对应的List public static List
parseSuffixExpreesionList(List
ls){ //定义两个栈 Stack
s1 = new Stack
();//符号栈 //说明:因为s2这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出 //因此比较麻烦,这里我们就不用Stack
直接使用List
s2 //Stack
s2 = new Stack
();//储存中间结果的栈s2 List
s2 = new ArrayList
();//储存中间结果的Lists2 //遍历ls for(String item:ls){ //如果是一个数,加入s2 if(item.matches("\\d+")){ s2.add(item); }else if(item.equals("(")){ s1.push(item); }else if(item.equals(")")){ //如果是右括号")",则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃 while (!s1.peek().equals("(")){ s2.add(s1.pop()); } s1.pop();//将(弹出s1栈,清除小括号 }else{ //当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较 //问题:我们缺少一个比较优先级高低的方法 while(s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item) ) { s2.add(s1.pop()); } //还需要将item压入栈 s1.push(item); } } //将s1中剩余的运算符依次弹出并加入s2 while(s1.size() != 0) { s2.add(s1.pop()); } return s2; //注意因为是存放到List, 因此按顺序输出就是对应的后缀表达式对应的List } //方法:将 中缀表达式转成对应的List // s="1+((2+3)×4)-5"; public static List
toInfixExpressionList(String s) { //定义一个List,存放中缀表达式 对应的内容 List
ls = new ArrayList
(); int i = 0; //这时是一个指针,用于遍历 中缀表达式字符串 String str; // 对多位数的拼接 char c; // 每遍历到一个字符,就放入到c do { //如果c是一个非数字,我需要加入到ls if((c=s.charAt(i)) < 48 || (c=s.charAt(i)) > 57) { ls.add("" + c); i++; //i需要后移 } else { //如果是一个数,需要考虑多位数 str = ""; //先将str 置成"" '0'[48]->'9'[57] while(i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57) { str += c;//拼接 i++; } ls.add(str); } }while(i < s.length()); return ls;//返回 } //将一个逆波兰表达式,依次将数据和运算符放入到ArrayList中 public static List
getListString(String suffixExpression){ //将 suffixExpression分割 String[] split = suffixExpression.split(" "); List
list = new ArrayList
(); for(String ele:split){ list.add(ele); } return list; } //完成对逆波兰表达式的运算 /** * (1). 从左至右扫描,将3和4压入堆栈; * (2). 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈; * (3). 将5入栈; * (4). 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈; * (5). 将6入栈; * (6). 最后是-运算符,计算出35-6的值,即29,由此得出最终结果 * */ public static int calculate(List
ls){ //创建一个栈,只需要一个栈即可 Stack
stack = new Stack
(); //遍历ls for(String item:ls){ //这里使用正则表达式来取出数 if(item.matches("\\d+")){//匹配的是多位数 //入栈 stack.push(item); }else{ //pop出两个数,并运算,再入栈 int num2 = Integer.parseInt(stack.pop()); int num1 = Integer.parseInt(stack.pop()); int res = 0; if(item.equals("+")){ res = num1 + num2; }else if(item.equals("-")){ res = num1 - num2; }else if(item.equals("*")){ res = num1 * num2; }else if(item.equals("/")){ res = num1 / num2; }else{ throw new RuntimeException("运算符有误"); } //把res入栈 stack.push(""+res); } } //最后溜在stack中的数据是运算结果 return Integer.parseInt(stack.pop()); } } //编写一个类 Operation 可以返回一个运算符 对应的优先级 class Operation { private static int ADD = 1; private static int SUB = 1; private static int MUL = 2; private static int DIV = 2; //写一个方法,返回对应的优先级数字 public static int getValue(String operation) { int result = 0; switch (operation) { case "+": result = ADD; break; case "-": result = SUB; break; case "*": result = MUL; break; case "/": result = DIV; break; default: System.out.println("不存在该运算符" + operation); break; } return result; } } ``` **运行结果** ``` 中缀表达式对应的List=[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5] 不存在该运算符( 不存在该运算符( 后缀表达式对应的List[1, 2, 3, +, 4, *, +, 5, -] expression=16 ``` [1]: https://lilinchao.com/usr/uploads/2020/01/3428795099.png
标签:
数据结构
,
栈
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/502.html
上一篇
数据结构学习--逆波兰计算器
下一篇
数据结构学习--递归简述
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
哈希表
Java工具类
设计模式
队列
字符串
FastDFS
国产数据库改造
Kafka
Filter
人工智能
CentOS
Scala
Ubuntu
MyBatis
Shiro
机器学习
Spark
Spark RDD
Spring
Java编程思想
Hive
Stream流
算法
pytorch
线程池
JavaScript
并发线程
HDFS
并发编程
LeetCode刷题
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭