具体步骤
/*
* 后缀表达式适合计算式进行运算,但是人却不容易写出来,尤其是表达式很长的情况下,
* 因此在开发中,我们需要将中缀表达式转成后缀表达式
*
* 具体步骤:
* 1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
* 2. 从左至右扫描中缀表达式
* 3. 遇到操作数时,将其压s2
* 4. 遇到运算符时,比较其与s1栈顶运算符的优先级
* 1. 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈
* 2. 否则,若优先级比栈顶运算符的高,也将运算符压入s1
* 3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较
* 5. 遇到括号时:
* 1. 如果是左括号“(”,则直接压入s1
* 2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
* 6. 重复步骤2至5,直到表达式的最右边
* 7. 将s1中剩余的运算符依次弹出并压入s2
* 8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
*/
中缀表达式转后缀表达式(逆波兰表达式)
public static String toReversePolishNotation(String formula) throws Exception{
// 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
Stack<String> s1 = new Stack<>();
Stack<String> s2 = new Stack<>();
String[] symbol = formula.split(" ");
int len = symbol.length;
// 从左至右扫描中缀表达式
for (int i = 0; i < len; i++) {
String currentSymbol = symbol[i];
// 遇到操作数时,将其压s2
if (MathUtil.isNumeric(currentSymbol)){
s2.push(currentSymbol);
continue;
}
if (MathUtil.isOper(currentSymbol)){
// 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,
// 直到遇到左括号为止,此时将这一对括号丢弃
if (")".equals(currentSymbol)){
while (!MathUtil.isLeftParenthesis(s1.peek()))
s2.push(s1.pop());
s1.pop();
continue;
}
while (true) {
// 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈
if (s1.isEmpty() || "(".equals(currentSymbol)){
s1.push(currentSymbol);
break;
}
int topPriority = MathUtil.priority(s1.peek());
int currentPriority = MathUtil.priority(currentSymbol);
// 若优先级比栈顶运算符的高,也将运算符压入s1
if (currentPriority > topPriority) {
s1.push(currentSymbol);
break;
}
// 若优先级不比栈顶运算符的高,将s1栈顶的运算符弹出并压入到s2中,
if (currentPriority <= topPriority)
s2.push(s1.pop());
}
}
}
// 将s1中剩余的运算符依次弹出并压入s2
while (!s1.isEmpty())
s2.push(s1.pop());
String result = "";
// 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
while (!s2.isEmpty())
result = s2.pop() + " " + result;
return result;
}
计算表达式结果
public static String calculate(String formula){
try {
String s = toReversePolishNotation(formula);
String[] symbol = s.split(" ");
Stack<String> stack = new Stack<>();
int len = symbol.length;
for (int i = 0; i < len; i++) {
String currentSymbol = symbol[i];
if (MathUtil.isOper(currentSymbol)){
String b = stack.pop();
String a = stack.pop();
// 计算两个数在操作符currentSymbol下的值
stack.push(String.valueOf(MathUtil.calculate(a,b,currentSymbol)));
continue;
}
stack.push(currentSymbol);
}
return stack.peek();
} catch (Exception e) {
return "表达式有误!";
}
}
自定义MathUtil工具类
/**
* 数学工具包类
* @Class: MathUtil
* @author: Oh_MyBug
* @Date: 2020/3/17 22:17
*/
class MathUtil {
private static final HashMap<String, Integer> OPERATTION_PRIORITY = new HashMap() {
{
put("(", -1);
put("+", 0);
put("-", 0);
put("*", 1);
put("/", 1);
put(")", 2);
}
};
/**
* 判断字符串str是否为数字
* @Function isNumeric
* @author Oh_MyBug
* @Date 2020/3/17 22:18
* @param
* @return 布尔值 是->true 否->false
*/
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
} catch (NumberFormatException e) {
return false;
}
return true;
}
/**
* 判断字符串str是否为操作符
* @Function isOper
* @author Oh_MyBug
* @Date 2020/3/17 22:19
* @param
* @return 布尔值 是->true 否->false
*/
public static boolean isOper(String str) {
return OPERATTION_PRIORITY.keySet().contains(str) ? true : false;
}
/**
* 判断操作符是否为左括弧
* @Function isLeftParenthesis
* @author Oh_MyBug
* @Date 2020/3/17 22:22
* @param
* @return 布尔值 是->true 否->false
*/
public static boolean isLeftParenthesis(String str){
return OPERATTION_PRIORITY.get(str) == OPERATTION_PRIORITY.get("(");
}
/**
* 判断操作符是否为右括弧
* @Function isRightParenthesis
* @author Oh_MyBug
* @Date 2020/3/17 22:22
* @param str
* @return 布尔值 是->true 否->false
*/
public static boolean isRightParenthesis(String str){
return OPERATTION_PRIORITY.get(str) == OPERATTION_PRIORITY.get(")");
}
/**
* 判断操作符优先级
* @Function priority
* @author Oh_MyBug
* @Date 2020/3/17 22:23
* @param str
* @return 操作符优先级
*/
public static int priority(String str) {
return OPERATTION_PRIORITY.get(str);
}
/**
* 计算两个数在操作符oper下的值
* @Function TODO
* @author Oh_MyBug
* @Date 2020/3/17 22:23
* @param num1
* @param num2
* @param oper
* @return 计算结果
*/
public static double calculate(String num1, String num2, String oper) {
double a = Double.parseDouble(num1);
double b = Double.parseDouble(num2);
switch (oper) {
case "+":
return a + b;
case "-":
return a - b;
case "*":
return a * b;
case "/":
if (b == 0) {
throw new RuntimeException("非法运算!");
}
return a / b;
default:
break;
}
return 0;
}
}
测试代码
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true){
System.out.print("请输入式子:");
String fomula = scanner.nextLine();
switch (fomula){
case "exit":
break;
default:
System.out.println(ReversePolishNotation.calculate(fomula));
break;
}
}
}
打印结果
请输入式子:1 + ( ( 2 + 3 ) * 4 ) + ( 2.6 - 1 )
22.6
请输入式子:1 + ( ( 2 + 3 ) * 4 )
21.0

本文介绍了一种将中缀表达式转换为后缀表达式(逆波兰表达式)的方法,通过使用两个栈来实现,详细解释了具体步骤,并提供了计算表达式结果的代码实现。
240

被折叠的 条评论
为什么被折叠?



