目錄
課前預習:
1.逆波蘭式的定義,如何將中綴表達式轉化成逆波蘭式
2.爲什麼要轉化成逆波蘭式,逆波蘭式有什麼優點
3.各運算符之間的優先級(+、-、*、/)
4.此計算器只支持輸入非負整數數,不支持輸入負數,要是非要輸入負數可以這樣(0-1)
代碼實現過程:
1.先定義一下各運算符的優先級
解釋:左括號優先級最低,+-略高,*/較高,右括號最高
int priority(string op)
{
if (op == "(") return 0;
if (op == "+" || op == "-") return 1;
else if (op == "*" || op == "/") return 2;
}
2.轉化成逆波蘭式
幾個關鍵的點
(1)碰到左括號直接進入符號棧
(2)右括號優先級最高,遇到右括號將符號棧中的運算符添加到逆波蘭式數組中,直到遇到左括號,並將左括號彈出
(3)當前爲運算符,如果棧頂的運算符優先級高於當前或等於(有些文章中將在符號棧中的運算符優先級看做高於棧外同類運算符,我這裏不這樣了,感覺還是我這樣簡單點)當前運算符,彈出棧頂運算符添加到逆波蘭式數組中(循環)
(4)最後如果符號棧非空,將符號棧中的元素彈出添加到逆波蘭式數組中
/*將表達式轉換成逆波蘭式*/
vector<string> toPolish(string str)
{
stack<string> opstack;
vector<string> polish;
string str1;
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '(') /*左括號*/
{
opstack.push("(");
continue;
}
if (str[i] >= '0'&&str[i] <= '9')/*數字*/
{
str1 = "";
while (i < str.size() && str[i] >= '0'&&str[i] <= '9')
{
str1 += str[i];
i++;
}
i--;
polish.push_back(str1);
continue;
}
if (str[i] == ')')/*右括號*/
{
/*出棧,直到匹配到左括號*/
while (!opstack.empty())
{
if(opstack.top() != "(")
{
polish.push_back(opstack.top());
opstack.pop();
}
else
{
opstack.pop();
break;
}
}
}
else/*加減乘除運算符*/
{
str1 = str[i];
while (!opstack.empty() && priority(opstack.top()) >= priority(str1))
{
polish.push_back(opstack.top());
opstack.pop();
}
opstack.push(str1); // 添加到符號棧中
}
}
//剩餘的運算符添加到polish中
while (!opstack.empty())
{
polish.push_back(opstack.top());
opstack.pop();
}
return polish;
}
3.計算逆波蘭式
逆波蘭式有個大大的優點,就是符號沒有優先級,也就是說我們碰到運算符就進行運算,非常簡便
/*將逆波蘭式進行計算*/
int calculation(vector<string> polish)
{
stack<int> data;
int a, b, c;
for (int i = 0; i < polish.size(); i++)
{
if (polish[i] == "+" || polish[i] == "-" || polish[i] == "*" || polish[i] == "/")
{
b = data.top(); data.pop();
a = data.top(); data.pop();
if (polish[i] == "+") c = a + b;
else if (polish[i] == "-") c = a - b;
else if (polish[i] == "*") c = a * b;
else if (polish[i] == "/") c = a / b;
data.push(c);
}
else
{
data.push(stoi(polish[i]));/*stoi函數功能:string to int */
}
}
return data.top();
}
以上就是實現過程,下面就是全部代碼:
#include <iostream>
#include<stack>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
int priority(string op);
vector<string> toPolish(string str);
int calculation(vector<string> polish);
int main()
{
string str = "1*(1+2*(1*2*2-3+5*1))";
int a = calculation(toPolish(str));
cout << a;
}
/*返回運算符的優先級*/
int priority(string op)
{
if (op == "(") return 0;
if (op == "+" || op == "-") return 1;
else if (op == "*" || op == "/") return 2;
}
/*將表達式轉換成逆波蘭式*/
vector<string> toPolish(string str)
{
stack<string> opstack;
vector<string> polish;
string str1;
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '(') /*左括號*/
{
opstack.push("(");
continue;
}
if (str[i] >= '0'&&str[i] <= '9')/*數字*/
{
str1 = "";
while (i < str.size() && str[i] >= '0'&&str[i] <= '9')
{
str1 += str[i];
i++;
}
i--;
polish.push_back(str1);
continue;
}
if (str[i] == ')')/*右括號*/
{
/*出棧,直到匹配到左括號*/
while (!opstack.empty())
{
if(opstack.top() != "(")
{
polish.push_back(opstack.top());
opstack.pop();
}
else
{
opstack.pop();
break;
}
}
}
else/*加減乘除運算符*/
{
str1 = str[i];
while (!opstack.empty() && priority(opstack.top()) >= priority(str1))
{
polish.push_back(opstack.top());
opstack.pop();
}
opstack.push(str1); // 添加到符號棧中
}
}
//剩餘的運算符添加到polish中
while (!opstack.empty())
{
polish.push_back(opstack.top());
opstack.pop();
}
return polish;
}
/*將逆波蘭式進行計算*/
int calculation(vector<string> polish)
{
stack<int> data;
int a, b, c;
for (int i = 0; i < polish.size(); i++)
{
if (polish[i] == "+" || polish[i] == "-" || polish[i] == "*" || polish[i] == "/")
{
b = data.top(); data.pop();
a = data.top(); data.pop();
if (polish[i] == "+") c = a + b;
else if (polish[i] == "-") c = a - b;
else if (polish[i] == "*") c = a * b;
else if (polish[i] == "/") c = a / b;
data.push(c);
}
else
{
data.push(stoi(polish[i]));/*stoi函數功能:string to int */
}
}
return data.top();
}
測試結果:
輸入:string str = "1*(1+2*(1*2*2-3+5*1))";
輸出:13
刷題檢測網站
如果想要練手,並檢驗是否正確,可以在Leetcode網站上檢測一下
題目和我的代碼稍有不同