欢迎光临Java中的客“栈”

就目前而言,相信大家对数组、链表还有栈都基本已经有了一些了解,本篇文章将以栈为主体,探究栈和数组,栈和链表之间的一些联系。

当然在开始对栈的学习之前,我们先回顾有关数组、链表的基础知识点。

学习代码就是一个不断遗忘且巩固的过程,如何让敲出来的代码在心中印象更为深刻呢?不妨为这些有规律的字母的排列组合赋予一些当下事物的灵动性。

在这里我不得不提到当下的热梗:诸如来自歌手2024中的“五旬老太守国门”、“叶赫那拉氏大战八国联军”等等,既然咱们英子在这期舞台上是那么的孤单无助,在本篇代码里我将在循环取出栈中元素时,为英子来点助力,毕竟,57岁正是拼搏的年龄,咱们英子不能输,一个不够就来俩,两个不够我就来N个,真舞台咱也上不去,那就只能在代码里为我们的歌手们呐喊助威了!(见三)

天天抖手,精神抖擞!

目录

一、链表与数组(Array and LinkedList)

1.关于数组 Array

2.关于链表 LinkedList

二、栈 (Stack)

1.泛型简介

2.什么是栈

3.数组与栈

1)栈的存与取

2)数组和栈删除之间的区别

3)代码实现

4.链表与栈

1)栈中数据的插入与删除

2)基本代码实现

3)头插法与尾插法

三、整体代码


一、链表与数组(Array and LinkedList)

1.关于数组 Array

数组在内存中是一段连续的空间,每段的编号都是从0开始的,依次递增,也称为数组的下标。

数组可以通过索引(下标)访问其任意位置的元素。

数组不能够自动扩容且长度固定不可变。

除了掌握数组的创建,还需要会使用的就是数组的存和取。

int[] array1 = new int[10];//动态初始化
int[] array2 = {1,2,3,4,5};//静态初始化

在整数型数组的动态初始化里,每个元素的初始值都为0,不同类型的数组初始值不同。

public class Test {
        //存
        public static void main(String[] args) {
            int[] array = new int[5];
            for (int i = 0; i < array.length; i++) {
                array[i] = i * 2 + 1;
            }
            for (int i = 0; i < array.length; i++) {
                System.out.println("array[" + i + "] = " + array[i]);
            }
        }
}
public class Test {
        //取
        public static void main(String[] args) {
            int[] arr1 = {1,2,3,4,5};
            for (int i = 0; i < arr1.length; i++) {
                System.out.print(arr1[i]+" ");
            }
            System.out.print("\n");
            
            int[] arr2 = new int[5];
            for (int j  = 0;j < arr2.length; j++){
                int value = arr2[j];
                System.out.print(value+" ");
            }
        }
        
}

运行结果:

1 2 3 4 5 
0 0 0 0 0 

2.关于链表 LinkedList

这里主要回顾单向链表。链表长度可变,且可以实现自动扩容,但不能通过下标进行访问。

链表使用节点对象储存数据,节点之间相互存储地址建立连接。

链表主要几个概念:头节点和尾结点。

头节点(head): 链表的第一个节点称为头节点,通常用来表示整个链表的起始位置。

尾节点(last): 链表的最后一个节点称为尾节点,其指针通常指向 null,表示链表的结束。

但与数组不同,链表中的元素在内存中不是连续存储的,而是通过指针(引用)相互连接起来。  

图示的为链表的一个节点node,value是这个节点的所存储的数据值,next为下一节点的地址。

二、栈 (Stack)

1.泛型简介

为什么叫泛型?一般提到关于“泛”的都是联想到广泛、宽泛、空泛、泛泛之交等词语、所以不难得出泛具有适用性广、通用性强等特征。所以在Java中的泛型一般用在尚不确定的数据类型中,可以暂替多种数据类型,以下段代码为例。

public class pandora_box<T> {
    private T value;

    public void setValue(T value){
        this.value=value;
        System.out.println(value);
    }

    public T getValue(){
        System.out.println(value);
        return value;
    }

    public static void main(String[] args) {
        pandora_box<String> box1 = new pandora_box<>();
        box1.getValue();
        box1.setValue("潘多拉魔盒");

        pandora_box<Integer> box2 = new pandora_box<>();
        box2.setValue(111);
        box2.getValue();

    }
}

输出结果:

null
潘多拉魔盒
111
111

2.什么是栈

 栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。 

底层可以使用数组或链表进行实现。

