后缀表达式(C语言版)

在前面我们已经学会了给定一个计算式(这是如何把计算式转化为后缀式的思路)自己写出它的后缀表达式,接下来我们得尝试让C语言写出其转换方法
大概思路:

  • 首先我们只进行只有加减的转换,下面且看例子

首先我们得明确,转换成的后缀式的数字和符号出现的顺序都没有改变,那么如果当计算式只含加减的符号时是不是可以这样想:把左边的计算式存入数组里,然后用指针对其一一识别,出现数字直接对其输出,而遇到运算符得等一会,等到遇到下一个运算符时直接输出,最后再把最后一个运算符进行输出

这时就有人会问了:为啥要等到下一个运算符呢

因为这里是求后缀表达式,对于一个单独的5+7而言,+要得在5和7的后面,而在面对5+7-8时,这个减号的位置就是转化为后缀式的加号的位置,因此下面的一个减号是定位前面的一个加号的,故等遇到-时加号再进行输出(最后一个符号直接再等都输出完了再输出即可)

  • 现在我们加大一点点难度,进行加减乘除的运算

这个我们可能又开始不会了但如果改成:5-A+6-9不知大家还会不会呢

当然,在这里我们得明确其后缀式结果的特征,很明显这里此时*在-的前面,而除却*以外的加减符号则按照顺序排列,而*的排列规矩又是什么样的呢,我们得继续探究

如果按照上一道题的逻辑,前面的5+6输出很正常(+遇到了56后面的-然后直接输出,然后得把-存入栈中),但是-遇到的下一个符号是*,而结果是-在*的后面,仔细一想后缀表达式的*输出的位置同计算式8*7后面的+的位置,因为(5+6)(8*7)-这里可以把括号里面的看作一个元素,那么我们只要在*遇到栈中的-时不进行输出,而把*存起来,当后面的+遇到*时再把*输出,此时再把前面一个-进行输出,而这种做出这种思路的方法,就是算数优先级

+-*/()
120

先忽略()为什么是0

以上面的5+6-8*7+9为例,我们先把+存入栈中,当下面一个优先级相等的-遇到+时,直接输出+,再把-存入栈中,下一个优先级大的*遇到减号时,存入栈中,当再下一个-遇到*时优先级比*小,*输出,然后接着和上面一个-比,优先级相等,上面一个-输出,然后最后的-进行输出(生动一点的就是 *优先级比-大因此得比-先计算,即先输出,而输出的位置又是下一个+的位置)

  • 接下来就是()

