数据结构基础——链表、栈、队列

链表是什么

链表是一种很常见的数据结构,是一种线性结构。他的数据形式类似我们日常认知中的锁链,使用每个节点保存下一个节点的指针的方式实现关联。

链表在删除和新增的时候,只需要修改前一个结点的指向位置即可,和数组相比并不需要进行整体位移,所以链表在修改操作上比数组要优秀。

简单的链表示例

data:A-next:b
data:b-next:c
地址c-data:C-next:e

使用链表的集合

我们长接触的链表结构主要有LinkedList、LinkedHashMap,队列、栈等。

链表分类

我们目前经常用到的链表主要有下面几种:

  • 单链表
  • 双向链表
  • 循环链表

单向链表

单向链表的一个节点被分为了两个部分,一部分为节点数据保存了节点了信息。一部分为next的地址。
根据这个结构,单向链表只能向一个方向进行遍历,查找一个节点的时候需要从第一个节点开始每次访问下一个节点,直到找到需要的位置。

图示

data:A-next:b
data:B-next:c
地址c-data:C-next:e
操作

新增

此时为原始数据

原始
data:A-next:b
data:B-next:c
地址c-data:C-next:e

在B和C之间添加O节点

修改指向
修改B的节点指向为o
断开连接
data:A-next:b
data:B-next:c
地址o-data:O-next:e
地址c-data:C-next:e

将O的next坐标设置为之前B的next

修改新节点的指向
新的指向关系
data:A-next:b
data:B-next:c
地址o-data:O-next:c
地址c-data:C-next:e

流程为:

  1. 定位需要添加节点的位置B。
  2. 将B指向的nextc,修改为o
  3. 将O中next指向为c。此时完成数据插入

删除

此时为原始数据,准备一处O节点

原始
data:A-next:b
data:B-next:c
地址o-data:O-next:c
地址c-data:C-next:e

此时获得O节点的上一节点,同时获取O节点next的指向信息

修改坐标
断开连接
添加新的连接
data:A-next:b
data:B-next:c
data:O-next:c
data:C-next:e

流程为:

  1. 遍历链表找到需要删除的节点的节点以及其上一节点。
  2. 将上一节点的next指向修改为被删除节点的next

双向链表

链表中的元素,除了能够指向下一个节点,同时还能够指向上一个元素节点,每个节点都存在两个指针。整个关联关系从前向后和从后向前都是可以的。

图示

data:A-next:b
pre:a-data:B-next:c
pre:b-data:C-next:e
操作

新增

原始
data:A-next:b
pre:a-data:B-next:c
pre:b-data:C-next:e

添加节点O,修改B和C节点的坐标

修改前后节点next和pre的指向
修改其next坐标为o
修改其pre坐标为o
data:A-next:b
pre:a-data:B-next:o
O
pre:c-data:C
为新节点添加前后指向
data:A-next:b
pre:a-data:B-next:o
pre:b-data:C-next:c
pre:c-data:C

流程为:

  1. 确定需要插入节点的位置。
  2. 将插入位置的上一节点的next指向新的节点,然后将原来下一节点的pre指向新的节点
  3. 添加新的节点的next和pre分别指向新的前后坐标

删除

原始数据
data:A-next:b
pre:a-data:B-next:o
pre:b-data:C-next:c
pre:c-data:C
修改被删除节点前后节点的next和pre
断开连接
断开连接
修改其next坐标为c-修改其pre坐标为b
data:A-next:b
pre:a-data:B-next:c
O
pre:b-data:C

流程为:

  1. 首先确定删除节点,然后根据pre和next确定其前后节点
  2. 将pre节点的next指向为被删除节点的next,将next节点的pre指向为被删除节点的pre信息

循环链表

循环链表指的是在链表的最后一个结点上指向第一个节点从而实现循环

图示

pre:c-data:A-next:b
pre:a-data:B-next:c
pre:b-data:C-next:a

判断循环链表

一个完美的圆形链表可以从某处开始循环当再次遍历到此位置的时候可以确定其为循环链表。但是对于其他情况则不能这样使用。比如这种部分循环的链表。在执行遍历后链表会在某处进入生死循环。

H
O
pre:c-data:A-next:b
pre:点a-data:B-next:c
pre:b-data:C-next:a

所以我们可以使用快慢指针的思想的思想去判断是否循环链表。

快慢指针的原理是:我们定义两个节点指针fast、slow。对这两个指针设置不同的步长,比如fast步长2、slow步长1。然后让他们同时从头部节点开始遍历链表,如果链表是循环的则快慢指针总会相遇。

当然除了快慢指针我们还可以将我们之前遍历过的数据缓存起来。每次遍历下一节点的时候去缓存中比对下此节点是否已经被遍历过。如果缓存中已经存在则证明链表中存在环形结构。

栈也是一种线性表,但是和链表不同之处。栈只允许从尾部操作数据。也就是只能对尾部的元素进行新增和删除操作。它按照先进先出原则进行操作(last in first out)

栈的数据添加和移除

在这里插入图片描述

java中的栈

java中java.util.Stack实现了出栈和入栈的操作,其通过继承Vector添加了自己的方法来实现入栈和出栈,还是用的父类Vector的方法来执行元素操作。

栈的操作

初始化

Stack s = new Stack();

压栈

压栈的时候使用

s.push("");

出栈

按照真正的栈的操作,执行出栈的时候栈顶元素会被移除,但是在java.util.Stack中提供了两个方法

peek:会查看栈顶元素但是并不会移除它。
pop:类似真正的出栈操作,会移除栈顶元素

    s.peek();
    s.pop();

判空

java为栈提供了empty方法来进行空值判断。

遍历

java为栈提供了removeAllElements方法来进行空值判断。

清空

java为栈提供了elements方法来进行空值判断。

队列

和栈相反,队列是一种只允许一端进行插入而在另一端进行删除的线性结构

队列的操作

假如存在以下队列

队列:头--尾
元素1
元素2
元素3
元素4

删除

执行删除操作的时候会将头部元素取出

队列:头--尾
元素2
元素3
元素4
元素1-被取出

插入

当我们插入数据的时候只能从尾部插入

队列:头--尾
元素1
元素2
元素3
元素4
新元素

java中的队列

JAVA中使用了java.util.Queue来实现了队列的相关内容。

双端队列

在JAVA中对队列做了一个扩展使用了java.util.Deque定义了一种可以从头部和尾部进行删除操作的队列。

java中队列关系图

在这里插入图片描述

java中队列的实现

在JAVA中对于队列提供了两种实现:

java.util.concurrent.LinkedBlockingQueue基于链表的实现

java.util.concurrent.ArrayBlockingQueue基于数组的实现

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大·风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值