对于计算一个表达式1+2*3/4,该如何处理,如何处理不同的操作符的优先级
栈的特点和队列相反,先进后出.
可以把队列类比于一个两头通透的通道,一端进入另一端拿出.
而栈是一个一头封闭的通道,从一端压入一端拿出.
下面是基于数组的实现,
import java.util.List;
/**
* @Project: StackCalculator
* @Description: 一个简单的基于数组的栈实现
* @Creator: sunwei
* @CreatDate: 2020/7/4
* @Modifier:
*/
public class ArrayStack<T> {
//栈顶指针
private int top = -1;
//数据
private Object[] data;
//栈大小
private int maxSize;
/**
* <p>Your Description about this Method</p>
* @param maxSize 栈大小
* @version 0.1.0
* @return
* @author SunWei
* @date 2020/7/4 16:56
* @since 0.1.0
*/
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
data = new Object[maxSize];
top = -1;
}
/**
* <p>入栈</p>
* @param obj 要压入的数据
* @version 0.1.0
* @return void
* @author SunWei
* @date 2020/7/4 16:56
* @since 0.1.0
*/
public void push(T obj) throws Exception {
if (isFull()) {
throw new Exception("stack is full");
}
top++;
data[top] = obj;
}
/**
* <p>出栈</p>
* @param
* @version 0.1.0
* @return T
* @author SunWei
* @date 2020/7/4 16:57
* @since 0.1.0
*/
public T pop() throws Exception {
if (isEmpty()) {
throw new Exception("stack is empty");
}
T value = (T)data[top--];
return value;
}
/**
* <p>判断是否为空</p>
* @param
* @version 0.1.0
* @return boolean
* @author SunWei
* @date 2020/7/4 16:57
* @since 0.1.0
*/
public boolean isEmpty() {
return top == -1;
}
/**
* <p>判断是否已满</p>
* @param
* @version 0.1.0
* @return boolean
* @author SunWei
* @date 2020/7/4 16:57
* @since 0.1.0
*/
public boolean isFull() {
return top == maxSize - 1;
}
/**
* <p>获取栈的长度</p>
* @param
* @version 0.1.0
* @return int
* @author SunWei
* @date 2020/7/4 16:57
* @since 0.1.0
*/
public int length() {
return top + 1;
}
/**
* <p>获取栈顶元素</p>
* @param
* @version 0.1.0
* @return T
* @author SunWei
* @date 2020/7/4 16:58
* @since 0.1.0
*/
public T get() {
return isEmpty() ? null : (T)data[top];
}
}
利用栈的特点,实现一个带有优先级的计算器,
栈的使用场景相当多,最经典的莫过于jvm中的虚拟机栈,一个方法的调用执行对于jvm而言就是一个栈帧从入栈到出栈的过程.
import cn.wei.ds.ArrayStack;
/**
* @Author :sunwei
* @Description:
* @Date create in 15:25 2020/7/4
* @Modified by:
*/
public class StackCalculator {
private ArrayStack<Double> numberStack;
private ArrayStack<String> operatonStack;
/**
* <p>一个有优先级的简单数字运算实现</p>
* @param equation 计算式
* @version 0.1.0
* @return double
* @author SunWei
* @date 2020/7/4 16:59
* @since 0.1.0
*/
public double calculate(String equation) throws Exception {
if (equation == null || equation.length() < 1) {
throw new Exception("equation is invalid");
}
numberStack = new ArrayStack(equation.length());
operatonStack = new ArrayStack(equation.length());
int aheadFlag = 0;
//将算式拆分成一个一个的字符
String[] arr = equation.split("|");
//将夹在低优先级中的高优先级运算全部做完
for (int i = 0; i < arr.length; i++) {
//操作符和数字个数关系不正确,算式不正确
if (numberStack.length() < operatonStack.length()) {
throw new Exception("equation is invalid");
}
if (priority(arr[i]) == -1) {//为数字
double value = Double.valueOf(arr[i]);
if (aheadFlag == 0 && numberStack.get() != null) {//前一个字符也是数字,做组合
double numer = numberStack.pop();
value = numer * 10 + Double.valueOf(arr[i]);
}
numberStack.push(value);
aheadFlag = 0;
} else {
if (aheadFlag == 1) {//前一个字符是运算符,这里抛出错误,+-10这种的暂时认为错误
throw new Exception("equation is invalid");
}
String obj = operatonStack.get();
if (obj == null) {//目前没有运算符,直接入栈
operatonStack.push(arr[i]);
} else if (priority(obj) > priority(arr[i])) {//当前运算符的优先级比上一个运算符低,需要做完上一个运算
String operation = operatonStack.pop();
double num1 = numberStack.pop();
double num2 = numberStack.pop();
double result = computer(num1, num2, operation);
numberStack.push(result);
operatonStack.push(arr[i]);
}else{//当前运算符的优先级比上一个运算符高或者相等,直接入栈
operatonStack.push(arr[i]);
}
aheadFlag = 1;
}
}
//运算优先级分割的运算,最终只留下了一个值就是最终结果
while(true){
if(numberStack.length()==1){
break;
}
Double num1 = numberStack.pop();
Double num2 = numberStack.pop();
String operation = operatonStack.pop();
double result = computer(num1, num2, operation);
numberStack.push(result);
}
return numberStack.get();
}
/**
* <p>判断是否为运算符</p>
* @param oper oper
* @version 0.1.0
* @return boolean
* @author SunWei
* @date 2020/7/4 16:59
* @since 0.1.0
*/
public boolean isOperation(String oper) {
return priority(oper) != -1;
}
/**
* <p>获取运算符优先级</p>
* @param oper oper
* @version 0.1.0
* @return int
* @author SunWei
* @date 2020/7/4 17:00
* @since 0.1.0
*/
public int priority(String oper) {
if ("+".equals(oper) || "-".equals(oper)) {
return 0;
} else if ("*".equals(oper) || "/".equals(oper)) {
return 1;
} else {
return -1;
}
}
/**
* <p>数字运算</p>
* @param num1 num1
* @param num2 num2
* @param operation operation
* @version 0.1.0
* @return double
* @author SunWei
* @date 2020/7/4 17:00
* @since 0.1.0
*/
public double computer(double num1, double num2, String operation) throws Exception {
switch (operation) {
case "+":
return num2 + num1;
case "-":
return num2 - num1;
case "*":
return num2 * num1;
case "/":
return num2 / num1;
default:
throw new Exception("operation is invalid");
}
}
}