中綴表達式轉逆波蘭表達式(後綴表達式)

編寫程序,將任意一個合法的中綴表達式轉換成逆波蘭式。

【問題描述】表達式計算是實現程序設計語言的基本問題之一。在計算機中進行算術表達式的計算可通過棧來實現。通常書寫的算術表達式由操作數、運算符以及圓括號連接而成。爲簡便起見,本題只討論雙目運算符。

算術表達式的兩種表示如下:

中綴表達式:把雙目運算符出現在兩個操作數中間的表示,稱爲算術表達式的中綴表示。中綴表示的算術表達式,稱爲中綴算術表達式,也稱中綴表達式。如表達式2+5*6就是中綴表達式。

後綴表達式:中綴表達式的計算比較複雜。能否把中綴表達式轉換成另一種形式的表達式,使計算簡單化呢?波蘭科學家盧卡謝維奇(Lukasiewicz)提出了算術表達式的另一種表示,即後綴表式,又稱逆波蘭式。

逆波蘭式即是將算術表達式用後綴方法表示,即,把運算符放在兩個運算對象的後面。逆波蘭式也稱後綴算術表達式,或後綴表達式。在逆波蘭式中,不存在括號,也不存在優先級的差別,計算過程完全按運算符出現的先後次序進行,整個計算過程僅需一遍掃描便可完成,比中綴表達式的計算簡單。

例如,12!4!-!5!/就是一個逆波蘭式。其中’!’表示操作數間的空格,因減法運算符在前,除法運算符在後,所以應先做減法,後做除法;減法的兩個操作數是它前面的12和4,其中第一個數12是被減數,第二個數4是減數;除法的兩個操作數是它前面的12減4的差(即8)和5,其中8是被除數,5是除數。

請查閱中綴表達式轉換成對應的後綴算術表達式的規則,完成本題。 表2是一些中綴表達式與後綴表達式對應的例子:

表1  中綴表達式與對應的逆波蘭式

中綴表達式

後綴表達式

3/5+6

3!5!/!6!+

16-9*(4+3)

16!9!4!3!+!*!-

2*(x+y)/(1-x)

2!x!y!+!*!1!x!-!/

(25+x)*(a*(a+b)+b)

25!x!+!a!a!b!+!*!b!+!*

【假設條件】本題應對輸入的中綴表達式,輸出其對應的逆波蘭式。假定表達式一定是合法的,且其中的數字均爲1位整數,運算符包括:+,-,*,/,(,)。輸入輸出均爲字符串形式。可以如下形式實現:void InfixToPostfix(char *infix, char *posfix);

 

數據結構的周作業,應該不會有同學看到這篇文章趴hhh

雖然中綴表達式符合人們的日常習慣,但是在計算機中,爲了方便計算表達式的值,一般都是採用前綴表達式或者後綴表達式,所以就需要我們能夠將中綴表達式進行相應的轉換,另外在題目中已經對後綴表達式進行了詳細的闡述,這裏不再贅述。

需要提到的是:算術表達式中由三個部分組成,操作數,運算符和圓括號。在中綴表達式中有時括號是必需的。計算過程中必須用括號將操作符和對應的操作數括起來,用於指示運算的次序。而在前綴表達式和後綴你表達式中不會存在括號,運算符都按照其優先級進行了相應的排序.

如果不儲存最後的後綴表達式,我們在掃描字符串的時候直接將其輸出的話,就只需要用到一個棧來儲存運算符。

轉換的過程如下,慢慢思考的話整個過程還是比較簡單的:

1,初始化儲存運算符的棧S1

2,從左往右掃描中綴表達式

3,遇到操作數的時候,將其輸出

4,遇到運算符的時候,比較其與S1棧頂運算符的優先級

  1,如果S1爲空,或者棧頂運算符爲左括號"(",直接將此運算符入棧

  2,否則如果優先級比棧頂運算符高,也將該運算符壓入S1,注意沒有相等

  3,否則將S1棧頂的運算符彈出並輸出,再次轉到4.1,令運算符與棧頂新的運算符進行比較

5,遇到括號:

  1,如果是左括號,直接壓入S1

  2,如果是右括號,捨棄右括號,並依次彈出S1棧頂的運算符,直到遇到左括號,再將左括號舍棄

6,重複步驟2-->5,直到表達式最右邊

7,將S1中剩餘的運算符依次彈出並輸出,最後顯示的就是轉換後的逆波蘭式(後綴表達式)

 

接下來是代碼實現,按照上面的分析步驟進行代碼編寫即可:

1,初始化儲存運算符的棧S1:

typedef struct{
	int top;
    char ch[100];
}Stack;
#define LEN sizeof(Stack)
Stack *init(){
	Stack* stack=(Stack*)malloc(LEN);
	stack->top=0;
	return stack;
}

  用數組來模擬棧,初始化空間爲ch[100],棧頂指針top最開始設置爲0

2,從左往右掃描中綴表達式

for(i=0;i<strlen(infix);)

  這裏的infix數組是輸入的中綴表達式字符串,沒有設置i++的原因是分情況進行討論,避免i重複累加

3,遇到操作數的時候,將其輸出

