栈的应用2——中缀表达式和后缀表达式的转换

中缀后缀

日常生活中,我们都是使用中缀表达式,如8*(5+3)这样的,这样的式子可以画成一个二叉树,而二叉树的遍历方式有三种,分别对应着三种表达式方式。
(感觉说多了,再说后面二叉树没东西讲了)
所以上面的式子可以写成8 5 3+ * ,虽然看着很诡异,但是要知道,对于计算机来说,看中缀表达式比看十进制难受多了(栈的应用1——数制转换),因为:
后缀表达式可以避免括号

游戏规则

在这道题里面,可以输入大小写的单字母变量,以及双目四则运算(加减乘除)还有括号,目的是将这个转换成一个后缀表达式,以去掉括号。

先分析一下,因为是去掉括号,所以需要匹配到一对括号然后一起删掉,那么问题来了,如果你在读入第一对括号的时候,正等着他的另一半,却等到了别人,这就尴尬了,所以呢,要先将他请到一边,(看看标题,看看标题),这个时候就是栈的用处了。

原则:

  1. 读到字母就输出;
  2. 左括号直接压栈别犹豫,犹豫就会白给;
  3. 加减乘除的运算符,要比较和栈顶元素的优先级,(栈空直接压入)要是高就直接压入,如果低就需要一直出栈直到栈空或者栈顶元素的优先级低于当前。
  4. 读到右括号的时候,需要将站内元素出栈直到碰到左括号,把两个一起删了。
  5. 结束读入,将栈清空,准确是全部出栈,可不是直接删了

那么问题来了,优先级相同呢?
这就是个坑!
为啥,(因为lz被这东西折磨了两天,代码数据反复横跳),因为前面说了这个东西可以用二叉树表示,而中缀就是一个中序遍历的结果。
而只给出二叉树的中序遍历不能唯一确定二叉树,后期给出。
所以后缀,也就是后序的结果不唯一,就差这这些优先级相同上面。

  1. 在比较入栈
  2. 出栈比较优先级

这两个位置会不一样。

贴代码

#include <iostream>
#include <cstring>
using namespace std;

struct link
{
    char data;
    struct link* next;
};

void get_in(struct link* head,char data)//入栈
{
    struct link* pr=(struct link*)malloc(sizeof(struct link));
    pr->next=head->next;
    head->next=pr;
    pr->data=data;
}

void get_out(struct link* head)//出栈
{
    struct link* pr=head->next;
    head->next=pr->next;
    cout<< pr->data;
    free(pr);
}

int judge(struct link* head)//判断栈空
{
    if(head->next!=NULL)
        return 1;//非空
    else
        return 0;
}

int compare(struct link* head,char data)//判断栈顶和当前的优先级大小
{
    int h,d;//栈顶元素分四级,左括号、加减、乘除、右括号。

    if(head->next->data=='*'||head->next->data=='/')
        h=1;
    else if(head->next->data=='+'||head->next->data=='-')
        h=0;
    else if(head->next->data=='(')
        h=-1;
    else
        h=2;

    if(data=='*'||data=='/')
        d=1;
    else 
        d=0;
        
    if(d>h)//当前大于栈顶
        return 1;
    else if(d==h)//相等
        return 0;
    else
        return -1;
}

void work(string in)
{
    int length=in.size();//先将字符串类转化成数组
    char a[length+1];
    strcpy(a,in.c_str());

    struct link* head=(struct link*)malloc(sizeof(struct link));//操作符栈
    head->next=NULL;

    for(int i=0;i<length;i++)
    {
        if((a[i]>64&&a[i]<91)||(a[i]>96&&a[i]<123))//字母
        {
            cout<< a[i];
        }

        else if(a[i]==40)//(
        {
            get_in(head,'(');
        }

        else if(a[i]==43||a[i]==45||a[i]==42||a[i]==47)// +-*/
        {
            if(!judge(head))//操作符栈空
                get_in(head,a[i]);//压栈

            else if(compare(head,a[i])==1 || compare(head,a[i])==0)//当前的操作符优先级高于等于操作符栈顶元素
            {
                get_in(head,a[i]);//压栈
            }

            else
            {
                while(judge(head)&&(compare(head,a[i])==-1||compare(head,a[i])==0))//当前优先级低,要让比他高的都出来
                {
                    get_out(head);
                }
                get_in(head,a[i]);//再压入
            }
        }
        else // )
        {
            while(judge(head)&&head->next->data!='(')
            {
                get_out(head);//将操作符栈的内容弹出到字母栈
            }
            struct link* pr=head->next;//这个是左括号
            head->next=pr->next;
            free(pr);//'('不需要进入字母栈
        }
    }

    while(head->next)
    {
        get_out(head);//最后操作符栈剩的都压入字母栈来里面
    }
    free(head);
}

int main()
{
    string in;
    cin>>in;
    work(in);
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值