• 【数据结构与算法】stack栈的介绍和实现、使用栈来实现中缀表达式求值


    1. 栈的介绍

    栈是一个先入后出的有序列表。允许插入(入栈push)和删除(出栈pop)的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)

    2. 栈的应用场景

    • 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中
    • 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中
    • 表达式(中缀表达式转后缀表达式)的转换与求值
    • 二叉树的遍历
    • 图形的深度优先(depth-first)搜索法

    3. 栈的实现

    使用数组模拟栈的使用,思路如下:

    1. 定义一个top来表示栈顶,初始化为-1
    2. 当有数据加入到栈时,top++,stack[top] = 数据
    3. 当从栈中取出数据时,int value = stack[top],top–

    实现如下

    import java.util.Scanner;
    
    public class ArrayStackDemo {
    
        public static void main(String[] args) {
            ArrayStack stack = new ArrayStack(3);
            String key = "";
            Scanner scanner = new Scanner(System.in);
            boolean loop = true;
    
            System.out.println("show: 表示显示栈");
            System.out.println("exit: 退出程序");
            System.out.println("push: 表示入栈");
            System.out.println("pop: 表示出栈");
            System.out.println("请输入你的选择:");
    
            while (loop) {
                key = scanner.next();
                switch (key) {
                    case "show":
                        stack.show();
                        break;
                    case "push":
                        System.out.println("请输入一个数");
                        int inputData = scanner.nextInt();
                        stack.push(inputData);
                        break;
                    case "pop":
                        try {
                            int outData = stack.pop();
                            System.out.printf("出栈的数据是%d\n", outData);
                        } catch (Exception e) {
                            System.out.println(e.getMessage());
                        }
                        break;
                    case "exit":
                        scanner.close();
                        loop = false;
                        System.out.println("程序退出");
                        break;
                    default:
                        break;
                }
            }
    
        }
    
    }
    
    // 用数组实现的栈
    class ArrayStack {
        // 栈的最大元素数量
        private int maxSize;
        private int[] stack;
        private int top = -1;
    
        public ArrayStack(int maxSize) {
            this.maxSize = maxSize;
            this.stack = new int[this.maxSize];
        }
    
        // 判断栈是否满了
        public boolean isFull() {
            return this.top == this.maxSize - 1;
        }
    
        // 判断栈是否空的
        public boolean isEmpty() {
            return this.top == -1;
        }
    
        // 入栈push
        public void push(int data) {
            // 先判断栈是否满了
            if (this.isFull()) {
                System.out.println("栈满了");
                return;
            }
            this.top++;
            this.stack[this.top] = data;
        }
    
        // 出栈pop
        public int pop() {
            // 先判断栈是否空
            if (this.isEmpty()) {
                throw new RuntimeException("栈空");
            }
            int data = this.stack[this.top];
            this.top--;
            return data;
        }
    
        // 从栈顶开始遍历显示栈的数据
        public void show() {
            if (this.isEmpty()) {
                System.out.println("栈空");
                return;
            }
            for (int i = this.top; i >= 0; i--) {
                System.out.printf("stack[%d]=%d\n", i, this.stack[i]);
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    运行程序,结果如下:

    show: 表示显示栈
    exit: 退出程序
    push: 表示入栈
    pop: 表示出栈
    请输入你的选择:
    push
    请输入一个数
    10
    show
    stack[0]=10
    pop
    出栈的数据是10
    exit
    程序退出
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4. 使用栈实现中缀表达式的转换与求值

    需求说明:输入一个字符串的表达式,如7*2*2-5+1-5+3-4,我们需要对这个字符串的表达式进行转换,然后求值。这个时候就可以使用栈解决。目前只处理+、-、*、/四个运算符,且字符串表达式不包含空格

    使用栈完成表达式计算的思路

    1. 通过一个index索引值,来遍历我们的表达式
    2. 如果是一个数字,就直接入数栈
    3. 如果是一个符号,情况如下:
      1. 如果当前的符号栈为空,就直接入符号栈
      2. 如果符号栈有运算符,就进行运算符优先级的比较。如果当前运算符的优先级小于或等于栈中的运算符,就需要从数栈中pop出两个数,再从符号栈中pop出一个符号,进行计算,再将计算的结果入数栈,然后将当前的运算符入符号栈;如果当前的运算符的优先级大于栈中的运算符,就直接入符号栈
    4. 当遍历完表达式,就顺序的从数栈和符号栈中pop出相应的数和符号,并进行计算
    5. 最后在数栈只有一个数字,就是表达式的结果

    实现如下

    public class StackExpressionCalculator {
    
        public static void main(String[] args) {
            String expression = "7*2*2-5+1-5+3-4";
    
            // 创建数栈和符号栈
            ArrayStack numberStack = new ArrayStack(10);
            ArrayStack operatorStack = new ArrayStack(10);
    
            // 定义计算的相关变量
            int index = 0;
            char tmpChar = ' ';    // 临时储存遍历的字符
            String concatNumber = "";   // 用于拼接多位数字
            int number1 = 0;
            int number2 = 0;
            char operator = ' ';
            int result = 0;
    
            while (true) {
                tmpChar = expression.charAt(index);
    
                if (operatorStack.isOperator(tmpChar)) {
                    if (!operatorStack.isEmpty()) {
                        // 数字0对应char为49
                        if (operatorStack.priority(tmpChar) <= operatorStack.priority((char) (operatorStack.getTop() + 48))) {
                            // 如果当前运算符的优先级,比符号栈顶的运算符优先级低,
                            // 则从数字栈取出两个数,从符号栈取出一个运算符进行计算,然后将计算结果入数字栈
                            // 最后将当前运算符入符号栈
                            number1 = numberStack.pop();
                            number2 = numberStack.pop();
                            operator = (char) (operatorStack.pop() + 48);
                            result = operatorStack.calculate(number1, number2, operator);
                            numberStack.push(result);
                            operatorStack.push(tmpChar - 48);
                        } else {
                            // 如果当前运算符的优先级,比符号栈顶的运算符优先级低, 就直接入符号栈
                            operatorStack.push(tmpChar - 48);
                        }
                    } else {
                        // 如果符号栈为空,则直接入符号栈
                        operatorStack.push(tmpChar - 48);
                    }
                } else {
                    // 如果是数字字符,则将数字字符拼接到数字字符串
                    concatNumber += tmpChar;
                    // 如果当前字符为最后一个字符,或下一个字符为符号字符,则将数字字符串入数字栈,然后数字字符串赋值为“”
                    if (index == (expression.length() - 1) || operatorStack.isOperator(expression.charAt(index + 1))) {
                        numberStack.push(Integer.parseInt(concatNumber));
                        concatNumber = "";
                    }
                }
                index++;
                // 字符串表达式遍历完成,进行退出
                if (index == expression.length()) {
                    break;
                }
            }
    
    
            // 当遍历完字符串表达式,就从数字栈和符号栈顺序取出值进行计算
            while (true) {
                // 如果符号栈为空,则表示计算结束
                if (operatorStack.isEmpty()) {
                    break;
                } else {
                    number1 = numberStack.pop();
                    number2 = numberStack.pop();
                    operator = (char) (operatorStack.pop() + 48);
                    result = operatorStack.calculate(number1, number2, operator);
                    numberStack.push(result);
                }
            }
            // 数栈中的最后一个数字,就是结果
            result = numberStack.pop();
            System.out.printf("表达式: %s = %d", expression, result);
    
        }
    }
    
    
    // 用数组实现的栈
    class ArrayStack {
        // 栈的最大元素数量
        private int maxSize;
        private int[] stack;
        private int top = -1;
    
        public ArrayStack(int maxSize) {
            this.maxSize = maxSize;
            this.stack = new int[this.maxSize];
        }
    
        // 判断栈是否满了
        public boolean isFull() {
            return this.top == this.maxSize - 1;
        }
    
        // 判断栈是否空的
        public boolean isEmpty() {
            return this.top == -1;
        }
    
        // 入栈push
        public void push(int data) {
            // 先判断栈是否满了
            if (this.isFull()) {
                System.out.println("栈满了");
                return;
            }
            this.top++;
            this.stack[this.top] = data;
        }
    
        // 出栈pop
        public int pop() {
            // 先判断栈是否空
            if (this.isEmpty()) {
                throw new RuntimeException("栈空");
            }
            int data = this.stack[this.top];
            this.top--;
            return data;
        }
    
        // 从栈顶开始遍历显示栈的数据
        public void show() {
            if (this.isEmpty()) {
                System.out.println("栈空");
                return;
            }
            for (int i = this.top; i >= 0; i--) {
                System.out.printf("stack[%d]=%d\n", i, this.stack[i]);
            }
        }
    
        // 返回栈顶的值(非pop)
        public int getTop() {
            return this.stack[this.top];
        }
    
    
        // 计算运算符的优先级,优先级用数字表示,数字越大,优先级越高
        public int priority(char operator) {
            if (operator == '*' || operator == '/') {
                return 1;
            } else if (operator == '+' || operator == '-') {
                return 0;
            } else {
                return -1;
            }
        }
    
        // 判断是不是一个运算符
        public boolean isOperator(char operator) {
            return operator == '+' || operator == '-' || operator == '*' || operator == '/';
        }
    
    
        // 用运算符对数字进行计算
        public int calculate(int number1, int number2, char operator) {
            int result = 0;
            switch (operator) {
                case '+':
                    result = number1 + number2;
                    break;
                case '-':
                    // 注意相减的顺序
                    result = number2 - number1;
                    break;
                case '*':
                    result = number1 * number2;
                    break;
                case '/':
                    result = number2 / number1;
                    break;
                default:
                    break;
            }
            return result;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182

    运算程序,结果如下:

    表达式: 7*2*2-5+1-5+3-4 = 18
    
    • 1

    如果计算722-5*1-5+3-4,因为连续出现两个减,所有计算结果错误,正常的结果为17,而此次的计算结果为29。连续出现两个除也会出错。可以使用逆波兰表达式进行解决,参考数据结构与算法之使用栈Stack来实现逆波兰表达式求值

  • 相关阅读:
    Cookie和session的区别
    Spring Boot Actuator通过Nginx配置限制外部访问
    回归模型介绍
    基于java+springboot+mybatis+vue+elementui的准妈妈孕期交流平台
    Gadmin企业级开发平台
    【Java基础】分支结构之switch语句及for循环结构
    异常概述
    排序和RMQ
    2023 编程资料合集汇总
    腾讯配合监管机构:未经批准不得发布新应用或更新版本
  • 原文地址:https://blog.csdn.net/yy8623977/article/details/126570899