我究竟做错了什么?使用堆栈实现后缀



我正在尝试使用堆栈为后缀表达式转换器编写infix。基本上,这是Wikipedia上发现的分流码算法的实现。

/*
    This function returns the precedence of a presented token. To keep comparisons
    simple, the higher the return value, the higher the precedence. Not to be 
    confused with priority.
    From https://web.archive.org/web/20120822075917/http://en.literateprograms.org:80/Special:DownloadCode/Shunting_yard_algorithm_(Python)
*/
int precedence(string token)
{
    switch(token.at(0))
    {
        case '+':
            return 1;
        case '-':
            return 1;
        case '*':
            return 2;
        case '/':
          return 2;
        case '(':
            return 0;
        case ')':
            return 0;
    }
    return 0;
}
/*
  Returns true if the supplied token is an operator. 
*/
bool is_operator(const string& token)
{
    return token == "*" 
        || token == "/" 
        || token == "+" 
        || token == "-";
}
/*
  Returns true if the supplied token is an operand (not an operator). 
*/
bool is_operand(const string& token)
{
    return !is_operator(token) && (token != "(") && (token != ")");
}
void display(const vector<string>& v)
{
    for(unsigned int i=0; i<v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
}
string associativity(const string& token)
{
    if(token == "*" || token == "+")
    {
        return "left";
    }
    else if(token == "/" || token =="-")
    {
        return "left";
    }
    return "?";
}
/*
    From wikipedia:
while there are tokens to be read:
    read a token.
    if the token is a number, then push it to the output queue.
    if the token is an operator, then:
        while (there is an operator at the top of the operator stack with
            greater precedence) or (the operator at the top of the operator stack has
                        equal precedence and
                        the operator is left associative) and
                      (the operator at the top of the stack is not a left bracket):
                pop operators from the operator stack, onto the output queue.
        push the read operator onto the operator stack.
    if the token is a left bracket (i.e. "("), then:
        push it onto the operator stack.
    if the token is a right bracket (i.e. ")"), then:
        while the operator at the top of the operator stack is not a left bracket:
            pop operators from the operator stack onto the output queue.
        pop the left bracket from the stack.
if there are no more tokens to read:
    while there are still operator tokens on the stack:
        pop the operator onto the output queue.
exit.
*/
vector<string> infix_to_postfix(const vector<string>& infix, bool& error)
{
    vector<string> postfix;
    stack<string> operators;
    for(string token : infix)
    {
        if(is_operand(token))
        {
            postfix.push_back(token);
        }
        if(is_operator(token))
        {
            while
            (
                (!operators.empty() && precedence(operators.peek()) > precedence(token))
            || (!operators.empty() && (precedence(operators.peek()) == precedence(token))   && (associativity(token) == "left") && (token != "("))
            )
            {
                string tk = operators.pop();
                if(tk != "(" && tk != ")")
                {
                    postfix.push_back(tk);
                }
            }
            operators.push(token);
        }
        if(token == "(")
        {
            operators.push(token);
        }
        if(token == ")")
        {
            while(!operators.empty() && operators.peek() != "(")
            {
                postfix.push_back(operators.pop());
            }
            if(!operators.empty())
            {
                operators.pop();
            }
        }
    }
    while(!operators.empty())
    {
        postfix.push_back(operators.pop());
    }
    return postfix; 
}

我希望该代码以包含相关令牌的向量的形式返回有效的后缀表达式。

以下评估功能返回我正在测试的更长表达式的怪异数字。

double evaluate(const vector<string>& postfix, bool& error)
{
    error = false;
    double result;
    stack<double> numbers;
    for(unsigned int i=0; i<postfix.size(); i++)
    {
        string token = postfix[i];
        if(is_operand(token))
        {
            numbers.push(stod(token));
        }
        else
        {
            double operand1 = numbers.pop();
            double operand2 = numbers.pop();
            switch(token.at(0))
            {
                case '+':
                    numbers.push(operand1 + operand2);
                    break;
                case '-':
                    numbers.push(operand1 - operand2);
                    break;
                case '*':
                    numbers.push(operand1 * operand2);
                    break;
                case '/':
                    numbers.push(operand1 / operand2);
                    break;
            }
        }
    }

例如,考虑此输入和输出:

Infix: ( 3 + 3 * 5 ) * 6 - 2 / 1 + 3 + 3 * 5 * ( 4 + 1 )
Postfix: 3 3 5 * + 6 * 2 1 / 3 3 5 4 1 + * * + + -
Result: -29.5

Google说其184。

更新:我包括Wikipedia的关联功能。我还更新了表达结果。

更新2:并入了使该代码起作用的评论。

显然,您的后修正转换输出已经错了。( 3 + 3 * 5 )应该成为3 3 5 * +,而不是3 3 + 5 *

       while
        (
            (!operators.empty() && precedence(token) <= precedence(operators.peek()))
            || (!operators.empty() && operators.peek() != "(")
        )

这部分是错误的。文本说 (pred(operators.peek()) > pred(token)) || (pred(operators.peek()) == pred(token) && token != "(")

因此,您总是在操作员不是关闭的paranthes时始终错误地弹出,而忽略操作员优先级。

        double operand1 = numbers.pop();
        double operand2 = numbers.pop();

那部分也是错误的。操作数2是堆栈上较高的一个。将它们切换。

相关内容

  • 没有找到相关文章

最新更新