数据结构与算法(四)——利用栈写一个简单的计算器

210 阅读2分钟

栈(Stack)

业务需求

给出一段含有加减乘除的字符串,计算其结果。

本例使用数组存储栈元素,也可采用链表。

  • 定义栈对象
class CalStack{
    int[] stack;
    int maxsize;
    int top=-1;

    public CalStack(int size) {
        this.maxsize = size;
        stack=new int[this.maxsize];
    }
}
  • 定义CalStack的基本方法
 public boolean isEmpty(){
        return top==-1;
    }

    public boolean isFull(){
        return top==maxsize-1;
    }

   //取栈元素但不弹栈
    public int peek(){
        return stack[top];
    }
    
    //压栈
     public void push(int num){

        if(!isFull()){
            stack[top+1]=num;
            top++;
        }else{
            System.out.println("栈满");
        }
    }

    //弹栈
    public int pop(){
        if(isEmpty()){
            throw new RuntimeException("栈空");
        }else{
            int temp=stack[top];
            top--;
            return temp;
        }
    }
    
    //定义操作符优先级
    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;
        switch (oper){
            case '+':
                res=num1+num2;
                break;
            case '-':
                res=num2-num1;
                break;
            case '*':
                res=num1*num2;
                break;
            case '/':
                res=num2/num1;
                break;
        }
        return res;
    }

重点内容

  • 字符的底层是int,两者ACSII码数值相差48,可以将操作符当做int来存储和比较。
  • 定义top变量指向栈顶元素。

遍历字符串

 String expression="3+2*6-2" ;
 int index=0;
 char ch=0;
 ch=expression.substring(index,index+1).charAt(0);

代码思路: 将字符串的每个字符分别存储在数栈和字符栈中。当字符栈中即将入栈的字符优先级小于栈顶操作符优先级则数栈弹出两个元素和字符栈栈顶元素做运算,将运算结果再压入数栈,否则操作符直接入栈。最后数栈和字符栈按顺序弹出运算得出结果。

       String expression="3+2*6-2" ;
       CalStack numStack=new CalStack(10);
       CalStack operStack=new CalStack(10);
       int index=0;
       int num1=0;
       int num2=0;
       int oper=0;
       int res=0;
       char ch=0;
          //遍历字符串进行压栈操作
          while(true){
              ch=expression.substring(index,index+1).charAt(0);
              if(operStack.isOper(ch)){
                  if(!operStack.isEmpty()){
                      if(operStack.priority(ch)<=operStack.priority(operStack.peek())){
                          num1=numStack.out();
                          num2=numStack.out();
                          oper=operStack.out();
                          res=numStack.cal(num1,num2,oper);
                          numStack.add(res);
                          operStack.add(ch);
                      }else{
                          operStack.add(ch);
                      }
                  }else{
                        operStack.add(ch);
                  }
              }else{
                  numStack.add(ch-48);
              }
              index++;
              if(index>=expression.length()){
                  break;
              }
          }
          //顺序运算
          while (!operStack.isEmpty()){
              num1=numStack.out();
              num2=numStack.out();
              oper=operStack.out();
              res=numStack.cal(num1,num2,oper);
              numStack.add(res);
          }
        System.out.println(res);
    }

以上代码存在的问题: 只能处理个位数的四则运算。

Tips: 可以在数字入栈之前查看字符串后一位是否为操作符,如果为数字则字符串自加直到下一位为操作符再入栈。

 String str="";
 str+=ch;
 //因为要访问index+1,需要考虑数组越界的问题,先判断index是不是字符串最后一位,如果是最后一位则直接入栈。
    if(index==expression.length()-1){
        numStack.add(Integer.parseInt(str));
        //每次压栈后要将str清零
        str="";
    }else{
        if(operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
            numStack.add(Integer.parseInt(str));
            str="";
        }
    }

源码参照github仓库链接