這幾天學習《算法》這本書,第一章後面的習題,關於算術表達式,前序表達式,中序表達式,後序表達式的實現,我學習了兩天,不斷的編寫調試,初步實現了具體功能。首先
中序表達式 | ((1+2)*((3-4)*(5-6)))) | |
後序表達式 | 12+34-56-** | |
前序表達式 | *+12*-34-56 |
中序表達式是我們人類習慣使用的表達,但是,計算機很難使用。計算機一般是採用棧的技術來實現的,要麼轉換爲前序表達式,要麼轉換爲後序表達式。
例如以後序表達式爲例,12+34-56-**
首先2與1+等於3,變成334-56-**
然後4-3變成,3156-**
然後6-5變成,311**
然後1*1,變成31*
最後等於3
即從右至左取數,直到取出一個運算符,將剛取出的緊挨着運算符的兩個操作數按運算符進行計算,結果回填至運算符。重複該步驟,直到最後只剩下一個字符串則剩下的字符串即爲結果。
後序表達式的字符串掃描方式正好和前序相反,是從左往右掃描,規則類似。
中序表達式轉後序表達式步驟
1、輸入字符串,如“2*3/(2-1)+3*(4-1)”
2、從字符串中取出下一個字符
2.1.如果是操作數,則直接輸出
2.2.如果是“(”,壓入棧中
2.3.如果是運算符但不是“(”,“)”,則不斷循環進行以下處理
2.3.1.如果棧爲空,則此運算符進棧,結束此步驟
2.3.2.如果棧頂是“(”,則此運算符進棧,結束此步驟
2.3.2.如果此運算符與棧頂優先級相同或者更高,此運算符進棧,結束此步驟
2.3.4.否則,運算符連續出棧,直到滿足上述三個條件之一,然後此運算符進棧
2.4、如果是“)”,則運算符連續出棧,直到遇見“(”爲止,將“(”出棧且丟棄之
3、如果還有更多的字符串,則轉到第2步
4、不在有未處理的字符串了,輸出棧中剩餘元素
程序源碼爲:
package sanzhang; import ref.Stack; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class exe6 { public static void main(String[] args) { // TODO Auto-generated method stub //String strold="2*3/(2-1)+3*(4-1)"; String strold="((1+2)*((3-4)*(5-6)))"; //String strold="(1+2)+(8/4)"; //String strold="3*(2-1)*3*(6/3)"; //存放棧 Stack<String> oper=new Stack<String>(); //轉換成字符型數組 char ch[]=strold.trim().toCharArray(); //定義一個字符串數組 String str[]=new String[ch.length]; //存放結果數組 List<String> list=new ArrayList<String>(); //將原來表達式字符數組轉換成字符串數組 for(int i=0;i<ch.length;i++) { str[i]=String.valueOf(ch[i]); } //逐個判斷字符串 for(int i=0;i<str.length;i++) { //當輸入的是操作數時,直接添加到結果表達式後 if(str[i].matches("^[1-9]\\d*$"))//正則表達式 { list.add(str[i]); } else //當輸入的是左括號的時候,直接入棧 if(str[i].equals("(")) { oper.push(str[i]); } //如果是右括號,則運算符連續出棧,直到遇見左括號爲止,左括號出棧且丟棄它 else if(str[i].equals(")")) { while(oper.size()> 0 && !oper.peek().equals("(")) { //運算符連續出棧 String ss = oper.pop(); list.add(ss); } //直到遇到左括號,並丟棄之 oper.pop(); } //如果爲操作符+-*/等 else { //如果棧爲空,直接進棧 if(oper.isEmpty()) { oper.push(str[i]); continue; } else //如果棧頂爲左括號,運算符進棧 if(oper.peek().equals("(")) { oper.push(str[i]); continue; } else //如果此運算符與棧頂優先級相同或更高,此運算符進棧,結束此步驟,取下一個字符, if(priority(str[i])>priority(oper.peek())) { oper.push(str[i]); } //如果三個條件均不滿足,則連續出棧,直到滿足其中三個一個,再進棧 else { do { list.add(oper.pop()); } while(!(oper.isEmpty()||oper.peek().equals("(")||priority(str[i])>priority(oper.peek()))); oper.push(str[i]); } } } //如果此時棧非空,全部輸出 while(!oper.isEmpty()) { list.add(oper.pop()); } //對結果動態數組遍歷 for(int i=0;i<list.size();i++) { System.out.print(list.get(i)+""); } System.out.println(); //輸出計算結果 System.out.println(calcauteAfterExpression(list)); } // 返回運算符的優先級 public static int priority(String temp) { char ch=temp.charAt(0); int pri; switch (ch) { case '+': pri = 1; break; case '-': pri = 1; break; case '*': pri = 2; break; case '/': pri = 2; break; default: pri = 0; break; } return pri; } //判斷是否爲運算符 public static boolean IsOperator(String temp) { if(temp.equals("+")||temp.equals("-")||temp.equals("*")||temp.equals("/")) return true; return false; } /// <summary> /// 計算後序表達式 /// </summary> //將操作數動態數組作爲參數進行傳遞 public static int calcauteAfterExpression(List<String> newExpression ) { int result=0 ; if (newExpression.size() > 1) { int i = 0; for (i = 0; i < newExpression.size(); i++) { //首先判斷是否爲運算符 if (IsOperator(newExpression.get(i))) { //取運算符左邊與運算符次左邊的進行運算 if (newExpression.get(i).equals("+")) { result =Integer.parseInt(newExpression.get(i-2))+Integer.parseInt(newExpression.get(i-1)); } else if (newExpression.get(i).equals("-")) { result =Integer.parseInt(newExpression.get(i-2))-Integer.parseInt(newExpression.get(i-1)); } else if (newExpression.get(i).equals("*")) { result =Integer.parseInt(newExpression.get(i-2))*Integer.parseInt(newExpression.get(i-1)); } else if (newExpression.get(i).equals("/")) { result =Integer.parseInt(newExpression.get(i-2))/Integer.parseInt(newExpression.get(i-1)); } break; } } //第一輪計算完畢,將運算符所在的位置用計算得到的結果進行替換,並把運算符左邊的元素和次左邊的元素移除 newExpression.set(i, String.valueOf(result)); newExpression.remove(i-1); newExpression.remove(i-2); //再進行遞歸運算 calcauteAfterExpression(newExpression); } //直到運算符全部用完,只剩下最後一個操作數,即爲我們所需要的值 return Integer.parseInt(newExpression.get(0)); } }
中序表達式轉前序表達式步驟
1、反轉輸入字符串,如“2*3/(2-1)+3*(4-1)” 反轉後爲“ )1-4(*3+)1-2(/3*2”,
2、從字符串中取出下一個字符
2.1.如果是操作數,則直接輸出
2.2.如果是“)”,壓入棧中
2.3.如果是運算符但不是“(”,“)”,則不斷循環進行以下處理
2.3.1.如果棧爲空,則此運算符進棧,結束此步驟
2.3.2.如果棧頂是“)”,則此運算符進棧,結束此步驟
2.3.2.如果此運算符與棧頂優先級相同或者更高,此運算符進棧,結束此步驟
2.3.4.否則,運算符連續出棧,直到滿足上述三個條件之一,然後此運算符進棧
2.4、如果是“(”,則運算符連續出棧,直到遇見“)”爲止,將“)”出棧且丟棄之
3、如果還有更多的字符串,則轉到第2步
4、不在有未處理的字符串了,輸出棧中剩餘元素
5、再次反轉字符串得到最終結果
package sanzhang; import java.util.*; public class exe7 { public static void main(String[] args) { // TODO Auto-generated method stub //String strold="2*3/(2-1)+3*(4-1)"; String strold="((1+2)*((3-4)*(5-6)))"; Stack<String> oper=new Stack<String>(); StringBuffer sb=new StringBuffer();//記錄結果表達式 char ch[]=strold.trim().toCharArray(); String str[]=new String[ch.length]; List<String> list=new ArrayList<String>(); for(int i=ch.length-1;i>=0;i--) { list.add(String.valueOf(ch[i])); } //獲得反轉字符串 for(int j=0;j<str.length;j++) { str[j]=list.get(j); } for(int i=0;i<str.length;i++) { //如果是操作數,直接輸出 if(str[i].matches("^[1-9]\\d*$")) { sb.append(str[i]); } //如果是“)”,壓入棧中 else if(str[i].equals(")")) { oper.push(str[i]); } //如果是左括號,則運算符連續出棧,直到遇見右括號爲止,右括號出棧且丟棄它 else if(str[i].equals("(")) { //右括號 while (oper.size()> 0 && !oper.peek().equals(")")) { String ss = oper.pop(); sb.append(ss); } //右括號出棧且丟棄它 oper.pop(); } else { //如果棧爲空,次運算符進棧,結束此步驟,取下一個字符 if (oper.size()== 0) { oper.push(str[i]); } //如果棧頂是“)”,此運算符進棧,結束次步驟,讀取下一個字符 else if (oper.peek().toString() == ")") { oper.push(str[i]); } //如果此運算符與棧頂優先級相同或更高,此運算符進棧,結束次步驟,取下一個字符, else if (priority(str[i])>=priority(oper.peek().toString())) { oper.push(str[i]); } //否則,運算符連續出棧,直至滿足上述三個條件之一退出此步驟 else { do { String podstr = oper.pop().toString(); sb.append(podstr); } while (!(oper.size() == 0 ||oper.peek().toString() == ")" || priority(str[i])>=priority(oper.peek().toString()))); oper.push(str[i]); } } } while(oper.size()!=0) { sb.append(oper.pop()); } System.out.println(sb.reverse()); } // 返回運算符的優先級 public static int priority(String temp) { char ch=temp.charAt(0); int pri; switch (ch) { case '+': pri = 1; break; case '-': pri = 1; break; case '*': pri = 2; break; case '/': pri = 2; break; default: pri = 0; break; } return pri; } }