中缀表达式: 是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法,但是不易被计算机所解析。
后缀表达式:是一个通用的算术或逻辑公式表示方法, 操作符是后缀形式处于操作数的后面(例:3 4 +),后缀表达式虽然不是人们所习惯的运算表示方法,但是易被计算机解析。
例如:对于中缀表达式 9+(3-1)*2+10/2 , 其后缀表达式是 9 3 1 - 3 * + 10 2 / + , 那么为了方便计算机解析计算,我们需要将中缀表达式转换成后缀表达式,然后再对后缀表达式进行解析。
1. 中缀表达式转后缀表达式:
- 当读到一个操作数时,立即将它放到输出中。读到的是操作符则需要接着判断是否该入栈。读到的是左圆括号则入栈。
- 在读到操作符时,如果栈为空或者栈顶操作符为(,则入栈。如果栈顶操作符不为(,且此操作符优先级小于或等于此时栈顶操作符,则将栈中元素弹出直至 ①遇到左括号 或者 ②栈顶元素为更低优先级 或者 ③栈为空为止,并将当前操作符入栈;否则当前操作符继续入栈。操作符中,+-优先级低,*/优先级高。
- 如果遇到一个右括号,那么就将栈中元素弹出并输出直至遇到左括号为止。但是这个左括号只被弹出,并不输出。
- 如果读到输入的末尾,若栈不为空则将栈元素弹出直到该栈变成空栈,并将弹出的符号写到输出中。
“9+(3-1)*2+10/2” 转换过程:
操作过程 |
栈中元素 |
输出 |
读入 9,输出 |
|
9 |
读入 +,栈为空,规则2,入栈 |
+ |
9 |
读入 ( ,左括号,规则1,入栈 |
+ ( |
9 |
读入 3,输出 |
+ ( |
9 3 |
读入 -,栈顶为(,规则2,入栈 |
+ ( - |
9 3 |
读入 1,输出 |
+ ( - |
9 3 1 |
读入 ) ,右括号,规则3,出栈并输出 |
+ |
9 3 1 - |
读入 *,*优先级高于栈顶+,规则,2,入栈 |
+ * |
9 3 1 - |
读入 3,输出 |
+ * |
9 3 1 - 3 |
读入 +,+优先级低于栈顶*,规则2,栈中元素出栈,当前操作符入栈 |
+ |
9 3 1 - 3 * + |
读入 10, 输出 |
+ |
9 3 1 - 3 * + 10 |
读入 / , /优先级高于+,入栈 |
+ / |
9 3 1 - 3 * + 10 |
读入 2, 输出 |
+ / |
9 3 1 - 3 * + 10 |
读至末尾,规则4,栈不为空,栈中元素出栈并输出 |
|
9 3 1 - 3 * + 10 / + |
2. 后缀表达式计算最终结果:
- 从左到右遍历表达式的每个数字和符号,遇到是数字则进栈,遇到是运算符则将栈顶两个元素出栈,进行运算并将运算结果进栈;
- 遍历完后缀表达式,此时栈中剩余的数字就是运算结果。
“9 3 1 - 3 * + 10 2 / +” 计算过程:
操作过程 |
栈中元素 |
读入 9,入栈 |
9 |
读入 3,入栈 |
9 3 |
读入 1,入栈 |
9 3 1 |
读入 -,运算并将结果入栈 |
9 2 |
读入 3,入栈 |
9 2 3 |
读入 *,运算并将结果入栈 |
9 6 |
读入 +,运算并将结果入栈 |
15 |
读入 10,入栈 |
15 10 |
读入 2,入栈 |
15 10 2 |
读入 /,运算并将结果入栈 |
15 5 |
读入 +,运算并将结果入栈 |
20 |
读入完毕,栈中元素即为结果 |
20 |
简单中缀表达式计算的java实现:
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 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
| public class SimpleCalcutor {
private class Item {
private String value; private Integer number;
public Item(String value) { this.value = value; try { number = Integer.parseInt(value); } catch (Exception ignore) { } }
public boolean isNumber() { return number != null; }
public int getNumber() { if (isNumber()) return number; throw new NumberFormatException(); }
public boolean isAdd() { return "+".equals(value); }
public boolean isSub() { return "-".equals(value); }
public boolean isMul() { return "*".equals(value); }
public boolean isDiv() { return "/".equals(value); }
public boolean isLeftBracket() { return "(".equals(value); }
public boolean isRightBracket() { return ")".equals(value); }
public int getPriority() { if (isAdd() || isSub()) return 0; if (isMul() || isDiv()) return 1; throw new RuntimeException("This is not +, -, *, /"); }
@Override public String toString() { return value != null ? value.toString() : null; } }
public int calculate(String calStr) { List<Item> infixes = parse(calStr); List<Item> postfixes = infix2postfix(infixes); return calculateByPostfix(postfixes); }
private List<Item> parse(String calStr) { Pattern pattern = Pattern.compile("\\D|\\d+"); Matcher m = pattern.matcher(calStr); List<Item> items = new ArrayList<Item>(); while (m.find()) { items.add(new Item(m.group(0))); } return items; }
private List<Item> infix2postfix(List<Item> infixes) { List<Item> postfixes = new ArrayList<Item>(); Stack<Item> stack = new Stack<Item>(); for (Item item : infixes) { if (item.isNumber()) { postfixes.add(item); } else if (item.isRightBracket()) { while (true) { Item tmp = stack.pop(); if (tmp.isLeftBracket()) break; postfixes.add(tmp); } } else if (item.isLeftBracket()) { stack.push(item); } else { if (stack.isEmpty()) { stack.push(item); continue; } Item top = stack.peek(); if (top.isLeftBracket()) { stack.push(item); continue; } if (item.getPriority() <= top.getPriority()) { while (true) { Item tmp = stack.peek(); if (tmp.isLeftBracket() || tmp.getPriority() < item.getPriority()) { break; } postfixes.add(tmp); stack.pop(); if (stack.isEmpty()) break; } stack.push(item); } else { stack.push(item); } } } while (!stack.isEmpty()) { postfixes.add(stack.pop()); } return postfixes; }
private int calculateByPostfix(List<Item> postfixes) { Stack<Integer> stack = new Stack<Integer>(); for (Item item : postfixes) { if (item.isNumber()) { stack.push(item.getNumber()); } else { int num1 = stack.pop(); int num2 = stack.pop(); int result; if (item.isAdd()) { result = num2 + num1; } else if (item.isSub()) { result = num2 - num1; } else if (item.isMul()) { result = num2 * num1; } else if (item.isDiv()) { result = num2 / num1; } else { throw new IllegalArgumentException("Operator invalid : " + item.value); } stack.push(result); } } return stack.pop(); }
public static void main(String[] args) { SimpleCalcutor calcutor = new SimpleCalcutor(); String calStr = "9+(3-1)*3+10/2"; int result = calcutor.calculate(calStr); System.out.println(result); }
}
|
源码github地址:
SimpleCalculator
参考链接:
利用栈将中缀表达式转换成后缀表达式