1.中缀表达式转后缀表达式
在计算普通的四则运算时,比如 1+(2+3*4-5)+6 该表达式即为中缀表达式,但对于计算机来说采用中缀表达式计算并不友好。所以需要将中缀表达式转换为对于计算机而言更容易计算的后缀表达式。
转换方法:
1. 创建一个栈 s1 和一个列表 s2。
2. 将中缀表达式从左至右依次遍历。(此后将遍历到的字符称为 s)
3. 当栈 s1 为空时,直接将 s 压入栈。
4. s 为数字时便将该数字添加至列表 s2 中;s 为 “(” 时将 s 压入栈 s1。
5. s 为运算符时,若 s1 栈顶为 “(” 则直接将s压入栈;反之,需要判断该运算符与 s1 栈顶运算符的优先级,若优先级大于栈顶运算符,则直接将 s 压入栈,若优先级小于或等于栈顶运算符,需要将栈顶运算符弹出并添加至 s2 列表中。
6. 步骤5结束后若 s 的优先级仍小于或等于栈顶运算符优先级,则重复步骤5。
7. s 为 “)” 时,将 s1 栈顶元素依次弹出并存入列表 s2 中,直到 s1 栈顶元素是 “(” 。然后将在栈顶的 “(” 也弹出。
8. 遍历结束后,将 s1 栈中的元素依次弹出并添加至 s2 列表中。最后把 s2 列表顺序输出即得到后缀表达式。
代码实现:
//参数zhong为中缀表达式列表
public static List<String> zhongToHou(List<String> zhong) {
//创建栈s1和列表s2
Stack<String> s1 = new Stack<>();
List<String > s2 = new ArrayList<>();
String s;
for (int i = 0; i < zhong.size();) {
s = zhong.get(i);
//为数字时直接压栈并将索引i向后移动
if (s.matches("\\d+")) {
s2.add(s);
i++;
} else if (s.equals("(")) {
//为左括号时直接压栈并将索引i向后移动
s1.push(s);
i++;
} else if (s.equals(")")) {
//为右括号时依次弹栈并存入列表s2,直到栈顶为左括号
while (!s1.peek().equals("(")) {
s2.add(s1.pop());
}
//将栈顶的左括号弹出
s1.pop();
//索引向后移动
i++;
} else {
//当栈为空或者栈顶为 “(” 或运算符优先级大于栈顶运算符的优先级时直接压栈,并将索引向后移动。(此处priorty()优先级判断的方法很简单自行编写)
if (s1.empty() || s1.peek().equals("(") || priorty(s.charAt(0)) > priorty(s1.peek().charAt(0))) {
s1.push(s);
i++;
} else {
//当小于或等于栈顶运算符优先级时,将栈顶运算符弹出并存入列表s2中,此时索引不移动,以便让该运算符继续判断。
s2.add(s1.pop());
}
}
}
//将栈中剩余元素依次弹出并存入列表s2
while (!s1.empty()) {
s2.add(s1.pop());
}
//最后返回后缀表达式列表s2
return s2;
}
2.后缀表达式的计算
以开头给出的例子 1+(2+3*4-5)+6, 该中缀表达式的后缀表达式为: “1 2 3 4 * + 5 - + 6 +”
计算方式:
- 建立一个空栈 stack。
- 遍历后缀表达式(此后将遍历到的字符称为 s)。
- 当 s 为数字时,将其压入 stack 栈。
- 当 s 为运算符时,弹出 stack 栈顶和次栈顶的两个数字,并将两个数字按照运算符 s 进行运算,然后将运算结果压入stack 栈 。
- 当遍历结束时,存留在栈 stack 中还剩下唯一一个数字,该数字便是运算结果。
代码实现:
/**
* 通过传入后缀表达式列表进行计算
* @param list
* @return
*/
public static String culculate(List<String> list) {
Stack<String> stack = new Stack<>();
int result = 0;
for (String s : list) {
//当s为数字时直接压栈
if (s.matches("\\d+")) {
stack.push(s);
} else {
//为运算符时弹出栈顶和次栈顶并进行运算
String num2 = stack.pop();
String num1 = stack.pop();
switch (s) {
case "+":
result = Integer.parseInt(num1) + Integer.parseInt(num2);
break;
case "-":
result = Integer.parseInt(num1) - Integer.parseInt(num2);
break;
case "*":
result = Integer.parseInt(num1) * Integer.parseInt(num2);
break;
case "/":
result = Integer.parseInt(num1) / Integer.parseInt(num2);
break;
default:
throw new RuntimeException("含有非法字符");
}
//将运算结果压入栈
stack.push(String.valueOf(result));
}
}
//返回运算结果
return stack.pop();
}