Java数据结构----------------栈(性质、介绍、图解代码)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 目录 1.什么是栈?2.栈的基本功能和结构3.栈的基本功能详细代码实现 1. 判断栈是否为空 2.获取栈中元素的个数 3.压栈(向栈顶放入元素) 4.出栈(拿出栈顶元素,并得到它的值) 5.获取栈顶元素(未拿出) 6.判断栈中是否包含该元素

1.什么是栈?


假如有一天你下课去小店,买了一条曼妥思准备回去上课的时候偷偷吃,你的同桌看见你的嘴巴一直在嚼,这时你小心翼翼的拿出一颗递给他,这时你就完成了一组出栈功能。如下图,右边就像你的曼妥思,你拿给同桌的肯定是从上往下的第一颗,也就是最上面的这颗糖,如果你下课还要给其他同学那你肯定是顺着往下继续给直到吃完为止。


image.png


这种只能从一端进行元素的添加和删除的操作受限的线性表,我们就称之为栈。当然这只是简易的单纯从数据结构的说法,我们的计算机内存中还有栈区,如果你想了解更多当然可以去自己了解。这里我只以最快的方式告诉你栈的逻辑结构


PS:栈的实现可以通过顺序表或链表实现,刚开始接触数据结构的同学不要思维定式,看着图里好像元素都靠在一起就像数组就得用顺序表,栈只要求我们只能在一端进行操作,保存数据的方式无论你选顺序表还是链表都是可以的。这里我更推荐使用链表实现,因为能用链表实现肯定也能用顺序表实现,我也以链表来演示。对于顺序表和链表不熟的同学推荐看看我的前三篇文章


1、java数据结构---顺序表    


2、java数据结构---单链表


3、 java数据结构---双向链表


2.栈的基本功能和结构


public class Stack<T> implements Iterable {
    //记录首节点
    private Node head;
    //记录栈中元素个数
    private int N;
    private class Node{
        public T item;
        private Node next;
        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
    public Stack(){
        this.head=new Node(null,null);
        this.N=0;
    }


因为是以链表存储,同样需要一个内部类Node表示结点,栈成员属性有Node头结点head以及一个int类型变量N计算存储元素个数。构造方法中,new出一个stack(栈)时,需要初始化一个值为空(头结点不存储元素),next也为空,因为我们此时栈还是空的。千万别写成this.head=null,这是完全不同的,这样写代表根本没有头结点。


ps:在这我们要注意,因为栈的操作都是在一端,所以为了我们操作方便,我们的头结点是在进行操作的这一端,而且栈顶的元素不是头结点,而是我们头结点的next。有人说这样头结点不是好像一直随着压栈出栈的操作一直动吗?我把头结点放栈底那它不是不用动更好吗。但是我们数据结构追求的是效率呀,如果你的头结点是在栈低,那每次对栈顶进行操作,你都要通过遍历去找到栈顶的结点,这耗费的时间是巨大的。


image.png


public boolean isEmpty()
判断栈是否为空
public int getLength()
获取栈中元素的个数
public void push(T t)
压栈(向栈顶放入元素)
public T pop()
出栈(拿出栈顶元素,并得到它的值)
public T getHeadNext()
获取栈顶元素(未拿出)
public boolean contains(T t)
判断栈中是否包含该元素


3.栈的基本功能详细代码实现


1. 判断栈是否为空


public boolean isEmpty(){
        return N==0;
    }

解析:因为我们有N统计栈中元素的个数,所以判断是否为空时,我们只需要返回N是否等于0即可。


2.获取栈中元素的个数


public int getLength(){
        return N;
    }

解析:同样是设计到元素的个数,需要获得栈中元素的个数,我们只需要返回N即可。感觉到这个N的好处了吗?


3.压栈(向栈顶放入元素)


/压栈
    public void push(T t){
        if(N==0){
            Node newNode = new Node(t, null);
            head.next=newNode;
        }else {
            //获取栈顶元素
            Node a = head.next;
            //创建新结点
            Node newNode = new Node(t, a);
            head.next = newNode;
        }
        N++;
    }

解析:首先对于压栈操作,我们需要有两种情况区分,第一种情况此时栈中是否有元素,如果此时N==0,代表无元素,那我们需要new出一个新结点,保存T的值,然后将其放在head的next,因为是第一个进入的所以为栈顶元素。第二种情况此时栈中有元素,即head的next是存在结点的,因为压栈是在栈顶加入元素,这就需要我们在头结点和原栈顶元素之间插入新元素,所以我们先获取原栈顶元素a。new出的新结点保存T的值,同时next指向原栈顶元素,这时再让头结点不指向a转而指向新结点newNode,这样我们就成功压栈。最后不要忘了无论第一种还是第二种情况我们都需要让N加1。


4.出栈(拿出栈顶元素,并得到它的值)


//出栈
    public T pop(){
        if(head.next==null){
            return null;
        }
        Node a=head.next;
        Node b=head.next.next;
        head.next=b;
        N--;
        return a.item;
    }

解析:同样需要进行对栈是否为空的判断,如果为空,我们返回null就好。如果不为空,我们首先获取栈顶结点并命名为a。再获取栈顶第二结点b,因为如果a出栈以后,b就变为栈顶元素了。我们直接让头结点head不指向a转而转向b即可,然后让N--,最后别忘记返回a.item,返回原栈顶结点的值。


ps:不难发现,出栈和压栈都与链表的插入和删除操作几乎一样,大家可以去对比一下,熟悉链表操作,对我们后续的各种数据结构的学习都是必要的


5.获取栈顶元素(未拿出)


//获取栈顶元素
    public T getHeadNext() {
        return head.next.item;
    }

解析:因为只需要得到栈顶元素不需要拿出,所以直接返回即可。注意不是返回head.next,我们需要的是值而不是结点。


6.判断栈中是否包含该元素


//判断栈中是否包含该元素
    public boolean contains(T t){
        Node a=head;
        while (a.next!=null){
            a=a.next;
            if(a.item==t) return true;
        }
        return false;
    }

 解析:因为栈是只能在一端进行操作的操作受限的线性表,所以想实现这个功能,我们只能通过循环遍历判断是否有需要找的元素,有则返回true,循环遍历结束还没找到,说明栈中没有,返回false即可


       总结:栈的逻辑结构比较简单,实现也容易,如果成功用链表实现了,那么也请用顺序表去实现栈结构,栈用的虽然少,但也是我们必须掌握的基础数据结构。


相关文章
|
12天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
35 3
|
22天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
38 5
|
19天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
56 2
|
1月前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
80 5
|
1月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
56 5
|
1月前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
8月前
|
Java
使用Java代码打印log日志
使用Java代码打印log日志
330 1
|
Java BI API
在Java代码中打日志需要注意什么?
日志是什么?日志是你在代码运行时打印出来的一些数据和记录,是快速排查问题的好帮手,是撕逼和甩锅的利器!
716 0
|
缓存 Java 网络架构
别在 Java 代码里乱打日志了,这才是正确的打日志姿势!
别在 Java 代码里乱打日志了,这才是正确的打日志姿势!
172 0
|
Java BI Apache
在Java代码中打日志需要注意什么?
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 为什么要打日志? 日志是什么?日志是你在代码运行时打印出来的一些数据和记录,是快速排查问题的好帮手! 做一件事情之前,先思考为什么。
在Java代码中打日志需要注意什么?

热门文章

最新文章