【数据结构】特殊的线性表——栈

在这里插入图片描述
🧧🧧🧧🧧🧧个人主页🎈🎈🎈🎈🎈
🧧🧧🧧🧧🧧数据结构专栏🎈🎈🎈🎈🎈
🧧🧧🧧🧧🧧上一篇文章:从链表到LinkedList类🎈🎈🎈🎈🎈

文章目录

  • 1.前言
    • 2.栈(Stack)
    • 2.1栈的概念
    • 2.2栈的使用
    • 2.3栈的模拟实现

1.前言

什么叫栈?要搞清楚这个概念,首先要明白“栈”原来的意思,如此才能把握本质。栈,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。栈这个数据结构是一个特殊的线性表,他只能在栈顶进行增删操作。

2.栈(Stack)

2.1栈的概念

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。

下面为图片说明:
在这里插入图片描述
生活中的例子:
枪压子弹:第一发打出去的子弹是最后压进去的子弹。
在这里插入图片描述

2.2栈的使用

2.2.1栈的方法:
push()
pop()
peek()
empty()
search()
需要掌握并且使用较多的只有这三种压栈push()出栈(删除栈顶数据)pop()查看栈顶数据pop()
在这里插入图片描述
2.2.2栈方法的代码实现:

public class ArrayTest {
     public static void main(String[] args) {
         Stack<Integer> stack = new Stack<>();
         //push 压栈/入栈
         stack.push(1);
         stack.push(2);
         stack.push(3);
         stack.push(4);
         //pop 出栈(相当于删除) 满足先进后出,后进先出。
         int ret = stack.pop();
         System.out.println(ret);
         //peek 与出栈一样,但不会删除,只是查看栈顶的数据
         int ret2 = stack.peek();
         System.out.println(ret2);
    }
}

2.2.3pop方法与peek方法的区别
前者不仅会返回栈顶的数据并且会将返回的那个栈顶数据在栈中删除,使得栈中没有这个数据,后者只是会返回栈中栈顶的数据不会删除。

我们来调试这个程序来看看这两个方法的区别:
1.pop:
未执行pop方法时栈顶的数据还在栈中。
在这里插入图片描述
执行pop方法之后,栈顶的数据4就被删除了,并返回了栈顶的数据,由ret接收。
在这里插入图片描述
2.peek:
未执行peek方法时栈顶的数据在栈中。
在这里插入图片描述
执行peek方法之后,栈顶的数据4并没有被删除了,而且还返回了栈顶的数据,由ret2接收。
在这里插入图片描述

2.3栈的模拟实现

我分三种方式去模拟实现栈分别是数组、单向链表、双向链表。
2…3.1用数组的来模拟实现栈
用数组去模拟实现栈我们需要一个数组,和一个记录数组中数据的有效个数变量。
1.先创建一个类,类中成员变量有一个数组,一个记录数组中数据的有效个数变量

public class ArrayStack {
    public int[] elem ;
    public int usedSize;//记录数组中有效数据的个数
    public static final int DEFAULT_CAPACITY = 10;
    public ArrayStack() {
        this.elem  = new int [DEFAULT_CAPACITY];
    }
}

2.实现push方法
先要判断栈中数据是否满,满了需要将数组的容量扩容。

public void push (int val) {
        //判断栈中是否满了
        if(is_Full()) {
            //扩容
            this.elem = Arrays.copyOf(elem,2*elem.length);
        }
        //将数据压入栈中
        elem[usedSize++] = val;
    }
    public boolean is_Full () {
        return usedSize == elem.length;
    }

3.实现pop方法,首先需要判断栈中的数据是否为空,如果为空则不需要用到pop方法

 public int pop () {
        //判断栈中是否为空
        if(is_Empty()) {
            //抛异常
            throw new EmptyStackException("栈空异常!!");
        }
        //数据还是存在数组中,只是记录数组有效个数usedSize变化了,但重新压入栈的数据会覆盖之前的数据。
        usedSize--;
        return elem[usedSize];
    }
    public boolean is_Empty() {
        return  usedSize == 0;
    }

注意:这里出栈的方式是将数组的有效个数减1,事实上原先的数据还是存在数组中的,只是无法访问到而已,如果有新数据压入栈中也可以直接将之前的数据给覆盖。

4.实现peek方法首先需要判断栈中的数据是否为空,如果为空则不需要用到peek方法

public int peek() {
        //判断栈中是否为空
        if(is_Empty()) {
            //抛异常
            throw new EmptyStackException("栈空异常!!");
        }
        return elem[usedSize-1];
    }

5.这里我在判断栈是否为空的时候,我用到了一个抛出异常的方法,这样更直接的知道栈是否为空。
这是我实现栈为空异常的代码:

public class EmptyStackException extends RuntimeException{
    public EmptyStackException() {
    }

    public EmptyStackException(String message) {
        super(message);
    }
}

6.测试代码

public class ArrayTest1 {
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack();
        arrayStack.push(1);
        arrayStack.push(2);
        arrayStack.push(3);
        int ret = arrayStack.pop();
        System.out.println(ret);
        int ret2 = arrayStack.peek();
        System.out.println(ret2);
    }
}

