栈:先进后出的结构,像子弹上膛,Java中方法的调用以及递归调用都是栈的数据结构
1、中缀表达式转后缀表达式
计算机进行计算的时候一般都是通过栈的结构进行计算的,它不能像人一样识别中缀表达式(想4 + 5 * 6),他只能利用栈的结构进行转化计算,他先转化为后缀表达式(也叫做逆波兰数)。
==代码==
//中缀表达式转化为后缀表达式
public static Collection<String> midToSuff(Collection<String> midExpression){
//栈保存运算符
//队列保存后缀表达式
/*
1、读取到数的时候加入队列
2、读取到运算符的时候
- 如果栈为null,直接入栈
- 栈不为空时候,和栈顶元素进行比较
- 比较优先级
优先级高的时候,直接进栈
- 优先级低的时候,进行讨论
- 入栈元素不为右括号
- 排除栈顶为左括号的情况,如果为栈顶左括号直接入栈
- 如果栈顶不为左括号,优先级进行比较,如果栈顶元素的优先及大于要入栈的运算符,栈顶元素弹出,入队列。继续循环比较
- 入栈元素为右括号
- 栈内符号出栈,直到遇见左括号,右括号不入栈,切左括号不入队列
*/ Stack<String> operator = new Stack<>();
Queue<String> suff = new LinkedList<>();
midExpression.stream().forEach(o -> {
if (StrUtil.isNumeric(o)) {
suff.offer(o);
}else {
if (operator.isEmpty()) {
operator.push(o);
}else {
if (priorityOperator(o) > priorityOperator(operator.peek())){
operator.push(o);
}else {
if(priorityOperator(o) == -3){
while (priorityOperator(operator.peek()) != 3){
suff.offer(operator.pop());
}
operator.pop();
}else {
while (true){
if (operator.isEmpty() || priorityOperator(operator.peek()) == 3 || priorityOperator(operator.peek()) < priorityOperator(o)) {
operator.push(o);
break;
}else {
suff.offer(operator.pop());
}
}
}
}
}
}
});
while (!operator.isEmpty()) {
suff.offer(operator.pop());
}
return suff;
}
private static int priorityOperator(String c){
switch (c){
case "+":;
case "-":
return 1;
case "*":;
case "/":
return 2;
case "(":
return 3;
case ")":
return -3;
}
return 0;
}
- 定义栈,利用栈的结构保存运算符
- 读取中缀表达式,如果遇到数字直接添加到队列(或者集合)
- 遇到运算符分该下情况
- 当运算符栈为空时直接添加入栈
- 运算符栈不为空的时候,待入栈元素和栈顶元素做比较运算符的优先级
- 当待入栈运算符优先级高于栈顶运算,直接入栈
- 待入栈元素运算符优先级低于栈顶元素,先判断特殊情况
)的情况,如果待入栈元素是右括号,则运算符出栈,并进入队列,循环进行,直到栈顶元素为(的时候,退出循环,并把(弹出栈,但不进入队列。 - 如果不是特殊元素,及非
)且待入栈元素小于栈顶元素,此时栈顶元素出栈并进入队列,待入栈元素继续和栈顶元素进行比较,直到栈顶元素的运算级别小于等于待入栈元素或者栈为null或者栈顶元素为(的时候,待入栈元素入栈。
2、计算
通过读取后缀表达式,经过栈工具的操作进行计算
public static Number calc(Collection<String> suffExpression){
Stack<BigDecimal> stack = new Stack<>();
suffExpression.stream().forEach(o -> {
if (StrUtil.isNumeric(o)) {
stack.push(new BigDecimal(o));
}else {
stack.push(calcEnum(stack.pop(),stack.pop(),o));
}
});
return stack.peek();
}
- 读取后缀表达式,定义栈空间
- 读取到数字的时候入栈
- 读取到操作符的时候,弹出栈顶元素和次栈顶元素,并和操作符结合计算,并把结果入栈
- 重复操作,直到后缀表达式集合到末端。