具體步驟
/*
* 後綴表達式適合計算式進行運算,但是人卻不容易寫出來,尤其是表達式很長的情況下,
* 因此在開發中,我們需要將中綴表達式轉成後綴表達式
*
* 具體步驟:
* 1. 初始化兩個棧:運算符棧s1和儲存中間結果的棧s2;
* 2. 從左至右掃描中綴表達式
* 3. 遇到操作數時,將其壓s2
* 4. 遇到運算符時,比較其與s1棧頂運算符的優先級
* 1. 如果s1爲空,或棧頂運算符爲左括號“(”,則直接將此運算符入棧
* 2. 否則,若優先級比棧頂運算符的高,也將運算符壓入s1
* 3. 否則,將s1棧頂的運算符彈出並壓入到s2中,再次轉到(4-1)與s1中新的棧頂運算符相比較
* 5. 遇到括號時:
* 1. 如果是左括號“(”,則直接壓入s1
* 2. 如果是右括號“)”,則依次彈出s1棧頂的運算符,並壓入s2,直到遇到左括號爲止,此時將這一對括號丟棄
* 6. 重複步驟2至5,直到表達式的最右邊
* 7. 將s1中剩餘的運算符依次彈出並壓入s2
* 8. 依次彈出s2中的元素並輸出,結果的逆序即爲中綴表達式對應的後綴表達式
*/
中綴表達式轉後綴表達式(逆波蘭表達式)
public static String toReversePolishNotation(String formula) throws Exception{
// 初始化兩個棧:運算符棧s1和儲存中間結果的棧s2;
Stack<String> s1 = new Stack<>();
Stack<String> s2 = new Stack<>();
String[] symbol = formula.split(" ");
int len = symbol.length;
// 從左至右掃描中綴表達式
for (int i = 0; i < len; i++) {
String currentSymbol = symbol[i];
// 遇到操作數時,將其壓s2
if (MathUtil.isNumeric(currentSymbol)){
s2.push(currentSymbol);
continue;
}
if (MathUtil.isOper(currentSymbol)){
// 如果是右括號“)”,則依次彈出s1棧頂的運算符,並壓入s2,
// 直到遇到左括號爲止,此時將這一對括號丟棄
if (")".equals(currentSymbol)){
while (!MathUtil.isLeftParenthesis(s1.peek()))
s2.push(s1.pop());
s1.pop();
continue;
}
while (true) {
// 如果s1爲空,或棧頂運算符爲左括號“(”,則直接將此運算符入棧
if (s1.isEmpty() || "(".equals(currentSymbol)){
s1.push(currentSymbol);
break;
}
int topPriority = MathUtil.priority(s1.peek());
int currentPriority = MathUtil.priority(currentSymbol);
// 若優先級比棧頂運算符的高,也將運算符壓入s1
if (currentPriority > topPriority) {
s1.push(currentSymbol);
break;
}
// 若優先級不比棧頂運算符的高,將s1棧頂的運算符彈出並壓入到s2中,
if (currentPriority <= topPriority)
s2.push(s1.pop());
}
}
}
// 將s1中剩餘的運算符依次彈出並壓入s2
while (!s1.isEmpty())
s2.push(s1.pop());
String result = "";
// 依次彈出s2中的元素並輸出,結果的逆序即爲中綴表達式對應的後綴表達式
while (!s2.isEmpty())
result = s2.pop() + " " + result;
return result;
}
計算表達式結果
public static String calculate(String formula){
try {
String s = toReversePolishNotation(formula);
String[] symbol = s.split(" ");
Stack<String> stack = new Stack<>();
int len = symbol.length;
for (int i = 0; i < len; i++) {
String currentSymbol = symbol[i];
if (MathUtil.isOper(currentSymbol)){
String b = stack.pop();
String a = stack.pop();
// 計算兩個數在操作符currentSymbol下的值
stack.push(String.valueOf(MathUtil.calculate(a,b,currentSymbol)));
continue;
}
stack.push(currentSymbol);
}
return stack.peek();
} catch (Exception e) {
return "表達式有誤!";
}
}
自定義MathUtil工具類
/**
* 數學工具包類
* @Class: MathUtil
* @author: Oh_MyBug
* @Date: 2020/3/17 22:17
*/
class MathUtil {
private static final HashMap<String, Integer> OPERATTION_PRIORITY = new HashMap() {
{
put("(", -1);
put("+", 0);
put("-", 0);
put("*", 1);
put("/", 1);
put(")", 2);
}
};
/**
* 判斷字符串str是否爲數字
* @Function isNumeric
* @author Oh_MyBug
* @Date 2020/3/17 22:18
* @param
* @return 布爾值 是->true 否->false
*/
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
} catch (NumberFormatException e) {
return false;
}
return true;
}
/**
* 判斷字符串str是否爲操作符
* @Function isOper
* @author Oh_MyBug
* @Date 2020/3/17 22:19
* @param
* @return 布爾值 是->true 否->false
*/
public static boolean isOper(String str) {
return OPERATTION_PRIORITY.keySet().contains(str) ? true : false;
}
/**
* 判斷操作符是否爲左括弧
* @Function isLeftParenthesis
* @author Oh_MyBug
* @Date 2020/3/17 22:22
* @param
* @return 布爾值 是->true 否->false
*/
public static boolean isLeftParenthesis(String str){
return OPERATTION_PRIORITY.get(str) == OPERATTION_PRIORITY.get("(");
}
/**
* 判斷操作符是否爲右括弧
* @Function isRightParenthesis
* @author Oh_MyBug
* @Date 2020/3/17 22:22
* @param str
* @return 布爾值 是->true 否->false
*/
public static boolean isRightParenthesis(String str){
return OPERATTION_PRIORITY.get(str) == OPERATTION_PRIORITY.get(")");
}
/**
* 判斷操作符優先級
* @Function priority
* @author Oh_MyBug
* @Date 2020/3/17 22:23
* @param str
* @return 操作符優先級
*/
public static int priority(String str) {
return OPERATTION_PRIORITY.get(str);
}
/**
* 計算兩個數在操作符oper下的值
* @Function TODO
* @author Oh_MyBug
* @Date 2020/3/17 22:23
* @param num1
* @param num2
* @param oper
* @return 計算結果
*/
public static double calculate(String num1, String num2, String oper) {
double a = Double.parseDouble(num1);
double b = Double.parseDouble(num2);
switch (oper) {
case "+":
return a + b;
case "-":
return a - b;
case "*":
return a * b;
case "/":
if (b == 0) {
throw new RuntimeException("非法運算!");
}
return a / b;
default:
break;
}
return 0;
}
}
測試代碼
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true){
System.out.print("請輸入式子:");
String fomula = scanner.nextLine();
switch (fomula){
case "exit":
break;
default:
System.out.println(ReversePolishNotation.calculate(fomula));
break;
}
}
}
打印結果
請輸入式子:1 + ( ( 2 + 3 ) * 4 ) + ( 2.6 - 1 )
22.6
請輸入式子:1 + ( ( 2 + 3 ) * 4 )
21.0