把中綴表達式轉換為后綴表達式。
基本思路是。每一個符號最開始都是懸而未決的。是否簡單的把符號放到左右數字的后面,都是由后面的符號決定。所以先插入第一個符號。后面拿到的符號必須和之前的符號(棧頂)比較,棧頂和新符號平級或者棧頂更優先,那么棧頂符號插入后綴表達式。
public static void main(String[] args) { // TODO Auto-generated method stub //linklist2(); //arraylist(); //stack(); caculate("3+2*(4-6)/2"); } //caculate public static void caculate(String expression) { //1.check expression. 2.postfix expression. 3.caculate postfix expression. //1. assume expression is ok. MyArrayList<Object> OBJexpression=new MyArrayList<Object>(); int expressionLength=expression.length(); for(int i=0;i<expressionLength;i++) { char tempChar=expression.charAt(i); String tempString=""; switch (tempChar) { case '+': tempString="+"; OBJexpression.Add(tempString); break; case '-': tempString="-"; OBJexpression.Add(tempString); break; case '*': tempString="*"; OBJexpression.Add(tempString); break; case '/': tempString="/"; OBJexpression.Add(tempString); break; case '(': tempString="("; OBJexpression.Add(tempString); break; case ')': tempString=")"; OBJexpression.Add(tempString); break; default: tempString=String.valueOf(tempChar); Integer tempint=Integer.valueOf(tempString); OBJexpression.Add(tempint); break; } } OBJexpression.ShowEach(); //2.transfor to postfix expression. 循環比較剛取出符號和棧頂符號。 待比較符號(棧頂),只要比剛取出符號大,或者平級,那么棧頂就出棧。 MyLinkedList2<Object> postfixExpression=new MyLinkedList2<Object>(); MyStack<String> tempFlag=new MyStack<String>(); for(int i=0;i<OBJexpression.Size();i++) { if(OBJexpression.Get(i) instanceof Integer) { if(i==OBJexpression.Size()-1) { postfixExpression.Add(OBJexpression.Get(i)); while(tempFlag.size()>=1) { postfixExpression.Add(tempFlag.pop()); } } else { postfixExpression.Add(OBJexpression.Get(i)); } } else { //1empty ->add. otherwize:compare. if(tempFlag.size()==0) { tempFlag.push(OBJexpression.Get(i).toString()); } else { if(OBJexpression.Get(i).toString()=="(") { tempFlag.push(OBJexpression.Get(i).toString()); } else if(OBJexpression.Get(i).toString()==")") { while(tempFlag.top()!="(") { String topFlag=tempFlag.pop(); postfixExpression.Add(topFlag); } tempFlag.pop(); } else { while(getLevel(OBJexpression.Get(i).toString()) <= getLevel(tempFlag.top()) && tempFlag.size()>=1) { String topFlag=tempFlag.pop(); postfixExpression.Add(topFlag); } tempFlag.push(OBJexpression.Get(i).toString()); } } } } postfixExpression.ShowEach(); //caculate expression. //1.數字放入 結果棧中,符號-》pop2個數字運算,push結果。直到符號空。 MyStack<Integer> resultStack=new MyStack<Integer>(); for(int i=0;i<postfixExpression.Size();i++) { if(postfixExpression.Get(i) instanceof Integer) { resultStack.push((Integer)postfixExpression.Get(i)); } else { Integer int2=resultStack.pop(); Integer int1=resultStack.pop(); Integer int3=simpleCaculate(int1, int2, postfixExpression.Get(i).toString().charAt(0)); resultStack.push(int3); } } if(resultStack.size()==1) { System.out.println("\r\nsum:"+resultStack.pop()); } int a=666; } private static Integer simpleCaculate(int int1,int int2,Character flag) { int ret=0; switch (flag) { case '+': ret=int1+int2; break; case '-': ret=int1-int2; break; case '*': ret=int1*int2; break; case '/': ret=int1/int2; break; } return ret; } private static int getLevel(String flag) { int result=-1; if(flag=="+" ||flag=="-") { result=1; } else if(flag=="*" ||flag=="/") { result=2; } else if(flag=="(" ||flag==")") { result=0; } return result; }
//一,無括號的n級符號算法。
//如2+3*6-4轉化為236*+4-。+號不能防入2和3后面,因為*號更優先。+號必須作用於3*6和2。
//分析:
//創建一個后綴表達式堆,一個臨時符號棧。
//讀入的數字放入后綴表達式堆。
//讀入的符號必須和后面的符號比較,只有優先級更高才能插入到后綴表達式堆后面。
//所以第一個符號一定先入符號棧,等后面符號出來,才能決定棧頂符號是否放入后綴表達式堆。
//因此每次讀到運算符,決定的不是這個運算符是否放入后綴表達式,而是決定前一個符號(棧頂符號)的去留。
//1)讀入的是數字,直接放入后綴表達式堆
//2)讀入的是符號:
// 2。1)如果符號棧為空,動作:放入棧,原因:只有一個符號,必須等待插入數字后,並讀起后面一個符號再處理。
// 2。2)如果符號棧非空,且優先級>=棧頂符號,動作:放入棧。原因:棧頂符號,優先級更低,暫時不能放入后綴表達式堆,而剛讀的符號也必須再一次等待插入數字后,並和后面一個符號比較再處理(我們並不固定符號優先級別只有2級,)。
// 2。3)如果符號棧非空,且優先級<=棧頂符號,動作,pop棧頂符號,防入后綴表達式堆。新讀的符號繼續和棧頂符號比較,重復第2)大步驟
// 原因:棧頂符號優先級別高,可以馬上放到它左右數字的后面形成后綴表達式。(讀入符號前,已經把棧頂的右邊數字防入后綴表達式堆)
// 繼續比較的原因,可以看作之前插入的棧頂符號,其實是插入了一個臨時結果,而此時的棧頂符號,必須和讀入的符號,再次爭奪臨時結果的處理優先級。自己看下2+3*6^5+2,^插入后,*和+爭奪6^5就清楚了。
//3)到達表達式結尾。動作:把符號從符號棧,從棧頂依次放入后綴表達式堆。用后綴方法,計算后綴表達式堆。
// 原因:此時符號棧的符號優先級肯定是逐步遞增的,否則中途有一個不是遞增那么它之前的符號已經進入后綴表達式堆了。
//這里2。3需要再次分析下。2。3和一直和棧頂符號比較,最終會走向2,1,或2。2。最后這個剛讀入的符號是一定會入符號棧的。
//所以,所有的符號和數字都在后綴表達式堆或臨時符號棧。而第3)又會把所有最終留下的符號放入后綴表達式堆。
//二。有括號的算法。
//如(2+3)*6-4轉化為23+6*
//分析:
//讀入的符號碰到(,因為()內其實是一個子表達式。必須優先處理。也就是把()內的數字和符號轉化為中綴表達式,防入到后綴表達式堆后(相當於放入了一個臨時結果)
//棧頂的符號再和)之后的符號比較優先級。
//1)讀入的是數字,直接放入后綴表達式堆
//2)讀入的是運算符號:
// 2。1)如果符號棧為空,動作:放入棧,原因:只有一個符號,必須等待插入數字后,並讀起后面一個符號再處理。
// 2。2)如果符號棧非空,且優先級>=棧頂符號,動作:放入棧。原因:棧頂符號,優先級更低,暫時不能放入后綴表達式堆,而剛讀的符號也必須再一次等待插入數字后,並和后面一個符號比較再處理(我們並不固定符號優先級別只有2級,)。
// 2。3)如果符號棧非空,且優先級<=棧頂符號,動作,pop棧頂符號,防入后綴表達式堆。新讀的符號繼續和棧頂符號比較,重復第2)大步驟。
// 原因:棧頂符號優先級別高,可以馬上放到它左右數字的后面形成后綴表達式。(讀入符號前,已經把棧頂的右邊數字防入后綴表達式堆)
// 繼續比較的原因,可以看作之前插入的棧頂符號,其實是插入了一個臨時結果,而此時的棧頂符號,必須和讀入的符號,再次爭奪臨時結果的處理優先級。自己看下2+3*6^5+2,^插入后,*和+爭奪6^5就清楚了。
// 2。4)如果符號棧非空,且符號是(,動作,新符號入棧,原因:(屏蔽了之前符號,(后的符號必須和之后的符號比較。
// 2。5)如果符號棧非空,且符號是),不可能存在,因為4)會保證成隊消除(),)沒有入棧的可能。
//3)讀入的是(,動作:(入棧,原因,棧頂符號,必須等待()括號內全部放入后綴表達式堆后,再和)之后的符號比較。
//4)讀入的是),動作,一直插入棧頂符號到后綴表達式堆,直到碰到(,並pop掉(。
// 原因:我們必須把()內的符號和數字全部處理完,下一步才能繼續讓前括號(之前的懸而未決的符號和后括號)后面的符號比較。
// 為什么一直插入符號就可以,因為此時符號棧最后的前括號(之后的符號優先級肯定是逐步遞增的,道理和之前的算法,第3)是一樣。
//2+3*6^5+2;