? ? ? ? 好久不見,真的很久都沒有更新博客了,最近很多事情,所以比較忙碌,沒有時間每天都學(xué)算法,但是我會擠時間盡量做到,每兩三天就更新博客,我會努力的,加油~
? ? 前言:計算器都見過吧,我們今天要講的就是類似于計算器計算數(shù)據(jù)的簡單實現(xiàn),我們需要注意一些問題,比如運算符優(yōu)先級,運算順序等等問題,話不多說,沖沖沖?。?!
目錄
1.問題引入
2.問題分析及解決方法
如何設(shè)計優(yōu)先級問題?
設(shè)計計算函數(shù)和啟動計算條件
完整代碼(可做為表達式計算模板使用)
3.金句頻道
1.問題引入
2.問題分析及解決方法
? ? ? ?首先,我們先來看一下整體思路:對于一個表達式,我們會讀入括號,運算符和數(shù)字三種字符,我們需要將這些字符區(qū)分開再進行計算,為了保證運算的正確性,由運算符帶來的優(yōu)先級問題是我們解決這個問題的關(guān)鍵,解決了運算符優(yōu)先級問題,我們就可以將運算符和數(shù)字分別存入一個棧中,用讀取到' ) '和讀取到優(yōu)先級比已經(jīng)保存在棧內(nèi)的運算符來作為啟動計算的條件(讀到右括號,我們就可以將整個括號內(nèi)部的部分算出來,再將算得結(jié)果壓入保存數(shù)字的棧中用于后續(xù)的計算,而對于讀取到優(yōu)先級低的運算符,因為我們以棧存儲數(shù)據(jù),導(dǎo)致我們在計算的時候就會按逆序進行計算,所以,我們每次讀取到一個運算符優(yōu)先級低于棧頂?shù)淖址?,都要先將棧?nèi)的運算符優(yōu)先級高的運算符的結(jié)果算出,從而不影響運算順序),最后,我們的運算符棧內(nèi)如果還剩下元素,直接計算即可。
如何設(shè)計優(yōu)先級問題?
? ? ? ?這里方法就有很多了,既可以用一個專門的函數(shù)來實現(xiàn),也可以用STL的map鍵值來實現(xiàn)等等,這里我們采用第二種方法,該方法比較簡單且代碼易擴展,方便后序添加運算符。
unordered_map<char, int> p{ {'+',1},{'-',1},{'*',2},{'/',2} };//用來表示運算符的優(yōu)先級,數(shù)字越大表示運算優(yōu)先級越高
設(shè)計計算函數(shù)和啟動計算條件
//計算函數(shù)
void f()
{
//這里需要注意,我們的棧內(nèi)保存的待運算數(shù)字和運算順序是反著的,會影響減法和除法的計算
auto b = num.top(); num.pop();
auto a = num.top(); num.pop();
auto c = op.top(); op.pop();
if (c == '+')
num.push(a + b);
else if (c == '-')
num.push(a - b);
else if (c == '*')
num.push(a * b);
else if (c == '/')
num.push(a / b);
//如果想要再拓展其他運算,可在此處繼續(xù)寫下去
}
//計算啟動條件
else if (s[i] == '(')//如果是左括號,直接入棧等待右括號到來再計算
op.push(s[i]);
else if (s[i] == ')')//右括號,準(zhǔn)備開始計算結(jié)果
{
while (op.top() != '(') f();//做括號內(nèi)的計算
op.pop();//彈出左括號
}
else
{
while (!op.empty() && p[op.top()] >= p[s[i]]) f();//如果遇到優(yōu)先級比前面已經(jīng)入棧的運算符的優(yōu)先極低的,則要先解決棧內(nèi)的計算再將該優(yōu)先級高的字符入棧
op.push(s[i]);
}
完整代碼(可做為表達式計算模板使用)
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
const int maxn = 1e5 + 10;
stack<int >num;
stack<char> op;//運算符
unordered_map<char, int> p{ {'+',1},{'-',1},{'*',2},{'/',2} };//用來表示運算符的優(yōu)先級,數(shù)字越大表示運算優(yōu)先級越高
void f()
{
//這里需要注意,我們的棧內(nèi)保存的待運算數(shù)字和運算順序是反著的,會影響減法和除法的計算
auto b = num.top(); num.pop();
auto a = num.top(); num.pop();
auto c = op.top(); op.pop();
if (c == '+')
num.push(a + b);
else if (c == '-')
num.push(a - b);
else if (c == '*')
num.push(a * b);
else if (c == '/')
num.push(a / b);
//如果想要再拓展其他運算,可在此處繼續(xù)寫下去
}
int main()
{
string s;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (isdigit(s[i]))//注意,這里需要注意10以上的數(shù),不能只看一個字符就完了
{
int j = i;
int temp = 0;
while (j < s.size() && isdigit(s[j]))
{
temp = temp * 10 + s[j++] - '0';
}
i = j-1;//j在退出循環(huán)之前已經(jīng)自增了,所以要減去
num.push(temp);
}
else if (s[i] == '(')//如果是左括號,直接入棧等待右括號到來再計算
op.push(s[i]);
else if (s[i] == ')')//右括號,準(zhǔn)備開始計算結(jié)果
{
while (op.top() != '(') f();//做括號內(nèi)的計算
op.pop();//彈出左括號
}
else
{
while (!op.empty() && p[op.top()] >= p[s[i]]) f();//如果遇到優(yōu)先級比前面已經(jīng)入棧的運算符的優(yōu)先極低的,則要先解決棧內(nèi)的計算再將該優(yōu)先級高的字符入棧
op.push(s[i]);
}
}
//如果最后棧內(nèi)還剩下字符,直接計算即可
while (op.size()) f();
printf("%d\n", num.top());
return 0;
}
? ? ?我們這里將計算函數(shù)和優(yōu)先級單獨設(shè)計,目的就是增加代碼的可復(fù)用性,main函數(shù)內(nèi)部沒有涉及運算符的種類和其他的特殊處理,將特異性的功能封裝成函數(shù)方便后序增添功能。
3.金句頻道
? ? ? ?常常熬不住的時候也想找個靠山靠一下,可怎么找都會發(fā)現(xiàn),有的山長滿荊棘,有的山上全是野獸,所以你應(yīng)該是自己的那座山。過度的依賴總會失掉自我,變得被動,不要總是整天“大佬帶我飛”,讓自己強起來才是一芳永逸的事。要相信每一次普通的改變,都可能改變原本的普通。
文章來源:http://www.zghlxwxcb.cn/news/detail-438154.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-438154.html
到了這里,關(guān)于表達式求值問題-雙棧模板化實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!