栈中元素的顺序是先进后出,添加的元素总在栈顶,出栈也是先出栈顶,就像弹夹一样。中缀表达式是我们人计算表达式的方式例如 (2*3-2)*(3+3*3)我们总会括号优先,* / 优先于+ -
使用栈结构计算这个表达式的核心思想就是搞两个栈,一个存放数字,一个存放符号。
package com.dfsn.cloud.eureka;
public class Stack<T> {
private Object arr[];
private int top = -1;
public Stack(int capacity) {
arr = new Object[capacity];
}
public void push(T t) {
if (isFull()) {
throw new RuntimeException("栈已满,无法添加");
}
top++;
arr[top] = t;
}
public T pop() {
if (isEmpty()) {
throw new RuntimeException("栈为空,没有元素");
}
return (T) arr[top--];
}
public T peek() {
if (isEmpty()) {
throw new RuntimeException("栈为空,没有元素");
}
return (T) arr[top];
}
public boolean isEmpty() {
return top == -1;
}
public boolean isFull() {
return top == arr.length - 1;
}
public void show() {
for (int i = 0; i <= top; i++) {
System.out.println(arr[i]);
}
}
public int size() {
return top + 1;
}
}
View Code
package com.dfsn.cloud.eureka;
//中缀表达式
public class NifixExpression {
public int calculate(String expression) {
// 限定最多10个数字
Stack<Integer> numberStack = new Stack<>(10);
// 10个数字需要9个字符
Stack<String> symbolStack = new Stack<>(9);
for (int i = 0; i < expression.length(); i++) {
String current = expression.substring(i, i + 1);
// 是数字还是字符
int symbolOrNumber = symbolOrNumber(current);
// 是数字
if (symbolOrNumber == 0) {
// 如果是数字,则需要判断后边的是不是数字,防止多位数
int concatNumber = concatNumber(expression.substring(i));
// 如果是多位数循环需要跳过比如 123+2
// 取出123 后下一个要取 + 也就是 i+(123.length),但循环本身会自增1所以只能+123.length-1
i += (concatNumber + "").length() - 1;
// 入数字栈
numberStack.push(concatNumber);
} else {// 是符号
if (symbolStack.isEmpty()) {
// 符号栈没有符号,则入栈
symbolStack.push(current);
} else {
// 如果是左括号直接入栈
if (current.equals("(")) {
symbolStack.push(current);
continue;
}
// 如果是右括号,则需要每次弹出一个符号和两个数字做运算
// 直到碰到 ( 符号结束,并把 ( 出栈
if (current.equals(")")) {
while (true) {
if (symbolStack.peek().equals("(")) {
symbolStack.pop();
break;
} else {
int number2 = numberStack.pop();
int number1 = numberStack.pop();
String symbol = symbolStack.pop();
int result = operation(number1, number2, symbol);
numberStack.push(result);
}
}
continue;
}
// 拿出符号栈顶元素和当前符号对比,如果栈顶符号是 ( 则为0,因为它只有遇到)才有意义
String stackTop = symbolStack.peek();
int stackTopPriority = priority(stackTop);
int priority = priority(current);
// 如果当前符号优先级大于栈顶符号优先级,将当前符号添加到栈顶
if (priority > stackTopPriority) {
symbolStack.push(current);
} else {
// 如果当前符号优先级小于等于栈顶运算符优先级,则从符号栈顶弹出一个符号
// 从数字栈中弹出两个数字做运算 注意:栈顶元素在右
// 将结果入数字栈,最后将当前运算符入符号栈
int number2 = numberStack.pop();
int number1 = numberStack.pop();
String symbol = symbolStack.pop();
int result = operation(number1, number2, symbol);
numberStack.push(result);
symbolStack.push(current);
}
}
}
}
// 最后两个队列可能还有元素,则顺序弹出1个符号和两个数字做运算,并且将结果入数字栈
while (true) {
if (symbolStack.isEmpty()) {
break;
} else {
int number2 = numberStack.pop();
int number1 = numberStack.pop();
String symbol = symbolStack.pop();
int result = operation(number1, number2, symbol);
numberStack.push(result);
}
}
if (numberStack.size() != 1) {
throw new RuntimeException("运算异常");
} else {
return numberStack.pop();
}
}
// 返回1表示是运算符,返回0表示是数字
public int symbolOrNumber(String expression) {
if (expression.equals("+") || expression.equals("-") || expression.equals("*") || expression.equals("/")
|| expression.equals("(") || expression.equals(")")) {
return 1;
} else if (expression.equals("0") || expression.equals("1") || expression.equals("2") || expression.equals("3")
|| expression.equals("4") || expression.equals("5") || expression.equals("6") || expression.equals("7")
|| expression.equals("8") || expression.equals("9")) {
return 0;
} else {
throw new RuntimeException("不是数字也不是运算符");
}
}
// 返回运算符的等级 * / 高
public int priority(String symbol) {
if (symbol.equals("+") || symbol.equals("-")) {
return 1;
} else if (symbol.equals("*") || symbol.equals("/")) {
return 2;
} else if (symbol.equals("(")) {
return 0;
} else {
throw new RuntimeException("无法识别运算符");
}
}
// 获取字符串中第一个连续数字
public int concatNumber(String str) {
StringBuilder strNumber = new StringBuilder();
int index = 0;
while (true) {
if (index > str.length() - 1) {
break;
}
String ch = str.charAt(index) + "";
if (symbolOrNumber(ch) == 0) {
strNumber.append(ch);
index++;
} else {
break;
}
}
return Integer.parseInt(strNumber.toString());
}
// 做运算
public int operation(int number1, int number2, String symbol) {
switch (symbol) {
case "+":
return number1 + number2;
case "-":
return number1 - number2;
case "*":
return number1 * number2;
case "/":
return number1 / number2;
default:
throw new RuntimeException("运算符不正确");
}
}
}
View Code