数据结构与算法
栈Stack、逆波兰表达式Reverse Polish Notation
1. 栈
栈的示意图:

- 只操作栈顶元素,栈底不变
- 每次元素进栈,
top上移;元素出栈,top下移 - 所以晚进栈的元素,会先出栈
- 栈滿的条件
top==Maxsize-1(Maxsize是初始化数组的值)
- 栈空的条件
top==-1(即初始状态)
tips:
我们已经分析过了队列,与队列进行比较。
Java实现
可以用数组实现,也可以用链表,类比队列的实现,较为简单。
1 | package Stack; |
2. 逆波兰表达式
前缀表达式
前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面,又称波兰表达式,如:
1 | - + 1 * + 2 3 4 5 |
中缀表达式
中缀表达式是我们生活中常见的表达式,如:
1 | 1+((2+3)*4)-5 |
后缀表达式
与前缀表达式相反,把运算符写在后面,操作数写在前面,又称逆波兰表达式,后缀表达式更加利于计算机的执行,所以常常把中缀表达式转成后缀表达式来执行。后缀表达式的例子,如:
1 | 1 2 3+4*+5- |
中缀表达式–>后缀表达式的转换
假如给定中缀表达式:
1 | 1+((2+3)*4)-5 |
中缀表达式转成后缀表达的算法:
- 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
- 从左至右扫描中缀表达式;
- 遇到操作数时,将其压s2;
- 遇到运算符时,比较其与s1栈顶运算符的优先级:
- 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
- 否则,若优先级比栈顶运算符的高,也将运算符压入s1;
- 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
- 遇到括号时:
- 如果是左括号“(”,则直接压入s1
- 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
- 重复步骤2至5,直到表达式的最右边
- 将s1中剩余的运算符依次弹出并压入s2
- 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
当然,最后也可以不动s1,把s2中的元素压入s1,然后输出s1即可。
上面是引用的资料,说了这么多,总结就这几句话:
- 在运算符只有
+ - * /时(其他情况暂不考虑) - 不是
运算符也不是括号,那就是字母或数字,直接扔到集合里(栈或队列也行) - 扫描到左括号
(,直接入符号栈 - 扫描到右括号
),不让它push入栈,把符号栈里的元素pop弹出并加入集合,直到pop出一个左括号(为止。注意,左括号(不加入集合 - 扫描到运算符:
- 与栈顶
top的运算符比较优先级,如果top的优先级比较高,弹出top并加入集合,继续看下一个top,如此循环,当top的元素优先级低时,就入栈。 - 栈为空时,当然是直接入栈;
top是左括号(时,无视它,也直接入栈。
- 与栈顶
java实现
将以下字符串转换成逆波兰表达式:
- 1+((2+3)*4)-5
- 22*(94+6/31-513)+44
- aa*(s+ad+c)-d
- 3A*(2b+5a+abc)-3abcd
转换支持字母和数字的组合,运算符只考虑+-*/,数字暂时只考虑正整数。
1 | package Stack; |
输出结果
1 | 1 2 3 + 4 * + 5 - |
计算逆波兰表达
经过上面的转换,我们得到一个后缀表达式,计算机计算后缀表达式的算法如下:
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
比如,逆波兰表达式:
1 | 3 4 + 5 × 6 - |
后缀表达式是没有括号的,所以对计算机来说,简单了许多,把运算符置后,方便栈运算。
直到了这个逻辑,那么代码实现就很简单了:
java实现
利用中缀–>后缀表达式的代码,我们直接计算中缀表达式,即(3+4)×5-6。
1 | //计算一个中缀表达式的结果,只考虑正整数、+-*/、不包含字母,考虑到操作数长度,全程使用long类型计算 |
输出结果
1 | 29 |
☘(๑•̀ㅂ•́)و✧预告:
Shirtiny:下篇文章是关于递归的,正在写