C++ 中的前缀表达式求值 [CodeEval]

Posted

技术标签:

【中文标题】C++ 中的前缀表达式求值 [CodeEval]【英文标题】:Prefix Expression Evaluation in C++ [CodeEval] 【发布时间】:2015-10-27 09:56:40 【问题描述】:

Here 是挑战的链接。 这是为了您的方便:

前缀表达式 描述: 给你一个前缀表达式。编写一个程序来评估它。 输入样本: 第一个参数将是一个输入文件,每行有一个前缀表达式。例如 * + 2 3 4 您的程序必须读取此内容并将其插入您喜欢的任何数据结构中。 遍历该数据结构并评估前缀表达式。每个令牌都是 由空格分隔。您可以假设出现的唯一有效运算符 在测试数据中是 '+'、'*' 和 '/' 输出样本: 打印到标准输出,前缀表达式的输出,每行一个。例如 20"

我的代码有时会被 CodeEval 拒绝,因为编译时间超过 10 秒。当它编译时,我得到了 85/100 的分数,因为我认为在 40 个测试用例中,我得到了一些不正确的。我相信我的算法是正确的,问题仅在于检查边界/极端情况。谁能帮我优化这段代码以在 CodeEval 中工作?

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <vector>
    #include <string>

    using namespace std;

    void tokenize(string& str, vector<string>& tokens)
    
        int pos;
        string token;
        while ((pos = str.find(" ")) != std::string::npos )
        
            token = str.substr(0,pos);
            tokens.push_back(token); 
            str.erase(0, pos + 1);  
        
        tokens.push_back(str.c_str());  
    

    bool isOperator(string str)
    
        if((str == "+") || (str == "-") || (str == "*") || (str == "/") )
            return true;
        else
            return false;
    

    int compute(string oper, int val1, int val2)
    
        if(oper == "+")
            return (val1 + val2);
        else if(oper == "*")
            return (val1 * val2);
        else if(oper == "/")
            return (val1 / val2); 
        else if(oper == "-")
            return (val1 - val2);
    

    void evalPrefix(vector<string>& expression)
    
        vector<int> numStack;
        int num1;
        int num2;

        for (int i = (expression.size() - 1); i >=0; i--)
        
            if(isOperator(expression[i]))
            
                num1 = numStack.back();
                numStack.pop_back();
                num2 = numStack.back();
                numStack.pop_back();
                numStack.push_back(compute(expression[i], num1, num2));
            
            else
            
                numStack.push_back(atoi(expression[i].c_str()));
            
        
        cout << numStack[0] << endl;
    



    int main(int argc, char *argv[]) 
    
        ifstream file(argv[1]);
        string line;
        string token; 
        vector<string> tokens; 

        while (!file.eof()) //processing the file
        
            getline(file, line);
            if(line.length() == 0)
                continue;
            else
            
                tokens.clear();
                tokenize(line, tokens); //tokenizing the file
                if(tokens.size())
                    evalPrefix(tokens);
            
        
        return 0;
     

这里是最新的代码(97.5分能够编译一次):

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <vector>
    #include <string>

    using namespace std;

    void tokenize(string& str, vector<string>& tokens)
    
        int pos;
        string token;
        while ((pos = str.find(" ")) != std::string::npos )
        
            token = str.substr(0,pos);
            tokens.push_back(token); 
            str.erase(0, pos + 1);  
        
        tokens.push_back(str.c_str());  
    

    bool isOperator(string str)
    
        if((str == "+") || (str == "*") || (str == "/") )
            return true;
        else
            return false;
    

    int compute(string oper, int val1, int val2)
    
        if(oper == "+")
            return (val1 + val2);
        else if(oper == "*")
            return (val1 * val2);
        else if(oper == "/")
            return (val1 / val2); 
        else
            return 0;
    

    void evalPrefix(vector<string>& expression)
    
        vector<int> numStack;
        int num1;
        int num2;

        for (int i = (expression.size() - 1); i >=0; i--)
        
            if(isOperator(expression[i]))
            
                num1 = numStack.back();
                numStack.pop_back();
                num2 = numStack.back();
                numStack.pop_back();
                numStack.push_back(compute(expression[i], num1, num2));
            
            else
            
                numStack.push_back(atoi(expression[i].c_str()));
            
        
        cout << numStack[0] << endl;
    



    int main(int argc, char *argv[]) 
    
        ifstream file(argv[1]);
        string line;
        string token; 
        vector<string> tokens; 

        while (getline(file, line)) //processing the file
        
            if(line.length() == 0)
                continue;
            else
            
                tokens.clear();
                tokenize(line, tokens); //tokenizing the file
                if(tokens.size())
                    evalPrefix(tokens);
            
        
        return 0;
     

【问题讨论】:

作为参考。 C# 中的此解决方案有效。他们是否在检查一些我没有的边界? github.com/rogerchang1/codeeval/blob/master/PrefixExpression.cs 一个问题是你不应该使用while (!file.eof()),见"Why is “while ( !feof (file) )” always wrong?"。 此外,如果您只想在空格上分隔标记,std::ostringstream 和普通输出运算符 &gt;&gt; 也应该可以工作。或者只是将std::copystd::ostream_iteratorstd::back_inserter 一起使用。 @JoachimPileborg 已修复。将其更改为 while(getline(file, line)) 通过更改 while 循环(访问文件),我能够将我的分数提高到 97.5。 【参考方案1】:

完成了。他们想要浮动值。谢谢。

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <vector>
    #include <string>

    using namespace std;

    void tokenize(string& str, vector<string>& tokens)
    
        int pos;
        string token;
        while ((pos = str.find(" ")) != std::string::npos )
        
            token = str.substr(0,pos);
            tokens.push_back(token); 
            str.erase(0, pos + 1);  
               
        tokens.push_back(str.c_str());  
    

    bool isOperator(string str)
    
        if((str == "+") || (str == "*") || (str == "/") )
            return true;
        else
            return false;
    

    float compute(string oper, float val1, float val2)
    
        if(oper == "+")
            return (val1 + val2);
        else if(oper == "*")
            return (val1 * val2);
        else if(oper == "/")
            return (val1 / val2); 
        else
            return 0;
    

    void evalPrefix(vector<string>& expression)
    
        vector<float> numStack;
        float num1;
        float num2;

        for (int i = (expression.size() - 1); i >=0; i--)
        
            if(isOperator(expression[i]))
            
                num1 = numStack.back();
                numStack.pop_back();
                num2 = numStack.back();
                numStack.pop_back();
                numStack.push_back(compute(expression[i], num1, num2));
            
            else
            
                numStack.push_back(atoi(expression[i].c_str()));
            
        
        int i = int (numStack[0] + 0.5);
        cout << i << endl;
    



    int main(int argc, char *argv[]) 
    
        ifstream file(argv[1]);
        string line;
        string token; 
        vector<string> tokens; 

        while (getline(file, line)) //processing the file
        
            if(line.length() == 0)
                continue;
            else
            
                tokens.clear();
                tokenize(line, tokens); //tokenizing the file
                if(tokens.size())
                    evalPrefix(tokens);
            
        
        return 0;
     

【讨论】:

以上是关于C++ 中的前缀表达式求值 [CodeEval]的主要内容,如果未能解决你的问题,请参考以下文章

求C++ 表达式求值得程序,最好简单说明数据结构和大致方法

前缀,中缀,后缀表达式求值

栈在表达式求值中的应用(C语言)

CodeEval 挑战:输入文件中的反转字符串

表达式求值

表达式求值