采取先进后出(LIFO:last in first of)原则: 即先存入的数据,最后才能取出

类比:放羽毛球的盒子,最先放进去的是最后一个拿出来的,或一个单向闭口的管道(最先存入的为栈底、最后一个存入的为栈顶)。

总结:栈的操作只涉及栈顶元素,而不会涉及栈底或中间的元素。

3.数组与栈

数组可以理解成为一种固定长度的栈。

1)栈的存与取

存:按照下标正常存入

取:从最后的元素开始依次向前

2)数组和栈删除之间的区别

数组:找到对应的下标,将改下标后一位置的元素逐一向前挪一个

栈:倒着一一取出直至找到需要删除的数据

对于插入数据数据呢?会很麻烦,一旦越过最后一个要取前面的步骤就会很繁琐。

3)代码实现

Object[ ]是一个数组,其中每个元素的类型都是Object。在 Java 中,Object 是所有类的祖先,因此 Object[ ] 数组可以存储任何类型的对象,包括基本数据类型的包装类对象和用户自定义的类对象。

由于Object是所有类的直接或间接父类,因此 Object[ ] 数组可以存储任意类型的对象,例如String、Integer、Double 等。当你不确定数组中需要存储哪种类型的对象时,可以使用         Object[ ] 数组作为一种通用的容器。(类比泛型的思想)

public class ArrayStack<E> {
    Object[] stackArr = new Object[10];
    int size=0;

    public void add(E e){
        //定义了一个公有的方法 add,用于向栈中添加元素
        //该方法使用泛型类型 T 作为参数类型,表示可以接受任意类型的对象(即传入)
        if (stackArr.length==size){
            System.out.println("小二提示:您的客栈已满!");
            return;
        }
        stackArr[size++]=e; //这行代码相当于stackArr[size]=e;size++;
        //将传入的元素 t 添加到栈顶(数组中的下一个空位置),并将 size 自增
        //这里利用 size 变量来记录当前栈中元素的个数,并在添加元素后更新 size
    }

    public E get(){
        //当你从栈中取出元素时,根据栈的特性,应当从栈顶开始取出元素!!!
        E element =(E)stackArr[size-1];//具体理解见word
        stackArr[size-1]=null;
        size--;
        return element;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("stackArr:{ ");
        for (int i = 0; i < size; i++) {
            sb.append(stackArr[i]).append(" "); // 将每个元素的值拼接到 str 中
        }
        sb.append("}");
        return sb.toString();
    }
    public static void main(String[] args) {
        ArrayStack<Object> arrStack = new ArrayStack<>();
        for (int i = 0; i < 10; i++){
            arrStack.add(i);
        }
        System.out.println("存-"+arrStack.toString());
        for (int i = 0; i < 10; i++){
            System.out.print("取-"+arrStack.get()+" ");
        }
    }
}

输出结果:

存-stackArr:{ 0 1 2 3 4 5 6 7 8 9 }
取-9 取-8 取-7 取-6 取-5 取-4 取-3 取-2 取-1 取-0 

4.链表与栈

链表可以理解为实现一种长度不固定的栈。

1)栈中数据的插入与删除

由于栈只能从栈顶开始对其中的数据进行取出,所以我们只能倒着一一取出直至找到需要删除的数据,那么对于插入数据数据呢?一样也很麻烦,一旦越过最后一个数据要取出前面的就会很麻烦。

2)基本代码实现

链表通过将数据存入节点对象中,而节点类的构造一般包括属性、数据变量、下一个节点对象变量(其中存储的为地址)。

添加或查找数据都可以通过一个头节点依次向下找。

class Node<E>{
    E value;//数据变量
    Node<E> next;

    public Node(E value){
        this.value=value;
    }

    public Node<E> setNext(){
        return next;
    }
    public void getNext(){
        this.next=next;
    }

}

public class myLinkedList<E> {
    Node<E> head;
    int size;

    public void add(E e){
        Node<E> node = new Node<>(e);
        //如果头节点为空
        if(head==null){
            head=node;
            size++;
            return;
        }else{
            //遍历链表找到最后一个节点,将新节点挂在最后一个节点上
            //利用递归的思想
            Node<E> current = head;
            while (current.next != null){
                current=current.next;
            }
            current.next=node;
            size++;
        }

    }

    public static void main(String[] args) {
        myLinkedList<Integer> myll = new myLinkedList<>();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i<100000;i++){
            myll.add(i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("人工链表用时:"+(endTime-startTime)+"ms");

        LinkedList<Integer> linkedList = new LinkedList<>();
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i<100000;i++){
            linkedList.add(i);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("系统链表用时:"+(endTime1-startTime1)+"ms");

    }

}

运行结果:

人工链表用时:5728ms

系统链表用时:4ms

思考:为何自制的链表与java系统自带的耗时差异如此之大?

可能的原因:在遍历上耗时过多。

3)头插法与尾插法

So如果我们不是通过找到头节点后再遍历循环挂到末尾上,直接让新节点成为头节点是不是就可以略去遍历循环的时间了呢?(头插法)

public void addFirst(E e){
    Node<E> node = new Node<>(e);
    if(head==null){
        head=node;
        size++;
        return;
    }else{
        node.next=head;//此时假设新节点node已经成为头节点,则当时的头节点的位置处于新节点的下一个
        head=node;//原本头节点的位置
        size++;
    }
}

运行结果

人工链表用时:98ms

系统链表用时:33ms

下面是尾插法的代码实现部分。

public void addLast(E e) {
    Node<E> node = new Node<>(e);
    if (head == null) {
        head = node;
        last = node;//此时头结点也是尾结点
        size++;
        return;
    } else {
        last.next = node;//此时假设新节点node已经成为头节点,则当时的头节点的位置处于新节点的下一个
        last = node;//原本头节点的位置
        size++;
    }
}

运行结果:

人工链表用时:94ms

系统链表用时:96ms

不难看出:尾插法的运行速度甚至比头插法还有java自带的耗时更少。

三、整体代码(叶赫那拉大战八国联军)

class Node<E>{
    E value;//数据变量
    Node<E> next;

    public Node(E value){
        this.value=value;
    }

    public void setNext(Node<E> next){
        this.next=next;
    }
    public Node<E> getNext(){
        return next;
    }

}

public class myLinkedList<E> {
    Node<E> head;
    Node<E> last;
    int size;

    public void addFirst(E e){
        Node<E> node = new Node<>(e);
        if(head==null){
            head=node;
            size++;
            return;
        }else{
            node.next=head;//此时假设新节点node已经成为头节点,则当时的头节点的位置处于新节点的下一个
            head=node;//原本头节点的位置
            size++;
        }
    }

    public void addLast(E e) {
        Node<E> node = new Node<>(e);
        if (head == null) {
            head = node;
            last = node;//此时头结点也是尾结点
            size++;
            return;
        } else {
            last.next = node;//此时假设新节点node已经成为头节点,则当时的头节点的位置处于新节点的下一个
            last = node;//原本头节点的位置
            size++;
        }
    }



    public void add(E e){
        Node<E> node = new Node<>(e);
        //如果头节点为空
        if(head==null){
            head=node;
            size++;
            return;
        }else{
            //遍历链表找到最后一个节点,将新节点挂在最后一个节点上
            //利用递归的思想
            Node<E> current = head;
            while (current.next != null){
                current=current.next;
            }
            current.next=node;
            size++;
        }

    }


    @Override
    public String toString(){
        String str = "{";
        Node<E> current = head;
        while (current.next!=null){
            str+=current.value+",";
            current=current.next;
        }
        str+=current.value+"}";
        return str;
    }

    public E get(int point){
        if(point<0 || point>=size){
            System.out.println("不好意思这位大人您越界了");
            return null;
        }
        Node<E> current = head;
        for (int i =0; i<point;i++){
            current=current.next;
        }
        return current.value;

    }

    public static void main(String[] args) {
        myLinkedList<String> stringList = new myLinkedList<>();
        for (int i=0;i<6;i++){
            stringList.addLast("叶赫那拉"+i);
        }
        for (int i=0;i<2;i++){
            stringList.addFirst("八国联军"+i);
        }
        //注意顺序不能调换!!!
        System.out.println(stringList.toString());
        System.out.println(stringList.get(3));

    }

    public static void test(){
        myLinkedList<Integer> myll = new myLinkedList<>();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i<1000000;i++){
            //myll.add(i);
            myll.addFirst(i);
            //myll.addLast(i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("人工链表用时:"+(endTime-startTime)+"ms");

        LinkedList<Integer> linkedList = new LinkedList<>();
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i<1000000;i++){
            linkedList.add(i);
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("系统链表用时:"+(endTime1-startTime1)+"ms");
    }

}

运行结果:

{八国联军1,八国联军0,叶赫那拉0,叶赫那拉1,叶赫那拉2,叶赫那拉3,叶赫那拉4,叶赫那拉5}
叶赫那拉1

写到最后发现这篇的结构与内容有点杂乱,可能是因为有段时间没有写博客的原因,让我逐渐调整调整,争取下一篇是那种短小精悍的小短篇,后续关于链表、数组、栈的内容还会出现,这次就当做一个初步了解啦。

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

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

相关文章

抛弃Elasticsearch ,MeiliSearch 从入门到入门,现在不精通

Elasticsearch 做为老牌搜索引擎&#xff0c;功能基本满足&#xff0c;但复杂&#xff0c;重量级&#xff0c;适合大数据量。 MeiliSearch 设计目标针对数据在 500GB 左右的搜索需求&#xff0c;极快&#xff0c;单文件&#xff0c;超轻量。 所以&#xff0c;对于中小型项目来说…

2024年,诺基亚手机发售仅一天就售罄

在智能手机越来越同质化的今天&#xff0c;各家都只卷性能和相机&#xff0c;大火的 AI 对于咱来说好像实用性又不太大&#xff0c;机圈属实整的有点儿无聊。 不过在阿红这两天上网冲浪的时候&#xff0c;一个陌生又熟悉的名字闯入了我的视线&#xff0c;——诺基亚&#xff08…

VMware Workstation 安装CentOS Linux操作系统

1.我们已经下载好VMware 创建新的虚拟机 2.选择典型 3.安装程序光盘映像文件 4.配置用户名密码 5.命名虚拟机&#xff0c;并确定位置 6.如图所示设置 7.等待&#xff08;时间会有点久&#xff09; 8.输入密码登入账号

##20 实现图像风格迁移:使用PyTorch深入学习的艺术之旅

文章目录 前言项目概述准备阶段图像处理模型选择风格和内容特征提取风格迁移算法优化过程结果展示完整代码与实验项目结论参考文献 前言 图像风格迁移是一种使一幅图像呈现另一幅画作风格的技术&#xff0c;通过深度学习&#xff0c;我们能够捕捉到内容图像的结构信息和风格图…

海外媒体发稿:如何在日本媒体投放新闻通稿-大舍传媒

导言 在全球化的时代背景下&#xff0c;海外媒体宣发对于企业来说非常重要。通过在海外媒体投放新闻通稿&#xff0c;企业能够拓展海外市场&#xff0c;增强知名度和影响力。本文将探讨如何在海外媒体投放新闻通稿&#xff0c;以帮助企业进行有效的海外宣传。 挖掘海外媒体资…

Java后端面试常见问题

Java后端面试 经历了两个月的面试和准备&#xff0c;下面对常见的八股文进行总结。有些问题是网上看到的面经里提到的&#xff0c;有些是我真实面试过程遇到的。 异常 1、异常分为哪几种&#xff1f;他们的父类是什么&#xff1f; 注意&#xff1a;所有异常对象的父类为Thr…

rocketmq的顺序消息开发注意事项

1. 参考消息重试&#xff0c;要对 MaxReconsumeTimes进行设置。之前就是因为没有进行设置&#xff0c;导致了队头阻塞问题。 rokcetmq和kafka一样&#xff0c;当顺序消息写入的多个队列中后&#xff0c;如果是顺序消息&#xff0c;当前的队列的队头一直消费失败的时候&#x…

2024 年 6 月 银行从业资格考试(银从)如何备考?

文章目录 一、考试介绍&#xff08;已了解的自行跳过此步骤&#xff09;&#xff08;一&#xff09;含金量&#xff08;二&#xff09;就业方向&#xff08;三&#xff09;适合人群&#xff08;四&#xff09;报考条件&#xff08;五&#xff09;题型分值&#xff08;六&#x…

新质生产力之工业互联网产业链

随着全球经济的数字化转型&#xff0c;新基建的概念逐渐成为推动工业发展的关键动力。在这一转型过程中&#xff0c;工业互联网作为新基建的核心组成部分&#xff0c;正逐渐塑造着未来工业的面貌。那么工业互联网产业链是如何构成的&#xff0c;以及它如何成为推动工业4.0和智能…

Linux服务器lvm磁盘管理fdisk和df磁盘大小不同修改

服务器端由于硬盘是通过VCenter原来100G磁盘复制的虚拟机,复制完成后,原来100G的磁盘通过选择 磁盘重新复制出150G的磁盘,开机后发现还是原来的100G的磁盘,通过fdisk -l 查看有个sdb是150G, 但是已经划转的lvm盘只有100G, 通过df查看也是原来的100G: pvs查看pv里也是10…

