概念:
逆波兰表达式也叫后缀表示法,即操作符号都置于操作数的后面,逆波兰表达式可以不用括号来标识操作符的优先级。例如:3+4 是一个中缀表达式,转换成逆波兰表达式为34+ 。有人可能会想有后缀表达式,中缀表达式,那有没有前缀表达式呢?答案是:有前缀表达式,也叫波兰表达式,上文中的3+4 用前缀表达式表示为+34。
用途:
了解了什么是逆波兰表达式,那它有什么具体的用途呢?
1.逆波兰表达式中不需要括号,用户只需按照表达式顺序求值,让堆栈自动记录中间结果;同样的,也不需要指定操作符的优先级
2.机器状态永远是一个堆栈状态,堆栈里是需要运算的操作数,栈内不会有操作符。
3.当有操作符时就计算,因此,表达式并不是从右至左整体计算而是每次由中心向外计算一部分,这样在复杂运算中就很少导致操作符错误。
计算原理:
逆波兰表达式进行数据计算的时候一般分为两步:
1.将中缀表达式转换为后缀表达式
2.对转换完成后的后缀表达式进行计算
package com.jason.datastruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;
public class ReversePolish {
private List<String> sList = new ArrayList<String>();// 中缀表达式集合
private List<String> dList = new ArrayList<String>();// 后缀表达式集合
private Stack<String> opStack = new Stack<String>();// 操作符栈
private Stack<String> rStack = new Stack<String>();// 结果运算栈
private final int level1 = 0;// +-的级别是0
private final int level2 = 1;// */的级别是1
private final int level3 = 3;// 左右括号是3
// 初始化
public ReversePolish(String input) {
// a+b-c*(d+e) 转换为实际值例如:1+2-3*(4+5)
StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
while (st.hasMoreTokens()) {
sList.add(st.nextToken());
}
}
public List<String> infix2ReversePolish() {
for (String string : sList) {
// 如果是数字 直接放入dlist 数组
if (isNumber(string)) {
dList.add(string);
} else if (isOperation(string)) {
// 如果是运算符 放入运算符栈
opHandler(string);
} else {
System.out.println("非法操作符");
}
}
// 将栈置空
while (!opStack.empty()) {
dList.add(opStack.pop());
}
return dList;
}
private void opHandler(String s) {
for (Object string : opStack.toArray()) {
System.out.print(string + "");
}
System.out.println();
// 如果运算符栈是空 直接放入栈
if (opStack.empty()) {
opStack.push(s);
return;
}
// 如果是(直接入栈
if (s.equals("(")) {
opStack.push(s);
return;
}
// 如果是) 将(和)之间的出栈
if (s.equals(")")) {
while (!"(".equals(opStack.peek())) {
dList.add(opStack.pop());
}
opStack.pop();
// String tmp = "";
// while (!"(".equals(tmp = opStack.pop())) {
// dList.add(tmp);
// }
return;
}
// 如果栈顶是( 直接入栈
if ("(".equals(opStack.peek())) {
opStack.push(s);
return;
}
// 如果运算符等级大于当前预算符 直接入栈
if (comparePriority(s, opStack.peek())) {
opStack.push(s);
return;
}
// 如果等级小 或者等于 栈里的出栈 // 小的入栈 (在调用一次)
if (!comparePriority(s, opStack.peek())) {
dList.add(opStack.pop());
opHandler(s);
}
}
// 判斷是否是数字
private boolean isNumber(String s) {
return s.matches("\\d+");
}
// 判断是否是运算符
private boolean isOperation(String s) {
return s.matches("[\\+\\-\\*\\/\\(\\)]");
}
// 判断op1 的优先级 是否大于 op2的优先级
private boolean comparePriority(String op1, String op2) {
return getLevel(op1) > getLevel(op2);
}
// 获得操作符的优先级
private int getLevel(String op) {
if ("+".equals(op) || "-".equals(op)) {
return level1;
}
if ("*".equals(op) || "/".equals(op)) {
return level2;
}
if ("(".equals(op) || ")".equals(op)) {
return level3;
}
return -1;
}
// 计算 反波兰表达式
public String resultFromReversePolish() {
for (String string : dList) {
// 如果是数字 入栈
if (isNumber(string)) {
rStack.push(string);
} else if (isOperation(string)) {
// 如果是运算符 取出上面2个 进行运算 结果入栈
if (string.equals("(") || string.equals(")")) {
return "公式错误";
}
int num2 = Integer.parseInt(rStack.pop());
int num1 = Integer.parseInt(rStack.pop());
String result = operation(num1, string, num2);
rStack.push(result);
}
}
if (rStack.empty()) {
return "";
}
return rStack.pop();
}
//运算
private String operation(int num1, String string, int num2) {
switch (string) {
case "+":
return num1 + num2 + "";
case "-":
return num1 - num2 + "";
case "*":
return num1 * num2 + "";
case "/":
return num1 / num2 + "";
default:
return "";
}
}
}
测试类:
package com.jason.datastruct;
import java.util.ArrayList;
public class ReversePolishTest {
public static void main(String[] args) {
String str="1+((2-3)*(4+5))+((6/2))";
System.out.println("中缀表达式:"+str);
ReversePolish rPolish=new ReversePolish(str);
ArrayList<String> reversePolish =(ArrayList<String>) rPolish.infix2ReversePolish();
System.out.println("转换 逆波兰表达式:");
for (String string : reversePolish) {
System.out.print(string+",");
}
//1,2,3,4,-,*,6,*,+,7,-,
System.out.println();
System.out.println("结果\t:"+rPolish.resultFromReversePolish());
}
}
结果:
中缀表达式:1+((2-3)*(4+5))+((6/2))
+
+(
+((
+((-
+(
+(*
+(*(
+(*(+
+(*
+
+
+(
+((
+((/
+(
转换 逆波兰表达式:
1,2,3,-,4,5,+,*,+,6,2,/,+,
结果 :-5