logo头像
Snippet 博客主题

前缀、中缀、后缀表达式

在函数式编程语言中,为了表示方便,出现了一些新的语法格式。所谓前缀、中缀、后缀表达式,它们之间的区别在于运算符相对与操作数的位置不同,为了说明它们的概念,首先来看一下中缀表达式。

所谓中缀表达式,就是将函数名放到两个操作数中间的表达式,其中,左侧的操作数代表函数对象或值,右侧的操作数代表函数的参数值。例如:

1
2
3
(3 + 4) × 5 - 6 就是中缀表达式
- × + 3 4 5 6 前缀表达式
3 4 + 5 × 6 - 后缀表达式

前缀表达式

前缀表达式又称为前缀记法、波兰式,主要用于表示运算符位于操作数之前的表达式。

中缀表达式

中缀表达式又称为中缀记法,操作符以中缀形式处于操作数的中间。

中缀表达式是人们常用的算术表示方法,虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。对计算机来说,计算前缀或后缀表达式的值非常简单。

后缀表达式

后缀表达式又称为后缀记法、逆波兰式,后缀表达式与前缀表达式类似,只是运算符位于操作数之后。

前缀表达式求值

从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。

例如前缀表达式“- × + 3 4 5 6”计算的步骤如下:
(1) 从右至左扫描,将6、5、4、3压入堆栈;
(2) 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做比较),计算出3+4的值,得7,再将7入栈;
(3) 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈;
(4) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。
可以看出,用计算机计算前缀表达式的值是很容易的。

后缀表达式求值

与前缀表达式类似,只是顺序是从左至右:
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。

