把中缀表达式转换为后缀表达式。
基本思路是。每一个符号最开始都是悬而未决的。是否简单的把符号放到左右数字的后面,都是由后面的符号决定。所以先插入第一个符号。后面拿到的符号必须和之前的符号(栈顶)比较,栈顶和新符号平级或者栈顶更优先,那么栈顶符号插入后缀表达式。
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(" sum:"+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;