栈的应用:中缀表达式转换为后缀表达式

栈是一种典型的受限线性表,关于线性表的链式存储结构 

数据结构:链表总结:https://blog.csdn.net/qq_41605114/article/details/104589975

栈的应用,更多体现在如何设置结点,如何设置头结点内容,和如何合理化的适当增添接口,下面的内容来源《大话数据结构》

赘述了中缀表达式转化为后缀表达式,和后缀表达式在计算机中是如何被应用的。

                  

           

           

          

                

            

         

              

               

        

                (图源:大话数据结构)       

此处 输出结果如下:

只展示中缀表达式如何变成后缀表达式: 

链表的基本结构如下:结点类型中成员较多,因为知道要储存数据的类型,就没有必要使用void *了。

char item保存运算符和没有数字,int grade保存的是 运算符的优先级,int Number是给字符数字转化为数值后,预留的空间

//stack 链式 头结点入栈,头结点出栈
struct StackNode
{
    char Item;//运算符本身
    int grade;//运算符优先级
    int Number;//数字
    StackNode * next;
};
//栈的性质
struct StackProperty
{
    StackNode header;
    int size;
};

//初始化
StackProperty * Insert_Stack();
//进栈
void Push_Stack(StackProperty * stacklist,StackNode * PushData);
//查看栈顶元素
StackNode * CheackTop_Stack(StackProperty * stacklist);
//出栈
void Pop_Stack(StackProperty * stacklist);
//销毁
void Destroy_Stack(StackProperty * stacklist);
//判断是不是运算符
bool BoolJudgeOperator(char data);
//运算符优先级
int ItemJudegOperator(char data);//判断运算符

以下为栈的接口,多了一个接口,就是常看栈顶元素,只是输出栈顶元素,并不出栈 

//初始化
StackProperty * Insert_Stack()
{
    StackProperty * mystack = new StackProperty;
    mystack->size = 0;
    mystack->header.next = nullptr;
    return mystack;

}
//进栈
void Push_Stack(StackProperty * stacklist,StackNode * PushData)
{
    if(nullptr == stacklist)
        return;
    if(nullptr == PushData)
        return;

    StackNode * mydata = new StackNode;
    //将要插入的内容 赋值给新分配好的空间
    mydata->grade = PushData->grade;
    mydata->Item = PushData->Item;
    mydata->next = PushData->next;

    mydata->next = stacklist->header.next;//更新插入元素的后驱
    stacklist->header.next = mydata;//更新头指针的指向
    stacklist->size++;
//    qDebug()<<"进栈元素"<<mydata->Item;

}
//出栈
void Pop_Stack(StackProperty * stacklist)
{
    if(nullptr == stacklist)
        return;

    StackNode * myDel = stacklist->header.next;//第一个结点,也就是要出栈的结点

    stacklist->header.next = myDel->next;//更新头结点后驱
    myDel->next = nullptr;//更新出栈结点的后驱

    stacklist->size--;
    delete myDel;
}

//查看栈顶元素
StackNode * CheackTop_Stack(StackProperty * stacklist)
{
    if(nullptr == stacklist)
        return nullptr;
    StackNode * myDel = stacklist->header.next;//第一个结点,也就是要出栈的结点
    return myDel;//直接将这个值转化为用户数据类型即可调用其中的数字或者运算符
}
//销毁
void Destroy_Stack(StackProperty * stacklist)
{
    if(nullptr == stacklist)
        return;
    delete stacklist;
}

中缀表达式转化为后缀表达式的思路:

  1. 数字,直接进栈
  2. 左括号运算符,直接进行
  3. 右括号运算符,从栈顶开始依次出栈,直到左括号出线,结束
  4. 要进栈的运算符栈顶运算符比较,优先级高于栈顶运算符,进栈。
  5. 优先级低于或等于栈顶运算符,栈顶运算符出栈,之后重复操作,继续进行优先级比较,完全比完后,该运算符进栈
  6. 循环完整个表达式,完成所有操作后,最后不要忘了,栈内结点全部出栈,作为表达式最后的输出

具体实现如下,通过优先级进行判断,运算符优先级规定,判断是数字还是运算符的接口,如下接口所示:

int ItemJudegOperator(char data)//判断运算符
{
    if(data == '+'||data == '-')
        return 2;
    else if(data == '/'||data == 'x')
        return 3;
    else if(data == '(')
        return -1;
    else if(data == ')')
        return 1;
    else
        return 0;
}
bool BoolJudgeOperator(char data)//判断运算符
{
    if(data == '+'||data == '-'||data == '/'||data == 'x'||data == '('||data == ')')
        return true;//是
    else
        return false;
}

下面是用代码实现以上逻辑

