​ 逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
​ 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
​ 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。

中缀表达式和后缀表达式

将字符串表达式放入数组

​ 将字符串表达式拆分成数组

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
public String[] notationStrToArray(String notationStr) {
List<String> list = new ArrayList();
notationStr = notationStr.replaceAll(" ", "");
char[] chars = notationStr.toCharArray();
int keepNum = 0;
int preflag = 0;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (preflag == 0 && c == 45) {
System.out.println("负数");
keepNum++;
} else if (isSymbol(c) && c != 32) {

if (keepNum > 0) {
String trim = notationStr.substring(i - keepNum, i).trim();
if (!trim.isEmpty()) list.add(trim);
keepNum = 0;
}
preflag = 0;
list.add(c + "");
} else {
preflag = 1;
keepNum++;
}
}
if (keepNum > 0) {
list.add(notationStr.substring(notationStr.length() - keepNum, notationStr.length()).trim());
}
System.out.println(list);
return list.toArray(new String[list.size()]);
}

中缀表达式转后缀表达式(逆波兰表达式)

​ 将普通平常使用的中缀表达式转成后缀表达式(逆波兰表达式)。

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
public String[] convertInfixToSuffix(String infixNotation) {
String[] strings = notationStrToArray(infixNotation);
Stack<String> symbolStack = new Stack<String>();//记录运算符
List<String> list = new ArrayList();//记录转换后的结果
for (String str : strings) {
if (str.matches("^-?\\d+$")) {// 判断是不是数字,如果是直接存入结果集
list.add(str);
} else if (str.equals("(")) { //判断是不是左括弧,是直接压入栈
symbolStack.push(str);
} else if (str.equals(")")) { //判断是不是右括弧,找到对应的左括弧
while (!symbolStack.peek().equals("(")) {
list.add(symbolStack.pop());
}
symbolStack.pop();
} else {
//str的优先级小于等于symbolStack栈顶运算符, 将symbolStack栈顶的运算符弹出并加入到sb中,再次往下判断直到结束
while (!symbolStack.isEmpty()) {
String peek = symbolStack.peek();
if ("(".equals(peek)) {
break;
} else if (comparPriority(str, peek) < 0) {
list.add(symbolStack.pop());
} else {
break;
}
}
symbolStack.push(str);
}
}
//将符号栈中的符号依次输入结果集
while (!symbolStack.isEmpty()) {
list.add(symbolStack.pop());
}
return list.toArray(new String[list.size()]);
}

比较运算符的优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public int comparPriority(String thissymbol, String othersymbol) {
int re = 0, thislevel = 0, otherlevel = 0;
if ("*".equals(thissymbol) || "/".equals(thissymbol)) {
thislevel = 1;
} else if ("+".equals(thissymbol) || "-".equals(thissymbol)) {
thislevel = 0;
} else {
throw new RuntimeException("运算符有误");
}
if ("*".equals(othersymbol) || "/".equals(othersymbol)) {
otherlevel = 1;
} else if ("+".equals(othersymbol) || "-".equals(othersymbol)) {
otherlevel = 0;
} else {
throw new RuntimeException("运算符有误");
}
return thislevel - otherlevel;
}

public boolean isSymbol(char val) {
return val == '+' || val == '-' || val == '*' || val == '/' || val == '(' || val == ')';
}

逆波兰表达式的运算

​ 逆波兰表达式的运算

方法一

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

public int evalRPN(String[] tokens) {
Stack<Integer> resStack = new Stack<Integer>();//记录运算符
for (String token : tokens) {
if (token.matches("^-?\\d+$")) {// 判断是不是数字,如果是直接存入结果集
resStack.push(Integer.parseInt(token));
} else {
int ev2 = resStack.pop();
int ev1 = resStack.pop();
int evre = 0;
switch (token) {
case "+":
evre = ev1 + ev2;
break;
case "-":
evre = ev1 - ev2;
break; //可选
case "*":
evre = ev1 * ev2;
break; //可选
case "/":
evre = ev1 / ev2;
break; //可选
//你可以有任意数量的case语句
default: //可选
//语句
}
resStack.push(evre);
}
}
return resStack.pop();
}

方法二(方法一的优化,推荐)

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
public int evalRPN1(String[] tokens) {
Stack<Integer> resStack = new Stack<Integer>();//记录运算符
for (String token : tokens) {
int ev1, ev2 = 0;
switch (token) {
case "+":
ev2 = resStack.pop();
ev1 = resStack.pop();
resStack.push(ev1 + ev2);
break;
case "-":
ev2 = resStack.pop();
ev1 = resStack.pop();
resStack.push(ev1 - ev2);
break;
case "*":
ev2 = resStack.pop();
ev1 = resStack.pop();
resStack.push(ev1 * ev2);
break;
case "/":
ev2 = resStack.pop();
ev1 = resStack.pop();
resStack.push(ev1 / ev2);
break;
//你可以有任意数量的case语句
default:
resStack.push(Integer.parseInt(token));
break;
}
}
return resStack.pop();
}

方法三(推荐,使用数组模拟栈,可以节省内存)

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
public int evalRPNArray(String[] tokens) {
int[] numStack = new int[tokens.length / 2 + 1];
int index = 0;
for (String s : tokens) {
switch (s) {
case "+":
numStack[index - 2] += numStack[--index];
break;
case "-":
numStack[index - 2] -= numStack[--index];
break;
case "*":
numStack[index - 2] *= numStack[--index];
break;
case "/":
numStack[index - 2] /= numStack[--index];
break;
default:
// numStack[index++] = Integer.valueOf(s);
//valueOf改为parseInt,减少自动拆箱装箱操作
numStack[index++] = Integer.parseInt(s);
break;
}
}
return numStack[0];
}

完整代码:Github