前綴、中綴、后綴表達式(逆波蘭表達式)
介紹
前綴表達式、中綴表達式、后綴表達式都是四則運算的表達方式,用以四則運算表達式求值
,即數學表達式的求職
中綴表達式
簡介
中綴表達式就是常見的運算表達式,如(3+4)×5-6
前綴表達式
簡介
前綴表達式又稱波蘭式,前綴表達式的運算符位於操作數之前
比如:- × + 3 4 5 6
前綴表達式的計算機求值
從右至左掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(棧頂元素 op 次頂元素),並將結果入棧;重復上述過程直到表達式最左端,最后運算得出的值即為表達式的結果
- 例如:- × + 3 4 5 6
- 從右至左掃描,將6、5、4、3壓入堆棧
- 遇到+運算符,因此彈出3和4(3為棧頂元素,4為次頂元素,注意與后綴表達式做比較),計算出3+4的值,得7,再將7入棧
- 接下來是×運算符,因此彈出7和5,計算出7×5=35,將35入棧
- 最后是-運算符,計算出35-6的值,即29,由此得出最終結果
將中綴表達式轉換為前綴表達式
轉換步驟如下:
- 初始化兩個棧:運算符棧s1,儲存中間結果的棧s2
- 從右至左掃描中綴表達式
- 遇到操作數時,將其壓入s2
- 遇到運算符時,比較其與s1棧頂運算符的優先級
- 如果s1為空,或棧頂運算符為右括號“)”,則直接將此運算符入棧
- 否則,若優先級比棧頂運算符的較高或相等,也將運算符壓入s1
- 否則,將s1棧頂的運算符彈出並壓入到s2中,再次轉到(4-1)與s1中新的棧頂運算符相比較
- 遇到括號時
- 如果是右括號“)”,則直接壓入s1
- 如果是左括號“(”,則依次彈出S1棧頂的運算符,並壓入S2,直到遇到右括號為止,此時將這一對括號丟棄
- 重復步驟2至5,直到表達式的最左邊
- 將s1中剩余的運算符依次彈出並壓入s2
- 依次彈出s2中的元素並輸出,結果即為中綴表達式對應的前綴表達式
例如:1+((2+3)×4)-5具體過程,如下表
掃描到的元素 | S2(棧底->棧頂) | S1 (棧底->棧頂) | 說明 |
---|---|---|---|
5 | 5 | 空 | 數字,直接入棧 |
- | 5 | - | s1為空,運算符直接入棧 |
) | 5 | -) | 右括號直接入棧 |
4 | 5 4 | -) | 數字直接入棧 |
x | 5 4 | -)x | s1棧頂是右括號,直接入棧 |
) | 5 4 | -)x) | 右括號直接入棧 |
3 | 5 4 3 | -)x) | 數字 |
+ | 5 4 3 | -)x)+ | s1棧頂是右括號,直接入棧 |
2 | 5 4 3 2 | -)x)+ | 數字 |
( | 5 4 3 2 + | -)x | 左括號,彈出運算符直至遇到右括號 |
( | 5 4 3 2 + x | - | 同上 |
+ | 5 4 3 2 + x | -+ | 優先級與-相同,入棧 |
1 | 5 4 3 2 + x 1 | -+ | 數字 |
到達最左端 | 5 4 3 2 + x 1 + - | 空 | s1剩余運算符 |
結果是:- + 1 × + 2 3 4 5
后綴表達式
簡介
后綴表達式又稱逆波蘭表達式,與前綴表達式相似,只是運算符位於操作數之后
比如:3 4 + 5 × 6 -
后綴表達式計算機求值
與前綴表達式類似,只是順序是從左至右:
從左至右掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(次頂元素 op 棧頂元素),並將結果入棧;重復上述過程直到表達式最右端,最后運算得出的值即為表達式的結果
例如后綴表達式“3 4 + 5 × 6 -”:
- 從左至右掃描,將3和4壓入堆棧;
- 遇到+運算符,因此彈出4和3(4為棧頂元素,3為次頂元素,注意與前綴表達式做比較),計算出3+4的值,得7,再將7入棧;
- 將5入棧;
- 接下來是×運算符,因此彈出5和7,計算出7×5=35,將35入棧;
- 將6入棧;
- 最后是-運算符,計算出35-6的值,即29,由此得出最終結果。
將中綴表達式轉換為后綴表達式
與轉換為前綴表達式相似,步驟如下:
- 初始化兩個棧:運算符棧s1和儲存中間結果的棧s2;
- 從左至右掃描中綴表達式;
- 遇到操作數時,將其壓s2;
- 遇到運算符時,比較其與s1棧頂運算符的優先級:
- 如果s1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
- 否則,若優先級比棧頂運算符的高,也將運算符壓入s1(注意轉換為前綴表達式時是優先級較高或相同,而這里則不包括相同的情況);
- 否則,將s1棧頂的運算符彈出並壓入到s2中,再次轉到(4-1)與s1中新的棧頂運算符相比較;
- 遇到括號時:
- 如果是左括號“(”,則直接壓入s1;
- 如果是右括號“)”,則依次彈出s1棧頂的運算符,並壓入s2,直到遇到左括號為止,此時將這一對括號丟棄;
- 重復步驟2至5,直到表達式的最右邊;
- 將s1中剩余的運算符依次彈出並壓入s2;
- 依次彈出s2中的元素並輸出,結果的逆序即為中綴表達式對應的后綴表達式(轉換為前綴表達式時不用逆序)
例如,將中綴表達式“1+((2+3)×4)-5”轉換為后綴表達式的過程如下:
掃描到的元素 | s2(棧底->棧頂) | s1 (棧底->棧頂) | 說明 |
---|---|---|---|
1 | 1 | 空 | 數字,直接入棧 |
+ | 1 | + | s1為空,運算符直接入棧 |
( | 1 | + ( | 左括號,直接入棧 |
( | 1 | + ( ( | 同上 |
2 | 1 2 | + ( ( | 數字 |
+ | 1 2 | + ( ( + | s1棧頂為左括號,運算符直接入棧 |
3 | 1 2 3 | + ( ( + | 數字 |
) | 1 2 3 + | + ( | 右括號,彈出運算符直至遇到左括號 |
× | 1 2 3 + | + ( × | s1棧頂為左括號,運算符直接入棧 |
4 | 1 2 3 + 4 | + ( × | 數字 |
) | 1 2 3 + 4 × | + | 右括號,彈出運算符直至遇到左括號 |
- | 1 2 3 + 4 × + | - | -與+優先級相同,因此彈出+,再壓入- |
5 | 1 2 3 + 4 × + 5 | - | 數字 |
到達最右端 | 1 2 3 + 4 × + 5 - | 空 | s1中剩余的運算符 |
因此結果為“1 2 3 + 4 × + 5 -”
代碼實現
public class Operation {
private static int ADDITION=1;
private static int SUBTRACTION=1;
private static int MULTIPLICATION=2;
private static int DIVISION=2;
public static int getValue(String operation){
int result;
switch (operation){
case "+":
result=ADDITION;
break;
case "-":
result=SUBTRACTION;
break;
case "*":
result=MULTIPLICATION;
break;
case "/":
result=DIVISION;
break;
default:
// System.out.println("不存在該運算符");
result=0;
}
return result;
}
}
public class PolishNotation {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("請輸入運算表達式:");
String expressionStr=sc.nextLine();
// System.out.println(expressionStr);
List<String> zx= toInfixExpression(expressionStr);
List<String> rpn=parseSuffixExpression(zx);
String rpnStr="";
for(String str:rpn){
rpnStr+=str;
}
System.out.println(rpnStr);
System.out.println("計算結果:"+ calculate(rpn));
}
/**
* 把字符串轉換成中序表達式
* @param s
* @return
*/
public static List<String> toInfixExpression(String s) {
List<String> ls = new ArrayList<String>();//存儲中序表達式
int i = 0;
String str;
char c;
do {
if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {
ls.add("" + c);
i++;
} else {
str = "";
while (i < s.length() && (c = s.charAt(i)) >= 48
&& (c = s.charAt(i)) <= 57) {
str += c;
i++;
}
ls.add(str);
}
} while (i < s.length());
return ls;
}
/**
* 轉換成逆波蘭表達式
* @param ls
* @return
*/
public static List<String> parseSuffixExpression(List<String> ls) {
Stack<String> s1=new Stack<String>();
Stack<String> s2=new Stack<String>();
List<String> lss = new ArrayList<String>();
for (String ss : ls) {
if (ss.matches("\\d+")) {
lss.add(ss);
} else if (ss.equals("(")) {
s1.push(ss);
} else if (ss.equals(")")) {
while (!s1.peek().equals("(")) {
lss.add(s1.pop());
}
s1.pop();
} else {
while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(ss)) {
lss.add(s1.pop());
}
s1.push(ss);
}
}
while (s1.size() != 0) {
lss.add(s1.pop());
}
return lss;
}
/**
* 通過逆波蘭表達式計算結果
* @param ls
* @return
*/
public static int calculate(List<String> ls) {
Stack<String> s=new Stack<String>();
for (String str : ls) {
if (str.matches("\\d+")) {
s.push(str);
} else {
int b = Integer.parseInt(s.pop());
int a = Integer.parseInt(s.pop());
int result=0;
if (str.equals("+")) {
result = a + b;
} else if (str.equals("-")) {
result = a - b;
} else if (str.equals("*")) {
result = a * b;
} else if (str.equals("\\")) {
result = a / b;
}
s.push("" + result);
}
}
System.out.println(s.peek());
return Integer.parseInt(s.pop());
}
}