• 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
  • 相关阅读:
    Java开发中的23种设计模式详解(转)
    主表和从表
    MyBatis开发中解决返回字段不全的问题
    个人常用配置文件解析
    SpringMVC+MyBatis开发中指定callSettersOnNulls,可解决返回字段不全的问题
    mybatis之sql执行有数据但返回结果为null
    Hadoop window win10 基础环境搭建(2.8.1)
    什么水平算精通C++ Builder?
    Delphi中取得汉字的首字母(十分巧妙)
    全部的Windows消息对应值
  • 原文地址:https://www.cnblogs.com/zhao-xin/p/13143333.html
Copyright © 2020-2023  润新知