PMR-440N7Q韩国施耐德三和相序继电器EOCR-PMR

韩国施耐德三和EOCR继电器PMR-440N7Q PMR-440-N 直流电动机保护器:DCL、DOCR-S/H 欠电流继电器:EUCR-3C 交流电压继电器:EOVR、EVR-PD、EVR-FD、EUVR 韩国三和EOCR电动机保护器:EOCR-SS、EOCR-SS1/SS2、EOCR-AR、EOCR-ST、EOCR-SP、EOCR-SP1/SP2、EOCR-SE、EOCR-SE2/SE PMR-44…

电巢直播XR鉴赏|一块绿幕,闪现进入异星战争的现场!

XR场景赏析 在浩瀚的宇宙深处&#xff0c;一颗神秘莫测的异星球映入我们的眼帘&#xff0c;这里&#xff0c;龙卷风与炮火交织&#xff0c;似乎永不停歇。 星球表面散布着无数的飞船残骸&#xff0c;它们是某场宇宙大战残酷的遗存&#xff0c;无声地诉说着过往的激烈冲突。地面…

java spring 11 推断构造方法 createBeanInstance

1.doCreateBean方法&#xff1a;这一部分&#xff0c;用到createBeanInstance方法&#xff1a; BeanWrapper instanceWrapper null;if (mbd.isSingleton()) {// 有可能在本Bean创建之前&#xff0c;就有其他Bean把当前Bean给创建出来了&#xff08;比如依赖注入过程中&#xf…

汇舟问卷:5年专业经验,海外渠道查无需烦恼!

大家好&#xff0c;我是汇舟问卷&#xff0c;拥有五年的行业经验&#xff0c;专注于海外问卷渠道查。 在海外问卷渠道查领域&#xff0c;我们拥有专业的知识和经验。无需为购买大量海外邮箱而烦恼&#xff0c;更无需担忧账号被封禁的风险。我们提供全天候24小时的服务&#xf…

【考研数学】跟「武忠祥」真不如「张宇」吗??

现在是张宇老师强势版本&#xff01; 24年之前&#xff0c;你说跟武忠祥老师好&#xff0c;我非常赞成&#xff0c;但是24年很多同学考完出来都说&#xff0c;早知道跟张宇了&#xff0c;都说24年考研数学偏&#xff0c;怪&#xff0c;难&#xff0c;计算量还大。 武忠祥老师…

AniPortrait详细讲解以及完整搭建流程(有问题留言)

AniPortrait是一款真实感人像动画的音频驱动合成的AI程序。 下面是它的github源码: GitHub - Zejun-Yang/AniPortrait: AniPortrait: Audio-Driven Synthesis of Photorealistic Portrait AnimationAniPortrait: Audio-Driven Synthesis of Photorealistic Portrait Animati…

更新Windows 11 后遇到的一些问题(更新中...)

目录 插入U盘后读取不到 在磁盘中新建文件夹需要管理员权限 导致不能安装一些软件 插入U盘后读取不到 解决方法&#xff1a;点击我的电脑或者是此电脑、选择管理、找到设备管理器、选择通用串行总线控制器、右键、选择启动。 第一步&#xff1a;点击我的电脑或者是此电脑、选…

18.04版本的ubuntu没有连接网络的图标(坑人版)

以下更新内核别看&#xff0c;因为后面安装驱动报一堆错误!!! 不升级内核成功方法跳转连接&#xff1a;https://blog.csdn.net/weixin_53765004/article/details/138771613?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2213877…

BGP学习三:BGP路由优选12条规则,闪亮登场啦啦啦啦啦

目录 一.BGP策略工具 &#xff08;1&#xff09;Router-policy作用 &#xff08;2&#xff09;组成部分 &#xff08;3&#xff09;router-policy注意事项 二.优选规则 ①丢弃下一跳不可达 (1)优选prefered-value值大的路由 1.首选优先级 (2)优选local-preference(本地…

【C++】从零开始构建二叉搜索树

送给大家一句话&#xff1a; 我们始终有选择的自由。选错了&#xff0c;只要真诚的反思&#xff0c;真诚面对&#xff0c;也随时有机会修正错误和选择。 – 《奇迹男孩(电影)》 &#x1f4bb;&#x1f4bb;&#x1f4bb;&#x1f4bb;&#x1f4bb;&#x1f4bb;&#x1f4bb;…