文章目录

  • 前言
  • 一、用栈实现综合计算器的思路
  • 二、代码实现
  • 2.代码中的问题



前言

学习打卡:栈的应用


提示:以下是本篇文章正文内容,下面案例可供参考

一、用栈实现综合计算器的思路

java 栈 统计大小 java利用栈实现计算器_数据结构

二、代码实现

代码如下(示例):

package DataStructures;

import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        //给出一个表达式进行测试
        String expression = "700+2*6-4";
        //创建两个栈,数栈,符号栈
        Stack2 numStack = new Stack2(10);
        Stack2 operStack = new Stack2(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的每一个字符
            ch = expression.substring(index,index+1).charAt(0);//substring返回的是字符串(String)还要转为字符类
            //判断ch是什么,做相应的处理
            if(operStack.isOper(ch)){//如果是一个运算符的话
                //判断当前的符号栈是否为空
                if(!operStack.isEmpty()){
                    //不为空,就判断优先级,如果当前的符号大于栈顶的符号优先级,直接存入
                    //当前小于或则等于栈顶的(最多只留下一个高级符在栈里),那就先把高级符号给算了,(数栈弹出两个,符号栈弹出一个,计算后结果存入数栈,再把当前符号存入)
                    if(operStack.priority(ch)<=operStack.priority(operStack.peek())){
                        //明明方法指定的参数是int类型的,为什么char也行??因为char对应有int的数字(Ascall码)
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1,num2,oper);
                        //把结果入数栈
                        numStack.push(res);
                        //把当前运算符号入栈
                        operStack.push(ch);//规定char类型的参数是不能接受int的,但是int可以接受char
                    }else{
                        //如果栈顶运算符大于当前运算符,直接入栈
                        operStack.push(ch);
                    }
                }else{
                    //如果为空直接入栈
                    operStack.push(ch);
                }
            }else{//如果是数字直接入栈(但是只能扫描到一位数字不能扫描多位)
                    //当处理多位数时,不能发现就立即入栈,因为可能是多位
                    //在扫描时,如果是数字,再后看一位,如果是数就继续扫描,是符号就入数栈
                    //定义一个变量字符串,用于拼接
                keepNum += ch;
                //如果ch已经是表达式最后一位了,就直接入栈,后面不用探了
                if(index == expression.length()-1){
                    numStack.push(Integer.parseInt(keepNum));//拼接是字符串要转化成数字
                }else{
                    //numStack.push(ch-48);//对于本来的数字变成char类在Ascall码里面是等于原来的数字加上48的,char在数字上要大一点
                    //判断下一个字符是不是数字,如果是数字,就继续扫描,是运算符,则入数栈
                    //看后一位,不是index
                    if(operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
                        //如果最后一位是运算符就可以入栈了keepnum="1"或则“123”要转化
                        numStack.push(Integer.parseInt(keepNum));
                        //因为要进行下一次拼接,所以要清空keepnum
                        keepNum = "";//如果是数字的话,不入栈,他会在下一个循环拼接上
                    }
                }
            }
            //然index+1;并判断是否扫描到最后
            index++;
            if(index>=expression.length()){//index最小的索引是从0开始,当加到length-1时就已经全部扫完了,再加一的话就是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);
        }
        System.out.printf("表达式%s = %d",expression,numStack.pop());//%s就是字符串,%c那就是字符喽
    }
}

class Stack2 {//在主类里定义类用static
    private int maxSize;//栈的大小
    private int[] stack;//数组,数组模拟栈,数据被存放在数组
    private int top = -1;//表示栈顶,初始化为-1

    //构造器
    public Stack2(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[maxSize];//数组要有初始化
    }

    //返回栈顶元素,并不是pop出来
    public int peek(){
        return stack[top];//栈顶指针没动,就不算pop
    }
    //栈满
    public boolean isFill() {
        return top == maxSize - 1;
    }

    //栈空
    public boolean isEmpty() {
        return top == -1;
    }

    //入栈
    public void push(int value) {
        //先判断是否满了
        if (isFill()) {
            System.out.println("栈满,无法加入数据");
        }
        top++;//初始值为-1;要先动
        stack[top] = value;
    }

    //出栈,将栈顶数据返回
    public int pop() {
        //判断是否为空
        if (isEmpty()) {
            throw new RuntimeException("栈空,没有数据");
        }
        int value = stack[top];
        top--;//栈顶指针下移了,相当于pop
        return value;
    }

    //显示栈,遍历,从栈顶遍历
    public void list() {
        //判断是否为空
        if (isEmpty()) {
            System.out.println("栈空,没有数据");
        }
        for (int i = top; i >= 0; i--) {
            System.out.printf("stack[%d]=%d\n", i, stack[i]);
        }
    }
    //返回运算符的优先级,优先级使用数字表示,数字越大优先级越高
    public int priority(int oper){//int可以接受char Ascall码里面有这个字符的对应数字 但是字符串是没有的
        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;
                //return res;
                break;
            case '-':
                res = num2-num1;//注意顺序,谁在前面
                //return res;
                break;
            case '*':
                res = num1*num2;
                //return res;
                break;
            case '/':
                res = num2/num1;//后面弹出来的在表达式中是前面的一个位置
                //return res;
                break;
            default:
                break;//不规则直接退出
        }
        return res;//这就减少了代码量重复代码。。。
    }
}

2.代码中的问题

  1. 利用先前就建立的栈原型:出栈,入栈,显示栈顶元素(后根据需求加的)等一些功能,进行实现需求时就可以直接引用里面的相关方法很方便(但还是要打那么多代码。。。麻烦)
  2. 里面的逻辑关系很杂,一不小心就可能弄错
  3. index扫描表达式时,对于数字只能扫描一位就入栈了,不满住多位运算,利用字符串拼接,扫到数字时先用空字符串拼接,(先判断此数字是否到达表达式的最后,如果到最后就不用扫,直接入栈)再扫描此数字的下一位,如果是符号就直接转化后入数栈,如果还是数字的话,就不会入栈,等到下一次循环时,就会被keepnum拼接上变成“12”之类的,又会基于这个数字扫描下一个,如果是运算符号,那就转化后入数栈。这样就实现了多位数字的入栈