一、中綴表達式轉換成後綴表達式
具體步驟如下:
1、初始化棧stack(暫時存放運算符)以及集合list(存放後綴表達式)
2、從左向右掃描中綴表達式
3、當前元素爲數字時,直接添加到list中
4、當前元素爲運算符時,需要比較當前運算符與stack中棧頂運算符的優先級
4.1、若stack爲空,或者棧頂運算符爲 '(' 時,當前運算符直接入棧
4.2、stack不爲空,當前運算符優先級高於棧頂運算符時,則將當前運算符直接入棧;
當前運算符優先級小於等於棧頂運算符時,則將棧頂運算符出棧添加到list中, 並重復4.1-4.2,將當前運算符繼續與新的棧頂運算符比較。
5、當前元素爲 '(' 時,直接壓入stack中
6、當前元素爲 ')' 時,循環stack,一次彈出stack棧頂運算符並添加到list中,直到遇到 '(' 爲止,此時將棧頂運算符爲 '(' 時直接出 棧,繼續掃描下一元素
7、重複步驟 2 至 6,直到中綴表達式被掃描完
8、將stack棧中剩餘的運算符依次彈出並添加到list中,最後得到後綴表達式
例1:中綴表達式:60 + 8 / 2
掃描到的元素 | stack(棧底->棧頂) | list | 說明 |
60 | 空 | 60 | 數字,直接添加到list |
+ | + | 60 | 棧空,運算符直接入棧 |
8 | + | 60,8 | 數字,直接添加到list |
/ | +,/ | 60,8 | / 優先級比 + 高,直接入棧 |
2 | +,/ | 60,8,2 | 數字,直接添加到list |
掃描結束 | + | 60,8,2,/ | 彈出棧頂運算符 |
掃描結束 | 空 | 60,8,2,/,+ | 彈出棧頂運算符 |
例2:中綴表達式 1+((2+3)*4)-6/2
掃描到的元素 | stack(棧底->棧頂) | list | 說明 |
1 | 空 | 1 | 數字,直接添加到list |
+ | + | 1 | 棧空,運算符直接入棧 |
( | +,( | 1 | 左括號,直接入棧 |
( | +,(,( | 1 | 左括號,直接入棧 |
2 | +,(,( | 1,2 | 數字,直接添加到list |
+ | +,(,(,+ | 1,2 | 棧頂爲 ( 時,運算符直接入棧 |
3 | +,(,(,+ | 1,2,3 | 數字,直接添加到list |
) | +,(, | 1,2,3,+ |
),(1)棧中運算符依次彈出添加到list,直到遇到左括號爲止,(2)將棧中左括號彈出 |
* | +,(,* | 1,2,3,+ | 棧頂元素爲 ( 時,運算符直接入棧 |
4 | +,(,* | 1,2,3,+,4 | 數字,直接添加到list |
) | + | 1,2,3,+,4,* | ),(1)棧中運算符依次彈出添加到list,直到遇到左括號爲止,(2)將棧中 ( 彈出 |
- | - | 1,2,3,+,4,*,+ | - 與 + 兩運算符優先級相等,(1)彈出棧頂運算符+並添加到list,(2) - 入棧 |
6 | - | 1,2,3,+,4,*,+,6 | 數字,直接添加到list |
/ | -,/ | 1,2,3,+,4,*,+,6 | / 優先級高於 -,將 / 入棧 |
2 | -,/ | 1,2,3,+,4,*,+,6,2 | 數字,直接添加到list |
掃描結束 | 空 | 1,2,3,+,4,*,+,6,2,/,- | 將棧中剩餘運算符依次彈出添加到list |
代碼實現:
//1 先將表達式轉換成list
public static List<String> expressionToList(String expression){
int i = 0;//下標,用於掃描表達式
char ch;//用於接收掃描字符
String numStr;//用於拼接多位數
ArrayList<String> list = new ArrayList<String>();//存放表達式
do {
//需要判斷ch是操作符還是數字,此處不理解的可以百度ACSII碼
if((ch = expression.charAt(i)) < 48 || (ch = expression.charAt(i)) > 57) {
list.add(""+ch);
i++;
}else {//如果是數字,則需要判斷是否是多位數
numStr = "";
while(i < expression.length() && (ch = expression.charAt(i)) >= 48 && (ch = expression.charAt(i)) <= 57) {
numStr+=ch;
i++;
}
list.add(numStr);
}
}while(i < expression.length());
return list;
}
//2 將中綴表達式轉爲後綴表達式
public static List<String> parseSuffixExpressionList(List<String> list){
Stack<String> stack = new Stack<String>();
ArrayList<String> resList = new ArrayList<String>();
//循環中綴表達式
for(String item : list) {
//是多位數時直接入棧
if(item.matches("\\d+")) {
resList.add(item);
//運算符時需要判斷入棧
}else if(item.equals("(")) {
stack.push(item);
}else if(item.equals(")")) {
while(true) {
if(stack.peek().equals("(")) {
break;
}
resList.add(stack.pop());
}
//此時需要將)彈出
stack.pop();
}else {
//(當前運算符優先級小於等於棧頂運算符)直接將棧頂元素出棧放入list
while(stack.size()!=0 && priority(item) <= priority(stack.peek())) {
resList.add(stack.pop());
}
//還需要將item壓入棧中
stack.push(item);
}
}
//將棧中剩餘運算符彈出放入到resList
while(stack.size()!=0) {
resList.add(stack.pop());
}
return resList;
}
//數字越大,則優先級就越高
public int priority(String oper) {
int result = 0;
if(oper.equals("*") || oper.equals("/")) {
return 2;
}else if(oper.equals("+") || oper.equals("-")){
return 1;
}else {
// System.out.println("不存在此運算符");
return result;
}
}
二、後綴表達式計算(不包含小數情況)
具體步驟如下:
1、初始化棧stack,並將後綴表達式從左向右掃描
2、當前元素爲數字時,直接入棧
3、當前元素爲運算符時,依次彈出棧中兩個數字,並進行運算,得到結果後入棧
4、重複1-3
直接上例子:(5+4)*3-7 對應的後綴表達式爲 5 4 + 3 * 7 -
1、從左向右掃描,將 5 和 4 入棧
2、遇到運算符 +,依次彈出棧中 4 和 5(4爲棧頂元素,5爲次頂元素),計算出 4 + 5 = 9,將 9 入棧
3、將數字 3 入棧。
4、遇到運算符 *,依次彈出棧中 3 和 7,計算出 3 * 9 = 27,將 27 入棧
5、將數字 7 入棧。
6、遇到運算符 -,依次彈出棧中 27 和 7,計算出 27 - 7 = 20,此時已掃描結束,最終結果爲 20
//1 首先將表達式轉換成list
public List<String> expressionToList(String expression){
int i = 0;//下標,用於掃描表達式
char ch;//用於接收掃描字符
String numStr;//用於拼接多位數
ArrayList<String> list = new ArrayList<String>();//存放表達式
do {
//需要判斷ch是操作符還是數字,此處不理解的可以百度ACSII碼
if((ch = expression.charAt(i)) < 48 || (ch = expression.charAt(i)) > 57) {
list.add(""+ch);
i++;
}else {//如果是數字,則需要判斷是否是多位數
numStr = "";
while(i < expression.length() && (ch = expression.charAt(i)) >= 48 && (ch = expression.charAt(i)) <= 57) {
numStr+=ch;
i++;
}
list.add(numStr);
}
}while(i < expression.length());//掃描結束
return list;
}
//2 運算方法
public void calculate(List<String> expressionList) {
//新建一個stack
Stack<String> stack = new Stack<String>();
int num1;//操作數
int num2;
int res;//運算結果
//開始掃描
for (String item : expressionList) {
if(item.matches("\\d+")) {// \d+表示1個或多個0到9的數字,是整數部分(至少是一位整數的整數部分)
//直接入棧
stack.push(item);
}else {
//操作符,彈出兩位數進行運算,運算結果重新進棧
num2 = Integer.parseInt(stack.pop());
num1 = Integer.parseInt(stack.pop());
res = 0;
//後綴表達式(逆波蘭表達式)是從左向右掃描
if(item.equals("+")) {
res = num1 + num2;
}else if(item.equals("-")) {
res = num1 - num2;
}else if(item.equals("*")) {
res = num1 * num2;
}else if(item.equals("/")) {
res = num1 / num2;
}else {
throw new RuntimeException("運算符錯誤");
}
stack.push(res+"");
}
}
//循環結束後只剩下運算結果
System.out.println("運算結果="+stack.pop());
}