逆波兰表达式求值

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();
    }
};

以上是关于逆波兰表达式求值的主要内容,如果未能解决你的问题,请参考以下文章

c语音编程,逆波兰表达式求值

逆波兰表达式求值424

逆波兰表达式求值

LeetCode 0150. 逆波兰表达式求值

LeetCode:逆波兰表达式求值150

波兰式与逆波兰式的转换和表达式求值