用栈模拟计算器以及中缀转后缀表达式(逆波兰表达式)
后缀表达式(逆波兰表达式)运算方法
-
从左向右读取表达式
- 遇到数字就压入栈中
- 遇到运算符就弹出栈顶和次顶元素。用次顶元素 运算符 栈顶元素,并将运算结果压入栈中,直到栈为空,最终结果就是运算结果
设计
中缀表达式转后缀表达式
- 从左向右读取中缀表达式,并且创建栈s1和队列s2 (因为s2只存不取且还要考虑出栈后逆序的问题,所以这里用队列来代替栈)
- 如果读到的元素的数字,就直接入队放入s2中
- 如果读到的是运算符(运算符判定)
- 如果s1为空,则将该运算符压入s1
- 如果s1不为空
- 如果该运算符为左括号,则直接压入s1
- 如果该运算符为右括号,则将s1中的元素依次出栈并入队到s2中,直到遇见左括号为止(括号不放入s2中)
- 如果该运算符的优先级高于s1栈顶的运算符,则将该元素压入s1
- 如果该运算符的优先级小于等于s1栈顶的运算符,则弹出s1栈顶的元素,并将其放入s2中,该运算符重新判定入栈操作(运算符判定步骤)
- 如果中缀表达式已经读取完毕,则将s1中的元素依次出栈,放入s2中
- s2中的元素依次出队,该顺序即为后缀表达式
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import java.util.ArrayList; import java.util.List; import java.util.Stack; public class PoiandNotation { public static void main(String[] args) { String expression = "1+((2+3)*4)-5" ; //定义一个中缀表达式 List<String> infixExpressionList = toInfixExpressionList(expression); System.out.println( "中缀表达式的list=" +infixExpressionList); List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList); System.out.println( "后缀表达式的List=" +suffixExpreesionList); System.out.println( "expression的结果为: " + calculate(suffixExpreesionList)); } /** * 将中缀表达式转化为后缀表达式(逆波兰表达式) * @param ls 传入的中缀表达式list集合 * @return */ public static List<String> parseSuffixExpreesionList(List<String> ls){ Stack<String> s1 = new Stack<>(); //用于暂存运算符 List<String> s2 = new ArrayList<>(); //用于存放逆波兰表达式,因为只存不取且还要考虑出栈后逆序的问题,所以这里用集合来代替栈 for (String item : ls){ //循环遍历中缀表达式的每一个元素 if (item.matches( "\\d+" )){ //多位数的情况直接入s2 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(); //取出左括号 } else { while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){ //当s1栈顶运算符优先级大于或等于当前扫描到的运算符优先级,则出栈放入s2 s2.add(s1.pop()); } s1.push(item); //把当前扫描到的运算符入栈到s1 } } //将s1剩余的运算符全部放入s2 while (s1.size() != 0 ){ s2.add(s1.pop()); } return s2; } /** * 将一个中缀表达式以集合的形式输入 * @param s 输入的中缀表达式 * @return */ public static List<String> toInfixExpressionList(String s){ List<String> ls = new ArrayList<>(); int i = 0 ; //用于扫描中缀表达式 char c; //把每一个扫描到的字符存到c里 String str; //用与拼接字符,存储多位数 do { if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57 ){ //如果不是数字,就直接放入集合中 ls.add( "" + c); i++; } else { str = "" ; //初始化 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; } /** * 用于计算后缀表达式 * @param getSuffixList 接收后缀表达式的集合 * @return */ public static int calculate(List<String> getSuffixList){ Stack<String> stack = new Stack<>(); for (String item : getSuffixList) { if (item.matches( "\\d+" )){ //如果是数字就直接入栈 stack.push(item); } else { 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; } stack.push( "" + res); } } return Integer.parseInt(stack.pop()); } } //定义运算符的优先级 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( "不存在该运算符" ); break ; } return result; } } |
结果
本文来自博客园,作者:腹白,转载请注明原文链接:https://www.cnblogs.com/wyh518/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?