什么是后缀、前缀、以及中缀表达式呢?他与我们平时在数学中见到的表达式有什么区别?第一次看这个名词,我还是有点蒙,难理解,所以做以下笔记,以便日后复习,也希望可以帮助读者,以相互促进。
文章目录
前言:
在学习数据结构与算法中,我们会见到前缀表达式、中缀表达式、后缀表达式,用来编写逆波兰计算器。那么什么是前中后、缀表达式呢?下面我们通过中缀表达式为引讲解。
一、什么是前、中、后缀表达式?
前、中、后缀表达式中,运算符在算式中的位置决定了他是前缀还是中后缀;
什么是后缀表达式?他与我们平时见到的表达式有什么区别?
解:我们平时在数学中见到的一般表达式我们称它为中缀表达式,呢么为什么要叫这个名字呢?百度给出如下说法:
中缀表达式(又称中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作符的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,在中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。
呢么我们就可以得出结论,前中后缀表达式实际上就是运算符在操作数之间出现的位置,在两个操作数之前,我们称为前缀表达式,在中间叫中缀表达式,后面就叫后缀表达式。
这里值得注意的是,在中缀表达式中会有括号这种符号,来区分运算的先后。
二、思路与分析:
在了解了前、后、中表达式后,下面我们看如何将一个中缀表达式转化为后缀表达式, 在写代码之前我们先顺一下思路,和步骤。
- 初始化一个存放运算符的栈。
- 对算术表达式从左向右进行扫描直到串尾:对获取的符号进行判断:
2.1)如果是数字:继续读取下一位,判断下一位是不是数字,
2.1.1)如果是数字:就将第二次读取的数字与之前的数字进行拼接,(在这之前我们需要定义一个空的字符串用来拼接数字)具体怎么拼接呢?(我们首先将第一次读取的数字,与空字符串拼接,在第二次读取的数字与字符串拼接,最后用Integer.parseInt(String str);方法将字符串转为整数)。
2.1.2)如果不是数字:就直接把第一次读取的数字直接输出到后缀表达式中.
2.2)如果是左括号:把左括号入运算符栈如果是右括号:把栈顶元素依次出栈到后缀表达式中,直到遇到运算符栈中的左括号,并把左括号出栈2.3)如果是运算符:如果该运算符的优先级高于栈顶运算符优先级,该运算符入栈;否则把(低于或等于)该运算符优化级的栈顶元素依次出栈到后缀表达式中,直到该运算符的优先级高于栈顶运算符为止,之后该运算符入运算符栈
3. 如果到串尾时,将符号栈中的所以元素依次出栈到后缀表达式中2.读入数据
三、实操代码(示例):
public class InfixToSuffix {
public static void main(String[] args) {
String infixExpretion = "1+((2+3)*4)-5";
List<String> strings = toInfixExpression(infixExpretion);
List<String> list = parseSuffixExpressionList(strings);
System.out.println(list);
}
public static List<String> toInfixExpression(String infixExpression){
List<String> ls = new ArrayList<>();
char c;
String str;
int i=0;
do{
if ((c=infixExpression.charAt(i)) <= 48 || (c=infixExpression.charAt(i)) >= 57){
ls.add("" + c);
i++;
}else{
str = "";
while (i<infixExpression.length() && (c=infixExpression.charAt(i)) >= 48 && (c=infixExpression.charAt(i)) <= 57){
str += c;
i++;
}
ls.add(str);
}
}while (i<infixExpression.length());
return ls;
}
public static List<String> parseSuffixExpressionList(List<String> list){
Stack<String> operStack = new Stack<>();
List<String> resList = new ArrayList<>();
for (String item : list){
if (item.matches("\\d+")){
resList.add(item);
}else if (item.equals("(")){
operStack.push(item);
//如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号,此时将这一对括号丢弃;
}else if (item.equals(")")){
while (!operStack.peek().equals("(")){
resList.add(operStack.pop());
}
operStack.pop();
}else{
while (operStack.size()!=0 && Operation.getValue(operStack.peek()) >= Operation.getValue(item)){
resList.add(operStack.pop());
}
operStack.push(item);
}
}
while (operStack.size()!=0){
resList.add(operStack.pop());
}
return resList;
}
}
class Operation{
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 1;
private static int DIV = 1;
private static int LEFT = 0;
public static int getValue(String oper){
int res = 0;
switch (oper){
case "+":
res = ADD;
break;
case "-":
res = SUB;
break;
case "*":
res = MUL;
break;
case "/":
res = DIV;
break;
case "(":
res = LEFT;
break;
default:
System.out.println("不存在该运算符");
break;
}
return res;
}
}
总结:
以上就是今天要讲的内容,本文仅仅简单介绍了前、中、后缀表达式,而前中后缀表达式是数据结构中很重要的一部分,后面我们会在编写逆波兰计算器中用到。