步骤:1、将表达式转化成逆波兰式 2、求逆波兰式的值
一、将表达式转化成逆波兰式
举个简单的例子,平常我们写的数学表达式a+b,就是一种中缀表达式,写成后缀表达式就是ab+。再举一个复杂的例子,中缀表达式(a+b)*c-(a+b)/e的逆波兰式是ab+c*ab+e/-。
(1)首先,需要分配1个栈,用于临时存储运算符,此运算符在栈内遵循越往栈顶优先级越高的原则;
(2)从中缀式的左端开始逐个读取字符x,逐序进行如下步骤:
1.若x是操作数,,将x直接加入ans后边;
2.若x是运算符,则分情况讨论:
若x是'(',则直接压入栈s;
若x是')',则将距离栈s栈顶的最近的'('之间的运算符,逐个出栈,依次加入ans,此时抛弃'(';
若x是除'('和')'外的运算符,则再分如下情况讨论:
若当前栈s的栈顶元素为'(',则将x直接压入栈s;
若当前栈s的栈顶元素不为'(',则将x与栈s的栈顶元素比较,若x的优先级大于栈顶运算符优先级,则将x直接压入栈s。否者,将栈顶运算符弹出,加入ans,直到栈顶运算符优先级别低于(不包括等于)x的优先级,此时再则将x压入栈;
【第二步是一个循环,要把中缀式读完。第三步是在循环之外】
(3)在进行完(2)后,检查栈是否为空,若不为空,则将栈中元素依次弹出并加入ans
(4)完成上述步骤后,ans便为逆波兰式输出结果。
#include<bits/stdc++.h>
using namespace std;
int judge(char data){
int res = 0;
switch (data) {
case '+':
res = 1;
break;
case '-':
res = 1;
break;
case '*':
res = 2;
break;
case '/':
res = 2;
break;
default:
break;
}
return res;
}
string getNiBolan(string str){
string newStr = "";
stack<int> s;
int length =(int)str.length();
for (int i =0 ; i<length; i++) {
char cur = str[i];
if (cur == '(') {
//新元素为(直接压栈
s.push(cur);
}
else if(cur ==')')
{
//新元素为)打印出(上面所有的
if(!s.empty())
{
//栈中有元素
while (!s.empty())
{
char peep = s.top();
s.pop();
if (peep != '(') {
newStr += peep;
}
else
break;
}
}
else
{
//没有元素遇到(直接报错
cout<<"the input is error";
exit(1);
}
}
else if ( ('A'<=cur&&cur<='Z')||('a'<=cur && cur<='z')||('0'<=cur && cur<='9') )
{
//新元素为字符或者数字直接赋值
newStr += cur;
}
else{
//新元素为+-*/
int curJudge1 = judge(cur);
//当栈不为空的时候判断
if (!s.empty())
{
while (!s.empty())
{
char peep = s.top();
//栈顶不为(
int curJudge2 = judge(peep);
//新元素大于等于栈顶的等级,直接压栈
if (curJudge1 >= curJudge2)
{
s.push(cur);
break;
}
else
{
//小于就赋值
s.pop();
newStr += peep;
}
}
if(s.empty())
s.push(cur);
}
else
{
//问题2;忘记在空的时候直接压栈
s.push(cur);
}
}
}
//问题1 忘记了输出出栈中的所有元素
while (!s.empty()) {
newStr += s.top();
s.pop();
}
return newStr;
}
int main()
{
string s = "(a+b)*c-(a+b)/e";
s = getNiBolan(s);
cout<<s;
return 0;
}
2、求逆波兰式的值
Example 1:
Input: ["2", "1", "+", "3", "*"]
Output: 9
Explanation: ((2 + 1) * 3) = 9
Example 2:
Input: ["4", "13", "5", "/", "+"]
Output: 6
Explanation: (4 + (13 / 5)) = 6
分析:弄一个栈,一个一个读逆波兰式,如果是数字就入栈,如果是算符就pop两个出来计算,再把结果压栈
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> s;
for(auto a : tokens)
{
if(a.size()==1 && !isdigit(a[0]))
{
int num2 = s.top();
s.pop();
int num1 = s.top();
s.pop();
switch(a[0])
{
case '+':
s.push(num1+num2);break;
case '-':
s.push(num1-num2);break;
case '*':
s.push(num1*num2);break;
case '/':
s.push(num1/num2);break;
}
}
else
{
s.push(atoi(a.c_str()));//c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同,atoi用于把字符串数字转为数字
}
}
return s.top();
}
};
为了方便程序,我们一般在中缀式转逆波兰式的时候,用一个列表装下每一个token(数字要拼接好) 。