使用栈完成表达式的计算思路:
先定义两个栈,一个栈存放操作数,另一个栈存放操作符号
1、通过一个index值(索引),来遍历表达式
2、如果index扫描到的是数字,就直接入数字栈
3、如果index扫描到的是一个符号,分如下情况:
3.1、如果当前的符号栈为空,就直接入栈
3.2、如果符号栈中有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop中取出两个数,再从符号栈中pop中取出一个数,进行运算,将得到的结果入数栈,然后将当前的操作符入符号栈
3.3、如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈
4、当表达式扫描完毕后,就顺序的从数栈和符号栈中华会馆pop出相应的数字和符号,并进行运算;
5、最后在数栈中只有一个数字,就是表达式的计算结果
例子:
计算 3+2*6-2 的结果
过程:
①先创建两个栈,一个数栈,用来存放数字,一个符号栈,用来存放操作符号
②数栈刚开始为空,index扫描到的是数字3,则3直接入数栈
③index继续扫描,扫描到的是 + 号,且符号栈为空,直接入符号栈
④index继续扫描,扫描到数字 2 ,则直接入数栈
⑤index继续扫描,扫描到的是 * 号,且它的优先级比符号栈中的 + 号要高,所以直接入符号栈
⑥index继续扫描,扫描到的是数字6,则直接入数栈
⑦index继续扫描,扫描到的是 - 号, 且它的优先级比符号栈中的 *号要低,所以 - 号先不入栈,而是从数栈中取出两个数字,取出的是6和2,且从符号栈中取出一个符号,取出的是 * 号,进行计算,得到结果12,再把它压入到数栈中,此时再把 - 号入符号栈;
⑧index继续扫描,扫描到的是数字2,则直接入数栈
⑨此时表达式已经扫描完毕,就需要顺序的从数栈和符号栈中pop出相应的数字和符号,进行运算;
此时数栈中的元素分别是2,12,3,符号栈中的元素分别是 - 和 +
⑩因为此时的表达式已经扫描完毕,所以要顺序地从数栈和符号栈中取出相应的数字和符号进行计算;
此时应该pop出数字 2 和 12 ,并且pop出运算符 -,这里需要注意的是, 2 和 12 进行剑法运算的时候,是==后pop出的元素对先pop出的元素进行运算 ==,也就是需要用 12 减去 2,得到的结果 10,再压入到数栈中;
11、最后,就是pop出数栈中的 10 和 3,并pop出符号栈中的 + 号,进行运算,3 + 10,得到结果13,此时符号栈已经为空,数栈中只剩下最后一个元素13,则 13 就是表达式的计算结果
代码实现如下:
public class Calculator {
public static void main(String[] args) {
//根据思路,完成表达式的计算
String expression = "30+20*6-2"; //如何处理多位数的问题
//创建两个栈,一个是数栈,一个是符号栈
ArrayStack1 numStack = new ArrayStack1(10);
ArrayStack1 operStack = new ArrayStack1(10);
//定义需要的相关变量
int index = 0; //用于扫描
int num1 = 0;
int num2 = 0;
int oper = 0;
int res = 0;
char ch = ' '; //将每次扫描得到的char保存到ch中
String keepNum = ""; //用于拼接多位数
//开始用while循环的扫描expression
while (true) {
//依 次得到expression的每一个字符
//字符串中有一个函数是substring方法,两个参数分别是开始位置和结束位置,这里就是获取了一个字符的字符串
//substring获取到的是字符串,但是ch是char类型,只能接收一个字符,所以用charAt来获得substring字符串中的其中一个字符
ch = expression.substring(index, index + 1).charAt(0);
//判断ch是什么,然后做相应的处理
if (operStack.isOper(ch)) { //如果是运算符
//判断当前的符号栈是否为空
if (!operStack.isEmpty()) {
//如果符号栈中有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中取出两个数
//并在符号栈中取出一个符号,进行运算,将得到的结果,入数栈,然后将当前的操作符入符号栈
if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
//把运算的结果加入到数栈中
numStack.push(res);
operStack.push(ch);
}
else { //如果当前的操作符的优先级大于栈中的操作符,就直接入栈
operStack.push(ch);
}
}
else { //如果符号栈为空,直接入栈
operStack.push(ch);
}
}
else { //如果是数字,直接入数栈
//分析思路:
//1.当处理多位数时,不能发现是一个数的时候就直接入栈,因为它可能是多位数,
//2.在处理数时,需要向expression的表达式的index后再看一位,如果是数就进行扫描,如果是符号才入栈
//3.因此需要定义一个字符串变量,用于拼接
keepNum += ch;
//如果ch已经是expression的最后一位,就直接入数栈
if (index == expression.length() - 1) {
numStack.push(Integer.parseInt(keepNum));
}
else {
//判断下一个字符是不是数字,如果是数字,就继续扫描,如果是运算符,就入数栈
//注意是往后看一位,不是index++
if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))) {
//如果后一位是运算符,则入栈,但是keepNum是一个字符串,需要把它转换成整型才可以,所以可以调用Integer.parseInt方法,把keepNum转换成整型
numStack.push(Integer.parseInt(keepNum));
//重要!!!,keepNum需要清空
keepNum = "";
}
}
}
//让index + 1,并判断是否扫描到了expression的最后
index++;
if (index >= expression.length()) {
break;
}
}
//当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数字和符号,并运行
while (true) {
//如果符号栈为空,则计算已经结束,数栈中只有一个数字【结果】
if (operStack.isEmpty()) {
break;
}
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
numStack.push(res); //入栈
}
//将数栈中最后的数字pop出,就是表达式的计算结果
int res2 = numStack.pop();
System.out.printf("表达式 %s = %d\n", expression, res2);
}
}
//先创建一个栈,这里用数组来模拟栈的实现
class ArrayStack1 {
private int maxSize; //栈的大小
private int[] stack1; //数组,数组模拟战,数据就存放在该数组当中
private int top = -1; //top表示栈顶,初始化为-1
//构造器
public ArrayStack1(int maxSize) {
this.maxSize = maxSize;
stack1 = new int[this.maxSize];
}
//栈满
public boolean isFull() {
return top == maxSize - 1;
}
//栈空
public boolean isEmpty() {
return top == -1;
}
//入栈
public void push(int value) {
if (isFull()) {
System.out.println("栈满,无法进行入栈操作");
return;
}
top++;
stack1[top] = value;
}
//出栈
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据");
}
int value = stack1[top];
top--;
return value;
}
//返回当前的栈顶的值,但不出栈
public int peek() {
return stack1[top];
}
//遍历栈
public void list() {
if (isEmpty()) {
System.out.println("栈空,无法进行遍历操作");
return;
}
for (int i = top; i >= 0; i--) {
System.out.printf("%d\t", stack1[i]);
}
System.out.println();
}
//返回运算符的优先级,优先级的顺序是由用户来决定的,优先级使用数字来表示
//数字越大,表示优先级越高
public int priority(int oper) {
if (oper == '*' || oper == '/') {
return 1;
} else if (oper == '+' || oper == '-') {
return 0;
} else {
return -1; //假定目前的表达式中只含有 +,-,*,/
}
}
//判断是否是一个运算符
public boolean isOper(char val) {
return val == '+' || val == '-' || val == '*' || val == '/';
}
//计算方法
public int cal(int num1, int num2, int oper) {
int res = 0; //res用于存放计算的结果
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;
}
}