8、栈-利用栈实现简单的计算器
来源:https://www.bilibili.com/video/BV1B4411H76f?p=33
一、思路
1、拿到一个表达式,当前默认只包含 加减乘除 。利用一个index参数遍历整个表达式,得到每一个数值和运算符。
2、设定两个栈,一个是存储数据的栈【数据栈】,另一个用来存储符号【符号栈】
3、如果当前遍历表达式得到的是一个数据,直接入【数据栈】
4、如果当前遍历表达式得到的是一个符号,分析一下【符号栈】的情况
4.1、【符号栈】为空,直接入栈
4.2、【符号栈】有操作符,比较当前符号与【符号栈】顶部符号的优先级,当前符号优先级比较低时,从【数据栈】pop两个数据,从【符号栈】pop一个符号,进行运算,得到的结果加入到【数据栈】,之后将当前遍历到的符号加入到【符号栈】。
4.3、当前遍历到的符号优先级比较高时,当前符号直接入【符号栈】
5、扫描完成,顺序从【数据栈】和【符号栈】pop出内容进行运算,得到结果。
二、实现
1、首先要在原有的数组模拟栈的类中加入一个数据计算的方法。注意:出栈是先入的后出,所以减法和除法要num2在前num1在后。
1 /** 2 * 计算 3 * @param num1 第一个数据 4 * @param num2 第二个数据 5 * @param oper 计算符号 6 * @return 7 */ 8 public int cal(int num1, int num2, int oper){ 9 int res = 0; 10 switch (oper){ 11 case '+': 12 res = num1 + num2; 13 break; 14 case '-': 15 res = num2 - num1; 16 break; 17 case '*': 18 res = num1 * num2; 19 case '/': 20 res = num2 / num1; 21 } 22 return res; 23 }
测试
1 System.out.println(numStack.cal(1, 2, '+')); 2 System.out.println(numStack.cal(1, 2, '-')); 3 System.out.println(numStack.cal(1, 2, '*')); 4 System.out.println(numStack.cal(1, 2, '/'));
结果
3 1 2 2
这里犯了一个错误,开始执行的时候结果错才发现的,漏掉了break,要记住
1 case '*': 2 res = num1 * num2; 3 break; 4 case '/': 5 res = num2 / num1; 6 break;
2、因为需要比较符号的优先级,而且当遍历到的计算符号优先级高时直接入栈,所以之前的符号不能出栈,只能获取,需要一个获取栈顶内容的方法,还需要一个获取符号优先级的方法
1 //获取栈顶的元素 2 public int peek(){ 3 return arr[top]; 4 } 5 6 //获取当前符号的优先级,返回值越大优先级越高 7 public int properties(int oper){ 8 if(oper == '+' || oper == '-'){ 9 return 1; 10 }else if (oper == '*' || oper == '/'){ 11 return 2; 12 }else { 13 return -1;//没有这个符号 14 } 15 }
3、遍历表达式的时候,还需要一个判断当前是数据还是计算符号的方法,因为不能保证这个数据是几位的。
1 public boolean isOper(int val){ 2 return val == '+' || val == '-' || val == '*' || val == '/'; 3 }
4、在主程序进行计算
1 public static void main(String[] args) { 2 ArrayStack2 numStack = new ArrayStack2(10);//数据栈 3 ArrayStack2 operStack = new ArrayStack2(10);//符号栈 4 String expression = "30+2*6-2";//表达式 5 6 int index = 0; 7 int num1 = 0; 8 int num2 = 0; 9 int oper = 0; 10 char ch = ' ';//从表达式扫描出的内容 11 String keepNum = "";//如果是多位数,用于拼接 12 13 int res = 0; 14 15 while (true){ 16 //取出位于index的内容 17 ch = expression.substring(index,index + 1).charAt(0); 18 19 if(operStack.isOper(ch)){ 20 //如果是一个符号的话 21 if(operStack.isEmpty()){ 22 //如果【符号栈】为空,符号入栈 23 operStack.push(ch); 24 }else { 25 //【符号栈】不为空,看下优先级 26 if(operStack.properties(ch) > operStack.properties(operStack.peek())){ 27 //当前的符号优先级大于【符号栈】顶部符号的优先级,直接入栈 28 operStack.push(ch); 29 }else { 30 //当前的符号优先级小于等于【符号栈】顶部符号的优先级 31 num1 = numStack.pop(); 32 num2 = numStack.pop(); 33 oper = operStack.pop(); 34 res = numStack.cal(num1,num2,oper); 35 numStack.push(res); 36 operStack.push(ch); 37 } 38 } 39 }else { 40 //如果是一个数据的话,看一下,下一个是不是还是数据 41 keepNum += ch;//先把当前的数据加入到keepNum 42 if(index == expression.length() - 1){ 43 //已经走到最后一个位置了,下面没有东西了 44 numStack.push(Integer.parseInt(keepNum)); 45 }else { 46 if (operStack.isOper(expression.substring(index + 1,index + 2).charAt(0))){ 47 //下面是一个符号,需要把当前的数据直接加入栈,然后清空keepNum 48 numStack.push(Integer.parseInt(keepNum)); 49 keepNum = ""; 50 } 51 } 52 } 53 //保证循环运行下去 54 index++; 55 //循环结束的条件,index从0开始,等于就相当于没有内容了 56 if (index >= expression.length()){ 57 break; 58 } 59 } 60 61 //全部入栈之后,将栈内的元素依次计算 62 while (true){ 63 if (operStack.isEmpty()){ 64 break; 65 }else { 66 num1 = numStack.pop(); 67 num2 = numStack.pop(); 68 oper = operStack.pop(); 69 res = numStack.cal(num1,num2,oper); 70 numStack.push(res); 71 } 72 } 73 System.out.println("计算结果为:"+res); 74 75 76 }
结果
计算结果为:40