缀式的相互转换
1.先了解什么事是前缀式,中缀式,后缀式
定义:这三种表达式其实就是算术表达式的三种写法,以 3+4-5为例
前缀式: 操作符在操作数前面 3+(4-5) -> +3-45(没有括号就3+4-5 前缀式:+-345 这样算结果不对,百度下,还是不太清楚)(可能是同等级优先级是要加一个括号括起来呢)
中缀式: 操作符在操作数中间 3+4-5 ->平常我们所熟悉的运算表达式
后缀式: 操作符在操作数后面 34+5- ->计算机计算就是用后缀式(不唯一)
2.中缀式转换为后缀式(计算机运算实现)
3+4-5
定义两个栈:符号栈(存放操作符),数字栈(存放数字和运算结果).
符号栈:定义运算符号的优先级,这个可以设置一个int类型变量实现
+,-定义优先级最低
*,/,% 定义优先级次低
^ 定义优先级最高
中缀式转换为后缀式只要一个符号栈就可以了,数字栈是解释计算机工作原理的,
算数表达式是要String类型,String类型转换为char数组
符号栈的进栈出栈规律:1.当遍历数组的时候遇到数字字符,则直接保存
2.当遇到符号字符时:当栈空是就直接进栈;否则就判断栈顶的运算符的优先级是否小于要进栈的符号
(记住是小于,等于或是大于都不行)
3.当栈顶符号优先级大于要进栈符号,则栈顶符号出栈,出栈符号保存,当下一个栈顶符号还是
优先级大于要进栈元素,则继续栈顶出栈,保存栈顶符号,直到要进栈符号满足进栈要求进栈为止
4.当进栈符号是左括号(时直接进栈
5.当进栈符号是右括号)时,一直出栈,知道遇到符号是左括号为止,出栈符号保存,左括号出栈不保存
6.当遍历完数组的时候就出栈所有符号,保存
3+4-5+(4*1)进栈过程 -> 保存使用StringBuffer s来,符号找用f来表示
1.遍历时遇到数字直接保存
s = 3,f = 空
2.遍历时遇到符号字符+号
这时符号栈为空,直接进栈
s = 3,f = +
3.遍历时遇到数字直接保存
s = 34,f = +
4.遍历时遇到符号字符-号
这时符号栈的栈顶符号是+号,+号的优先级和-号一样,进栈要求是要进栈符号优先级要大于栈顶符号
那么就要出栈+号,出栈后符号栈为空,符号栈为空就直接-号进栈
s = 34+,f = -
5.遍历时遇到数字直接保存
s = 34+5,f = -
6.遍历时遇到左括号,直接进栈
s = 34+5-,f = +("左括号为栈顶"
7.遍历时遇到符号*
符号*优先级是比+,-高但是栈顶是左括号,那是否进栈呢?
答:遇到左括号直接进栈,不考虑左括号优先级,左右括号的优先级是最低的,但不要去设置
为什么不进行设置?因为会引起冲突,
什么冲突?当1+1(1*1)时
+进栈为栈顶,优先级是比(左括号高,则是否进栈呢?
当然进栈,可是违背了符号栈进栈规律,是的,这就是冲突了,所以就
不要设置,直接自己默认知道就行,也可以麻烦一点多设置几个判断条件解决
反正我是没试过.
s = 34+5-,f = +(
s = 34+5-41,f = +(*
s = 34+5-41*+,f = +(*
8.遍历时遇到右括号时,不进栈,直接出栈栈顶符号,直到栈顶符号是左括号
这里栈顶是*号,出栈,出栈后栈顶符号是左括号,停止循环出栈.这时的栈顶符号
是左括号,这里是要出栈的,为什么上面不直接把左括号一起出栈得了,回答:这样循环退出条件
如何设置,这样想?不是左括号的时候就退出出栈循环?那这循环就是费了,循环退出条件得符号是
左括号的时候,退出出栈循环后还要进行一次出栈,不过这次出栈得是有条件的,就是左括号的时候,
为了防止有其他情况而胡乱出栈的情况,左括号和右括号都是不保存的
s = 34+5-41* f = +
9.数组遍历结束,循环出栈符号栈所有的符号了
s = 34+5-41*+ f = 空
34+5-41*+就是后缀式了,有人可能问了,和上面的例子不一样呀,也和定义有所不同
那行,使用3+4-5变成后缀式看看
s = 3 , f = 空
s = 3 , f = +
s = 34 , f = +
s = 34+ , f = -
s = 34+5 , f = -
s = 34+5- , f = 空
有括号就不理解了肯定是不行的
使用数字栈的时候是已经把中缀式转换为后缀式了,这是用后缀式来进行的操作
数字栈的进栈出栈规律: s = 34+5-41*+
1.把StringBuffer使用toString方法转换为String类型,再转换为char数组
2.遍历数组,当遇到数字字符直接进数字栈
3.当遇到符号字符时(一般情况下是数字栈数字是等于或超过两个的,不然就是后缀式错误)
,编写一个方法,功能是根据符号字符判断运算符,并接收数字栈的栈顶数字和次栈顶数字,返回栈顶数字和次栈顶数字的运算结果
这里注意:进行减运算时,次栈顶数字-栈顶数字,除和模运算也是次栈顶数字/(%)栈顶数字
把运算结果进栈
4.一直循环做2~3步,知道char数组遍历完成后就出栈最终运算结果
基本是每两个数字进行一次运算,再把运算结果进栈,又变成了两个数字进行运算
34+5-41*+
数字栈用m表示 ,运算过程用t表示(随意)
m = 34 t = 无
遇到符号+字符,进行方法判断
if('+' == 字符数组[i]){
int k = m.出栈 - '0';
int j = m.出栈 - '0';
return k+j;
}
if('/' == 字符数组[i]){
int k = m.出栈 - '0'; 栈顶数字
int j = m.出栈 - '0'; 次栈顶数字
return j/k;
}
注意:只有减法,除法模运算才很注意数的左右位置(就是除数与被除数关系)
m = 3 4 ,t = 3+4
m = 7 , t = 无
m = 7 5 ,t = 无
遇到符号-字符,进行方法判断
m = 7 5 ,t = 7-5
m = 2 , t =无
34+5-41*+变成了241*+
遇到符号*字符,进行方法判断
m = 2 4 1 , t = 4*1
m = 2 4 , t = 无
遇到符号+字符,进行方法判断
m = 2 4 , t = 2+4
m = 6
最后栈中是最后的运算结果:3+4-5+(4*1)=6
3.中缀式转换前缀式,从从右往左开始扫描中缀式
同上定义两个栈,一个数字栈,一个符号栈,和运算符的优先级,级别同上
String类型的数学运算表达式转换为char数组,循环,循环反向,i--嘛,懂!就是下标等于数组长度,然后自减;
符号栈用f表示,保存用StringBuffer类型的s表示
符号栈进栈出栈规则:
1.当遇到数字字符时,直接保存
2.当遇到符号字符时,符号栈为空栈直接进栈;
当栈顶符号优先级小于等于要进栈符号则进栈(要进栈符号优先级要大于等于栈顶符号);
(这里就是与上面第二个不同点了,第一个不同点就是扫面方向各自不同)
当栈顶符号优先级大于要进栈符号则循环出栈,直到满足优先级大于等于栈顶符号或栈空
3.当遇到右括号时直接进栈
当遇到左括号时循环出栈,直到栈顶符号是右括号 ->这里就是与上面第三个不同点
同样不保存左右括号,出栈栈顶符号为右括号时停止,然后弹出右括号
4.数组循环结束后出栈所有符号并保存
3+4-5+(4*1)
从右开始到最左结束
1.遇到右括号直接进栈
s = 空 , f = )
2.遇到数字,直接保存
s = 1 , f = )
3.遇到*号,判断优先级,判断可以进栈
s = 1 , f = )*
4.遇到数字,直接保存
s = 14 , f = )*
5.遇到左括号(,循环出栈,直到栈顶为右括号时停止,然后再一次出栈去掉右括号
s = 14* , f = 空
6.遇到+号,空栈,直接进栈
s = 14* , f = +
7.遇到5
s = 14*5 , f = +
8.遇到-号,优先级等于+号,进栈
s = 14*5 , f = +-
9.遇到4
s = 14*54 , f = +-
10.遇到+,优先级等于-,进栈
s = 14*54 , f = +-+
11.遇到3
s = 14*543 , f = +-+
12.数组遍历结束,出栈所有并保存
s = 14*543+-+ , f = 空
前缀式: +-+345*41
(没错,反过来,本来是使用一个普通栈进行保存出栈符号的,但让本人自己更好理解嘛都一样)
计算器使用前缀式进行运算
数字栈m表示,过程t表示
规律:大体同上,就是扫描不是从左往右,而是从右往左;这里是栈顶数字 -(/,%) 次栈顶数字
遇到数字就进栈,遇到符号就判断进行什么运算
+-+345*41
1. m = 14 , t = 无
2. m = 14 , t = 4*1 -> 栈顶数字:运算符号:次栈顶数字
3. m = 4 , t = 无
4. m = 4543 , t = 3+4
5. m = 457 , t = 7-5
6. m = 42 , t = 2+4
7. m = 6
出栈得结果
3+4-5+(4*1)= 6