清理LeetCode评估反向波兰表示法的代码

时间:2016-03-25 21:58:46

标签: c++

我为LeetCode OJ问题编写了以下代码Evaluate Reverse Polish Notation

<pre>
</pre>

代码无疑是正确的。但是,我觉得代码的某些部分并不干净。实际上,我想写这样的代码:

int evalRPN(vector<string>& tokens) 
{
    int n = tokens.size();
    if (n == 0)
        return 0;
    stack<int> S;
    int a, b;
    for (int i = 0; i < n; i++)
    {
        string tmp = tokens[i];
        if (tmp == "+")
        {
            a = S.top(); S.pop();
            b = S.top(); S.pop();
            S.push(b + a);
        }
        else if (tmp == "-")
        {
            a = S.top(); S.pop();
            b = S.top(); S.pop();
            S.push(b - a);
        }
        else if (tmp == "*")
        {
            a = S.top(); S.pop();
            b = S.top(); S.pop();
            S.push(b * a);
        }
        else if (tmp == "/")
        {
            a = S.top(); S.pop();
            b = S.top(); S.pop();
            S.push(b / a);
        }
        else
        {
            S.push(stoi(tmp));
        }
    }
    return S.top();
}
  1. int evalRPN(vector<string>& tokens) { int n = tokens.size(); if (n == 0) return 0; stack<int> S; int a, b; for (int i = 0; i < n; i++) { string tmp = tokens[i]; if (tmp is any of "+", "-", "*", "/") // <== [1] { a = S.top(); S.pop(); b = S.top(); S.pop(); S.push(compute(a, b, tmp)); // <== [2] } else { S.push(stoi(tmp)); } } return S.top(); } ,我不想写[1],我想要更清晰的代码来检查tmp == "+" || tmp == "-" || tmp == "*" || tmp == "/"是否是四个运营商中的任何一个;
  2. tmp中,函数[2]将输出操作数compute(int a, int b, string& tmp)a和运算符b的结果。但我仍然不想使用任何tmpif - else可能会被接受,但我不知道如何在switch使用。如果存在,则欢迎使用Lambda函数或任何可能的运算符函数。
  3. 有没有办法做到这一点?

2 个答案:

答案 0 :(得分:2)

这适用于C ++ 11或更高版本。 (如果使用带有-std=c++11标志的g ++编译)。

#include <map>
#include <functional>
// ...

int evalRPN(vector<string>& tokens) 
{
    // map of string -> lambda
    std::map<std::string, std::function<int(int,int)>> ops;

    // fill the map 
    ops["+"] = [](int a,int b) { return b+a; };
    ops["-"] = [](int a,int b) { return b-a; };
    ops["*"] = [](int a,int b) { return b*a; };
    ops["/"] = [](int a,int b) { return b/a; };    

    int n = tokens.size();
    if (n == 0)
        return 0;

    stack<int> S;
    int a, b;
    for (int i = 0; i < n; i++)
    {
        string tmp = tokens[i];
        // find the operator in map
        auto opit = ops.find(tmp);
        if ( opit != ops.end() ) {
            // if token is in map (ie. if it is operator)
            a = S.top(); S.pop();
            b = S.top(); S.pop();
            // get the function
            auto fn = opit->second;
            // and push it's result to stack
            S.push( fn(a,b) );
        } else {
            // if not operator push to stack
            S.push(stoi(tmp));
        }

    }
    return S.top();
}

答案 1 :(得分:1)

至少,我可以为您解决问题的第一部分,即if语句。我认为以下方法可行:

std::string operators = "+-*/";
std::string tmp = tokens[i];
if(operators.find(tmp) != std::string::npos)
{
    a = S.top(); S.pop();
    b = S.top(); S.pop();
    S.push(compute(a, b, tmp)); // <== [2]
}
else
{
    S.push(stoi(tmp));
}

我在这里做的很简单:我有一个包含所有运算符的字符串,我只是在该字符串中搜索tmp。如果它在该字符串中的位置不是npos,则tmp必须是运算符。

对于第二部分,我有两个想法:

它仍然有点笨拙,但你写了一个switch声明是可以接受的,那么怎么样:

int compute(int a, int b, std::string op)
{
    switch (op[0]) {
        case '+':
            return b+a;
        case '-':
            return b-a;
        case '*':
            return b*a;
        case '/':
            return b/a;
    }
}

另一个想法:最初,我认为你可以使用operator+和co来避免为已经实现过的东西编写你的胜利函数,但事实证明这是不可能的。但是,您可以使用其他功能:

int compute(int a, int b, std::string op)
{
    static std::map<std::string,std::function<int(int,int)> >  operations;
    operations["+"] = std::plus<int>();
    operations["-"] = std::minus<int>();
    operations["*"] = std::multiplies<int>();
    operations["/"] = std::divides<int>();

    return operations[op](b,a);
}

查看http://ideone.com/wSl5zQ以获取完整实现,该实现读取一行RPN表单stdin并计算结果。