文章目录
一、定义
1. 前缀表达式(波兰)
所有的符号都是在要运算的操作数字的前面出现。例如 /++ab*cde
2.中缀表达式
所有的符号都是在要运算的操作数字的中间出现。例如(a+b+c*d)/e
3.后缀表达式(逆波兰)
所有的符号都是在要运算的操作数字的后面出现。例如 abcd*++e/
二、相互转换
1.转换注意
- 前缀和后缀都有唯一的运算次序,中缀式的运算次序不唯一。后缀式和前缀式都是由中缀式按照某一种运算次序而生成的。
- 因此一个中缀式可能对应有多种后缀式或者前缀式,但后缀式和前缀式只有一个中缀式与之对应。
- 例如a+b+c 可以先算a+b 也可以先算b+c 这样的话就有两种后缀式与其对应,分别是ab+c+ 和abc++
- 一般用后缀多一些,后缀对应从左到右,前缀对应从右到左。不管是转到中缀,还是中缀转,都是这个顺序。
2.转换方法
- 中缀 可以转换为 前缀 |后缀(因为计算机识别中缀很困难,所以一般这样转),
- 转换方法为:加括号法(适合手写),栈法,二叉树法
3.具体步骤
-
中缀 -->前缀(加括号法)
-
确定表达式计算顺序,手动加括号 。原始(a+b+c*d)/e → (((a+b)+(c*d))/e) 【这里就体现了中缀转前缀不唯一的性质】
-
从里往外开始运算,符号在前,操作数字在后,不要写括号。
-
(a+b) → +ab
-
(c*d) → *cd
-
((a+b)+(c*d))→ ++ab*cd
-
(((a+b)+(c*d))/e) → /++ab*cde 即为前缀表达式。
-
-
- 中缀 -->后缀(加括号法)
- 确定表达式计算顺序,手动加括号 。原始(a+b+c*d)/e → (((a+b)+(c*d))/e) 【这里就体现了中缀转后缀不唯一的性质】
-
从里往外开始运算,符号在后,操作数字在前,不要写括号。【这里和中缀转前缀相反】,不再赘述。
- 中缀 -->前缀(栈法)
- 初始化一个空栈(实际写的时候还需要再创建一个栈来存储计算过程中产生的中间结果,此处用一个便于理解思想)
- 从右到左扫描中缀表达式。
- 如果扫描到操作数,则输出。
- 如果扫描到运算符:
- 如果是右括号‘)’,直接入栈
- 如果是左括号‘(’,则一次弹出栈顶运算符,直至遇到右括号‘)’为止,并且将括号舍弃。
- 如果不是左右括号:
- 如果此时栈中为空,直接将运算符入栈。
- 如果此时栈中为‘)’右括号 ,将其入栈。
- 如果当前扫描的运算符优先级高于或等于!!栈顶运算符,则入栈。
- 如果栈顶运算符优先级高于当前扫描的运算符,则将栈顶运算符输出,同时扫描到的运算符继续与栈中运算符比较。
- 之后将扫描到的运算符入栈!
- 重复步骤,直至扫描完成。输出栈中剩余的运算符。
-
输出的内容就是转换后的前缀表达式。但是实际计算的时候一般会创建一个空栈temp来存储中间结果,每次输出就是压入到temp中,最后转换成的后缀表达式就是temp中的元素输出。
- 中缀 -->后缀(栈法)
- 初始化一个空栈(实际写的时候还需要再创建一个栈来存储计算过程中产生的中间结果,此处用一个便于理解思想)
- 从左到右扫描中缀表达式。
- 如果扫描到操作数,则输出。
- 如果扫描到运算符:
- 如果是左括号‘(’,直接入栈
- 如果是右括号‘)’,则一次弹出栈顶运算符,直至遇到左括号‘(’为止,并且将括号舍弃。
- 如果不是左右括号:
- 如果此时栈中为空,直接将运算符入栈。
- 如果此时栈中为‘( ’左括号 ,将其入栈。
- 如果当前扫描的运算符优先级高于栈顶运算符,则入栈。(没有等于)
- 如果栈顶运算符优先级高于当前扫描的运算符,则将栈顶运算符输出,同时扫描到的运算符继续与栈中运算符比较。(如果优先级相等,也将栈中运算符输出。)
- 之后将扫描到的运算符入栈!
- 重复步骤,直至扫描完成。输出栈中剩余的运算符。
-
输出的内容就是转换后的后缀表达式。但是实际计算的时候一般会创建一个空栈temp来存储中间结果,每次输出就是压入到temp中,最后转换成的后缀表达式就是temp中的元素输出再逆序。
- 中缀 -->前缀(二叉树法)
- 中缀表达式先转换成二叉树
- 计算数作为叶子节点
- 运算符作为中间节点
- 依照算数优先级(不唯一)
- 可以多加括号便于学习理解
- 对二叉树进行前序遍历得到前缀表达式(也叫先根遍历、先序遍历)
- 根→左→右
- 先访问根节点,再遍历左子树,最后遍历右子树。
- 示例(a+b+c*d)/e
- 按照算数优先级切分表达式→ (a+b+c*d), / , e 其中左叶子为(a+b+c*d) 中间节点为运算符/ ,右叶子为e.
- 继续分割左叶子 (a+b+c*d)分为(a+b) + (c*d) 【体现出不唯一】,其中左叶子为(a+b) 中间节点为运算符+ ,右叶子为(c*d).
- 继续差分至所有不可再拆,转换完成。
- 得到中缀表达式二叉树。
(懒得画了) - 进行前序遍历,也就是先根遍历得到结果,很简单 按照根左右 进行遍历,不再赘述。
- 中缀表达式先转换成二叉树
- 中缀 -->后缀(二叉树法)
- 中缀表达式先转换成二叉树
- 对二叉树进行后序遍历得到后缀表达式
- 参考中缀→前缀,只是在最后对二叉树进行后序遍历,也就是后根遍历。
- 左→右→根,同理不再赘述。
- 前缀-->中缀(加括号法)
- 从右向左加括号,(可以想象为栈,碰见操作符每次从栈顶取两个数,见方法8好理解)
- 将其划分成简单不可再分的二元式,括号内进行前缀转中缀。
- /++ab*cde → /++ab(*cd)e → /+(+ab)(*cd)e → /(+(+ab)(*cd))e →(/(+(+ab)(*cd))e)
- 对每个小括号进行前缀转中缀 得到:(((a+b)+(c*d))/e)
- 去掉多余小括号得到:(a+b+c*d)/e即为中缀表达式。
- 前缀-->中缀(利用栈+构建二叉树)
- 初始化一个空栈
- 对前缀表达式从右到左扫描:/++ab*cde
- 如果碰到操作数,就建立一个单节点树且入栈。
- 如果是运算符号,则从栈中弹出两个元素(单节点树)形成一个新的树,把运算符号设置为树的根。先弹出的为左子树,后弹出的为右子树。(先出为左,后出为右,符号为根)
- 然后把指向该树的指针入栈。
- 循环结束得到一个二叉树。进行中序遍历(中根遍历)得到中缀表达式。
- 左→根→右
- 后缀-->中缀(加括号法)
- 从左向右加括号,(可以想象为栈,碰见操作符每次从栈顶取两个数,见方法10好理解)
- 将其划分成简单不可再分的二元式,括号内进行后缀转中缀。
- 跟前缀转中缀道理差不多,不再赘述。参考法7。
- 后缀-->中缀(利用栈+构建二叉树)
- 初始化一个空栈
- 对前缀表达式从左到右扫描:ab+cd*+e/
- 如果碰到操作数,就建立一个单节点树且入栈。
- 如果是运算符号,则从栈中弹出两个元素(单节点树)形成一个新的树,把运算符号设置为树的根。先弹出的为左子树,后弹出的为右子树。(先出为左,后出为右,符号为根)
- 然后把指向该树的指针入栈。
- 循环结束得到一个二叉树。进行中序遍历(中根遍历)得到中缀表达式。
- 左→根→右
三、前缀/后缀计算
-
前缀计算
- 从右往左进行扫描
- 遇到操作数入栈,遇到运算符就弹出两个操作数,计算后入栈。
- 重复操作至扫描结束,计算的值为结果。
-
后缀计算
- 从左向右进行扫描
- 遇到操作数入栈,遇到运算符就弹出两个操作数,计算后入栈。
- 重复操作至扫描结束,计算的值为结果。
总结
重回赛道,好多内容都遗忘了,做做归纳梳理。
梳理不易,有错误麻烦帮忙指出,谢谢啦。
有用请点个赞谢谢~
转载请注明出处,谢谢~~
Go! Go!