棧的應用之中綴轉字尾
棧的應用之中綴轉字尾詳解
先理一下大概的思路:
中綴表示式一般有運算元,運算子,括號,運算子和括號又存在運算優先順序問題,這就是我們需要處理的問題。
中綴表示式轉字尾表示式時:
1、遇到運算元或 ‘.’ 直接寫入字尾表示式;
2、遇到左括號直接進入操作符的棧中;
3、遇到運算子時,將該運算子與3、棧頂元素比較,如果優先順序高於棧頂元素,直接入棧,反之則將棧頂元素出棧,並寫入字尾表示式,該運算子入棧;
4、 遇到右括號時,將棧中元素出棧並寫入字尾表示式,直到遇到左括號結束,並將左括號也出棧;
5、最後將棧中元素全部出棧並寫入字尾表示式。
下面來看具體步驟和程式碼:
一、中綴轉字尾
1、定義一個運算子判斷函式,如果該字元是運算子,返回1;否則返回0
int is_operation(char op){ //op是要判斷的字元
switch(op){
case '+':
case '-':
case '*':
case '/':return 1;
default:return 0;
}
}
2.定義一個整型函式,用來返回運算子的優先順序大小(不是運算子(比如 ‘#’ )的符號優先順序為-1 )
int priority(char op){ switch(op){ case '#':return -1; case '(':return 0; case '+': case '-':return 1; case '*': case '/':return 2; default:return -1; } }
3.開始轉化:這裡定義了一個opst[]陣列來作為操作符棧。
在中綴表示式的末尾加上一個 ‘#’ 來作為迴圈結束的條件
while(e[i] != '#'){}
在迴圈體內:
1)遇到數字和小數點直接寫入字尾表示式
if((e[i] >= '0' && e[i] <= '9') || e[i] == '.'){
f[j++] = e[i]; //f[]是存放字尾表示式的陣列
//e[]是存放中綴表示式的陣列
}
2)遇到左括號直接進操作符棧
else if(e[i] == '('){ opst[top] = e[i]; top++; //opst[]是操作符棧 }
3)遇到右括號把左括號後的操作符全部寫入字尾表示式
else if(e[i] == ')'){
t = top - 1; //用 t 變數來表示棧頂下面的那個值(找到'(')
while(opst[t] != '('){ //直到遇到'('才結束迴圈
f[j++] = opst[--top]; //寫入字尾表示式並出棧
t = top - 1;
}
top -- ; //將'('出棧
}
4)比較運算子優先順序大小
else if(is_operation(e[i])){
f[j++] = ' ';//用空格分開兩個運算元
while(priority(e[i]) <= priority(opst[top-1])){
f[j++] = opst[--top];//優先順序小的出棧
}
opst[top] = e[i]; top++;//當前元素進棧
}
5)把剩餘的操作符出棧並寫入字尾表示式
while(top) f[j++] = opst[--top];
此時已經把中綴表示式轉成了字尾表示式,然後我們需要先把運算元從字元轉為數字,再進行運算。
二、字尾表示式的計算
1.運算元:字元轉為浮點型數字(整數部分和小數部分)。
這裡的i一定要用指標,因為要在該函式裡改變i的值並使之在呼叫的地方有效。
double readNumber(char f[],int *i){}
1)整數部分
字元轉浮點型,這裡有兩種方法:
第一種是直接用 f[ i ] - '0’ ,第二種是使用atof函式:atof(f[i]).
這裡的x每加一次都要*10,這是因為十進位制的進位制是10.
while(f[*i] >= '0' && f[*i] <= '9'){ //直到這個整數全部讀出了就結束(遇到其他符號)。
x = x*10 + (f[*i] - '0'); //還原運算元
(*i)++; //向後尋找
}
2)小數部分
這裡與整數部分類似,就是多了個標誌變數k,k每加1,說明該數的小數部分就多了一位,在最後需要除以相應的位數。
if(f[*i] == '.'){
(*i)++; //後移一位(移到'.'的後面一位)
while(f[*i] >= '0' && f[*i] <= '9'){
x = x*10 + (f[*i] - '0');
(*i)++;
k++; //小數部分多一位,k+1
}
}
while(k!=0){ //每次迴圈除以10,直到k為0
x = x/10.0;
k -- ;
}
2.計算字尾表示式的值
定義兩個浮點型變數x1,x2 來表示兩個運算元, obst[]表示運算元棧
1)迴圈,直到遇到’#'結束
while(f[i] != '#'){}
2)將運算元入棧
if(f[i] >= '0' && f[i] <= '9'){
obst[top] = readNumber(f,&i);
top++;
}
3)如果是空格(即字尾表示式裡的運算元分隔符),就繼續向下
else if(f[i] == ' ') i++;
4)進行四則運算
else if(f[i] == '+'){
x1 = obst[--top];
x2 = obst[--top];
obst[top] = x1 + x2; //將運算結果存入運算元棧,繼續進行運算
top++; i++;
}
else if(f[i] == '-'){
x1 = obst[--top];
x2 = obst[--top];
obst[top] = x1 - x2;
top++; i++;
}
else if(f[i] == '*'){
x1 = obst[--top];
x2 = obst[--top];
obst[top] = x1 * x2;
top++; i++;
}
else if(f[i] == '/'){
x1 = obst[--top];
x2 = obst[--top];
obst[top] = x2 / x1;
top++; i++;
}
5)返回運算元棧的第一個數字,即為最後的結果。
return obst[0]; //字尾表示式運算的最後結果
到這裡,中綴轉字尾表示式,以及字尾表示式的運算都搞定啦。
希望能幫到對中綴轉字尾還是不太理解的同學。
最後在此附上程式完整程式碼. GitHub地址:https://github.com/jie12366/postfix.git