編寫程序,將任意一個合法的中綴表達式轉換成逆波蘭式。
【問題描述】表達式計算是實現程序設計語言的基本問題之一。在計算機中進行算術表達式的計算可通過棧來實現。通常書寫的算術表達式由操作數、運算符以及圓括號連接而成。爲簡便起見,本題只討論雙目運算符。
算術表達式的兩種表示如下:
⑴中綴表達式:把雙目運算符出現在兩個操作數中間的表示,稱爲算術表達式的中綴表示。中綴表示的算術表達式,稱爲中綴算術表達式,也稱中綴表達式。如表達式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,所以判斷不起作用,但是題目裏面是:
給出的是一位整數,即合法的式子,我們就能夠得到正確的結果,以上
參考博客: