中缀表达式:
表达式中操作符位于操作符中间
,如:(3+4)*5-6,上述通过栈实现的即中缀表达式计算器。
前缀表达式(
波兰表达式
):表达式中运算符在操作数前面
,计算机在进行计算时从右往左
依次扫描,遇到操作数压入操作数栈,遇到操作符弹出操作数栈栈顶的两个元素进行元素,并将其结果压入操作数栈继续扫描。最终得到计算结果。如:(3+4)*5-6 =>
"- 6 * 5 + 4 3"
后缀表达式(
逆波兰表达式,更适合计算机的运行
):表达式中运算符在操作数后面
,计算机在进行计算时从左往右
依次扫描,遇到操作数压入操作数栈,遇到操作符弹出操作数栈栈顶的两个元素进行元素,并将其结果压入操作数栈继续扫描。最终得到计算结果。如:(3+4)*5-6 =>
"3 4 + 5 * 6 -"
package 栈;
import java.util.Stack;
/**
* @author lyq on 2019-12-24 9:53 上午
* @desc 栈实现表达式(只含+、-、*、"\")计算器
* 实现思路:
* 创建两个栈分别用于存放 操作数 和 操作符;
* 遍历表达式:
* - 如果遍历元素为数直接入操作数栈;
* - 如果遍历元素为操作符:
* - 如果当前操作符优先级小于等于操作数栈当前栈顶元素的优先级,则从操作数栈中弹出两个操作数,并从符号栈弹出栈顶符号,根据弹出的操作符执行运算;
* 将结果入操作数栈;将当前操作符入操作数栈;
* - 如果当前操作符优先级大于操作数栈当前栈顶元素的优先级,则入操作数栈。
*/
public class StackCalculation {
private String expression = null;
public StackCalculation(String expression) {
this.expression = expression;
}
public void calculate(){
// 存放操作数的栈
Stack<Integer> numStack = new Stack();
// 存放操作符的栈
Stack<Character> operStack = new Stack<>();
char[] chars = expression.toCharArray();
// 用于处理
String tempMultiNum = "";
for (int i = 0;i < chars.length;i++) {
char c = chars[i];
if (!checkOperation(c)) {
tempMultiNum += c;
if (i == (chars.length-1)) {
numStack.push(Integer.parseInt(tempMultiNum));
}
continue;
} else {
if (tempMultiNum.length() > 0) {
numStack.push(Integer.parseInt(tempMultiNum));
tempMultiNum = "";
}
if (operStack.isEmpty()) {
operStack.push(c);
} else {
int cur = getPriority(c);
int top = getPriority(operStack.peek());
if (cur > top) {
operStack.push(c);
} else {
Integer numLater = numStack.pop();
Integer numBefore = numStack.pop();
Character topOper = operStack.pop();
int tempResult = cal(numBefore, numLater, topOper);
numStack.push(tempResult);
operStack.push(c);
}
}
}
}
while (!operStack.isEmpty()) {
Integer numLater = numStack.pop();
Integer numBefore = numStack.pop();
Character topOper = operStack.pop();
int tempResult = cal(numBefore, numLater, topOper);
numStack.push(tempResult);
}
System.out.println(numStack.pop());
}
/**
* 获取操作符的优先级
* @param c
* @return
*/
private int getPriority(char c){
if (c == '*' || c == '/') {
return 1;
} else if (c == '+' || c == '-') {
return 0;
} else {
return -1;
}
}
/**
* 检查遍历元素是否为操作符
* @param c
* @return
*/
private boolean checkOperation(char c) {
if (c == '+' || c == '-' || c == '*' || c == '/') {
return true;
}
return false;
}
/**
* 计算结果
* @param numBefore
* @param numLater
* @param oper
* @return
*/
private int cal(int numBefore, int numLater, char oper){
int tempResult = 0;
switch (oper) {
case '+':
tempResult = numLater + numBefore;
break;
case '-':
tempResult = numBefore - numLater;
break;
case '*':
tempResult = numBefore * numLater;
break;
case '/':
tempResult = numBefore/numLater;
break;
default:
break;
}
return tempResult;
}
public static void main(String[] args) {
StackCalculation stackCalculation = new StackCalculation("70*2+2-5*3-1");
stackCalculation.calculate();
}
}
1、初始化两个栈:运算符栈s1,存储中间结果的栈s2;
2、从左至右扫描中缀表达式;
3、扫描到操作数时压入s2;
4、扫描到运算符时:
(1)如果s1为空 或 s1栈顶为"(" 或 该运算符优先级高于s1栈顶运算符,则将该运算符入s1;
(2)否则将s1栈顶运算符压入s2,继续执行 4.(1) 的操作;
5、遇到括号时:
(1)如果是"(“直接压入s1;
(2)如果是”)“则依次弹出s1栈顶运算符压入s2,直到遇到”(",此时将这一对括号丢弃。
6、重复2-5,直到表达式最右边;
7、将s1中的剩余运算符依次弹出压入s2;
8、依次弹出s2中的元素并输出,结果的逆序即为该中缀表达式的后缀表达式
。
package 栈;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* @author lyq on 2019-12-24 2:05 下午
* @desc 中缀表达式转后缀表达式
*/
public class MidToSufferExp {
private String midExp;
public MidToSufferExp(String midExp) {
this.midExp = midExp;
}
/**
* 将中缀表达式转换为list
* @return
*/
public static List<String> convertToList(String midExp){
List<String> result = new ArrayList<>();
int i = 0;
char c;
// 多位数
String multiNum;
do {
c = midExp.charAt(i);
// 如果c不是数字
if (c < 48 || c > 57) {
result.add(String.valueOf(c));
i++;
} else {
multiNum = "";
while (i < midExp.length() && (c = midExp.charAt(i)) >= 48 && (c = midExp.charAt(i)) <= 57) {
multiNum += midExp.charAt(i);
i++;
}
result.add(multiNum);
}
} while (i < midExp.length());
return result;
}
public static Stack convertToSuffuxExp(List<String> list) {
Stack<String> s1 = new Stack<>();
Stack<String> s2 = new Stack<>();
for (String s : list) {
// 如果是数字直接入s2
if (s.matches("\\d+")) {
s2.push(s);
// 如果是"(" 直接入s1
} else if (s1.size() == 0 || s.equals("(")){
s1.push(s);
// 如果是")",则执行括号消除操作
} else if (s.equals(")")) {
while (!(s1.peek().equals("("))){
s2.add(s1.pop());
}
// 消除括号
s1.pop();
} else {
// 获取当前操作符的优先级
int cur = getPriority(s);
while ((!s1.isEmpty()) && (getPriority(s1.peek()) >= getPriority(s))) {
s2.push(s1.pop());
}
s1.push(s);
}
}
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
return s2;
}
private static int getPriority(String s){
if (s.equals("*") || s.equals("/")) {
return 1;
} else if (s.equals("+") || s.equals("-")) {
return 0;
} else {
return -1;
}
}
public static void main(String[] args) {
String midExp = "3+(70*2)-6/2+3";
List<String> list = convertToList(midExp);
Stack stack = convertToSuffuxExp(list);
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
}