学习笔记——前缀、中缀及后缀表达式
@
前缀表达式
基本释义
前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。为纪念其发明者波兰数学家Jan Lukasiewicz,前缀表达式也称为“波兰式”。
例如,- 1 + 2 3,它等价于1-(2+3)。
求值方法
对前缀表达式求值,要从右至左扫描表达式,首先从右边第一个字符开始判断,若当前字符是数字则一直到数字串的末尾再记录下来,若为运算符,则将右边离得最近的两个“数字串”作相应运算,然后以此作为一个新的“数字串”并记录下来;扫描到表达式最左端时扫描结束,最后运算的值即为表达式的值。
转换算法
-
首先构造一个运算符栈(也可放置括号),运算符(以括号为分界点)在栈内遵循越往栈顶优先级不降低的原则进行排列。
-
从右至左扫描中缀表达式,从右边第一个字符开始判断:
如果当前字符是数字,则分析到数字串的结尾并将数字串直接输出。 如果是运算符,则比较优先级。如果当前运算符的优先级大于等于栈顶运算符的优先级(当栈顶是括号时,直接入栈),则将运算符直接入栈;否则将栈顶运算符出栈并输出,直到当前运算符的优先级大于等于栈顶运算符的优先级(当栈顶是括号时,直接入栈),再将当前运算符入栈。 如果是括号,则根据括号的方向进行处理。如果是向右的括号,则直接入栈;否则,遇向左的括号前将所有的运算符全部出栈并输出,遇右括号后将向左、向右的两括号一起出栈(并不输出)。
-
重复操作2直至扫描结束,将栈内剩余运算符全部出栈并输出,再逆序输出字符串。中缀表达式也就转换为前缀表达式了。
实例分析
中缀表达式:1 +(( 2 + 3 * 4 )- 5 ---→ 前缀表达式:- + 1 * + 2 3 4 5
中缀表达式
中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作(一般转成后缀表达式.)
后缀表达式
释义
后缀表达式(将运算符写在操作数之后),也叫逆波兰式(Reverse Polish notation,RPN,或逆波兰记法)。
相对于中缀表达式而言,逆波兰式在计算机看来是比较简单的结构因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。
转换算法
将一个普通的中缀表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为存放结果(逆波兰式)的栈S2(空栈),S1栈可先放入优先级最低的运算符#,**注意**,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈。
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
实例分析
下面以(a+b)* c为例子进行说明:
(a+b) * c的逆波兰式为ab+c * ,假设计算机把ab+c* 按从左到右的顺序压入栈中,并且按照遇到运算符就把栈顶两个元素出栈,执行运算,得到的结果再入栈的原则来进行处理,那么ab+c * 的执行结果如下:
1)a入栈(0位置)
2)b入栈(1位置)
3)遇到运算符“ + ”,将a和b出栈,执行a+b的操作,得到结果d=a+b,再将d入栈(0位置)
4)c入栈(1位置)
5)遇到运算符“ * ”,将d和c出栈,执行d*c的操作,得到结果e,再将e入栈(0位置)
经过以上运算,计算机就可以得到(a+b)*c的运算结果e了。
代码实现(Java)
import java.util.ArrayDeque;
import java.util.Deque;
public class postfixExpression {
//仅支持int型整数,浮点型懒的搞:)
public static void main(String[] args) {
String str = "2 3+ 4*1 +5-"; //16
System.out.println(posExpression(str));
str = "4 2 3 *+10 5/-"; //8
System.out.println(posExpression(str));
str = "1 2 3 + *"; //5
System.out.println(posExpression(str));
}
public static int posExpression(String str) {
Deque<Integer> stack = new ArrayDeque<>();
int num1, num2, res = 0;
char cur;
for (int i = 0; i < str.length(); i++) {
cur = str.charAt(i);
if (isOprator(cur)) {
num2 = stack.pop();
num1 = stack.pop();
if (cur == '+') {
res = num1 + num2;
stack.push(res);
} else if (cur == '-') {
res = num1 - num2;
stack.push(res);
} else if (cur == '*') {
res = num1 * num2;
stack.push(res);
} else if (cur == '/') {
res = num1 / num2;
stack.push(res);
}
} else if (Character.isDigit(cur)) { //是数字
int dig = 0, j = i;
while (j < str.length() && Character.isDigit(str.charAt(j))) {
dig = dig * 10 + (int) (str.charAt(j++) - '0');
}
stack.push(dig);
i = j - 1;
}
}
return res;
}
public static boolean isOprator(char c) {
String str = "" + c;
return (str.equals("+") || str.equals("-") ||
str.equals("*") || str.equals("/"));
}
}