【问题标题】:Clean up the code for LeetCode Evaluate Reverse Polish Notation清理 LeetCode Evaluate Reverse Polish Notation 的代码
【发布时间】:2016-07-13 17:27:45
【问题描述】:

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

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

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

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. [1],我不想写tmp == "+" || tmp == "-" || tmp == "*" || tmp == "/",我想要更简洁的代码来检查tmp是四个运算符中的任何一个;
  2. [2]中,函数compute(int a, int b, string&amp; tmp)将输出操作数ab和运算符tmp的结果。但是我仍然不想使用任何if - elseswitch 可能会被接受,但我不知道如何在此处使用string)。欢迎使用 Lambda 函数或任何可能的运算符函数(如果存在)。

有没有办法做到这一点?

【问题讨论】:

  • SQL 等一些语言有关键字in,它可以让你做你在 1 中要求的事情,但是我很确定在 C++ 中没有类似的东西。
  • 我讨厌写很多条件语句
  • 可以将数组传递给方法,然后循环遍历数组。
  • 不喜欢 switch 语句?
  • 是的。给我看代码

标签: c++


【解决方案1】:

这应该适用于 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();
}

【讨论】:

    【解决方案2】:

    至少,我可以为您解决问题的第一部分,即 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 并计算结果。

    【讨论】:

    • 应该是b-ab/a
    • @stjepano 谢谢,我改了。无论如何,您的解决方案更好。顺便说一句:您是否也尝试用内置的运算符函数替换 lambdas?我无法让它工作,因为它们超载了。
    • 不,我没有尝试过,但听起来应该可以。
    猜你喜欢
    • 2021-09-04
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多