目录

一、基本概念

二、中缀表达式转后缀表达式

例       中缀表达式  2*(3+5)+7/1-4  转换为后缀表达式

三、后缀表达式的计算

例       后缀表达式  2 3 5 + * 7 1 / + 4 -  的计算

四、算法实现


一、基本概念

1、中缀表达式:

操作符以中缀形式位于运算数中间(如:3+2),是我们日常通用的算术和逻辑公式表示方法。

2、后缀表达式:

又称逆波兰式Reverse Polish Notation - RPN),操作符以后缀形式位于两个运算数后(如:3+2的后缀表达形式就是3 2 +)。

3、前缀表达式:

又称波兰式Polish Notation),操作符以前缀形式位于两个运算数前(如:3+2的前缀表达形式就是+ 3 2)。

中缀表达式往往需要使用括号将操作符和对应的操作数括起来,用于指示运算的次序

e.g:5*(2+1) 虽然 * 的优先级高于 +  ,但括号的存在表示应优先执行括号内的 + 运算。

中缀表达式适合于人类的思维结构和运算习惯,但并不适用于计算机

尤其是包含括号的中缀表达式,对计算机而言是非常复杂的结构。

适用于计算机的后缀表达式

与中缀表达式不同,后缀表达式不需要使用括号来标识操作符的优先级。

后缀表达式的计算按 操作符 从左到右出现的顺序依次执行(不考虑运算符之间的优先级),对于计算机而言是比较简单的结构。

二、中缀表达式转后缀表达式

从左至右依次遍历中缀表达式各个字符(需要准备一个字符栈存储操作符和括号)

1、字符为 运算数 :

直接送入后缀表达式(注:需要先分析出完整的运算数)。

2、字符为 左括号

直接入栈(注:左括号入栈后优先级降至最低)。

3、字符为 右括号

直接出栈,并将出栈字符依次送入后缀表达式,直到栈顶字符为左括号(左括号也要出栈,但不送入后缀表达式)。

总结:只要满足 栈顶为左括号 即可进行最后一次出栈。

4、字符为 操作符

若栈空,直接入栈。

若栈非空,判断栈顶操作符,若栈顶操作符优先级低于该操作符,该操作符入栈;否则一直出栈,并将出栈字符依次送入后缀表达式,直到栈空或栈顶操作符优先级低于该操作符,该操作符再入栈。

总结:只要满足 栈空 或者 优先级高于栈顶操作符 即可停止出栈,并将该操作符入栈。

5、重复以上步骤直至遍历完成中缀表达式,接着判断字符栈是否为空,非空则直接出栈,并将出栈字符依次送入后缀表达式。

注:中缀表达式遍历完成,栈中可能还有字符未输出,故需要判断栈空。

   例       中缀表达式  2*(3+5)+7/1-4  转换为后缀表达式

从左至右依次遍历中缀表达式各个字符:

第一个字符为运算数,直接输出:


第二个字符为操作符,满足 栈空/优先级高于栈顶操作符 条件,该操作符入栈:


第三个字符为左括号,直接入栈(入栈后优先级降至最低):


第四个字符为运算数,直接输出:


第五个字符为操作符,满足 栈空/优先级高于栈顶操作符 条件,该操作符入栈:


第六个字符为运算数,直接输出:


第七个字符为右括号,直接出栈并输出,直到栈顶为左括号时进行最后一次出栈(不输出):



第八个字符为操作符,不满足 栈空/优先级高于栈顶操作符 条件,出栈直至满足条件



第九个字符为运算数,直接输出:


第十个字符为操作符,满足 栈空/优先级高于栈顶操作符 条件,该操作符入栈:


第十一个字符为运算数,直接输出:


第十二个字符为操作符,不满足 栈空/优先级高于栈顶操作符 条件,出栈直至满足条件:




第十三个字符为运算数,直接输出:


中缀表达式遍历完成判断字符栈中是否还有操作符,如有则出栈并输出:


转换完成:

三、后缀表达式的计算

从左至右依次遍历后缀表达式各个字符(需要准备一个运算数栈存储运算数和操作结果)

1、字符为 运算数

直接入栈(注:需要先分析出完整的运算数并将其转换为对应的数据类型)

2、字符为 操作符

连续出栈两次,使用出栈的两个数据进行相应计算,并将计算结果入栈

e.g:第一个出栈的运算数为 a ,第二个出栈的运算数为 b ,此时的操作符为 - ,则计算 b-a  (注:a和b顺序不能反),并将结果入栈。

