逆波兰表达式求值
Posted 做1个快乐的程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逆波兰表达式求值相关的知识,希望对你有一定的参考价值。
题目:根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
题目分析:我们观察发现,在逆波兰表达式中,其给定的表达式中,运算符的优先级已经是最优的了,即我们在遍历后缀表达式时,遇到操作符就要用操作符计算前面的两个值,并将结果保存,继续向后遍历。
因此,我们可以利用栈的特性(后进先出、先进后出)完成这道题目,准备一个栈stack,然后遍历给定的字符串数组,如果遇到的是数字则一直入栈,如果遇到操作符,就弹出栈顶的两个元素,先弹出的元素作右操作数,后弹出的元素作左操作数,然后将运算结果压栈,继续遍历字符串数组。
上图是对整个过程的分析,这里我们需要对终止条件进行判定,当字符串数组走到末尾时,即可弹出栈中的数据,进行输出。
class Solution {
public:
//形参用来接收栈、左右两个操作数,先取出的为右操作数,然后弹栈,再取出一个为左操作数,然后弹栈
void getNum(stack<int>& st, int& left, int& right)
{
right = st.top();
st.pop();
left = st.top();
st.pop();
}
int evalRPN(vector<string>& tokens) {
//事先定义一个stack栈,用于存放数据
stack<int> st;
//进行循环,依次取vector<string>中的数据
for(const auto& str : tokens)
{
//定义两个left和right变量用来表示左右两个操作数
int left,right;
//因为取到的数据有+、-、*、/和数值5种情况,我们这里采用switch-case语句进行分析
//对取到的每个字符串数组的第一个元素进行判断
switch(str[0])
{
//不管字符串数组的第一个字符为何种操作符,都要进行取栈顶元素,然后求值,然后压栈
//所以定义一个getNum函数用来完成,避免代码重复
case '+':
getNum(st, left, right);
st.push(left + right);
break;
case '-':
getNum(st, left, right);
st.push(left - right);
break;
case '*':
getNum(st, left, right);
st.push(left * right);
break;
case '/':
getNum(st, left, right);
st.push(left / right);
break;
//如果取到的字符不是操作符,则说明为有效数值,将其转换为int类型,然后压栈
default:
st.push(stoi(str));
break;
}
}
//当循环结束后,弹出栈顶元素即为结果
return st.top();
}
};
但是运行后,发现代码报错,这是为什么呢?通过测试用例我们发现,当字符串数组种某个位置为负数,比如-25时,程序就会报错,这是因为当读取到"-25"的第一个字符为’-’,代码走case ‘-’ ,结果却取不到两个操作数,导致错误,针对以上错误,
法一:我们对case ‘-’ 分支加一个if语句判断。
class Solution {
public:
void getOPNum(stack<int>& st, int& left, int& right)
{
right = st.top();
st.pop();
left = st.top();
st.pop();
}
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(const auto& str : tokens)
{
int left,right;
switch(str[0])
{
case '+':
getNum(st, left, right);
st.push(left + right);
break;
case '-':
//加一个if-else判断分支,当该字符串大小为1时,说明其只有一个'-',为操作符,执行上述操作
if(str.size() == 1)
{
getNum(st, left, right);
st.push(left - right);
}
//当该字符串大小不为1,说明其为数值,将其转为int类型,然后压栈
else
{
st.push(stoi(str));
}
break;
case '*':
getNum(st, left, right);
st.push(left * right);
break;
case '/':
getNum(st, left, right);
st.push(left / right);
break;
default:
st.push(stoi(str));
break;
}
}
return st.top();
}
};
法二:我们取字符串的末尾字符进行判断,如果是“-”,末尾字符是’-’,如果是"-25",末尾字符为’5’,为数值,从而避免问题。
class Solution {
public:
void getNum(stack<int>& st, int& left, int& right)
{
right = st.top();
st.pop();
left = st.top();
st.pop();
}
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(const auto& str : tokens)
{
int left,right;
//str.back()取字符串最后一个数据
switch(str.back())
{
case '+':
getNum(st, left, right);
st.push(left + right);
break;
case '-':
getNum(st, left, right);
st.push(left - right);
break;
case '*':
getNum(st, left, right);
st.push(left * right);
break;
case '/':
getNum(st, left, right);
st.push(left / right);
break;
default:
st.push(stoi(str));
break;
}
}
return st.top();
}
};
以上是关于逆波兰表达式求值的主要内容,如果未能解决你的问题,请参考以下文章