首先明白:

前缀表达式:符号在前,如-×+3456

中缀表达式:符号在中间,如(3 + 4) × 5 - 6

后缀表达式:符号在最后,如34+5×6-,后缀表达式不出现括号。

中缀表达式转后缀表达式的方法:

1.遇到数字:直接输出(添加到后缀表达式中)
2.栈为空时,遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,将栈的元素全部输出,直到弹出栈的是左括
号为止,且左括号不输出直接删除
5.遇到其他运算符:加减乘除:若当前运算符小于等于栈中运算符优先级,依次出栈,然后再将该运算符入栈
6.最终将栈中的符号依次出栈,输出。

运算符优先级(常用的记忆一下,和常识吻合)
1 [] () (同级)
3 */
4 +-

代码

//定义一个运算符栈op
struct{char data[MAXSIZE]; //存放运算符int top;  //栈顶指针
}op;
void trans(char exp[],char postexp[]){char ch;int i,j;    //i是中缀exp的下标,j是后缀postexp的下标op.top=-1;ch=exp[i];  //获取输入的第一个字符 i++;while(ch!='\0'){switch(ch){case '(':    //遇到左括号直接入栈 op.top++;op.data[op.top]=ch;break;case ')':    //遇到右括号,栈顶元素不断出栈直到遇到左括号 while(op.data[op.top]!='('){postexp[j]=op.data[op.top];j++;op.top--;}op.top--;  //遇到了左括号,直接删除 break; case '+':   //因为加减运算符优先级最低,不大于任何其他运算符,所以直接入栈 case '-':while(op.top!=-1&&op.data[op.top]!='('){ //栈不为空且没有遇到左括号,都直接出栈 postexp[j]=op.data[op.top];j++;op.top--;}op.top++;         //即:栈为空或遇到了左括号,当前运算符进栈 op.data[op.top]=ch;break;case '*':case '/':while(op.top!=-1&&op.data[op.top]!='('&&(op.data[op.top]=='*'||op.data[op.top]=='/')){postexp[j]=op.data[op.top];  //栈不为空且没有遇到左括号且遇到了同级符号:都出栈 j++;op.top--;}op.top++;   //不满足上述时,入栈 op.data[op.top]=ch;break;case ' ':break;   //过滤空格//default一般用在最后,表示非以上的任何情况下而发生的情况,default:while(ch>='0'&&ch<='9'){ //输入的是数字 postexp[j]=ch;   //直接入栈 j++;ch=exp[i];  //遍历下一个数字 i++;} i--;postexp[j]='#';  //用#标识一个数值串结束 j++;break;       }ch=exp[i];i++;}while(op.top!=-1){   //此时exp扫描完毕,栈不空时出栈并存放到postexp中 postexp[j]=op.data[op.top];j++;op.top--;}postexp[j]='\0';   //添加结束标识,后缀表达式输入完毕
}

转换的另一种方法:手工加括号

例如:5+2*(1+6)-(8/2)

1)  先按照运算符的优先级对中缀表达式加括号,

先计算2*(1+6),加上括号,得到5+(2*(1+6))-8/2

再计算除法,得到5+(2*(1+6))-(8/2)

再计算加法,得到(5+(2*(1+6)))-(8/2)

最后进行减法,得到((5+(2*(1+6)))-(8/2))

2)  将每一个右括号替换成其离得最近的符号

得到 ( ( 5 ( 2 ( 1 6 + * + (8 2 / -

3)  去除所有的左括号 ,得到 5 2 1 6 + * + 8 2 / -

该方法不能用程序实现

前缀表达式求值

  1. 从右至左扫描表达式
  2. 遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算,并将结果入栈
  3. 重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果

示例:
计算前缀表达式的值:- + 1 × + 2 3 4 5

  1. 从右至左扫描,将5,4,3,2压入堆栈;
    2)遇到+运算符,弹出2和3(2为栈顶元素,3为次顶元素),计算2+3的值,得到5,将5压入栈;
    3)遇到×运算符,弹出5和4,计算5×4的值,得到20,将20压入栈;
    4)遇到1,将1压入栈;
    5)遇到+运算符,弹出1和20,计算1+20的值,得到21,将21压入栈;
    6)遇到-运算符,弹出21和5,计算21-5的值,得到16为最终结果

可以看到,用计算机计算前缀表达式是非常容易的,不像计算后缀表达式需要使用正则匹配

后缀表达式求值

与前缀表达式类似,只是顺序是从左至右:

  1. 从左至右扫描表达式
  2. 遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算,并将结果入栈
  3. 重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果

示例:
计算后缀表达式的值:1 2 3 + 4 × + 5 -

1)从左至右扫描,将1,2,3压入栈;
2)遇到+运算符,3和2弹出,计算2+3的值,得到5,将5压入栈;
3)遇到4,将4压入栈
4)遇到×运算符,弹出4和5,计算5×4的值,得到20,将20压入栈;
5)遇到+运算符,弹出20和1,计算1+20的值,得到21,将21压入栈;
6)遇到5,将5压入栈;
7)遇到-运算符,弹出5和21,计算21-5的值,得到16为最终结果

代码

struct{float data[MAXSIZE];int top;   //栈顶指针
};
float compvalue(char postexp[]){float d;char ch;int i=0;   //i作为postexp下标 st.top=-1;ch=postexp[i];i++;while(ch!='\0'){switch(ch){case '+':st.data[st.top-1]=st.data[st.top-1]+st.data[st.top];st.top--;break;case '-':st.data[st.top-1]=st.data[st.top-1]-st.data[st.top];st.top--;break;case '*':st.data[st.top-1]=st.data[st.top-1]*st.data[st.top];st.top--;break;case '/':if(st.data[st.top]!=0){st.data[st.top-1]=st.data[st.top-1]/st.data[st.top];}else{printf("除零错误!\n");exit(0);  //异常退出 }st.top--;break;default:d=0;while(ch>='0'&&ch<='9'){d=d*10+ch-'0';   //将数字字符转换成对应的数字存入d ch=postexp[i];i++;}st.top++;st.data[st.top]=d;}ch=postexp[i];i++;}return st.data[st.top];
}

测试

#define MAXSIZE 100
#include <stdio.h>
int main()
{int i = 0;char exp[] = {"(2*2)*1+3*2/1"};char postexp[MAXSIZE];trans(exp,postexp);while (postexp[i] != '\0'){printf("%c",postexp[i]);i++;}printf("\n");printf("运算结果为:%f.\n", compvalue(postexp));return 0;
}

中缀表达式求值

口诀:

操作数直入左栈
运算符入栈有规则
若遇栈空直接入栈
若栈不空看优先级
栈顶元素优先级只有大于扫描元素的优先级才出栈
否则遇到都入栈
左括号入栈直到遇到右括号吐出来

中缀表达式求值过程:

例:求5+7*3*(2+1)

(1)准备两个空栈,数字入左栈,符号入右栈

(2)5进左栈,+进右栈

(3)7进左栈,*的优先级大于+,直接进右栈

(4)3进左栈

(5)*的优先级等于*,第一个*出栈,并且左栈要弹出两个元素进行运算,即3*7=21,并将新的运算结果压入左栈

(6)第二个*进右栈,左括号(直接进栈

(7)2进左栈

(8)+直接进右栈

(9)1进左栈

(10)遇到右括号,之前的元素全部弹出进行运算直到遇见左括号

(11)1+2=3,将3压入左栈,(左括号删除

(12)21*3=63,将63压入左栈

(13)63+5=68,最后的左栈元素为68

总结

  • 前缀表达式和后缀表达式计算的时候都是从一个方向扫描表达式,遇到数字压入栈,遇到运算符弹出栈顶的两个数进行运算并将结果入栈,重复知道结束
  • 前缀和后缀表达式已经内在地包含运算顺序,因此不用括号来确定优先级

【数据结构】详解栈的应用之表达式求值相关推荐

  1. 栈的应用-算数表达式求值

    List item ** 实验要求** 河 南 师 范 大 学 20学年-21学年第 1 学期 数据结构实验任务书 专业名称: 实验学时: 4 课程名称:数据结构 任课教师: 王亚丽 实验题目:栈的应 ...

  2. 栈应用:后缀表达式求值

    在上一篇博客 栈应用:中缀表达式转后缀表达式 中我们知道如何通过栈将中缀表达式转为后缀表达式,这次我们继续用栈 来实现后缀表达式求值,结合上一篇博客. 上一篇博客中是用c语言实现的,由于c语言中不支持 ...

  3. python数据结构和算法 时间复杂度分析 乱序单词检测 线性数据结构 栈stack 字符匹配 表达式求值 queue队列 链表 递归 动态规划 排序和搜索 树 图

    python数据结构和算法 参考 本文github 计算机科学是解决问题的研究.计算机科学使用抽象作为表示过程和数据的工具.抽象的数据类型允许程序员通过隐藏数据的细节来管理问题领域的复杂性.Pytho ...

  4. 数据结构之栈的应用:表达式求值

    表达式求值 思维导图: 求值算法: 中缀转后缀求值:(后缀求值) 中缀转前缀求值:(前缀求值) 转化算法:(中缀转后缀) 中缀表达式的计算(中缀转后缀+后缀求值): 总结: 思维导图: 求值算法: * ...

  5. C/C++ 栈的应用:表达式求值

    表达式求值(中缀->后缀) 思路 算符间的优先关系 关键代码 思路 1.初始化两个栈,OPTR保存运算符,OPND保存操作数 2.从左->右边获元素. 3.遇操作数,进栈OPND. 3.遇 ...

  6. C语言栈的应用——后缀表达式求值

    算法思路 ​ 上次已经完成了由中缀表达式转后缀表达式的算法,而后缀表达式的优点就是可以从左至右直接读取,没有算数优先级的考量,所以直接进行运算即可. ​ 该算法需要使用一个栈用来保存操作数,在读取到数 ...

  7. 栈的应用之表达式求值

    表达式求值 表达式求值是栈的一个重要的应用.例如计算器中的加减乘除表达式的计算,都会使用栈来进行求值. 表达式的表示方法主要有中缀表示法和后缀表示法. (老师的代码,现在的我能力有限,没法过多研究c+ ...

  8. 栈应用:中缀表达式求值

    后缀表达式求值比较简单,基本过程为:遇到数字则进栈,遇到运算符则出栈俩数字然后计算结果,再把结果入栈,过程比较简单,不再复习了,下面着重记录中缀表达式求值 中缀表达式求值可以先将中缀转后缀,再用后缀计 ...

  9. 数据结构实验之栈三:后缀式求值

    题目描述 对于一个基于二元运算符的后缀表示式(基本操作数都是一位正整数),求其代表的算术表达式的值. 输入 输入一个算术表达式的后缀式字符串,以'#'作为结束标志. 输出 求该后缀式所对应的算术表达式 ...

最新文章

  1. 十一后我的新房就要准备准修了
  2. 突发!又一个程序员在东南亚出事了...
  3. AdaBoostClassifier实战
  4. Halcon初学者知识【17】如何将零件提取dxf图
  5. 深入理解gradle中的task
  6. pygame 文字输入交互_pygame能接收用户的文本输入吗?
  7. linux下进程监控6,Linux进程监控技术—精通软件性能测试与LoadRunner最佳实战(6)...
  8. Pandas Window对象
  9. Maven学习总结(35)——Maven项目错误 JAX-RS (REST Web Services) 2.0 can not be installed问题...
  10. FireFox 插件SQLite Manager 学习
  11. python redis模块常用_python redis 模块
  12. (MATLAB)把视频读得明明白白
  13. 储存卡数据怎么恢复?恢复靠它
  14. 数据库死锁的预防与解除
  15. 火柴棍能组成的最大数字
  16. stm32cube 和 RTX v5一起用的方法
  17. python写文件字母_Python - 文件读写
  18. three.js光效扫描
  19. 绝缘子红外图像检测项目(TF2)
  20. MySql函数DATE_FORMAT( )基本用法

热门文章

  1. unity网络实战开发(丛林战争)-正式开发阶段(013-游戏服务器端框架搭建)
  2. HP小型机 nPartiton 分区管理
  3. Stochastically Stable Negativity for Analytically Linear Subalgebras——ShaneZhang
  4. Makefile:132: recipe for target ‘base/.depend.mk‘ failed
  5. linux内存管理笔记(八)---内核临时页表的创建
  6. 让li 横排显示的CSS代码
  7. android gps 差分定位,基于Android的高精度GPS定位与土地测量应用设计
  8. 聊聊汽车ECU中单片机开发
  9. 台北淡水 渔人码头之行
  10. 警惕 NFT 中可能存在的骗局