第二个while中的三个if else 就是完全遵循中缀转后缀的法则进行的,运算符的优先级是通过数字来分档判断的,完整版见后面

    while( MathInfix[SizeOFLoop]!='\0' )
    {
        //先判断是不是数字
        if( BoolJudgeOperator( MathInfix[SizeOFLoop] ) )//判断是不是操作符号
        {
            int IntFlagForItem = ItemJudegOperator(MathInfix[SizeOFLoop]);

            while(MyStack->header.next != nullptr)//看看有没有要出栈的
            {
                //和栈顶元素比优先级
                StackNode * TopItem = CheackTop_Stack(MyStack);
                if(IntFlagForItem == -1||IntFlagForItem>TopItem->grade)//左括号||优先级高 进栈
                {
                    break;//直接让该运算符进栈
                }
                else if(IntFlagForItem == 1)//右括号
                {


                    break;
                }
                //要入栈运算符的优先级低于栈顶元素,栈顶输出,并且循环,直到优先级
                else if(IntFlagForItem < TopItem->grade||IntFlagForItem == TopItem->grade)
                {

                    break;
                }
            }
            if(IntFlagForItem != 1)//右括号
            {
                //出栈的出完了,进栈
                StackNode S = {MathInfix[SizeOFLoop],ItemJudegOperator(MathInfix[SizeOFLoop]),0,nullptr};
                Push_Stack(MyStack,&S);
                //这个要分配空间了,在销毁的部分要求销毁

            }

执行程序完整版本

    char MathInfix[] = "9+(3-1)x3+10/2";
    StackProperty * MyStack = Insert_Stack();//创建头结点
    StackProperty * ResultStack = Insert_Stack();//创建头结点,存放后缀表达式
    int SizeOFLoop = 0;//循环次数

    while( MathInfix[SizeOFLoop]!='\0' )
    {
        //先判断是不是数字
        if( BoolJudgeOperator( MathInfix[SizeOFLoop] ) )//判断是不是操作符号
        {
            int IntFlagForItem = ItemJudegOperator(MathInfix[SizeOFLoop]);

            while(MyStack->header.next != nullptr)//看看有没有要出栈的
            {
                //和栈顶元素比优先级
                StackNode * TopItem = CheackTop_Stack(MyStack);
                if(IntFlagForItem == -1||IntFlagForItem>TopItem->grade)//左括号||优先级高 进栈
                {
                    break;//直接让该运算符进栈
                }
                else if(IntFlagForItem == 1)//右括号
                {
                    //循环出栈,直到‘(’也出栈
                    while(MyStack->header.next != nullptr)
                    {
                        //栈顶元素
                        StackNode * Temp_TopItem = CheackTop_Stack(MyStack);
                        if(Temp_TopItem->Item == '(')
                        {
                            //左括号出栈
                            Pop_Stack(MyStack);
                            break;//直接跳出循环
                        }
                        else
                        {
                            //栈顶出栈
                            StackNode * ItemForPostfit = CheackTop_Stack(MyStack);
                            //输出
                            StackNode S_Result = {ItemForPostfit->Item,ItemForPostfit->grade,0,nullptr};
                            Push_Stack(ResultStack,&S_Result);

                            //释放结点
                            Pop_Stack(MyStack);
                        }
                    }
                    break;
                }
                //要入栈运算符的优先级低于栈顶元素,栈顶输出,并且循环,直到优先级
                else if(IntFlagForItem < TopItem->grade||IntFlagForItem == TopItem->grade)
                {
                    while(MyStack->header.next != nullptr)//栈空,则不再继续
                    {
                        //栈顶元素
                        StackNode * Temp_TopItem = CheackTop_Stack(MyStack);
                        //确定栈顶元素的优先级
                        int Temp_IntFlagForItem = ItemJudegOperator(Temp_TopItem->Item);
                        if(IntFlagForItem < Temp_IntFlagForItem||IntFlagForItem == Temp_IntFlagForItem)
                        {
                            //栈顶元素需要输出

                            //栈顶出栈
                            StackNode * ItemForPostfit = CheackTop_Stack(MyStack);
                            //输出
                            StackNode S_Result = {ItemForPostfit->Item,ItemForPostfit->grade,0,nullptr};
                            Push_Stack(ResultStack,&S_Result);
                            //释放结点
                            Pop_Stack(MyStack);

                        }
                        else if(IntFlagForItem>Temp_IntFlagForItem)
                        {
                            break;//插入元素的优先级不等于也不小于,也就是大的时候,出栈
                        }
                        
                    }
                    break;
                }
            }
            if(IntFlagForItem != 1)//右括号
            {
                //出栈的出完了,进栈
                StackNode S = {MathInfix[SizeOFLoop],ItemJudegOperator(MathInfix[SizeOFLoop]),0,nullptr};
                Push_Stack(MyStack,&S);
                //这个要分配空间了,在销毁的部分要求销毁

            }


        }
        else//不是的话,就是数字,数字是要输出的
        {
            //在输出字符串中保存该内容
            StackNode S_Result = {MathInfix[SizeOFLoop],0,0,nullptr};
            Push_Stack(ResultStack,&S_Result);
        }
        SizeOFLoop++;

    }


    qDebug()<<"将栈中结点全部弹出,添加到输出中,然后再销毁";
    while(MyStack->header.next != nullptr)
    {
        //栈顶出栈
        StackNode * ItemForPostfit = CheackTop_Stack(MyStack);
        //输出
        StackNode S_Result = {ItemForPostfit->Item,ItemForPostfit->grade,0,nullptr};
        Push_Stack(ResultStack,&S_Result);
        //释放结点
        Pop_Stack(MyStack);
    }
    char result[ResultStack->size+1];
    result[ResultStack->size] = '\0';
    int intexforresult = ResultStack->size - 1;
    while(ResultStack->header.next != nullptr)
    {
        //栈顶出栈
        StackNode * Result_ItemForPostfit = CheackTop_Stack(ResultStack);
        //输出
        qDebug()<<Result_ItemForPostfit->Item;
        result[intexforresult] = Result_ItemForPostfit->Item;
        intexforresult--;
        //释放结点
        Pop_Stack(ResultStack);
    }
    qDebug()<<result;

    qDebug()<<"销毁";
    Destroy_Stack(MyStack);
    Destroy_Stack(ResultStack);
发布了85 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41605114/article/details/104651983