1. 程式人生 > >棧的應用之中綴轉字尾

棧的應用之中綴轉字尾

棧的應用之中綴轉字尾詳解

先理一下大概的思路:
中綴表示式一般有運算元,運算子,括號,運算子和括號又存在運算優先順序問題,這就是我們需要處理的問題。
中綴表示式轉字尾表示式時:
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