栈实现综合计算器
主要模拟的是利用栈的先进后出的特性实现中缀表达式的计算功能。
1.思路分析:
使用栈实现表达式计算的思路
- 首先需要一个index值来扫描遍历我们的表达式,提取出数据和操作符
- 如果是数据,则push进数据栈
- 如果是操作符,则push进操作符栈,其中需要考虑以下几种情况
3.1 如果发现当前的符号栈为 空,就直接入栈
3.2如果操作符栈有操作符,就进行比较。如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数,同时在从符号栈中pop出一个符号,进行运算,并且将得到结果push进数据栈,然后将当前的操作符入操作符栈; 如果当前的操作符的优先级大于栈中的操作符, 就直接入操作符栈。 - 当表达式扫描完毕,就顺序的从数据栈和操作符栈中pop出相应的数和符号,并计算。
- 最后在数据栈只有一个数字,就是表达式的结果。
2.代码实现:
1.创建栈对象的同时增加一些方法
2.方法主要包括:
- 判断栈满/栈空
- 出栈/入栈
- 遍历栈
- 返回运算符的优先级
- 判断是否为运算符
- 返回栈顶的运算符
- 计算方法
class ArrayStack2 {
private int maxSize;
private int top;
private int[] stack;
public ArrayStack2(int MaxSize) {
this.maxSize = MaxSize;
top = -1;
stack = new int[this.maxSize];
}
// 查看当前栈顶的操作符
public int peak() {
return stack[top];
}
// 判断栈满
public boolean isFull() {
return top == maxSize - 1;
}
// 判断栈空
public boolean isEmpty() {
return top == -1;
}
// 入栈-push
public void pushNum(int value) {
if (isFull()) {
System.out.println("栈满,无法入栈~");
} else {
top++;
stack[top] = value;
}
}
// 出栈-pop
public int popNum() {
if (isEmpty()) {
System.out.println("空栈,请存入数据~");
return 0;
} else {
int value = stack[top];
top--;
return value;
}
}
// 遍历栈
public void show() {
if (isEmpty()) {
System.out.println("空栈,无数据~");
} else {
for (int i = top; i >= 0; i--) {
System.out.printf("stack[%d] = %d", i, stack[i]);
System.out.println();
}
}
}
// 返回运算符的优先级
/**
*
* @param oper:用数字1和0来代表操作符的优先级
* @return
*/
public int priority(int oper) {
if (oper == '*' || oper == '/') {
return 1;
} else if (oper == '+' || oper == '-') {
return 0;
} else {
return -1;
}
}
// 判断是不是运算符
public boolean isOper(int oper) {
return oper == '+' || oper == '-' || oper == '*' || oper == '/';
}
// 计算方法
public int cal(int num1, int num2, int oper) {
int res = 0;// 用于存储结果
switch (oper) {
case '+':
res = num1 + num2;
break;
case '-':
res = num2 - num1;
break;
case '*':
res = num1 * num2;
break;
case '/':
res = num2 / num1;
break;
default:
break;
}
return res;
}
}
3.主函数部分代码的实现主要包括了两大部分:
- 表达式的遍历以及数据和操作符的入栈操作
- 数据和操作符的出栈与计算
public class Calculator {
public static void main(String[] args) {
String expression = "3+2*6-2";// 表达式
// 创建两个栈
ArrayStack2 numStack = new ArrayStack2(10);// 用于存放数字
ArrayStack2 operStack = new ArrayStack2(10);// 用于存放操作符
// 初始化相关变量
int index = 0;// 用于扫描表达式
int num1 = 0;
int num2 = 0;
int oper = 0;
int res = 0;
// 保存每次扫描得到的ch
char ch = ' ';
// 1.首先,扫描表达式expression
while (true) {
// 依次得到每一个字符
ch = expression.substring(index, index + 1).charAt(0);
// 判断ch是数字还是操作符,然后做相应的操作
if (operStack.isOper(ch)) {
// 如果是操作符,两种情况:1.operStack内有操作符,判断优先级2.没有操作符,直接入栈
// 没有操作符,直接入栈
if (operStack.isEmpty()) {
operStack.pushNum(ch);
} else {
// 如果栈顶有操作符,两种思路:
// 1.如果优先级ch > 栈顶的,直接入栈
// 2.如果优先级ch < 栈顶的,先把栈顶的取出来,并且从数据栈中取数做运算,然后分别把结果和ch再入栈到对应的栈中
if (operStack.priority(ch) <= operStack.priority(operStack.peak())) {
// 1.取出数据和操作符
num1 = numStack.popNum();
num2 = numStack.popNum();
oper = operStack.popNum();
// 2.做运算
res = numStack.cal(num1, num2, oper);
// 3.对应的数据和操作符入栈
numStack.pushNum(res);
operStack.pushNum(ch);
} else {
operStack.pushNum(ch);
}
}
} else {
// 如果是数字。直接入栈——numStack
numStack.pushNum(ch - 48);// 此时因为是字符的格式,在Ascii码表中,数字和对应的字符格式相差48
}
index++;
if(index >= expression.length()){
break;
}
}
//2.扫描完毕后,顺序的取出数据和操作符进行运算
while(true){
num1 = numStack.popNum();
num2 = numStack.popNum();
oper = operStack.popNum();
res = numStack.cal(num1, num2, oper);
numStack.pushNum(res);
if(operStack.isEmpty()){//此时,操作符没有,数据栈中只有一个数值就是最终结果
break;
}
}
//pop出数据栈中的最终结果
res = numStack.popNum();
System.out.println("表达式的最终结果为: " + res);
}
}
3.缺陷:
这个版本的中缀表达式的计算方法只适合一位数的数字进行加减乘除的计算,后期还需要进行改进,通过字符串拼接的方式实现多位数的计算,同时还需要拓展其他运算方法,比如乘法,开根等。以及考虑到空白的问题,需要使用到去白的方法,如trim,replace,strip等。