2.3.2用单向链表来模拟实现栈
1.先把这个单向链表最基本的节点结构构建出来,在这里我们采用了内部类,往大的说链表就是一个类,弹链表是由多个节点一个一个链接起来的,所以往小的说节点又是个类,该类中成员变量有存储节点的值,也有引用。

public class SinglyLinkedStack {
    static class ListNode {
        public int val;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
}

2.模拟实现push方法,在这里我们需要注意的是前面我们用数组的方式来模拟实现栈的时间复杂度为O(1)所以我们在用单向链表来模拟实现栈的时间复杂度也要保证为O(1)。在单向链表中有两种方式将数据存储在链表,一种是头插法,一种是尾插法,在这里只有头插法满足我们的要求,所以我们用头插法来实现压栈方法。

public void push(int val) {
        ListNode node = new ListNode(val);
        node.next = this.head;
        this.head = node;
    }

3.模拟实现pop方法,在删除节点的时候,我们也有两个方向来删除,一个是从头节点删,一个是从尾节点删,但需要满足时间复杂度O(1),我们采用删头节点的方式来实现pop方法。

public int pop() {
        int ret = head.val;
        this.head = head.next;
        return ret;
    }

4.模拟实现peek方法,可以直接去访问头节点的值。

public int peek() {
        return head.val;
    }

2.2.3用双向链表来模拟实现栈
在模拟之前我们可以先看看在LinkedList类中是有push、pop、peek方法的。
在这里插入图片描述
我们可以直接实列化LinkedList的一个对象来使用这些方法。

public class ListTest {
    public static void main(String[] args) {
        LinkedList<Integer> stack = new LinkedList<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack.pop());
        System.out.println(stack.peek());
    }
}

1.在模拟实现栈之前我们也需要将最基本的结构确定,和单向链表是相差不差的,只是多了一个前引用。

public class LinkedStack {
    static class ListNode {
        public int val;
        public ListNode prev;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    public ListNode last;
}    

2.push方法在双向链表中不管是头插还是尾插,压栈的时间复杂度都是O(1)。
2.1头插法

//1.头插法
    public void push1(int val) {
        ListNode node = new ListNode(val);
        if(head == null) {
            head = node;
            last = node;
        }
        else {
            node.next = head;
            head.prev =node;
            head= node;
        }
    }

2.2尾插法

public void push2(int val) {
        ListNode node = new ListNode(val);
        if(head == null) {
            head = node;
            last = node;
        }
        else {
            node.prev = last;
            last.next =node;
            last = node;
        }
    }

3.pop方法的模拟实现,不管在头节点出还是在尾节点出时间复杂度都是O(1)
3.1删头节点

public int pop1() {
        ListNode cur = head.next;
        int ret = head.val;
        head = cur;
        return ret;
    }

3.2删尾节点

public int pop2() {
        ListNode cur = last.prev;
        int ret = last.val;
        last = cur;
        return ret;
    }

4.模拟实现peek方法,采用的头插法,直接返回头节点的值,采用的尾插法,直接返回尾节点的值。
4.1头插法

public int peek1() {
        return head.val;
    }

4.2尾插法