3、重复以上步骤直至遍历完成后缀表达式,最后栈中的数据就是中缀表达式的计算结果。

       后缀表达式  2 3 5 + * 7 1 / + 4 -  的计算

从左至右依次遍历后缀表达式各个字符:

第一个字符为运算数,直接入栈:


第二个字符为运算数,直接入栈:


第三个字符为运算数,直接入栈:


第四个字符为操作符,直接出栈两次:


继续出栈:


执行: 第二次出栈运算数    操作符    第一次出栈运算数 

即:3 + 5

结果:8

将计算结果入栈:


第五个字符为操作符,直接出栈两次:


执行: 第二次出栈运算数    操作符    第一次出栈运算数 

即:2 * 8

结果:16

将计算结果入栈:


第六个字符为运算数,直接入栈:


第七个字符为运算数,直接入栈:


第八个字符为操作符,直接出栈两次:


执行: 第二次出栈运算数    操作符    第一次出栈运算数 

即:7 / 1

结果:7

将计算结果入栈:


第九个字符为操作符,直接出栈两次:


执行: 第二次出栈运算数    操作符    第一次出栈运算数 

即:16 + 7

结果:23

将计算结果入栈:


第十个字符为运算数,直接入栈:


第十一个字符为操作符,直接出栈两次:


执行: 第二次出栈运算数    操作符    第一次出栈运算数 

即:23 - 4

结果:19

将计算结果入栈:


后缀表达式遍历完成,栈中数据即为最终计算结果:

四、算法实现