例如后缀表达式“3 4 + 5 × 6 -”的计算步骤如下:
(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,由此得出最终结果。

前缀、中缀、后缀表达式相互转换

将中缀表达式转换为前缀表达式

遵循以下步骤:
(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) 初始化两个栈:运算符栈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
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package com.xzh;
import java.util.Scanner;
import java.util.Stack;
public class Demo {
public static final String USAGE = "== usage ==\n"
+ "input the expressions, and then the program "
+ "will calculate them and show the result.\n"
+ "input 'bye' to exit.\n";
public static void main(String[] args) {
System.out.println(USAGE);
Scanner scanner = new Scanner(System.in);
String input = "";
final String CLOSE_MARK = "bye";
System.out.println("input an expression:");
input = scanner.nextLine();
while (input.length() != 0
&& !CLOSE_MARK.equals((input))) {
System.out.print("Polish Notation (PN):");
try {
toPolishNotation(input);
} catch (NumberFormatException e) {
System.out.println("\ninput error, not a number.");
} catch (IllegalArgumentException e) {
System.out.println("\ninput error:" + e.getMessage());
} catch (Exception e) {
System.out.println("\ninput error, invalid expression.");
}
System.out.print("Reverse Polish Notation (RPN):");
try {
toReversePolishNotation(input);
} catch (NumberFormatException e) {
System.out.println("\ninput error, not a number.");
} catch (IllegalArgumentException e) {
System.out.println("\ninput error:" + e.getMessage());
} catch (Exception e) {
System.out.println("\ninput error, invalid expression.");
}
System.out.println("input a new expression:");
input = scanner.nextLine();
}
System.out.println("program exits");
}
/**
* parse the expression , and calculate it.
* @param input
* @throws IllegalArgumentException
* @throws NumberFormatException
*/
private static void toPolishNotation(String input)
throws IllegalArgumentException, NumberFormatException {
int len = input.length();
char c, tempChar;
Stack<Character> s1 = new Stack<Character>();
Stack<Double> s2 = new Stack<Double>();
Stack<Object> expression = new Stack<Object>();
double number;
int lastIndex = -1;
for (int i=len-1; i>=0; --i) {
c = input.charAt(i);
if (Character.isDigit(c)) {
lastIndex = readDoubleReverse(input, i);
number = Double.parseDouble(input.substring(lastIndex, i+1));
s2.push(number);
i = lastIndex;
if ((int) number == number)
expression.push((int) number);
else
expression.push(number);
} else if (isOperator(c)) {
while (!s1.isEmpty()
&& s1.peek() != ')'
&& priorityCompare(c, s1.peek()) < 0) {
expression.push(s1.peek());
s2.push(calc(s2.pop(), s2.pop(), s1.pop()));
}
s1.push(c);
} else if (c == ')') {
s1.push(c);
} else if (c == '(') {
while ((tempChar=s1.pop()) != ')') {
expression.push(tempChar);
s2.push(calc(s2.pop(), s2.pop(), tempChar));
if (s1.isEmpty()) {
throw new IllegalArgumentException(
"bracket dosen't match, missing right bracket ')'.");
}
}
} else if (c == ' ') {
// ignore
} else {
throw new IllegalArgumentException(
"wrong character '" + c + "'");
}
}
while (!s1.isEmpty()) {
tempChar = s1.pop();
expression.push(tempChar);
s2.push(calc(s2.pop(), s2.pop(), tempChar));
}
while (!expression.isEmpty()) {
System.out.print(expression.pop() + " ");
}
double result = s2.pop();
if (!s2.isEmpty())
throw new IllegalArgumentException("input is a wrong expression.");
System.out.println();
if ((int) result == result)
System.out.println("the result is " + (int) result);
else
System.out.println("the result is " + result);
}
/**
* parse the expression, and calculate it.
* @param input
* @throws IllegalArgumentException
* @throws NumberFormatException
*/
private static void toReversePolishNotation(String input)
throws IllegalArgumentException, NumberFormatException {
int len = input.length();
char c, tempChar;
Stack<Character> s1 = new Stack<Character>();
Stack<Double> s2 = new Stack<Double>();
double number;
int lastIndex = -1;
for (int i=0; i<len; ++i) {
c = input.charAt(i);
if (Character.isDigit(c) || c == '.') {
lastIndex = readDouble(input, i);
number = Double.parseDouble(input.substring(i, lastIndex));
s2.push(number);
i = lastIndex - 1;
if ((int) number == number)
System.out.print((int) number + " ");
else
System.out.print(number + " ");
} else if (isOperator(c)) {
while (!s1.isEmpty()
&& s1.peek() != '('
&& priorityCompare(c, s1.peek()) <= 0) {
System.out.print(s1.peek() + " ");
double num1 = s2.pop();
double num2 = s2.pop();
s2.push(calc(num2, num1, s1.pop()));
}
s1.push(c);
} else if (c == '(') {
s1.push(c);
} else if (c == ')') {
while ((tempChar=s1.pop()) != '(') {
System.out.print(tempChar + " ");
double num1 = s2.pop();
double num2 = s2.pop();
s2.push(calc(num2, num1, tempChar));
if (s1.isEmpty()) {
throw new IllegalArgumentException(
"bracket dosen't match, missing left bracket '('.");
}
}
} else if (c == ' ') {
// ignore
} else {
throw new IllegalArgumentException(
"wrong character '" + c + "'");
}
}
while (!s1.isEmpty()) {
tempChar = s1.pop();
System.out.print(tempChar + " ");
double num1 = s2.pop();
double num2 = s2.pop();
s2.push(calc(num2, num1, tempChar));
}
double result = s2.pop();
if (!s2.isEmpty())
throw new IllegalArgumentException("input is a wrong expression.");
System.out.println();
if ((int) result == result)
System.out.println("the result is " + (int) result);
else
System.out.println("the result is " + result);
}
/**
* calculate the two number with the operation.
* @param num1
* @param num2
* @param op
* @return
* @throws IllegalArgumentException
*/
private static double calc(double num1, double num2, char op)
throws IllegalArgumentException {
switch (op) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
if (num2 == 0) throw new IllegalArgumentException("divisor can't be 0.");
return num1 / num2;
default:
return 0; // will never catch up here
}
}
private static int priorityCompare(char op1, char op2) {
switch (op1) {
case '+': case '-':
return (op2 == '*' || op2 == '/' ? -1 : 0);
case '*': case '/':
return (op2 == '+' || op2 == '-' ? 1 : 0);
}
return 1;
}
/**
* read the next number (reverse)
* @param input
* @param start
* @return
* @throws IllegalArgumentException
*/
private static int readDoubleReverse(String input, int start)
throws IllegalArgumentException {
int dotIndex = -1;
char c;
for (int i=start; i>=0; --i) {
c = input.charAt(i);
if (c == '.') {
if (dotIndex != -1)
throw new IllegalArgumentException(
"there have more than 1 dots in the number.");
else
dotIndex = i;
} else if (!Character.isDigit(c)) {
return i + 1;
} else if (i == 0) {
return 0;
}
}
throw new IllegalArgumentException("not a number.");
}
/**
* read the next number
* @param input
* @param start
* @return
* @throws IllegalArgumentException
*/
private static int readDouble(String input, int start)
throws IllegalArgumentException {
int len = input.length();
int dotIndex = -1;
char c;
for (int i=start; i<len; ++i) {
c = input.charAt(i);
if (c == '.') {
if (dotIndex != -1)
throw new IllegalArgumentException(
"there have more than 1 dots in the number.");
else if (i == len - 1)
throw new IllegalArgumentException(
"not a number, dot can't be the last part of a number.");
else
dotIndex = i;
} else if (!Character.isDigit(c)) {
if (dotIndex == -1 || i - dotIndex > 1)
return i;
else
throw new IllegalArgumentException(
"not a number, dot can't be the last part of a number.");
} else if (i == len - 1) {
return len;
}
}
throw new IllegalArgumentException("not a number.");
}
/**
* return true if the character is an operator.
* @param c
* @return
*/
private static boolean isOperator(char c) {
return (c=='+' || c=='-' || c=='*' || c=='/');
}
}
支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

上一篇