 public int peek2() {
        return last.val;
    }

希望大家可以给我点点关注,点点赞,并且在评论区发表你们的想法和意见,我会认真看每一条评论,你们的支持就是我的最大鼓励。🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/450560.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPF —— 数据绑定(初级)

数据绑定&#xff1a;把数据以一个变量的方式绑定到一个标签上,以后可以通过对变量修改&#xff0c;达到修改属性的目的 之前修改某一个label标题&#xff0c;之前写法this.l1.content"李四" 数据绑定写法&#xff1a;label content {Bind path title} …

Redis中AOF数据持久化

AOF介绍 AOF&#xff08;Append Only File&#xff09;持久化&#xff1a;以独立日志的方式存储了 Redis 服务器的顺序指令序列&#xff0c;并只记录对内存进行修改的指令。 当Redis服务发生雪崩等故障时&#xff0c;可以重启服务并重新执行AOF文件中的指令达到恢复数据的目的…

Oracle之ADG与DG的区别?

在上云后的Oracle数据灾备场景中&#xff0c;我们经常听到DBA迁移工程师讲到“在这个项目中用ADG进行数据实时备份&#xff0c;ADG比DG更好&#xff01;”。究竟ADG作Oracle数据灾备的优势在什么地方&#xff1f; 一、ADG主要解决了DG时代读写不能并行的问题 DG时代的数据同步…

计算机设计大赛 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…

es配置elk实现增量同步以及全量同步

需要配置这个文件 input {stdin {}jdbc {# mysql 数据库链接,center为数据库名,jdbc版本比较大的要加上&#xff1f;后面那串字符jdbc_connection_string > "jdbc:mysql://192.168.161.131:3307/mz-master"# 用户名和密码jdbc_user > "root"jdbc_pas…

bug--xxoobject has no attribute xxx

Python 创建类的实例后却不能调用写的方法&#xff0c;检查了半天原来是缩进的问题&#xff0c;def函数不应该和class并列 只能说这个英文空格太小了&#xff0c;看不出来。。。。

RVGS-06-1-1PN-A2电磁引导式溢流阀

RVGS-03-2-2PN-D2、RVGS-04-3-1PN-D2、RVGS-06-2-3P-A2、RVGS-03-1-2P-D2、RVGS-10-3-1P-A2、RVGS-06-1-1PN-A2、RVGS-03-1-2PN-D2、RVGS-06-2-3P-D2油田YUTIEN电磁引导式溢流阀和电磁换向阀的组合&#xff0c;配套的面阀为DSW-02-2B3B或者DSW-02-2B2。由于电磁阀直接安装在溢流…

Python笔记:使用Python脚本实现SSH登录

调试IDE&#xff1a;PyCharm Python库&#xff1a;Paramiko 首先安装Paramiko包到PyCharm&#xff0c;具体步骤为&#xff1a;在打开的PyCharm工具中&#xff0c;选择顶部菜单栏中“File”下的“Settings”&#xff0c;在设置对话框中&#xff0c;选择“Project”下的“Proje…

头脑风暴法是什么?10个值得推荐的头脑风暴模板!

身处职场的你&#xff0c;想必对头脑风暴这个术语并不陌生&#xff0c;它可能是某个同事或者领导的口头禅&#xff0c;每当遇到需要给出方案的场景&#xff0c;头脑风暴或者“脑暴”就会从他们嘴里脱口而出&#xff0c;但你真的了解&#xff0c;头脑风暴是什么意思吗&#xff1…

鸿蒙原生应用元服务开发-WebGL网页图形库开发无着色器绘制2D图形

无着色器绘制2D图形 使用WebGL开发时&#xff0c;为保证界面图形显示效果&#xff0c;请使用真机运行。 此场景为未使用WebGL绘制的2D图形&#xff08;CPU绘制非GPU绘制&#xff09;。开发示例如下&#xff1a; 1.创建页面布局。index.hml示例如下&#xff1a; <div class…

day01vue学习

day01 一、为什么要学习Vue 1.前端必备技能 2.岗位多&#xff0c;绝大互联网公司都在使用Vue 3.提高开发效率 4.高薪必备技能&#xff08;Vue2Vue3&#xff09; 二、什么是Vue 概念&#xff1a;Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套 **构建用户界面 ** 的 …

elementUi中表格超出一行省略,鼠标放入显示完整提示

一、想要的效果 二、代码&#xff0c;加入show-overflow-tooltip即可 <el-table-column min-width"220" prop"content" show-overflow-tooltip> </el-table-column>

#车载诊断协议DoIP系列 —— 套接字处理 在线检查

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝完再挣扎,出门靠自己,四海皆为家。人生的面吃一…

ABAP接口部分-Web Service提供者与消费者

ABAP接口部分-Web Service提供者与消费者 文章目录 ABAP接口部分-Web Service提供者与消费者Web Service提供者Web Service测试配置[SOA网址](https://mysap.goodsap.cn:44300/sap/bc/webdynpro/sap/appl_soap_management )测试 Web Service消费者创建Services Consumer消费者创…

光学硬件——二向色片

二向色镜&#xff08;Dichroic Mirrors &#xff09;又称双色镜&#xff0c;常用于激光技术中。 产品介绍&#xff1a; 指45度入射或大角度入射时&#xff0c;把光源分离出特定的光谱改变部分光谱光路方向&#xff0c;常用于酶标仪器、荧光显微镜系统、投影光引擎系统、激光灯…

MySQL--索引底层数据结构详解

索引是什么&#xff1f; 索引是帮助MySQL高效获取数据的排好序的数据结构&#xff0c;因此可知索引是数据结构。 概念很抽象&#xff0c;但是类比生活中的例子就很容易理解&#xff0c;比如一本厚厚的书&#xff0c;我们想取找某一小节&#xff0c;我们可以根据目录去快速找到…

魔法之线:探索string类的神秘世界

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

Java SE String类(一):常用方法(上)

1. 常用方法 1.1 字符串构造 String类的常用构造方法只有以下三种 public class Main {public static void main(String[] args) {String s1 "hello";//使用常量串进行构造String s2 new String("hello");//创建String对象char[] array {h,e,l,l,o};…

基于springboot的医护人员排班系统

预览地址 论文预览https://pan.imgbed.link/kkpreview/onlinePreview?urlaHR0cHM6Ly9wYW4uaW1nYmVkLmxpbmsvZmlsZS8yMTYxNT9mdWxsZmlsZW5hbWU95Z%2B65LqOc3ByaW5nYm9vdOeahOWMu%2BaKpOS6uuWRmOaOkuePreezu%2Be7n%2BiuuuaWhy5kb2M%3D 链接&#xff1a;https://pan.baidu.com/s/…

数据复制:释放新质生产力的关键钥匙

今年两会&#xff0c;新质生产力成为最热词汇&#xff0c;引起社会各界广泛关注。 所谓新质生产力&#xff0c;本质是一种新型的生产力形态&#xff0c;它由技术革命性突破、生产要素创新性配置、产业深度转型升级而催生&#xff0c;以劳动者、劳动资料、劳动对象及其优化组合…