中綴表示式轉字尾表示式求值(棧的應用)
阿新 • • 發佈:2019-01-02
咱們熟悉的四則運算表示式,中綴表示式,例如 (12+3)*2-6/2
利用堆疊的方法把中綴表示式轉換成保值的字尾表示式(又稱逆波蘭表示法),並最終變為計算機可以直接執行的指令,得到表示式的值
挺簡單的不假,也好理解,但就是一直無緣無故的卡著,卡的蛋疼……
也不能說完全的無緣無故,其實是手生了吧,太生了……
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<stack> using namespace std; #define N 1000 char infix[N]; //中綴表示式(未分離,都在一個字串裡) char expression[N][10]; //儲存預處理過的表示式,也就是每個元素都分離過的表示式 char suffix[N][10]; //儲存字尾表示式的運算元 int count;//表示式中元素的個數(一個完整到數字(可能不止一位數)或者符號) int suffixLength;//字尾表示式的長度 int level(char a){ switch(a){ case '#':return 0; case '+': case '-':return 1; case '*': case '/':return 2; case '^':return 3; default:break; } return -1; } int isDigital(char x){ if( (x>='0'&&x<='9') || (x>='A'&&x<='Z') || (x>='a'&&x<='z') || (x=='.') ) return 1; return 0; } int isNumber(char *str){ int i; for(i=0;str[i];i++){ if(isDigital(str[i])==0)return 0; } return 1; } /************************************* 預處理中綴表示式,把連續的字元分離成不同的元素,用字串陣列(expression[][]) 儲存,方便後面的計算,因為這裡考慮了運算數可能不全是個位數 比如:(12+3) 在處理成字尾表示式時,是123+,容易產生歧義(1+23 ? 12+3) *************************************/ void pretreatment(char *str){ int i,j,numberFlag; char temp[3]; char number[10]; count=0; numberFlag=0; for(j=0,i=0;str[i];i++){ if(isDigital(str[i])==0){ if(numberFlag==1){ number[j]=0; strcpy(expression[count++],number); j=0; numberFlag=0; } if(str[i]!=' '){ temp[0]=str[i];temp[1]=0; strcpy(expression[count++],temp); } } else { numberFlag=1; number[j++]=str[i]; } } puts("分離後的表示式為"); for(i=0;i<count;i++){ printf("%s ",expression[i]); }puts(""); puts(""); } /***************************************** 中綴表示式 轉 字尾表示式 遍歷字串,對於str[i] str[i]是運算數(或者是字母代替的運算變數)輸出; str[i]是符號,有兩種情況 (1),是右括號,棧頂元素輸出,直到與str[i]匹配的左括號出棧(左括號不用輸出列印) (2),是運算子,判斷str[i]與棧頂元素的優先順序,str[i]優先順序 不高於 棧頂符號,則棧 頂元素輸出,直到棧空 或者 棧頂符號優先順序低於str[i] *****************************************/ void infix_to_suffix(char str[N][10]){ memset(suffix,0,sizeof(suffix)); suffixLength=0; stack <char*> st; int i=0; char Mark[2]="#"; st.push(Mark); do{ if(isNumber(str[i])==1)//運算數直接儲存到字尾表示式中 strcpy(suffix[suffixLength++],str[i]); else if(str[i][0]=='(') //是 左括號,直接入棧 st.push(str[i]); else if(str[i][0]==')'){ //是 右括號,棧頂出棧,直到與其匹配的左括號出棧 while( strcmp(st.top(),"(")!=0 ){ char temp[10]; strcpy(temp,st.top()); strcpy(suffix[suffixLength++],temp); st.pop(); } st.pop(); } else if( strcmp(st.top(),"(")==0 )//是 運算子,且棧頂是左括號,則該運算子直接入棧 st.push(str[i]); else { //是 運算子,且棧頂元素優先順序不小於運算子,則棧頂元素一直 //出棧,直到 棧空 或者 遇到一個優先順序低於該運算子的元素 while( !st.empty() ){ char temp[10]; strcpy(temp,st.top()); if( level(str[i][0]) > level(temp[0]) ) break; strcpy(suffix[suffixLength++],temp); st.pop(); } st.push(str[i]); } i++; }while(str[i][0]!=0); while( strcmp(st.top(),"#")!=0 ){ //將棧取空結束 char temp[10]; strcpy(temp,st.top()); strcpy(suffix[suffixLength++],temp); st.pop(); } puts("字尾表示式為:"); for(i=0;i<suffixLength;i++){ printf("%s",suffix[i]); }puts(""); puts(""); } /************************************** 計算字尾表示式的值 **************************************/ char kt[N][10]; int stackTop; void getResult(char str[N][10]){ stackTop=0; /*這裡要注意,記憶體的分配方案導致 i 的位置就在temp[9]旁邊,然後strcpy()函式直接拷貝記憶體的話,在temp越界情況下會覆蓋 i 的值*/ int i; char temp[10]; for(i=0;i<suffixLength;i++){ if(isNumber(str[i])==1){ strcpy(kt[stackTop++],str[i]); } else { char a[10],b[10]; double na,nb,nc; strcpy(a,kt[stackTop-1]); na = atof(a); stackTop--; strcpy(b,kt[stackTop-1]); nb = atof(b); stackTop--; if(str[i][0]=='+')nc=nb+na; else if(str[i][0]=='-')nc=nb-na; else if(str[i][0]=='*')nc=nb*na; else if(str[i][0]=='/')nc=nb/na; sprintf(temp,"%lf",nc); strcpy(kt[stackTop++],temp); } } puts("計算出字尾表示式的結果:"); printf("%s\n",kt[stackTop-1]); } int main(){ char temp[N]; while(gets(infix)){ strcpy(temp,infix); pretreatment( strcat(temp," ") ); infix_to_suffix(expression); getResult(suffix); } return 0; }