一、前言
- 刚好公司业务需要,需要分析一个语法表达式转成一个业务需要的结果
- 所以接触到
逆波兰表达式
。刚好可以满足我想要的结果。
二、逆波兰表达式
逆波兰表达式又叫做后缀表达式,跟 波兰表达式(前缀表达式)相对应
波兰逻辑学家 J・卢卡西维兹(J・ Lukasiewicz)
于1929年首先提出的一种表达式的表示方法 。
我们习惯将表达式写成 ( 1 + 2 ) * ( 3 + 4)
,加减乘除等运算符写在中间,因此称呼为 中缀表达式。
而波兰表达式的写法为 (* (+ 1 2) (+ 3 4))
,将运算符写在前面,因而也称为前缀表达式。
逆波兰表达式的写法为 ((1 2 +) (3 4 +) *)
,将运算符写在后面,因而也称为后缀表达式。
波兰表达式和逆波兰表达式有个好处,就算将圆括号去掉也没有歧义。
三、表达式的原理
- 看了简单的概念,还是云里雾里,管它什么表达式呢,到底怎么计算的?
- 主要用到了
栈
结构,我们怎么把中缀表达式转成计算器更容易处理的后缀表达式呢?
1、转换流程
- 1、把字符串从左到右遍历解析成每项是
数字
或者 运算符
放到同一个List中
- 2、然后初始化2个栈,一个是数字栈,一个是符号栈
- 3、遍历第一步生成的List
- 如果是数字,直接放入到 数字栈中
- 如果是左括号,直接放入到 符号栈中
- 如果是右括号,就需要把和它对应的左括号中间的所有符号,从符号栈出栈放到数字栈中
- 如果是符号
- 如果当前符号栈为空或比符号栈顶的符号优先级高则直接入符号栈
- 如果优先级小于等于符号栈顶则把栈顶的符号取出放到数字栈
- 重复上面的操作,直到栈顶符号优先级小于它,把它放入符号栈中
- 4、当遍历结束之后,遍历符号栈数据,把它们取出放到数字栈中
- 5、最终数字栈的数据就是我们想得到的后缀表达式顺序了。
四、代码实现
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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
| public class Main { public static void main(String[] args) {
String str ="(1+2)*(3+4)"; List<String> list = toExpressionList(str); System.out.println("拆分成项:"+list); List<String> suffixList = infixToSuffix(list); System.out.println("后缀表达式:"+suffixList); System.out.println("后缀表达式的计算结果为:"+toCalculation(suffixList)); }
public static List<String> toExpressionList(String str) { List<String> list = new ArrayList<>(str.length()); int i = 0; char c; StringBuilder tempStr = new StringBuilder(); while (i < str.length()) { c = str.charAt(i); if (isSymbol(c)) { if (addItem(list, tempStr.toString())) { tempStr = new StringBuilder(); } list.add("" + c); } else { tempStr.append(c); } i++; } addItem(list, tempStr.toString()); return list; }
private static boolean addItem(List<String> list, String item) { if (StringUtils.isNoneBlank(item)) { list.add(item.trim()); return true; } return false; }
private static boolean isSymbol(Object c) { if (c instanceof Character) { char value = ((Character) c).charValue(); return value == '+' || value == '-' || value == '*' || value == '/' || value == '('|| value == ')'; } else if (c instanceof String) { String value = c.toString(); return "+".equals(value) || "-".equals(value) || "*".equals(value) || "/".equals(value) || "(".equals(value)|| ")".equals(value); } return false; }
public static String toCalculation(List<String> list){ Deque<String> stack = new LinkedList<>(); for(String item: list){ if(isNumber(item)){ stack.push(item); }else { BigDecimal x = new BigDecimal(stack.pop()); BigDecimal y = new BigDecimal(stack.pop()); switch (item){ case "+": stack.push(x.add(y).toPlainString()); break; case "-": stack.push(y.subtract(x).toPlainString()); break; case "*": stack.push(x.multiply(y).toPlainString()); break; case "/": stack.push(y.divide(x,BigDecimal.ROUND_DOWN).toPlainString()); break; default: throw new RuntimeException("输入错误!"); } } } return stack.pop(); }
private static List<String> infixToSuffix(List<String> list) { List<String> dataStack = new ArrayList<>(); Deque<String> symbolStack = new LinkedList<>(); for (String item : list) { if (!isSymbol(item)) { dataStack.add(item); } else if (item.equals("(")) { symbolStack.push(item); } else if (item.equals(")")) { while (!symbolStack.peek().equals("(")) { dataStack.add(symbolStack.pop()); } symbolStack.pop(); } else if (symbolStack.peek() == null || judgePriority(item) > judgePriority(symbolStack.peek())) { symbolStack.push(item); } else { while (symbolStack.peek() != null && judgePriority(item) <= judgePriority(symbolStack.peek())) { dataStack.add(symbolStack.pop()); } symbolStack.push(item); } } while (symbolStack.peek() != null) { dataStack.add(symbolStack.pop()); } return dataStack; }
public static int judgePriority(String str){ switch (str){ case "*": case "/": return 2; case "+": case "-": return 1; case "(": case ")": return 0; default: throw new RuntimeException("输入有误!"+str); } }
private static Pattern pattern = Pattern.compile("[+-]?[0-9]+(\\.[0-9]{1,4})?");
public static boolean isNumber(String str) { Matcher m = pattern.matcher(str); return m.matches(); }
}
|
1 2 3
| 拆分成项:[(, 1, +, 2, ), *, (, 3, +, 4, )] 后缀表达式:[1, 2, +, 3, 4, +, *] 后缀表达式的计算结果为:21
|
您的打赏,是我创作的动力!不给钱?那我只能靠想象力充饥了。
微信支付
支付宝