程序代码:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<ctype.h>#define ERROR 0
#define OK 1
#define STACK_INT_SIZE 10  /*存储空间初始分配量*/
#define STACKINCREMENT 5  /*存储空间分配增量*/
#define M 50typedef char ElemType; /*定义字符数据类型*/
typedef double ElemType2;  /*定义运算数数据类型*//*字符栈*/
typedef struct{ElemType *base;ElemType *top;int stacksize;
}SqStack;/*运算数栈*/
typedef struct{ElemType2 *base;ElemType2 *top;int stacksize;
}NStack;int InitStack(SqStack *S);   /*构造空栈*/
int push(SqStack *S,ElemType e); /*入栈*/
int Pop(SqStack *S,ElemType *e);  /*出栈*/
int StackEmpty(SqStack *s);  /*栈空判断*/
void in2post(ElemType *str,ElemType *p);  /*中缀表达式转后缀表达式*/
double cal_post(char *str);  /*计算后缀表达式*//*字符栈初始化*/
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;
}/*InitStack*//*运算数栈初始化*/
int InitStack_N(NStack *S){S->base=(ElemType2 *)malloc(STACK_INT_SIZE * sizeof(ElemType2));if(!S->base)return ERROR;S->top = S->base;S->stacksize = STACK_INT_SIZE;return OK;
}/*字符栈入栈*/
int Push(SqStack *S,ElemType e){//判断栈满if(S->top - S->base >= S->stacksize){S->base = (ElemType *)realloc(S->base,(S->stacksize + STACKINCREMENT)*sizeof(ElemType));if(NULL == S->base)  //分配失败return ERROR;S->top = S->base + S->stacksize;S->stacksize = S->stacksize+STACKINCREMENT;}*S->top = e;S->top++;return OK;
}/*运算数栈入栈*/
int Push_N(NStack *S,ElemType2 e){if(S->top - S->base >= S->stacksize){S->base = (ElemType2 *)realloc(S->base,(S->stacksize + STACKINCREMENT)*sizeof(ElemType2));if(NULL == S->base)return ERROR;S->top = S->base + S->stacksize;S->stacksize = S->stacksize+STACKINCREMENT;}*S->top = e;S->top++;return OK;
}/*字符栈出栈*/
int Pop(SqStack *S,ElemType *e){//判断栈空if(S->top == S->base)return ERROR;S->top--;*e=*S->top;return OK;
}/*Pop*//*运算数栈出栈*/
int Pop_N(NStack *S,ElemType2 *e){if(S->top == S->base)return ERROR;S->top--;*e=*S->top;return OK;
}/*判断栈空*/
int StackEmpty(SqStack *s){if(s->top == s->base)return OK;return ERROR;
}/*StackEmpty*///str为待转换的中缀表达式字符串,p为转换后的后缀表达式字符串
void in2post(ElemType *str,ElemType *p){   /*infix to postfix*/SqStack s;   InitStack(&s);   //初始化一个空字符栈ElemType e;int i;int j=0;for(i=0 ; i<strlen(str) ; i++)  //遍历中缀表达式{//遇到数字和小数点直接输出//使用循环完整接收一个运算数while(isdigit(str[i]) || '.'==str[i]){p[j++]=str[i++];if(!isdigit(str[i]) && '.'!=str[i])p[j++]=' ';   //一个数字完整输出后使用空格与其它运算符或数字分隔开}//遇到左括号直接入栈if('('==str[i])Push(&s,str[i]);//遇到右括号直接出栈,直到栈顶为左括号if(')'==str[i]){while('(' != *(s.top-1)){Pop(&s,&e);p[j++]=e;p[j++]=' ';}Pop(&s,&e);  //左括号出栈但不输出}//遇到+或—//1.栈空/栈顶为左括号:直接入栈//2.否则一直出栈,直到栈空/栈顶为左括号,再入栈if('+'==str[i] || '-'==str[i]){while(!StackEmpty(&s) && '('!=*(s.top-1)){Pop(&s,&e);p[j++]=e;p[j++]=' ';}Push(&s,str[i]);}//遇到*或///1.栈空/栈顶为左括号/栈顶操作符为+ or -:直接入栈//2.否则一直出栈,直到满足1,再入栈if('*'==str[i] || '/'==str[i] || '%'==str[i]){while(!StackEmpty(&s) && '('!=*(s.top-1) && '+'!=*(s.top-1) && '-'!=*(s.top-1)){Pop(&s,&e);p[j++]=e;p[j++]=' ';}Push(&s,str[i]);}}//中缀表达式遍历完成,还需检查栈中是否有未输出字符//判断栈空,非空则直接出栈并输出(左括号不用输出)while(!StackEmpty(&s)){Pop(&s,&e);if('('!=e)p[j++]=e;p[j++]=' ';}p[--j]='\0';
}/*infix2postfix*///str为待计算的后缀表达式,返回值为计算结果
double cal_post(char *str){   /*计算后缀表达式*/int i;ElemType2 e,a,b;char d[M];NStack n;InitStack_N(&n);   //初始化一个运算数栈保存运算数for(i=0;i<strlen(str);i++){int j=0;while(isdigit(str[i]) || '.'==str[i]){d[j++]=str[i++];d[j]='\0';if(!isdigit(str[i]) && '.'!=str[i]){e=atof(d);   //使用atof()将字符串形式的运算数转换为double型数据Push_N(&n,e);   //运算数入栈}}switch(str[i]){case '+':Pop_N(&n,&b);Pop_N(&n,&a);Push_N(&n,a+b);break;case '-':Pop_N(&n,&b);Pop_N(&n,&a);Push_N(&n,a-b);break;case '*':Pop_N(&n,&b);Pop_N(&n,&a);Push_N(&n,a*b);break;case '/':Pop_N(&n,&b);Pop_N(&n,&a);Push_N(&n,a/b);break;}}Pop_N(&n,&e);return e;
}/*calculate_postfix*/int main()
{char str[M];char post[M];int i;printf("\n输入一串中缀表达式:\n");gets(str);printf("\n对应的后缀表达式:\n");in2post(str,post);printf("%s",post);printf("\n\n计算后缀表达式:\n");printf("%f",cal_post(post));return 0;
}

运行结果:

《数据结构》:中缀表达式转后缀表达式 后缀表达式的计算相关推荐

  1. 数据结构中缀表达式转后缀表达式与后缀表达式的求值实训报告_动图+源码,演示 Java 中常用数据结构执行过程及原理...

    程序员的成长之路互联网/程序员/成长/职场 关注 阅读本文大概需要 3.7 分钟. 作者:大道方圆cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, ...

  2. 中缀表达式转换为前缀及后缀表达式并求值【摘】

    它们都是对表达式的记法,因此也被称为前缀记法.中缀记法和后缀记法.它们之间的区别在于运算符相对与操作数的位置不同:前缀表达式的运算符位于与其相关的操作数之前:中缀和后缀同理. 举例: (3 + 4) ...

  3. 使用栈解决的一类经典问题:表达式转换及求值;中缀表达式;前缀表达式,后缀表达式,中缀转前缀;中缀转后缀;后缀表达式求值;波兰式,逆波兰式

    文章目录 背景知识 表达式转换问题(考研经典) 一:手工转换 (1)中缀转前缀和中缀转后缀 (2)前缀转中缀和后缀转中缀 二:用栈实现表达式转换 (1)中缀转后缀 (2)中缀转前缀 表达式计算问题(使 ...

  4. 中缀、后缀、前缀表达式

    一.简介 对于1+((2*3)-4)/2 的数学表达式怎么求值? 分析: 数学表达式求值有优先级,不能简单的从左往右依次计算, 需要从优先级高的开始计算 中缀表达式是一种通用的算术或逻辑公式表示方法, ...

  5. 由中缀表达式求后缀、前缀表达式cpp代码

    前缀中缀后缀定义 一个表达式树.前序遍历得到前缀,中序遍历得到中缀,后序遍历得到后缀.单纯的中缀表达式会引起计算歧义,所以为了计算一般要完全括号化:或者将中缀转换为前缀或者后缀.注意:前缀和后缀没有歧 ...

  6. 表达式求值(中缀转后缀及后缀表达式求值)

    .中缀表达式转后缀表达式: 中缀表达式转后缀表达式遵循以下原则: 1.遇到操作数,直接输出: 2.栈为空时,遇到运算符,入栈: 3.遇到左括号,将其入栈: 4.遇到右括号,执行出栈操作,并将出栈的元素 ...

  7. 【Java】LeetCode 150. 逆波兰表达式求值 (后缀表达式)

    题目: 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除法只保留整数部分. 给定逆波兰表达式总是有效的.换句话 ...

  8. PHP字符串运算结果,PHP 实现后缀表达式(接受四则运算字符串,输出计算结果,附代码)...

    最近接触了一个有趣的需求:给定变量a.b.c.d等若干,要求由用户输入的普通四则运算字符串(包含加减乘除括号),算出具体的值. 例如,a=1,b=2,c=3,d=4,给出 a+b/(d-c),应计算出 ...

  9. 前缀表达式后缀表达式_你知道波兰表达式和逆波兰表达式吗

    什么是波兰表达式 我们日常的运算表达式通常是如下形式,这种成为中缀表达式,也就是运算符在运算数的中间.这种表达式人类很容易识别,并根据其进行计算,但计算机识别这种表达式非常困难. a + b * (c ...

  10. 栈的应用(递归:例子裴波那契数列 四则运算表达式求值 :后缀(逆波兰) )

    递归: -栈有一个很重要的应用:在程序设计语言中实现递归. 当你往镜子前面一站,镜子里面就有-一个你的像. 但你试过两面镜子一起照吗?如果A.B两面镜子相互面对面放着,你往中间- -站,嘿,两面镜子里 ...

最新文章

  1. Gevent异步服务类实现多姿势WEB实时展示
  2. Keras【Deep Learning With Python】—使用keras-神经网络来做线性回归问题
  3. Flash Builder非法关闭导致无法启动
  4. tdk怎么设置_你真的做好网站的标题、描述、关键词(TDK)设置了吗?
  5. Python爬虫学习——布隆过滤器
  6. Linux操作Oracle(3)——Oracle OPatch打补丁遇到问题详细汇总详细记录
  7. 【matlab】访问元胞数组
  8. 【浅墨著作】《逐梦旅程:Windows游戏编程之从零开始》勘误配套源代码下载...
  9. 毕业论文知网查重心得体会——吐血奉献
  10. nand flash与烧录器
  11. RGB 颜色格式转换
  12. 单位局域网连接的计算机太多,解决交换机端口不匹配导致局域网连接缓慢-ARP经验...
  13. 新浪微博产品的细微体验,你发现了么?
  14. 宝塔linux面板ping网址找不到主机,云服务器安装宝塔面板后无法ping通ip地址问题的解决方法...
  15. 表格查询(去除重复数据)
  16. c语言怎样画坐标轴,c语言 用小星星画各种图形(菜鸟学C语言)
  17. 淘宝app详情接口,淘宝详情页接口,商品信息查询,商品详细信息接口,h5详情,宝贝详情页接口,商品属性接口,
  18. 计量经济学及Stata应用 第四章习题
  19. UG软件的简述和使用场景经验介绍
  20. mysql创表的工种_mysql测试数据库employees一些sql语句

热门文章

  1. 九宫格图片怎么操作?这里有你想要的方法
  2. 直播新架构升级:全量支撑淘宝双11直播
  3. File类,字节字符输入输出流,缓冲流,标准流,对象序列化流
  4. 数字计算机模拟人脑,人造突触问世计算机模拟人脑不是梦
  5. 在Linux下完美运行Windows PC版QQ/TIM教程
  6. 【转载】SOP SO SOIC TSSOP SSOP 封装直观比较图
  7. GB/T 10707 橡胶燃烧性能
  8. MATLAB 如何生成彩色的eps文件
  9. 简单工厂模式(C语言实现)
  10. 校园网同时连手机和电脑、用数据线给电脑连网