使用棧實現中綴表達式轉換成後綴表達式並計算結果(逆波蘭計算器)

一、中綴表達式轉換成後綴表達式

具體步驟如下:

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());
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章