• 【数据结构】栈的模拟和使用理解


    栈(Stack)

    栈的概念

    栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.
    进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,遵守先进后出,后进先出的原则

    压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
    出栈:栈的删除操作叫做出栈。出数据在栈顶
    在这里插入图片描述
    在集合框架中,Stack的继承实现关系如下:
    在这里插入图片描述从上图中可以看到,Stack继承了Vector,Vector和ArrayList类似,都是动态的顺序表
    不同的是Vector类,是线程安全的动态数组,但是性能较差 , 现在已经不是很常用了 , 可以说已经过时了

    栈的使用

    方法解释
    Stack()构造一个空的栈
    E push(E e)将e入栈,并返回e
    E pop()将栈顶元素出栈并返回
    E peek()获取栈顶元素
    int size()获取栈中有效元素个数
    boolean empty()检测栈是否为空
    public static void main(String[] args) {
            Stack<Integer> stack = new Stack<>();//创建一个栈
            stack.push(1);//添加一个元素到栈中
            stack.push(2);
            stack.push(3);
            stack.push(4);
            System.out.println("当前元素有:"+ stack.size());
            System.out.println(stack);
    
            int x = stack.pop();//取出栈顶的元素返回
            System.out.println(x);
            System.out.println("当前元素有:"+ stack.size());
    
            int n = stack.peek();//获取当前栈顶的元素
            System.out.println(n);
    
            if(stack.empty()){
                System.out.println("空栈!");
            }else{
                System.out.println("当前栈空间为:"+stack.size());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    栈相关的应用场景

    1. . 改变元素的序列

    若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()
    A: 1、4、3、2
    B: 2、3、4、1
    C: 3、1、4、2
    D: 3、4、2、1

    图解:
    在这里插入图片描述

    一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。
    A:1、2、3、4、5、A、B、C、D、E
    B: E、D、C、B、A、5、4、3、2、1
    C: A、B、C、D、E、1、2、3、4、5
    D: 5、4、3、2、1、E、D、C、B、A

    图解:
    在这里插入图片描述

    栈的模拟实现

    public class MyStack {
        public int[] elen;
        public int usedsize;
    
        public MyStack() {
            this.elen = new int[10];
        }
    
        //压栈
        public int push(int val){
            if(isFull()){
                // 扩容
                elen = Arrays.copyOf(elen,2*elen.length);
            }
            this.elen[usedsize] = val;
            usedsize++;
            return val;
        }
        // 判断数组的空间是否满了
        public boolean isFull(){
            return usedsize == elen.length;
        }
        
        // 弹出
        public int pop(){
            if(empty()){
                throw new MyEmptyStackException("栈为空!");
            }
            int n = elen[usedsize-1];
            usedsize--;
            return n;
    
            // 第二种方法  这种方法和上面比较简洁一点
            // return elen[--usedsize];
        }
        // 判断数组是否为空
        public boolean empty(){
            return usedsize == 0;
        }
    
       // 获取栈顶元素
        public int peet(){
            if(empty()){
                throw new MyEmptyStackException("栈为空!");
            }
            return elen[usedsize-1];
        }
    }
    
    • 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

    中缀表达式 转 后缀表达式

    • 基本概念
      中缀表达式
      操作符以中缀形式位于运算数中间,日常通用的算术和逻辑公式表示方法,(例如:1+2 、 3*4)
      后缀表达式
      又称逆波兰式,操作符以后缀形式位于两个运算数后,(例如:1+2 在转换成后缀表达形式就是1 2 +)
      前缀表达式:
      又称波兰式,操作符以前缀形式位于两个运算数前(如:3+2的前缀表达形式就是+ 3 2)

    例如:
    在这里插入图片描述
    中缀转后缀表达式通常是应用在计算器上
    👀👀👀
    例如:

    力扣链接: 逆波兰表达式求值

    将后缀表达式:1 2 3 * + 4 5 * 6 + 7 * + 进行计算,求结果?
    在这里插入图片描述

    public int evalRPN(String[] tokens) {
            Stack<Integer> stack = new Stack<>();
            //1.遍利 tokens 数组,判断当中的字符串的类型
            for(String x : tokens){
                //如果不是运算符的情况下
                if(!isOperations(x)){
                    // Integer.parseInt() 是把字符串转换成整数
                    stack.push(Integer.parseInt(x));// 压栈
    
                }else{
                    int n2 = stack.pop();
                    int n1 = stack.pop();
                    switch(x) {
                        case "+":
                            stack.push(n1+n2);
                            break;
                         case "-":
                            stack.push(n1-n2);
                           break;
                        case "*":
                            stack.push(n1*n2);
                            break;
                        case "/":
                            stack.push(n1/n2);
                            break;
                    }
                }
            }
            return stack.pop();
       }
        // 判断是否是运算符
        public boolean isOperations(String s){
            if(s.equals("+") ||s.equals("-") ||s.equals("*") ||s.equals("/") ){
                return true;
            }
            return false;
        }
    
    • 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

    栈、虚拟机栈和栈帧的区别

    • 栈:是一种先进后出得数据结构
    • 虚拟机栈:是JVM的一块内存空间
    • 栈帧:在调用的过程中,Java虚拟机栈的一块内存

    目前实现的栈底层是数组实现的,所以可以叫做顺序栈
    栈也可以用单链表实现,叫做链式栈

    • 如果是单链表实现栈有二种情况:
      尾插入栈:
      入栈的时间复杂度是O(N),因为要找尾结点
      在这里插入图片描述
      头插入栈:
      入栈的时间复杂度是O(1),出栈也是从头出,不需要找尾巴

    在这里插入图片描述

    如果是双向链表,二边都可以入栈和出栈,时间复杂对都是O(1)

  • 相关阅读:
    运营级智慧校园系统源码 智慧校园小程序源码+电子班牌+人脸识别系统
    Python实现---南邮离散数学实验三:盖住关系的求取及格的判定
    腾讯测试大鸟分享4个关于 Python 函数(方法)的冷知识
    海康G5系列(armv7l) heop模式下交叉编译Qt qmqtt demo,出现moc缺少高版本GLibc问题之解决
    spring boot集成pg
    关于我学习Go语言在CSDN分享的心得体会
    vue-router清除url地址栏路由参数
    yolov8_track追踪加分割(yolo目标检测+追踪+分割)
    程序设计实验第二周
    第三方支付“进件”是什么意思
  • 原文地址:https://blog.csdn.net/m0_66483195/article/details/127855487