首先我们得清楚为啥()的优先级要比+-/*都小,我们要清楚,符号的出栈规则为上面一个符号的优先级大于等于遇到的这一个时(谁大谁先输出,也就是后入栈),才输出,而()不能进行输出,故优先级为0

接下来是几个例子

(5+8)-758+7-
7-(5+8)758+-
4-(5-7*8)+94578*--9+

这里可能还是一脸懵逼,但是如果我把结果也加个括号就变成了

这里就有人会说了:这个结果不能带括号,我这里呢是想告诉各位:括号里面的运算逻辑其实呢和原本的运算逻辑是一样的(咳咳,我有那意思,就是不咋会表达,如果各位没理解的话还是直接看下面的事例分析吧)

以4-(5-7*8)+9为例

4输出,-输入,当判断是(时不能和前面的-进行比较,必须得是()外面的+9中的+与()前面的-进行比较(括号里的你就把它当成一个元素),那么当是(时直接入栈,接着是5输出,-优先级比(大,入栈,7输出,*优先级比-大,入栈,8输出,然后是),遇到是)时又不断出栈,即把*和-进行输出,然后再把(进行出栈

这里可能还是有人不太了解,我再举个简单的例子

7-(5+8)这里的7输出,-入栈,(入栈,+入栈,)时回退到前面找(,然后+出栈,(直接出栈但不输出

7-(5+8-6)这里的5+8-6时的-遇到前面入栈的+时+出栈

下面是入栈的一些函数

 #define ERROR 0
 #define OK 1
 #define STACK_INT_SIZE 10
 #define STACKINCREMENT 5
 typedef  char ElemType;
 typedef struct
 {
     ElemType* base;
     ElemType* top;
     int stacksize;
 } SqStack;
 ​
 int initStack(SqStack* s);
 int emptyStack(SqStack* s);
 int pushStack(SqStack* s, ElemType e);
 int popStack(SqStack* s, ElemType* e);
 int getTop(SqStack* s, ElemType* e);
 ​
 int initStack(SqStack* s) //栈的创建
 {
     s->base = (ElemType*)malloc(STACK_INT_SIZE * sizeof(ElemType));
     if (!s->base)
         return ERROR;
     s->top = s->base;
     s->stacksize = STACK_INT_SIZE;
     return OK;
 }
 ​
 int emptyStack(SqStack* s) //判断是否为栈空
 {
     return s->base == s->top;
 }
 ​
 int pushStack(SqStack* s, ElemType e) //入栈
 {
     if (s->top - s->base >= s->stacksize)
     {
         s->base = (ElemType*)realloc(s->base, (s->stacksize + STACKINCREMENT) * sizeof(ElemType));
         if (!s->base)
             return ERROR;
         s->top = s->base + s->stacksize;
         s->stacksize += STACKINCREMENT;
     }
     *s->top++ = e;
     return OK;
 }
 ​
 int popStack(SqStack* s, ElemType* e) //出栈
 {
     if (emptyStack(s))
         return ERROR;
     s->top--;
     *e = *s->top;
     return OK;
 }
 ​
 int getTop(SqStack* s, ElemType* e) //取栈顶元素
 {
     if (emptyStack(s))
         return ERROR;
     *e = *(s->top-1);
     return OK;
 }

这里关于栈的相关知识以后有时间再一一总结,故在此跳过,为了便于大家理解,下面直接先介绍主函数

 int main()
 {
     char result[80] = { '\0' }, exp[80] = { '\0' };
     //补充代码实现读入多个表达式,并输出每个表达式的后缀式
     while (1)
     {
         scanf("%s", exp);
         if (exp[0] == '#')
         {
             break;
         }
         convert(exp, result);
         printf("%s\n", result);
     }
     return 0;
 }

  • 以单独输出#结束,故有esp[0]=='#'

  • 输入的数存入exp里面,输出的数存入result里面,而convert则是对exp的数进行处理

    这一个是对算数优先级处理的函数

 
int f(char c)
 {
         switch (c) 
         {
         case '+':
         case '-':
             return 1;
         case '*':
         case '/':
             return 2;
         default:
             return 0;
         }
     }

这个则是用于后缀表达式的函数

void convert(char* exp, char* result) {
     SqStack s;
     initStack(&s);
     char* p = exp;//p指向exp
     char* r = result;//r指向result
     while (*p != '#')
     {
         if (isdigit(*p))//判断*p是否为数字
         {
             while (isdigit(*p))
                 *r++ = *p++;
             *r++ = ' ';//保证这个数后面有空格
         }
         else if (*p == '(')//当*p为(时直接存入栈中
             pushStack(&s, *p++);
         else if (*p == ')')
         {
             ElemType e;
             while (getTop(&s, &e) && e != '(')
             {
                 popStack(&s, &e);//这里是对()中残余的符号进行输出
                 *r++ = e;
                 *r++ = ' ';
             }
             popStack(&s, &e); //这里是把(进行出栈
             p++; //p指向下一个位置
         }
         else if (f(*p) > f(*(s.top - 1)))//优先级大于栈顶的入栈
            pushStack(&s, *p++);
         else
         {
             while (!emptyStack(&s) && f(*p) <= f(*(s.top - 1)))
             {
                 popStack(&s, r++);
                 *r++ = ' ';
             }//优先级小于栈顶的一直出栈
             pushStack(&s, *p++);
         }
         }
     while (!emptyStack(&s))//把残余的出栈
     {
         popStack(&s, r++);
         *r++ = ' ';
     }
     *r = '\0';
     }

  • 28
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值