后缀表达式
为什么使用后缀表达式:
后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后,就比如中缀表达式12+3*4-5,后缀表达式为12 3 4 * + 5 - 。转换成这种表达式之后,计算结果的过程就会容易的多。
下面是得到后缀表达式后,是怎么运算的,通过这个可以看到为什么使用后缀表达式。
后缀表达式中的各个数据
12 | 3 | 4 | * | + | 5 | - |
计算过程将会使用到栈这种数据结构,具体过程为。
依次得到后缀表达式中的每一个元素,执行下列两个操作。
1.当遇到数据就入栈。比如第一个数是12 ,说明12入栈。第二个数也入栈,依次直到遇到运算符,进行2步骤。
入栈的数据
4 |
3 |
12 |
2.当遇到运算符就出栈,并将栈顶的两个数据取出,进行运算,将运算结果入栈。比如当前的3 、4 取出,进行乘法运算,得到12,将12入栈。
计算后栈中的数据
12 |
12 |
循环执行步骤1和步骤2,直到后缀表达式结束--------得到结果为19。
由此发现后缀表达式在运算过程中,解决了考虑优先级的关系----使计算变得更容易。
中缀表达式------后缀表达式:
怎么将中缀表达式转成后缀表达式?会使用到栈和队列。
首先用数组保存各个操作数和运算符。
数组中的各个数据
12 | 3 | 4 | * | + | 5 | - |
依次得到数组中的每一个元素,执行下列两个操作。
1.如果元素是操作数,就直接入队列。比如第一个数为12,入队列。
队列中的数据
12 |
2.如果元素是运算符,就要进行对栈进行判断
1.如果栈是空栈,直接入栈。
栈中的数据
+ |
2.如果栈不是空栈,使当前元素和栈顶的运算符进行判断,如果当前的运算符的优先级高于栈顶的优先级,就直接入栈。
比如当前元素是*,栈顶元素是+。
栈的原始数据
+ |
- |
比较优先级之后的数据
* 入栈 |
+ |
- |
依次和栈顶元素比较,直到出现当前元素优先级高于栈顶元素或栈为空,元素入栈。
比如当前运算是*,栈中的栈顶元素依次为* + -
栈中的原始数据
* 和 当前元素*比较 * 出栈,入队列。 |
+ 和 当前元素*比较 当前元素* 入栈 |
- |
计算后的栈中数据
* 这个元素是当前元素入栈得到的 |
+ |
- |
最后在队列中的数据就是后缀表达式了。
每一个人都有自己的理解,很有必有看一下数据结构这本书。
在数据结构这本书中的67页,有详细的过程,思路是一样的,可能更容易理解。
实现代码 :
比较加减乘除运算符的优先级
// 判断运算符的优先级----其实可以使用带判断大小的枚举更好一些。
public int precedence(String first,String next) {
int number_1=0;
int number_2=0;
switch(first) {
case "+":
number_1=1;
break;
case "-":
number_1=1;
break;
case "*":
number_1=2;
break;
case "/":
number_1=2;
break;
}
switch(next) {
case "+":
number_2=1;
break;
case "-":
number_2=1;
break;
case "*":
number_2=2;
break;
case "/":
number_2=2;
break;
}
return number_1==number_2?0:number_1-number_2;
}
中缀表达式转后缀表达式
在这里我使用的是链表队列来保存中缀表达式的操作数和运算符。
/**
* 将中缀表达式转换成后缀表达式,返回的是一个后缀表达式的队列
* @param nifix 中缀表达式
* @return
*/
public LinkedList<String> toPostfix(LinkedList<String> nifix) {
Stack<String> opStack = new Stack<>();
LinkedList<String> postfix = new LinkedList<>();
Pattern pattern = Pattern.compile("\\+|-|\\*|/");
for(String str: nifix) {
if(!pattern.matcher(str).matches()) {
postfix.add(str);
}
else {
if(opStack.isEmpty()) {
opStack.push(str);
}
else {
// 比较当前的 栈顶字符 和 str 的大小关系。
while(!opStack.isEmpty()&&precedence(opStack.peek(),str)>=0) {
postfix.add(opStack.pop());
}
opStack.push(str);
}
}
}
while(!opStack.isEmpty()) {
postfix.add(opStack.pop());
}
return postfix;
}
实现加减乘除运算的方法
/**
* 实现加减乘除运算
*
* @param a 第一个操作数
* @param mark 运算符
* @param b 第二个操作数
* @return result---运算结果
*/
public String computer(String a,String mark,String b) {
BigDecimal frist = new BigDecimal(a);
BigDecimal next = new BigDecimal(b);
switch(mark) {
case "+":
result=String.valueOf(frist.add(next));
break;
case "-":
result=String.valueOf(frist.subtract(next));
break;
case "*":
result=String.valueOf(frist.multiply(next));
break;
case "/":
result=String.valueOf(frist.divide(next));
break;
}
return result;
}
后缀表达式的计算
// 用LinkedList列表实现队列的功能,计算后缀表达式的结果。
public String postfixResult(LinkedList<String> postfix) {
Stack<String> numberStack = new Stack<>();
Pattern pattern = Pattern.compile("\\+|-|\\*|/");
for(String str:postfix) {
if(!pattern.matcher(str).matches()) {
numberStack.push(str);
}
else {
String next = numberStack.pop();
String frist = numberStack.pop();
result = computer(frist,str,next);
numberStack.push(result);
}
}
return numberStack.pop();
}