計算中綴表示式

2021-08-19 18:06:14 字數 3638 閱讀 7431

「計算中綴表示式」可以稱得上是乙個特別經典的關於棧的演算法題,幾乎在所有資料結構教材中都會涉及,而且很多公司面試或者筆試的時候都會把這道題作為乙個考察點。可以說,這是一道必須要掌握的演算法題。中綴表示式、字尾表示式等概念在這裡就不贅述了,讓我們直奔主題。

題目:輸入乙個中綴表示式,計算其結果。

輸入的前提假設:

(1)只考慮+、-、*、/這四種運算子,中綴表示式中只有一種括號:();

(2)輸入的中綴表示式中只有整數,沒有小數;

(3)假定輸入是合法的。

很多文章或課本喜歡一步到位,直接討論如何從中綴表示式計算結果。但對於初學者來說,跨度未免大了點。這裡循序漸進,從易到難,先討論如何將中綴表示式轉化為字尾表示式,再討論如何計算字尾表示式。最後在前面兩步的基礎上,討論如何一步到位,直接計算中綴表示式的結果:

在日常應用中,算術表示式中運算子總是出現在兩個運算元之間,例如5*(7-2*3)+8/2,這種形式稱為中綴表示式。計算乙個中綴表示式需要知道運算子的優先順序和結合性。乘除是高優先順序,加減是低優先順序,優先順序相同時他們都是左結合的,也就是從左計算到右。有括號就要計算括號內的表示式。

中綴表示式利於人的理解,但不便於計算機的處理。因此需要將中綴表示式轉換成字尾表示式,以方便計算機處理。所謂字尾表示式就是將運算子放在運算數之後。字尾表示式也稱為逆波蘭表示式。

比如:中綴表示式為:1+(2-3)*4+4/2

對應字尾表示式為:1 2 3 - 4* + 4 2 / +

如何將乙個中綴表示式轉化為字尾表示式?我們需要借助棧的力量,用它來存放運算子。演算法流程如下:

首先將各種運算子(包括括號)的優先順序排列如下(數字越大,優先順序越高):

1:(2:+ -

3:* /

4:)對輸入的中綴表示式從左到右遍歷:

1)如果遇到數字,直接新增到字尾表示式末尾;

2)如果遇到運算子+、-、*、/:

先判斷棧是否為空。若是,則直接將此運算子壓入棧。若不是,則檢視當前棧頂元素。若棧頂元素優先順序大於或等於此操作符級別,則彈出棧頂元素,將棧頂元素新增到字尾表示式中,並繼續進行上述判斷。如果不滿足上述判斷或者棧為空,將這個運算子入棧。要注意的是,經過上述步驟,這個運算子最終一定會入棧。

3)如果遇到括號:

如果是左括號,直接入棧。如果是右括號,彈出棧中第乙個左括號前所有的操作符,並將左括號彈出。(右括號別入棧)。

4)字串遍歷結束後,如果棧不為空,則彈出棧中所有元素,將它們新增到字尾表示式的末尾,直到棧為空。

字尾表示式的計算就相當簡單了。準備乙個數字棧。從左到右掃瞄字尾表示式,如果是數字,放入數字棧。如果是符號,從數字棧中彈出兩個數字,第乙個取出的數字為右運算數,第二個為左運算數,進行運算。然後將結果放進數字棧中。如此反覆,直到讀完整個表示式後,留在數字棧中的那個數字就是最終結果。

c++**如下,要注意,下面的**預設中綴表示式中所有數字都是整數,並且都在0到9之間。而且計算結果都是整數(比如5/2=2)。

#include#include#includeusing namespace std;

int getpriority(char ch)

string getpostfixexpression(string str)

elseif (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')

else

else break;

}mystack.push(str[i]);}}

else

mystack.pop();}}

i++;

}//遍歷完後,若棧非空,彈出所有元素

while (!mystack.empty())

return res;}

int calculator(string str)

else

else if (str[i] == '-')

else if (str[i] == '*')

else if (str[i] == '/')

mystack.push(num3);}}

return mystack.top();}

int main()

其實將前面的兩步結合起來,就可以得到直接計算的方法。準備乙個數字棧和乙個符號棧。

從左到右遍歷中綴表示式。如果遇到數字,入數字棧。

如果遇到符號(四個運算子以及括號),跟前面的「中綴表示式轉字尾表示式」過程一樣,對符號棧進行處理。處理過程中,對每乙個出棧的運算子:+ - * /,根據「計算字尾表示式」的方法,計算結果(跟數字棧配合)。

如果遍歷完中綴表示式後符號棧還非空,就繼續出符號棧的運算子,計算,直到符號棧為空。最後數字棧剩下的數字就是結果。

下面給出用c++實現「計算中綴表示式」的**,裡面考慮了「數字不止1位」,並且用浮點型來表示最終運算結果。要求中綴表示式中只能包含整數和運算子(不能包含小數),並且是合法的。

#include#include#includeusing namespace std;

int getpriority(char ch)

void calculate(stack&mystack, char operation)

else if (operation == '-')

else if (operation == '*')

else if (operation == '/')

mystack.push(num3);

}double calculator(string str)

tmp_num = str.substr(i, j - i);

mystack_number.push(atoi(tmp_num.c_str()));

i = j;

} else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')

else

else break;

}mystack_operation.push(str[i]);

}i++;

} else

mystack_operation.pop();

}i++;

} }//遍歷完後,若棧非空,彈出所有元素

給出一道思考題:如果加入乘方'^',應該如何處理?要注意,乘方運算是右結合的。

其實很簡單。只有兩處修改:

1)將乘方新增到優先順序中:

1:(2:+ -

3:* /

4:^5:)

2)在讀中綴表示式的時候,如果讀到乘方^,就將它放進符號棧中。因為乘方的優先順序是最高的,而且是右結合的,所以無論它前面出現的是什麼運算,這些運算都不能執行。而且它本身能否執行也是不知道的,因此只能進棧。

大家自己試試吧~要記住,學習程式設計,動手去寫**永遠是第一位的。

【參考資料】

[1][2]翁惠玉, 俞勇. 資料結構:思想與實現[m]. 高等教育出版社, 2009.

中綴表示式計算

雙棧法 數字棧和運算子棧 1.從前向後遇見數字就壓入數字棧 2.遇見左括號壓棧 3.遇見右括號則彈出數字棧頂兩個數字,和乙個運算子棧乙個運算子進行計算,直至遇見左括號,退括號,計算結果壓棧 4.遇見運算子,若符號棧頂的元素小於當前運算子優先順序,則入棧 若相等或大於則數字彈出倆,符號彈出乙個計算,直...

中綴表示式轉字尾表示式及其計算

演算法 1.迴圈讀取輸入的字串 2.讀取到運算元 輸出 3.讀取到 彈出棧的內容到輸出流直到遇到 最後將 或 入棧 4.讀取到 彈出棧的內容到輸出流直到遇到 最後將 或 入棧 5.讀取到 入棧 6.讀取到 彈出棧的內容到輸出流直到遇到 圓括號不輸出。個人實現的 如下 public static st...

中綴表示式轉字尾表示式與計算

1.建立兩個棧,乙個儲存數字和字尾表示式s1,乙個儲存符號棧s2 2.儲存流程 1 如果符號棧s2為空,直接存入符號。2 如果不為空,當前符號優先順序等於或者大於棧的符號,直接存入。3 如果不為空,當前符號優先順序雄小於棧的符號,先彈出乙個符號棧頂的元素,再比較,然後再存入 4 如果遇到 直接存入。...