if(infix[i]>='0'&&infix[i]<='9'){
    while(infix[i]>='0'&&infix[i]<='9'){
        printf("%c",infix[i]);
        i++;		
    }
    printf("!");
}

  我們不再使用另一個隊列或數組對其結果進行儲存,而是直接將符合的結果直接輸出,節省了空間並且簡化操作,輸出獨立的數字之後再輸出"!"進行分割

4,遇到運算符的時候,比較其與S1棧頂運算符的優先級

這裏與棧頂運算符優先級的比較,爲了避免重複寫代碼,我們將其模塊化寫成check()函數,傳入兩個棧頂運算符和當前運算符進行優先級比較。

當前運算符的優先級比棧頂運算符的優先級高的時候,我們就令其入棧,而仔細思考之後只有一種情況,也就是棧頂運算符爲"+,-,("的時候,並且當前運算符爲"/ *"的時候,纔會入棧,其餘情況是相等或者低於,就不用入棧,直接彈出棧頂元素,然後用新的棧頂元素繼續比較

bool check(char a,char b){
	//a爲棧頂元素,b爲當前元素
	//返回true時,將當前元素壓入棧中, 即當前運算符比棧頂運算符的優先級高
	//返回false時 ,即當前運算符與棧頂運算符的優先級相等或低 
	if(a=='('){
		return true;
	}
	if((a=='+'||a=='-')&&(b=='*'||b=='/')){
		return true;
	}else{
		return false;
	}
}

5,遇到括號:

括號分爲左括號和右括號,左括號直接入棧,右括號的話直接拋棄,並且彈出棧中左括號上面的所有運算符,再拋棄左括號

if(infix[i]==')'){
    while(stack->ch[stack->top]!='('){
        pop(stack);
        if(stack->top>0||i<strlen(infix)){
            printf("!");
        }
    }
    stack->top--;
    i++;
}else if(stack->top==0||infix[i]=='('){
    push(stack,infix[i]);
    i++;
}

  

6,重複步驟2-->5,直到表達式最右邊

第六步直接在for循環裏面完成了,就不用再說

7,將S1中剩餘的運算符依次彈出並輸出,最後顯示的就是轉換後的逆波蘭式(後綴表達式)

 

while(stack->top){
	pop(stack);
	if(stack->top>0||i<strlen(infix)){
	    printf("!");
	}
}

  

 

然後是完整代碼:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
	int top;
    char ch[100];
}Stack;
int flag=1;
#define LEN sizeof(Stack)
Stack *init(){
	Stack* stack=(Stack*)malloc(LEN);
	stack->top=0;
	return stack;
}
void push(Stack* stack,char ch){
	stack->top++;
	stack->ch[stack->top]=ch;
}
void pop(Stack* stack){
	if(stack->top==0){
		return;
	}
	printf("%c",stack->ch[stack->top]);
	stack->top--;
}
bool check(char a,char b){
	//a爲棧頂元素,b爲當前元素
	//返回true時,將當前元素壓入棧中, 即當前運算符比棧頂運算符的優先級高
	//返回false時 ,即當前運算符與棧頂運算符的優先級相等或低 
	if(a=='('){
		return true;
	}
	if((a=='+'||a=='-')&&(b=='*'||b=='/')){
		return true;
	}else{
		return false;
	}
}
void InfixToPostfix(char *infix){
	Stack *stack=init();
	int i;
	for(i=0;i<strlen(infix);){
		if(infix[i]>='0'&&infix[i]<='9'){
			while(infix[i]>='0'&&infix[i]<='9'){
				printf("%c",infix[i]);
				i++;		
			}
			printf("!");
		}
		if(infix[i]==')'){
			while(stack->ch[stack->top]!='('){
				pop(stack);
				if(stack->top>0||i<strlen(infix)){
					printf("!");
				}
			}
			stack->top--;
			i++;
		}else if(stack->top==0||infix[i]=='('){
			push(stack,infix[i]);
			i++;
		}else if(check(stack->ch[stack->top],infix[i])){
			push(stack,infix[i]);
			i++;	
		}else{
			pop(stack);
			if(stack->top>0||i<strlen(infix)){
				printf("!");
			}
		}
	}
	while(stack->top){
		pop(stack);
		if(stack->top>0||i<strlen(infix)){
			printf("!");
		}
	}
}
int main(){
	char infix[100]="3/5+6";
	InfixToPostfix(infix);
	return 0;
}

  

主函數裏面的infix是我們輸入的字符串,當其中綴表達式爲:16-9*(4+3) 的時候,輸出的結果爲:

 

 

 再測試一下題目裏面的3/5+6式子,輸出結果爲:

 

 

 

對於這種式子是會失敗的:2*(x+y)/(1-x)

從前面的代碼也可以看出來,我們判斷數字是0--9之間,但是這裏是x,y,所以判斷不起作用,但是題目裏面是:

 

 

 給出的是一位整數,即合法的式子,我們就能夠得到正確的結果,以上

 

參考博客:

https://www.cnblogs.com/lanhaicode/p/10776166.html

https://www.cnblogs.com/lulipro/p/7450886.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章