使用栈解决的一类经典问题:表达式转换及求值;中缀表达式;前缀表达式,后缀表达式,中缀转前缀;中缀转后缀;后缀表达式求值;波兰式,逆波兰式
文章目錄
- 背景知識
- 表達(dá)式轉(zhuǎn)換問題(考研經(jīng)典)
- 一:手工轉(zhuǎn)換
- (1)中綴轉(zhuǎn)前綴和中綴轉(zhuǎn)后綴
- (2)前綴轉(zhuǎn)中綴和后綴轉(zhuǎn)中綴
- 二:用棧實(shí)現(xiàn)表達(dá)式轉(zhuǎn)換
- (1)中綴轉(zhuǎn)后綴
- (2)中綴轉(zhuǎn)前綴
- 表達(dá)式計(jì)算問題(使用棧實(shí)現(xiàn))
背景知識
中綴表達(dá)式:a+b
前綴表達(dá)式(波蘭式):+ab
后綴表達(dá)式(逆波蘭式):ab+
表達(dá)式轉(zhuǎn)換問題(考研經(jīng)典)
一:手工轉(zhuǎn)換
考研中有一類經(jīng)典的問題就是表達(dá)式的轉(zhuǎn)換問題,經(jīng)常要把一個(gè)類型的表達(dá)式轉(zhuǎn)換為另一個(gè)類型的表達(dá)式
所以這里我們主要說一下中綴轉(zhuǎn)前綴,前綴轉(zhuǎn)中綴,中綴轉(zhuǎn)后綴和后綴轉(zhuǎn)中綴即可。這樣這三種形式任意兩個(gè)之間的轉(zhuǎn)換都可以借助上面四種轉(zhuǎn)換直接或間接完成
所用表達(dá)式的三種形式如下
(1)中綴轉(zhuǎn)前綴和中綴轉(zhuǎn)后綴
首先每遇到兩個(gè)操作數(shù),一個(gè)運(yùn)算符就把他們用括號扣起來(用括號括起來的可以看做一個(gè)操作數(shù))
如下
把上面的結(jié)果全部抄一遍(對應(yīng)位置,不要錯(cuò)亂),抄的時(shí)候不要抄操作數(shù),把操作數(shù)的位置空出來。然后依據(jù)原來的結(jié)果,把運(yùn)算符移出到括號前面面,注意只需要移動(dòng)到該運(yùn)算符原來所在的括號前面就可以了,不要一次移動(dòng)多層
如下
轉(zhuǎn)化為后綴表達(dá)式時(shí),只需要移動(dòng)到括號后面就可以了,由于非常簡單,這里我就不演示了,結(jié)果在最上面
(2)前綴轉(zhuǎn)中綴和后綴轉(zhuǎn)中綴
前綴轉(zhuǎn)中綴時(shí),從后向前掃描前綴表達(dá)式,每遇到兩個(gè)操作數(shù)一個(gè)運(yùn)算符就把運(yùn)算符放到兩個(gè)操作數(shù)中間,注意有的時(shí)候可能會(huì)連續(xù)遇到三個(gè)及以上的操作數(shù),這時(shí)就不要管后面的操作數(shù)了,你只需要向前找,一直找到運(yùn)算符然后結(jié)合后面的兩個(gè)操作數(shù)組合在一起
如下,其中紅色部分表示待處理的運(yùn)算符和操作數(shù)
對于后綴轉(zhuǎn)中綴,和前綴轉(zhuǎn)中綴實(shí)則是一樣的,只不過后綴轉(zhuǎn)中綴的時(shí)候需要從前向后掃描,由于也比較簡單這里就不演示了
二:用棧實(shí)現(xiàn)表達(dá)式轉(zhuǎn)換
表達(dá)式轉(zhuǎn)換是棧的應(yīng)用的一個(gè)非常典型的例子,主要利用的就是棧的先進(jìn)后出的特性,代碼的邏輯不復(fù)雜,但是就是比較多一點(diǎn)
這里用棧實(shí)現(xiàn)表達(dá)式轉(zhuǎn)換主要指的是中綴轉(zhuǎn)前綴或者后綴,后其他形式的表達(dá)式的轉(zhuǎn)換沒有具體的意義,因?yàn)檗D(zhuǎn)為前綴和后綴的目的就是讓計(jì)算機(jī)進(jìn)行求值,所以這里主要講的就是中綴轉(zhuǎn)換為前綴或后綴的代碼。由于C語言中處理?xiàng)1容^麻煩,所以這里采用C++,省去一些造輪子的步驟
(1)中綴轉(zhuǎn)后綴
中綴式轉(zhuǎn)后綴式需要兩個(gè)棧完成,然后從后向前掃描中綴表達(dá)式,先不討論怎樣入棧,記住:所有的操作數(shù)入S1棧,所有的括號和運(yùn)算符入S2棧
如下,首先由于S2空,此時(shí)掃描到了左括號,遇到左括號直接入棧
接著此時(shí)掃描到了操作數(shù)a,直接入S1,所有操作數(shù)直接入S1
接著此時(shí)掃描到了“+”號,此時(shí)S2棧頂元素為左括號,任何運(yùn)算符遇到左括號直接入棧
繼續(xù)進(jìn)行,掃描到b直接入S1。然后此時(shí)掃描到了右括號,當(dāng)掃描到右括號時(shí)將S2中從棧頂元素到左括號之間的元素依次出S2,入S1,但是左括號忽略掉,也就是不要了
接著掃描到“*”,入S2,然后掃描到操作數(shù)“c”,入S1。此時(shí)掃描到“+”,由于掃描到的元素符優(yōu)先級小于等于S2棧頂運(yùn)算符優(yōu)先級,故將棧頂運(yùn)算符出棧入S1,然后接著再拿掃描到的運(yùn)算符與新的棧頂元素比較,如果還是小于等于重復(fù)上述步驟,如果是大于則直接入棧,這里由于“*”出棧后,S2為空,故直接入“+”
接著再入操作數(shù)d。此時(shí)來到運(yùn)算符-,由于掃描到的運(yùn)算符的優(yōu)先級小于等于棧頂元素優(yōu)先級,故重復(fù)
剩余部分就不再演示了,此時(shí)大家觀看S1棧,是不是已經(jīng)有了后綴式的雛形了呢
代碼如下
#include <iostream> #include <stack> #include <string> using namespace std;int getpriority(char c) {if (c == '+' || c == '-'){return -1;//加減優(yōu)先級小}else{return 1;//乘除優(yōu)先級大} }void convert(string& express, stack<char>& s1, stack<char>& s2) {int i = 0;while (express[i] != '\0')//掃描中綴表達(dá)式{if ('0' <= express[i] && express[i] >= '9')//如果掃描到了操作數(shù),直接入s1{s1.push(express[i++]);}else if (express[i] == '(')//如果掃描到了左括號,直接入s2{s2.push(express[i++]);}else if (express[i] == '+' || express[i] == '-' || express[i] == '*' || express[i] == '/')//掃描到運(yùn)算符進(jìn)行優(yōu)先級判斷{if (s2.empty() || s2.top() == '(' || getpriority(express[i]) > getpriority(s2.top()))//如果此時(shí)S2為空或者棧頂元素為左括號,或者掃描到的運(yùn)算符優(yōu)先級大于棧頂運(yùn)算符優(yōu)先級,則S2{s2.push(express[i++]);}else//反之優(yōu)先級如果是小于等于的話,那么就要把運(yùn)算符出棧然后入S1{char temp = s2.top();s2.pop();s1.push(temp);}}else if (express[i] == ')')//最后一種情況就是掃描到了右括號,那么就把S2從棧頂?shù)阶罄ㄌ柕脑匾来纬鰲H霔?/span>{while (s2.top() != '('){char temp = s2.top();s2.pop();s1.push(temp);}//注意最后停止循環(huán)的時(shí)候S2的棧頂元素是左括號,但是不要把左括號入棧,所以直接丟掉左括號s2.pop();i++;//不要忘記后移}}while (!(s2.empty()))//如果S2沒有空,那么依次出S2,入S1{char temp = s2.top();s2.pop();s1.push(temp);}}int main() {stack<char> s1;//結(jié)果棧,入操作數(shù)stack<char> s2;//輔助棧,入運(yùn)算符和括號stack<char> result;//輸出用string expression("(a+b)*c+d-(e+g)*h");cout << "轉(zhuǎn)換前為中綴式:" << expression << endl;convert(expression, s1, s2);cout << "轉(zhuǎn)換為中綴式:";while (!(s1.empty())){char temp = s1.top();s1.pop();result.push(temp);}while (!(result.empty())){cout << result.top();result.pop();}}(2)中綴轉(zhuǎn)前綴
中綴轉(zhuǎn)前綴基本和中綴轉(zhuǎn)后綴一致,不同點(diǎn)如下
- 掃描時(shí)從后向前掃描中綴式
- 遇到右括號直接入棧,遇到左括號進(jìn)行出棧
- 掃描到的運(yùn)算符優(yōu)先級如果大于等于棧頂運(yùn)算符優(yōu)先級,直接入棧
表達(dá)式計(jì)算問題(使用棧實(shí)現(xiàn))
我們轉(zhuǎn)換表達(dá)式的目的就在于讓計(jì)算機(jī)實(shí)現(xiàn)表達(dá)式的求值,或者說,計(jì)算機(jī)是不認(rèn)識也不清楚中綴式的含義的,只有人能讀懂,但是我們轉(zhuǎn)換為前綴或者后綴后卻可以借助棧的性質(zhì)來完成計(jì)算
這里我們就以LeetCode 150:逆波蘭式求值,也就是后綴表達(dá)式求值為例,前綴式基本一致
求解時(shí),準(zhǔn)備一個(gè)棧,從左向右掃描后綴表達(dá)式,遇到操作數(shù)就入棧,遇到運(yùn)算符則出棧兩個(gè)操作數(shù),先出棧的作為右操作數(shù),后出棧的作為左操作數(shù),然后運(yùn)算之后把結(jié)果繼續(xù)壓入棧內(nèi),重復(fù)以上步驟,最后棧中的棧頂元素就是結(jié)果
前綴表達(dá)式和這個(gè)基本一致,不同點(diǎn)就是要從后向前掃描,然后先出棧的是左操作數(shù),后出棧的是右操作數(shù)
總結(jié)
以上是生活随笔為你收集整理的使用栈解决的一类经典问题:表达式转换及求值;中缀表达式;前缀表达式,后缀表达式,中缀转前缀;中缀转后缀;后缀表达式求值;波兰式,逆波兰式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于自己
- 下一篇: iOS开发 贝塞尔曲线UIBezierP