這個表達式計算是我好早之前學的 但是昨天聽完 我一瞬間竟然忘了這東西怎么寫 又翻了翻代碼 想起來了 不如寫下來
為什么會出現前綴 后綴 中綴的形式 是因為 我們在計算表達式的時候 實際上可以看做是一個插入一棵樹上 然后對應這個樹上的前序 后序 中序的一個遍歷順序
那么不同的 遍歷順序 表達式計算方式也會有所不同 我們這里講一下 前后綴表達式的計算 以及如何將中綴轉化為后綴 在進行計算 這是一般做法
應該都知道 表達式計算都要搞一個棧 別說了 我不信你不知道;
介紹概念 中綴表達式(中綴記法)我們最常寫的式子 中綴表達式是一種通用的算術或邏輯公式表示方法,
操作符以中綴形式處於操作數的中間。
雖然人的大腦很容易理解與分析中綴表達式,但對計算機來說中綴表達式卻是很復雜的,
因此計算表達式的值時,通常需要先將中綴表達式轉換為前綴或后綴表達式,
然后再進行求值。對計算機來說,計算前綴或后綴表達式的值非常簡單。
前綴表達式(前綴記法、波蘭式)前綴表達式的運算符位於操作數之前。
前綴表達式的計算機求值:
從右至左掃描表達式,遇到數字時,將數字壓入堆棧,遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(棧頂元素 op 次頂元素),並將結果入棧;
重復上述過程直到表達式最左端,最后運算得出的值即為表達式的結果。
例如前綴表達式“- × + 3 4 5 6”:
(1) 從右至左掃描,將6 5 4 3壓入堆棧;
(2) 遇到+運算符,因此彈出3和4(注意棧的應用 此時3 4是棧頂),計算出3+4的值,得7,再將7入棧;
(3) 接下來是×運算符,因此彈出7和5,計算出7×5=35,將35入棧;
(4) 最后是-運算符,計算出35-6的值,即29,由此得出最終結果。
然后我們考慮 后綴表達式的計算
與上面稍有不同 我們從左向右依次便利這個表達式 遇到是數字就進棧 遇到是符號 就將處於棧頂兩個數字出棧 進行運算
運算結果進棧 一直到最終獲得結果
后綴表達式也叫做 逆波蘭表達式 這樣的式子的特點 是沒有 括號的 所以我們直接模擬就可以了
但是我們在這里要討論一下 中綴表達式的計算
也就是 我們最常寫的式子 但是 計算起來 我們有兩個方法 將其轉化成 前綴表達式 或者轉化成 后綴表達式 在按照上面的 方式 計算 這里說一
下 轉化為后綴表達式
先說一下 怎么轉化 這里我們假定 只有小括號 只有整數 輸入合法 例如:
中綴表達式為:1+(2-3)*4+4/2
對應后綴表達式為:1 2 3 - 4* + 4 2 / +
如何將一個中綴表達式轉化為后綴表達式?我們需要借助棧,用它來存放運算符。
首先將各種運算符(包括括號)的優先級排列如下(數字越大,優先級越高):
1: ( 要注意的是 小括號優先級是最低的qwq
2:+ -
3:* /
4 :^
5:)
這里只考慮到有乘方的形式
對輸入的中綴表達式從左到右遍歷:
1)如果遇到數字,直接添加到后綴表達式末尾;
2)如果遇到運算符+、-、*、/:
先判斷棧是否為空。若是,則直接將此運算符壓入棧。若不是,則查看當前棧頂元素。若棧頂元素優先級大於或等於此操作符級別,則彈出
棧頂元素,將棧頂元素添加到后綴表達式中,並繼續進行上述判斷。如果不滿足上述判斷或者棧為空,將這個運算符入棧。要注意的是,經
過上述步驟,這個運算符最終一定會入棧。
3)如果遇到括號:如果是左括號,直接入棧。如果是右括號,彈出棧中第一個左括號前所有的操作符,並將左括號彈出。
4)字符串遍歷結束后,如果棧不為空,則彈出棧中所有元素,將它們添加到后綴表達式的末尾,直到棧為空。
通過上述過程 我們就得到了 這個中綴表達式 對應的后綴表達式 那么 我們怎么計算后綴表達式也清楚了 但是這種發現有點 麻煩 我們還要記
錄這個后綴表達式是什么
對於一些題目 不需要你輸出 后綴表達式 那我們考慮直接計算 不記錄這個后綴表達式 直接將兩步結合起來;
我們考慮開兩個棧 一個數字棧 一個符號棧 我們讀入當前的中綴表達式 遇到數字 我們將其壓入數字棧 遇到符號 按照剛才的方式處理
對符號棧進行處理 對應優先級的順序 也就是說 對於一個操作符 我們將優先級大於等於當前符號的 都計算出來
方法類似於后綴表達式 一個符號 兩個數字 計算結果壓入棧中;
所以我們無需計算出具體的后綴表達式 直接計算即可;
鑒於寫文章的作者比較懶 所以以上都沒有代碼 不
過luogu上倒是有后綴表達式 以及簡單的中綴表達式計算的例題 如1449 但為啥都是普及-啊
所以 只有計算中綴的一個題目 涉及 負數 多位數字的處理 以及加 減 乘 整除 乘方 括號 多種運算
給出一個表達式,其中運算符僅包含+,-,*,/,^
(加 減 乘 整除 乘方)要求求出表達式的最終值。
數據可能會出現括號情況,還有可能出現多余括號情況。
數據保證不會出現大於或等於231的答案。
數據可能會出現負數情況。
輸入格式
輸入僅一行,即為表達式。
輸出格式
輸出僅一行,既為表達式算出的結果。
輸入樣例:
(2+2)^(1+1)
輸出樣例:
16
我們按照上面的思路來一遍就好了 注意好好處理數字
#include<bits/stdc++.h> using namespace std; stack<int> num; stack<char> ops; inline int mul(int a,int k) {//慢速冪??? int res=1; while(k--) res*=a; return res; } void cal() {//計算表達式的值 按照后綴表達式的方式 int num1,num2,num3; num1=num.top(); num.pop(); num2=num.top(); num.pop(); char op=ops.top(); ops.pop(); if(op=='+') num3=num2+num1; else if (op=='-') num3=num2-num1; else if (op=='*') num3=num2*num1; else if (op=='/') num3=num2/num1; else num3=mul(num2,num1); num.push(num3);//計算結果壓入棧中 } int main() { string str; cin >> str; string left; for(int i=0;i<str.size();i++) left+='('; str=left+str+')';//處理多余括號的情況 可以多左括號 但是多右括號就麻煩了 for(int i=0;i<str.size();i++) { if(str[i]>='0'&&str[i]<='9') { int j=i,t=0; while(str[j]>='0'&&str[j]<='9') { t=t*10+str[j]-'0'; j++; } num.push(t);//處理多位數字的情況 題目並沒有保證是10以內的數字 i=j-1; } else { char c=str[i]; if(c=='(') ops.push(c);//左括號 直接入棧 else if(c=='+'||c=='-') { if(c=='-'&&i&&!(str[i-1]>='0'&&str[i-1]<='9')&&str[i-1]!=')') {//處理負數的情況 將減去一個數 改成+負數 int j=i+1,t=0; while(str[j]>='0'&&str[j]<='9') { t=t*10+str[j]-'0'; j++; } num.push(-t); i=j-1; } else { while(ops.top()!='(') cal(); ops.push(c); } } else if(c=='*'||c=='/') { while(ops.top()=='*'||ops.top()=='/'||ops.top()=='^') cal();//優先級大於等於加減的計算完 ops.push(c); } else if(c=='^') { while(ops.top()=='^') cal();//乘方的優先級最高 ops.push(c); } else if(c==')') { while(ops.top()!='(') cal();//遇到右括號 ops.pop(); } else cout<<"sbsbsbsb"<<endl;//無解????? } } cout<<num.top()<<endl; return 0; }