繁体   English   中英

为什么使用堆栈作为ADT崩溃将中缀转换为后缀表示法?

[英]Why does this conversion of infix to postfix notation using stack as an ADT crash?

#include<iostream>
#include<cstring>
using namespace std;
#define MAX 5
struct node
{
    char data;
    struct node *next;
};
class stack
{
    public:
        node *top;
        stack()         //constructor
        {
            top=NULL;
        }
        char Top()     //return top element without popping
        {
            return(top->data);
        }
        int empty()     //check empty
        {
            if(top==NULL)
                return(1);
            return(0);
        }
        void push(char x)     //push function
        {
            node *p;
            p=new node;
            p->data=x;
            p->next=top;
            top=p;
        }
        char pop()         //pop function
        {
            node *p;
            char x;
            p=top;
            top=top->next;
            x=p->data;
            delete(p);
            return(x);
        }
        int precedence(char x)   //check precedence of operators
        {
            if(x=='(')
                return 0;
            else if(x=='+'||x=='-')
                return 1;
            else if(x=='*'||x=='/'||x=='%')
                return 2;
            return 3;
        }
        void infix_to_postfix(char infix[],char postfix[]);
};
void infix_to_postfix(char infix[],char postfix[])
{
    stack s;
    char x,token;
    int i,j=0;
    for(i=0;infix[i]!='\0';i++)
    {
        token=infix[i];
        if(isalnum(token))
            postfix[j++]=token;
        else
            if(token=='(')
                s.push(token);
            else
                if(token==')')
                {
                    while((x=s.pop())!='(')
                        postfix[j++]=x;
                }

                else
                {
                    while(s.precedence(token)<=s.precedence(s.Top())&& !s.empty())
                        postfix[j++]=s.pop();
                    s.push(token);
                }
    }
    while(!s.empty())
    {
        x=s.pop();
        postfix[j++]=x;
    }
    postfix[j++]='\0';
}
int main()
{
    char infix[30],postfix[30];
    cout<<"\nEnter the infix expression::\n";
    cin>>infix;
    infix_to_postfix(infix,postfix);
    cout<<"/nThe equivalent postfix expression is::"<<postfix;
    return 0;
}

上面的代码在Ubuntu中使用gedit给出了分段错误...而当在Windows中使用turbo C运行相同的代码时,所需的更改如下...正确运行...

#include<stdio.h>
#include<conio.h>
#include<iostream.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#define MAX 5
struct node
{
    char data;
    struct node *next;
};
class stack
{
    public:
        node *top;
        stack()         //constructor
        {
            top=NULL;
        }
        char Top()     //return top element without popping
        {
            return(top->data);
        }
        int empty()     //check empty
        {
            if(top==NULL)
                return(1);
            return(0);
        }
        void push(char x)     //push function
        {
            node *p;
            p=new node;
            p->data=x;
            p->next=top;
            top=p;
        }
        char pop()         //pop function
        {
            node *p;
            char x;
            p=top;
            top=top->next;
            x=p->data;
            delete(p);
            return(x);
        }
        int precedence(char x)   //check precedence of operators
        {
            if(x=='(')
                return 0;
            else if(x=='+'||x=='-')
                return 1;
            else if(x=='*'||x=='/'||x=='%')
                return 2;
            return 3;
        }
        void infix_to_postfix(char infix[],char postfix[]);
};
void infix_to_postfix(char infix[],char postfix[])
{
    stack s;
    char x,token;
    int i,j=0;
    for(i=0;infix[i]!='\0';i++)
    {
        token=infix[i];
        if(isalnum(token))
            postfix[j++]=token;
        else
            if(token=='(')
                s.push(token);
            else
                if(token==')')
                {
                    while((x=s.pop())!='(')
                        postfix[j++]=x;
                }

                else
                {
                    while(s.precedence(token)<=s.precedence(s.Top())&& !s.empty())
                        postfix[j++]=s.pop();
                    s.push(token);
                }
    }
    while(!s.empty())
    {
        x=s.pop();
        postfix[j++]=x;
    }
    postfix[j++]='\0';
}
int main()
{
    char infix[30],postfix[30];
    cout<<"\nEnter the infix expression::\n";
    cin>>infix;
    infix_to_postfix(infix,postfix);
    cout<<"\nEquivalent postfix expression is::"<<postfix;
    getch();
return 0;
}

为什么Ubuntu出现问题???

在直接取消引用top->data之前top->data您永远不会检查输入堆栈是否为空。 具体来说,这个循环:

  while(s.precedence(token)<=s.precedence(s.Top())&& !s.empty())
        postfix[j++]=s.pop();
  s.push(token);

可以,并且在您的情况下, 取消引用空堆栈,因为通过s.Top()取消引用顶部指针检查空状态。 您可以通过使用布尔短路和正确的评估顺序来避免不适当的取消引用:

  while(!s.empty() && s.precedence(token)<=s.precedence(s.Top()))
        postfix[j++]=s.pop();
  s.push(token);

输入

A*(B+C/(D-A))

产量

等效的后缀表达式是:: ABCDA-/+*

也就是说,这非常脆弱。 除非特别指示这样做,否则你没有理由不首先使用自定义堆栈,因为标准适配器std::stack<>将删除大约90%的代码,我强烈建议利用那。

最后,这是一个彻头彻尾的错误。 Windows或Ubuntu没有区别。 它调用未定义的行为。 它没有在Windows上崩溃意味着你很幸运(或者没有,因为你认为它没问题,因为它没有崩溃); 不对。 如果你想知道我是怎么注意到的,我在代码中看到了它,但是用Valgrind证实了这一点,这立即证实了我的怀疑。


使用标准库进行重型提升

当您在大多数操作中使用标准库中的类时,这会变得相当简单,您可以在下面看到。 我保持你的算法完整,但只是使用std::stack adapter和std::string类的guts:

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

static int precedence(char x)   //check precedence of operators
{
    if(x=='(')
        return 0;
    else if(x=='+'||x=='-')
        return 1;
    else if(x=='*'||x=='/'||x=='%')
        return 2;
    return 3;
}

std::string infix_to_postfix(const std::string& infix)
{
    std::stack<char> s;
    std::string postfix;

    for (auto ch : infix)
    {
        if (isalnum(ch))
            postfix.push_back(ch);

        else if (ch == '(')
            s.push(ch);

        else if(ch == ')')
        {
            while (!s.empty())
            {
                ch = s.top();
                s.pop();
                if (ch == '(')
                    break;
                postfix.push_back(ch);
            }
        }

        else
        {
            while(!s.empty() && precedence(ch)<=precedence(s.top()))
            {
                postfix.push_back(s.top());
                s.pop();
            }
            s.push(ch);
        }
    }

    while(!s.empty())
    {
        postfix.push_back(s.top());
        s.pop();
    }

    return postfix;
}

int main()
{
    const char infix[] = "A*(B+C/(D-A)+2*(E-F))";
    cout << "\nThe equivalent postfix expression is: " << infix_to_postfix(infix);
    return 0;
}

输入

A*(B+C/(DA)+2*(EF))

产量

等效的后缀表达式为: ABCDA-/+2EF-*+*

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM