逆波兰表达式
来源:互联网 发布:mysql alias 编辑:程序博客网 时间:2024/05/22 01:43
问题来由:
读入一个字符串形式的四则运算表达式,输出对应的计算结果。如读入的是“6 * ( 5 + ( 2 + 3) * 8 + 3)”,那么解析后的输出结果应为288。
思路:
- 一般的计算过程是这样的,首先计算优先级最高的小括号里面的内容,即“( 5 + ( 2 + 3) * 8 + 3)”,
- 将“2 + 3”的计算结果并存为A,接着用计算“A*8”,并存为B
- 计算“5+B+3”,结果存为C
- 最后计算“6*C”,计算完毕
我们可以将这种操作顺序书写如下:
6 5 2 3 + 8 * + 3 + *
这个记法就是逆波兰(reverse Polish)表达式,其求值过程恰好就是上面所描述的过程。逆波兰表达式又叫做后缀(postfix)表达式。在通常的表达式中,运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家 J.Lukasiewicz于1929年提出了另一种表示表达式的方法。按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。
后缀表达式的计算
计算后缀表达式最简单的方法就是使用一个栈:
- 当读到一个数字时就将它压入栈中
- 读到一个运算符时,就从栈中弹出两个数字,并将该运算符作用于这两个数字,然后将计算结果再压入栈中
下面演示下“6 5 2 3 + 8 * + 3 + *”的处理过程
- 首先读到 6 5 2 3 四个数字,没啥说的,直接打入栈中(6 5 2 3)
- 读到运算符“+”,从栈中弹出两个数字“3”、“2”,计算 3+2 = 5,将计算结果压入栈中;(6 5 5)
- 读到8,压入栈(6 5 5 8)
- 读到“*”,从栈中弹出两个数字“8”、“5”,计算 8 * 5 = 40,将计算结果压入栈中;(6 5 40)
- 读到“+”,从栈中弹出两个数字“40”、“5”,计算 40 + 5 = 45,将计算结果压入栈中;(6 45)
- 读到3,压入栈(6 45 3)
- 读到“+”,从栈中弹出两个数字“3”、“45”,计算 3 + 45 = 48,将计算结果压入栈中;(6 48)
- 读到“*”,从栈中弹出两个数字“48”、“6”,计算 48 * 6 = 288,计算完毕!!!
计算一个后缀表达式话费的时间是O(N),该算法的计算非常简单,同时不需要知道任何的计算优先级。
那么现在的问题就是如何将一个正常的表达式转换为后缀表达式???
其实真正的难点在于如何将一个正常的字符串表达式(中缀表达式)变成一个后缀表达式。如将6 * ( 5 + ( 2 + 3) * 8 + 3)变为6 5 2 3 + 8 * + 3 + *
逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
逛博客的时候发现了这个有意思的东西,很久之前碰到过这个问题,有认真的想过,也只是想过,也没有具体做过,今天碰到神人,把这个具体的写出来, 遂转来之,仅供参考学习之用,原文地址在此首先约定表达式中运算符的优先级,从大到小依次为:()、* 和 /、+ 和 -。暂时只考虑四则运算。
顺序读取字符串表达式,规则:
- 读到的是操作数,直接输出;
- 读到的是操作符(+-*/)(记为read),将其与栈顶的操作符(记为top)进行优先级比较:read>top,read入栈,继续读下一个;read≤top,top出栈,并输出到list中,read继续和新的top比较;top为空,read直接入栈;若top是“(”,read直接入栈,因为“(”优先级最高;
- 括号的处理:读到左括号“(”,直接将其压入栈中,并且除非遇到右括号“)”,“(”是不会弹出的;读到右括号“)”,将“(”之上的元素全部依次输出,并弹出“(”但不输出;
准备:一个栈stack暂存运算符,一个list存放输出,仍以6 * ( 5 + ( 2 + 3) * 8 + 3)为例。
- 读到“6”,直接输出【list:6;stack:】
- 读到“*”,与栈顶top比较,top为空,“*”入栈【list:6;stack:*】
- 读到“(”,直接入栈【list:6;stack:*,(】
- 读到“5”,直接输出【list:6,5;stack:*,(】
- 读到“+”,与栈顶top比较,“+”<“(”,入栈【list:6,5;stack:*,(,+】
- 读到“(”,直接入栈【list:6,5;stack:*,(,+,(】
- 读到“2”,直接输出【list:6,5,2,;stack:*,(,+,(】
- 读到“+”,与栈顶“(”比较,“+”<“(”,入栈【list:6,5,2,;stack:*,(,+,(,+】
- 读到“3”,直接输出【list:6,5,2,3,;stack:*,(,+,(,+】
- 读到“)”,输出“(”之上的元素【list:6,5,2,3,+;stack:*,(,+,】
- 读到“*”,与栈顶的“+”比较, “*”>“+”,“*”入栈【list:6,5,2,3,+;stack:*,(,+,*,】
- 读到“8”,直接输出【list:6,5,2,3,+,8,;stack:*,(,+,*,】
- 读到“+”,与栈顶的“*”比较,“+”<“*”,“*”出栈并输出【list:6,5,2,3,+,8,*;stack:*,(,+,】;
- “+”,与栈顶的“+”比较,“+”=“+”,“+”出栈并输出【list:6,5,2,3,+,8,*,+;stack:*,(,】;
- “+”,与栈顶的“(”比较,“+”<“(”,“+”入栈【list:6,5,2,3,+,8,*,+;stack:*,(,+】;
- 读到“3”,直接输出,【list:6,5,2,3,+,8,*,+,3;stack:*,(,+】
- 读到“)”,输出“(”之上的元素,【list:6,5,2,3,+,8,*,+,3,+;stack:*,】
- 输出栈中所有剩下的,【list:6,5,2,3,+,8,*,+,3,+,*;stack:,】
- 最终的后缀表达式就是:6 5 2 3 + 8 * + 3 + *
至此,中缀表达式到后缀表达式的任务已经全部完成!
但是需要注意的是,本文中只是做了当运算数据为个位数的处理,当为多位数时该怎么做呢?
另外当遇到“/”处时,要对被除数进行非0判断;
另外还可以考虑含有负数的运算,含有小数的以及幂运算
那都是数据如何处理的问题了,整体思路应该都差不多!
- 波兰、逆波兰表达式
- 波兰表达式和逆波兰表达式
- 波兰表达式和逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式rpn
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式实验
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- 逆波兰表达式
- LaTeX----表格处理
- CSS竖排
- Broadleaf电商系统开发(二) - 启动项目
- js选项卡切换实战
- LTE:PHICH物理层处理过程及资源映射
- 逆波兰表达式
- 两颗骰子
- 火车票务管理系统数据库分析
- cocos2dx3.2升级Android5的坑
- js下拉菜单(鼠标+键盘双操作)
- NodeJs应用场景【学习路线图】
- UVa 10024 - Curling up the cube
- 二叉树的迭代前中后遍历以及不用栈的遍历C语言
- win7安装 “安装程序无法创建新的系统分区”问题