1:什么是中缀表达式,前缀表达式,后缀表达式?
正如我们常常潜意识认为我们所说的数字都是十进制,对于数字的其他进制感觉不正确一样,其实只是我们不熟悉而已,其他进制其实也不过就是一种对数据的表达方式而已。对于我们的表达式也是一样。
eg:表达式2*3+(5-7);
我们上面所看到的也就是我们平时常用的书写表达式的方式就是我们所谓的“中缀表达式”
前缀表达式与后缀表达式都是一种没有括号的算术表达式,两者都与中缀表达式有所不同。前缀表达式其将运算符写在前面,操作数写在后面。后缀表达式其将运算符写在后面,操作数写在前面。
2:中缀表达式如何转化为前缀表达式与后缀表达式?
这里我给出一个中缀表达式:a+b*c-(d+e)
<1>第一种方法
第一步:按照运算符的优先级对所有的运算单位加括号 式子变成:((a+(b*c))-(d+e))
第二步:转换前缀与后缀表达式
- 前缀
把运算符号移动到对应的括号前面,则变成了:-(+(a*(bc))+(de)),去掉括号即前缀式: - + a * b c + d e
- 后缀
把运算符号移动到对应的括号后面,则变成了:((a(bc)* )+(de)+ )-,去掉括号即后缀式:a b c * + d e + -
我们发现前缀式,后缀式他们都是不需要用括号来进行优先级的确定的。
<2>第二种方法
- 中缀转前缀(波兰式)
转化过程需要用到栈,具体操作如下
(1):从右向左遍历如果遇到操作数,我们就直接将其输出。
(2):如果遇到操作符,则我们将其放入到栈中,遇到右括号时我们也将其放入栈中。(操作符放入有条件,看4)
(3): 如果遇到一个左括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
(4): 当前操作符进行压栈时,如果发现当前栈顶元素优先级小于等于自己(或者栈为空)时,当前操作符直接压栈;但如果当前栈顶元素优先级大于当前操作符,当前的操作符就不能入栈,先需要将栈顶元素输出,接着和最新的栈顶元素比较,直到发现比自己优先级低的元素(或者栈为空),当前的操作符才可以压到栈中。
ps:如果栈顶元素是“)”,我们直接插入当前的操作符,因为“)”只有在遇到" ( "的情况下我们才弹出" ) ",其他情况我们都不会弹出" ) "。而且括号弹出但是并不输出。
(5): 如果我们读到了输入的末尾,则将栈中所有元素依次输出。
(6): 最后一步是将当前输出的总的表达式翻转即可。
实例操作:中缀表达式 a+b*c-(d+e)
首先从右向左我们读到“)”,直接压栈;输出e;栈顶元素为“)”,+直接压栈;输出d;遇到“(”,弹出+;栈为空,-压栈;输出c;*优先级高于-,*入栈;输出b;+优先级低于*,输出*,+优先级高于-,+入栈;输出a;当前表达式遍历完成,将栈内剩余元素全部输出,即输出+,输出-;
当前所有的输出为:e d + c b * a + -
将当前输出的表达式翻转的最终的前缀表达式即:- + a * b c + d e
- 中缀转后缀(逆波兰式)
转化过程依旧需要用到栈,具体操作如下
(1):从左向右遍历如果遇到操作数,我们就直接将其输出。
(2):如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。(操作符放入有条件,看4)
(3): 如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
(4): 当前操作符进行压栈时,如果发现当前栈顶元素优先级小于自己(或者栈为空)时,当前操作符直接压栈;但如果当前栈顶元素优先级大于当前操作符,当前的操作符就不能入栈,先需要将栈顶元素输出,接着和最新的栈顶元素比较,直到发现比自己优先级低的元素(或者栈为空),当前的操作符才可以压到栈中。
ps:如果栈顶元素是“(”,我们直接插入当前的操作符,因为“(”只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。而且括号弹出但是并不输出。
5)如果我们读到了输入的末尾,则将栈中所有元素依次输出。
实例操作:中缀表达式 a+b*c-(d+e)
首先读到a,输出a; 读到+,因为栈目前为空将+压栈; 输出b; *的优先级大于+,将*压栈;输出c; -运算符优先级小于*,输出*,-运算符优先级小于+,输出+,当前栈为空,压入-;遇到“(”,直接压栈;输出d;+运算符所要比较的当前的栈顶元素是"(",所以直接压栈;输出e;遇到“)”,将栈里面“(”之前的操作符全都输出,即输出+;当前表达式已经遍历完,所以将栈里剩余操作符全部输出,即输出-。所以我们最终的结果就是a b c * + d e + -
总结表:
3:前缀表达式与后缀表达书如何转化为中缀表达式?
对于上面所举的例子,中缀表达式是2*3+(5-7),其前缀表达式是:+ * 2 3 - 5 7 后缀表达式是 2 3 * 5 7 - +
前缀转中缀
从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算,并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。
例如前缀表达式“+ * 2 3 - 5 7”:
- 从右至左扫描,将7 5压入堆栈;
- 遇到-运算符,因此弹出5和7(5为栈顶元素,7为次顶元素,注意与后缀表达式做比较),计算出5-7的值,得-2,再将-2入栈
- 接下来是将3 2压入堆栈;
- 遇到*操作符,弹出2和3,计算出2*3的值,得6,再将6入栈
- 最后是+运算符,计算出6+(-2)的值,即4,由此得出最终结果。
- 可以看出,用计算机计算前缀表达式的值是很容易的。
后缀转中缀
基本思路和上面的一样:递归,碰到操作符就进入递归。
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(注意,次栈顶元素是前一位(eg:被减数),栈顶元素是后一位(eg:减数)),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
例如后缀表达式“2 3 * 5 7 - +”:
- 从左至右扫描,将2 3压入堆栈;
- 遇到*运算符,因此弹出3和2(3为栈顶元素,2为次顶元素,注意两者运算前后次序),计算出2*3的值,得6,再将6入栈
- 接下来是将5 7压入堆栈;
- 遇到-操作符,弹出7和5,计算出5-7的值,得-2,再将-2入栈
- 最后是+运算符,计算出6+(-2)的值,即4,由此得出最终结果。