1、介绍
中缀表达式:( ( 78 - 72 ) * 4 - ( 1 + 3 ) / 2 ) * 7
后缀表达式:78, 72, -, 4, *, 1, 3, +, 2, /, -, 7, *(前缀表达式与后缀表达式相反,这里不做介绍)
中缀表达式便于记忆,容易理解,但是计算机不容易理解,毕竟计算机全是 只认识01,不能理解复杂的逻辑,所以,将中缀表达式装换成后缀表达式,便于程序处理。
2、算法思想
2.1、中缀----后缀
(1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
(2) 从左至右扫描中缀表达式;
(3) 遇到操作数时,将其压入S2;
(4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
(4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
(4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
(5) 遇到括号时:
(5-1) 如果是左括号“(”,则直接压入S1;
(5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
(6) 重复步骤(2)至(5),直到表达式的最右边;
(7) 将S1中剩余的运算符依次弹出并压入S2;
(8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。
2.2、后缀计算
从左至右扫描表达式,遇到数字时,将数字压入堆栈,
遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;
重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
3 Code
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;
/**
* 中缀表达式得到后缀表达式
* @author yanbu
*
*/
public class MidToSuffix {
/*将中缀表达式转换为后缀表达式: 核心思想
与转换为前缀表达式相似,遵循以下步骤:
(1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
(2) 从左至右扫描中缀表达式;
(3) 遇到操作数时,将其压入S2;
(4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
(4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
(4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
(5) 遇到括号时:
(5-1) 如果是左括号“(”,则直接压入S1;
(5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
(6) 重复步骤(2)至(5),直到表达式的最右边;
(7) 将S1中剩余的运算符依次弹出并压入S2;
(8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。*/
/**
* 运算符栈S1
*/
Stack<String> s1 = new Stack<>();
/**
* 中间结果的栈S2
*/
Stack<Object> s2 = new Stack<>();
/**
* 存储中缀表达式 格式自己定义
* 这里每个表达式元素之间均以空格隔开
*/
List<String> exps = new ArrayList<>();
String expression;
/**
* 存储操作符优先级
*/
Map<String, Integer> op = new HashMap<String, Integer>();
public MidToSuffix(){
op.put("+", 1);
op.put("-", 1);
op.put("*", 2);
op.put("/", 2);
}
public void dealExps(){
String[] exs = expression.split(" ");
for (String exp : exs) {
if(!exp.trim().equals("")){
this.exps.add(exp.trim());
}
}
}
/**
* 从左至右扫描中缀表达式
*/
public void initStacl(){
for (String exp : exps) {
System.out.println("s1:" + s1 +" " + "s2:" + s2);
switch (exp) {
case "(": //处理括号()--参考操作(5)
s1.push(exp);
break;
case ")":
s1ToS2();
break;
default:
op4(exp);
break;
}
}
s1ToS2();
}
/**
* 操作(5),括号处理
* 依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
* /n同时可用于s1元素全部入栈S2
*/
public void s1ToS2(){
while(!s1.empty()){
String ops = s1.pop();
if(ops.equals("(")){
return;
}
s2.push(ops);
}
}
/**
* 操作(4)
* @param exp
*/
public void op4(String exp){
//参考操作(4)
if(Pattern.matches("^[0-9]*$", exp)){ //遇到操作数时,将其压入S2;
s2.push(Integer.parseInt(exp));
}else{
if(s1.isEmpty() || s1.peek().equals("(")){ //s1为空,操作符入栈S1
s1.push(exp);
}else{
if(op.get(exp) > op.get(s1.peek())){ //比较操作符优先级,大于直接入栈 否则栈s1顶元素出栈,该操作符入栈
s1.push(exp);
}else{
s2.push(s1.pop()); //栈顶元素出栈
s1.push(exp); //操作符入栈
}
}
}
}
public void setExpression(String expression){
this.expression = expression;
}
/**
* 获取后缀表达式
* @param expression
* @return
*/
public Stack<Object> getSuffix(String expression){
setExpression(expression);
dealExps();
initStacl();
return this.s2;
}
}
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
/**
* 计算后缀表达式
* @author yanbu
*/
public class CpuSuffix {
MidToSuffix midToSuffix = new MidToSuffix();
/** 核心思想
* 从左至右扫描表达式,
* 遇到数字时,将数字压入堆栈,
* 遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;
* 重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
* @param args
*/
/**
* 用于存放计算结果
*/
public Stack<Object> s1 = new Stack<>();
public void initSuffix(String MidExp){
Stack<Object> stack = midToSuffix.getSuffix(MidExp);
System.out.println("suffix:" + stack);
Set<String> op = midToSuffix.op.keySet();
for (Object object : stack.toArray()) {
System.err.println(s1);
if(op.contains(object)){
Integer num2 = (Integer)s1.pop();
Integer num1 = (Integer)s1.pop();
s1.push(op(object.toString(),num1,num2));
}else{
s1.push(object);
}
}
System.err.println(s1);
}
public int op(String op, int num1,int num2){
switch (op) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num1 / num2;
default:
return 0;
}
}
public static void main(String[] args) {
CpuSuffix cpuSuffix = new CpuSuffix();
String exp = new Scanner(System.in).nextLine();
cpuSuffix.initSuffix(exp);
}
}
Console:
( ( 78 - 72 ) * 4 - ( 1 + 3 ) / 2 ) * 7
s1:[] s2:[]
s1:[(] s2:[]
s1:[(, (] s2:[]
s1:[(, (] s2:[78]
s1:[(, (, -] s2:[78]
s1:[(, (, -] s2:[78, 72]
s1:[(] s2:[78, 72, -]
s1:[(, *] s2:[78, 72, -]
s1:[(, *] s2:[78, 72, -, 4]
s1:[(, -] s2:[78, 72, -, 4, *]
s1:[(, -, (] s2:[78, 72, -, 4, *]
s1:[(, -, (] s2:[78, 72, -, 4, *, 1]
s1:[(, -, (, +] s2:[78, 72, -, 4, *, 1]
s1:[(, -, (, +] s2:[78, 72, -, 4, *, 1, 3]
s1:[(, -] s2:[78, 72, -, 4, *, 1, 3, +]
s1:[(, -, /] s2:[78, 72, -, 4, *, 1, 3, +]
s1:[(, -, /] s2:[78, 72, -, 4, *, 1, 3, +, 2]
s1:[] s2:[78, 72, -, 4, *, 1, 3, +, 2, /, -]
s1:[*] s2:[78, 72, -, 4, *, 1, 3, +, 2, /, -]
suffix:[78, 72, -, 4, *, 1, 3, +, 2, /, -, 7, *]
[]
[78]
[78, 72]
[6]
[6, 4]
[24]
[24, 1]
[24, 1, 3]
[24, 4]
[24, 4, 2]
[24, 2]
[22]
[22, 7]
[154]