字符串表達式的計算
步驟:
(1) 初始化兩個棧:運算符棧S1和儲存中間結果的棧S2;
(2) 從左至右掃描中綴表達式;
(3) 遇到操作數時,將其壓入S2;
(4) 遇到運算符時,比較其與S1棧頂運算符的優先級:
(4-1) 如果S1為空,或棧頂運算符為左括號“(”,則直接將此運算符入棧;
(4-2) 比棧頂高,也將運算符壓入S1 (注意轉換為前綴表達式時是優先級較高或相同,而這里則不包括相同的情況);
(4-3) 比棧頂低或相同,將S1棧頂的運算符彈出並壓入到S2中,再次轉到(4-1)與S1中新的棧頂運算符相比較;
(5) 遇到括號時:
(5-1) 如果是左括號“(”,則直接壓入S1;
(5-2) 如果是右括號“)”,則依次彈出S1棧頂的運算符,並壓入S2,直到遇到左括號為止,此時將這一對括號丟棄;
(6) 重復步驟(2)至(5),直到表達式的最右邊;
(7) 將S1中剩余的運算符依次彈出並壓入S2;
(8) 依次彈出S2中的元素並輸出,結果的逆序即為中綴表達式對應的后綴表達式(轉換為前綴表達式時不用逆序)。
例:1+((2+3)×4)-5
java版 | 詳見
import java.util.LinkedList; import java.util.List; import java.util.Scanner; import java.util.Stack; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.nextLine(); sc.close(); System.out.println(getResult(getPost(s))); } /** * 計算后綴表達式的值 * @param list 后綴表達式 * @return */ public static int getResult(List<Character> list) { Stack<String> stack = new Stack<>(); for(int i = 0; i < list.size(); i++) { char c = list.get(i); if(c >= '0' && c <= '9') { //當遇到操作數直接壓棧 stack.push(c + ""); } else {//當遇到操作符的時候,從棧中彈出兩個元素,然后根據運算符的不同做相應的運算,然后把運算結果壓棧。 int b = Integer.parseInt(stack.pop()); int a = Integer.parseInt(stack.pop()); if(c == '+') stack.push(a + b + ""); else if(c == '-') stack.push(a - b + ""); else if(c == '*') stack.push(a * b + ""); else stack.push(a / b + ""); } } //最終棧中肯定只剩下一個元素,就是計算的結果。 return Integer.parseInt(stack.pop()); } /** * 把中綴表達式轉為后綴表達式 * 前提條件:操作數的范圍為0-9,操作符為+,-,*,/,以及() * @param s 字符串表達式 * @return */ public static List<Character> getPost(String s) { Stack<Character> stack = new Stack<>(); //保存操作符 LinkedList<Character> list = new LinkedList<>(); //保存最終的后綴表達式 for(int i = 0; i < s.length(); i++) { char c = s.charAt(i); if(c >= '0' && c <= '9') list.add(c); //操作數直接輸出到后綴表達式中 else if(c == '+' || c == '-' || c == '*' || c == '/') { //把比當前操作符c的優先級高或者等於c的優先級的操作符依次彈出棧並保存到后綴表達式中,直到遇到棧頂操作符的優先級比c低 while(!stack.isEmpty()) { if(compare(stack.peek()) >= compare(c)) { list.add(stack.pop()); } else break; } stack.push(c);//當前操作符c入棧 } else if(c == '(') stack.push(c); //左括號直接入棧 else { //當遇到右括號的時候,把棧中的操作符依次彈出並追加到后綴表達式中,直到遇到左括號停止,並把左括號彈出。 while(stack.peek() != '(') { list.add(stack.pop()); } stack.pop(); } } //把棧中所有的操作符全部彈出追加到后綴表達式中 while(!stack.isEmpty())list.add(stack.pop()); return list; } /** * 計算運算符的優先級 * @param c 運算符 * @return */ public static int compare(char c) { if(c == '+' || c == '-') return 1; else if(c == '*' || c == '/') return 2; else return 0; } }
c++版
#define STACK_MAX 64 #define BOTTOM_NUMBER -1 typedef struct{ int TOP; const int BOTTOM; char STACK_M[STACK_MAX]; }STACK_BASE_TY; 我們采用數組STACK_M 作為棧的實體,BOTTOM作為棧底, 使用數組作為棧的實體,那么就可以規定棧底的索引值為“-1”。 棧從0~STACK_MAX-1正向增長。 當然我們還要編寫棧的操作方法,為了方便管理我們編寫一個結構體來管理函數。 typedef struct { void (*Initial) ( STACK_BASE_TY *pStack); int (*Push) ( STACK_BASE_TY *pStack, int data); int (*Pop) ( STACK_BASE_TY *pStack, char *pdata); char (*GetTopData) ( STACK_BASE_TY *pStack); int (*GetTopLocate) ( STACK_BASE_TY *pStack); }STACK_OPTION_TY; 我們規划一下每個函數的功能: 1.初始化棧,初始化棧的目的是建立一個空棧。即將TOP指針指向BOTTOM。pStack指向要初始化的棧的實體。 2.壓棧,將一個數據的值壓入棧頂。返回0,棧滿,壓入錯誤;返回1,壓棧成功。 3.出棧,彈出棧頂的數據。*pdata接收出棧數據的值。返回0,棧空,出棧錯誤;返回1,出棧成功。 4.獲取棧頂數據值,但是棧頂指針不發生變化。 5.獲取棧頂的位置。 void initialStack( STACK_BASE_TY *pStack ) { int i; pStack->TOP = -1; for( i =0; i< STACK_MAX; i++ ) pStack->STACK_M[i]=0; } int pushStack( STACK_BASE_TY *pStack, int data ) { pStack->TOP++; if( pStack->TOP>=STACK_MAX ) { pStack->TOP--; return 0; } else { pStack->STACK_M[ pStack->TOP] = data; return 1; } } int popStack( STACK_BASE_TY *pStack, char *pdata ) { if(pStack->TOP<=pStack->BOTTOM) { return 0; } else { *pdata = pStack->STACK_M[pStack->TOP]; pStack->TOP--; return 1; } } int getStackTopLocate(STACK_BASE_TY *pStack) { return pStack->TOP; } char getTopData( STACK_BASE_TY *pStack ) { return pStack->STACK_M[pStack->TOP]; } 定義兩個棧, STACK_BASE_TY statck_option={0,-1,{0,0}}; STACK_BASE_TY statck_result={0,-1,{0,0}}; STACK_BASE_TY* const pOptionStatck = &statck_option; STACK_BASE_TY* const pResultStatck = &statck_result; statck_option存放運算符號,statck_result存放最終結果。 STACK_OPTION_TY stackOption = {initialStack,pushStack,popStack,getTopData,getStackTopLocate} ; 定義一個函數結構體,並且初始化,使得我們可以方便的調用棧的操作方法。 const char str[] = "(1+2+3)*(4+5)"; 測試公式 int main( ) { unsigned int i; char temp; char opCh_0,opCh_1; int compPr; stackOption.Initial(pOptionStatck); stackOption.Initial(pResultStatck); for( i=0; i<strlen(str); i++) { switch( str[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': stackOption.Push(pResultStatck,str[i]); break; case '+': case '-': if( stackOption.GetTopLocate(pOptionStatck) ==-1 ) { stackOption.Push(pOptionStatck,str[i]); } else { opCh_0 = stackOption.GetTopData(pOptionStatck); if( opCh_0=='(') { stackOption.Push(pOptionStatck,str[i]); } else { while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&& (opCh_0!='(')) { if(stackOption.Pop(pOptionStatck,&opCh_0 )!=0) { if(opCh_0!='(') { stackOption.Push(pResultStatck, opCh_0); } } } stackOption.Push(pOptionStatck,str[i] ); } } break; case '*': case '/': if( stackOption.GetTopLocate(pOptionStatck) ==-1 ) { stackOption.Push(pOptionStatck,str[i]); } else { opCh_0 = stackOption.GetTopData(pOptionStatck); if(( opCh_0=='(')||(opCh_0=='+')||(opCh_0=='-')) { stackOption.Push(pOptionStatck,str[i]); } else { while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&& (opCh_0!='(')) { opCh_0 = stackOption.GetTopData(pOptionStatck); if(( opCh_0=='(')||(opCh_0=='+')||(opCh_0=='-')) { break; } else { stackOption.Pop(pOptionStatck,&opCh_0); stackOption.Push(pResultStatck,opCh_0); } } stackOption.Push(pOptionStatck,str[i] ); } } break; case '(': stackOption.Push(pOptionStatck,str[i]); break; case ')': if( stackOption.GetTopLocate(pOptionStatck) ==-1 ) { } else { opCh_0 = stackOption.GetTopData(pOptionStatck); if( opCh_0=='(') { stackOption.Pop(pOptionStatck,&opCh_0); } else { while((stackOption.GetTopLocate(pOptionStatck) !=-1 )&& (opCh_0!='(')) { opCh_0 = stackOption.GetTopData(pOptionStatck); if( opCh_0!='(') { stackOption.Pop(pOptionStatck,&opCh_0); stackOption.Push(pResultStatck,opCh_0); } else { stackOption.Pop(pOptionStatck,&opCh_0); } } } } break; default: break; } } while(stackOption.Pop(pOptionStatck,&opCh_0)!=0) { stackOption.Push(pResultStatck,opCh_0); } while(stackOption.Pop(pResultStatck,&opCh_0)!=0) { printf("%c,",opCh_0); } printf("\n"); return 0; }