龙空技术网

关于线性结构中的双向链表如何实现

千锋教育 138

前言:

此时姐妹们对“java实现一个双向链表”大概比较注意,各位老铁们都想要了解一些“java实现一个双向链表”的相关资讯。那么小编同时在网上汇集了一些关于“java实现一个双向链表””的相关知识,希望看官们能喜欢,你们一起来了解一下吧!

前言

在上一篇文章中,主要是给大家介绍了单向链表的特点及其原理,但是我们没有通过代码进行练习。今天我会继续通过一篇文章,来给大家讲解双向链表的内容,尤其是会通过代码来进行链表的操作,希望大家重点关注哦。

全文大约【3500】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考...

一. 双向链表简介1. 概念

在上一篇文章中,我们在介绍链表的种类时,曾经提到过双向链表。双向链表相比较于单链表,除数据域外,还具前和后两个指向指针。

双向链表中的结构术语可以解释为:

data链表每个结点中存储的数据域;next链表每个结点中包含的指向下一个结点地址的指针域;prev链表每个结点中包含的前一个结点地址的指针域。2. 编码定义

根据上述对双向链表结点的定义,我们给出双向链表结点结构的Java定义实现:

双向链表是一条真实存在的链表,由多个结点组成。在实际的编程中,通常会标记链表的两个特殊结点,分别为:头结点、尾结点。用另外一个变量size表示链表中元素的个数。

头结点: 链表中的第一个结点尾结点: 链表中的最后一个元素

因此有如下链表类的定义:

在本篇文章接下来的内容中,我们将利用该DNode、DoubleLinkList两个定义来实现双向链表的各项操作。

二. 常见操作

因为双向链表是单链表的基础上扩展出来的结构,因此双向链表的很多操作与单链表的操作都是相同的,比如:查找元素、更新元素、插入元素、删除元素

1. 查找元素

1.1 查找头结点

因为DoubleLinkList中已经记录了头结点head,因此头结点的查找非常简单,如下:

时间复杂度为O(1)。

1.2 查找尾结点

与头结点同理,查找尾结点的时间复杂度同样为O(1),编码如下:

1.3 查找指定位置结点

当需要查找指定位置的结点元素时,双向链表比单链表的实现方式有所不同,原因是:

单链表因为是单向的,因此只能从头结点向后单向查找;但双向链表前后均可查找,因此在进行指定位置查找时,为了提高查找效率,会首先判断要查找的位置处于链表的前半段还是后半段,若前半段则从头结点向后查找,若后半段则从尾结点向前查找,具体编程如下所示:

在上述代码中,size >> 1 的写法比较少见,“>>”在计算机编程中代表移位操作。常见的移位操作有两种:

>>:向右移位操作,将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃,左边移出的空位一律补0,或者补符号位。<<:向左移位操作,将一个二进制位的操作数按指定移动的位数向左移动,移出位被丢弃,右边移出的空位一律补0。

通过实际的编程验证,我们可以知道:执行右移1位操作,变量数据会缩小为原来的1/2。左移相反。同时,我们可以分析出时间复杂度为O(n)。

2. 更新元素

更新元素操作需要两步:

找到要更新的元素执行更新操作

根据位置的不同,可以将更新操作分为三种情况:更新头结点,更新尾结点,更新指定位置结点。

2.1 更新头结点

更新头结点代码与查找头结点类似,如下:

更新头结点的时间复杂度为O(1)。

2.2 更新尾结点

更新尾结点的时间复杂度同样是O(1)。

2.3 更新指定位置结点

如上代码所示,修改指定结点元素的值采用的算法也是:先判断要操作的位置在前半段还是后半段,然后再进行精准查找,最后执行修改操作。

指定位置修改操作的时间复杂度为O(n)。

3. 插入元素

分析过了查找元素和更新元素操作的具体情况,我们很清晰的便能分析出插入元素操作的具体情况,其实也分为三种具体情景:头结点位置插入,尾结点位置插入,指定位置插入元素

3.1 头结点位置插入

根据如上代码,我们可以看到,在头结点位置插入新的元素,只需要将新添加的结点置为head结点,同时处理好新结点和原链表中头结点的指向关系即可。很明显,头结点位置插入的时间复杂度为O(1)。

3.2 尾结点位置插入

尾结点插入与头结点插入原理相同,只需要替换为尾结点以及指针的指向。如下所示:

时间复杂度为O(1)。

3.3 指定位置插入

在进行指定位置插入时,编程代码稍多些,原因是需要以下几步完成:

判断插入的位置是否超范围若插入的位置在最后,则执行在尾结点的插入逻辑先根据要插入的位置,查找并获取到对应位置的结点元素然后执行插入逻辑

根据上述代码,我们可以发现插入指定位置的代码,需要用到查找指定位置的操作,先查找再插入,因此时间复杂度同样为O(n)。

4. 删除元素

有了前面的分析经验,我们可以非常自然的分析出删除操作同样分三种:删除头结点、删除尾结点、删除指定结点。接下来,一起来看看详细的情况:

4.1 删除头结点

删除头结点只涉及头结点的逻辑判断和操作,因此删除头结点时间复杂度为O(1)。

4.2 删除尾结点

与删除头结点原理相同,操作尾结点。代码如下:

很明显,删除尾结点的时间复杂度为O(1)。

4.3 删除指定结点

删除指定结点的编码实现如下:

如上代码所示,删除指定位置的结点元素也需要先执行index(index)查找算法,至于index的实现,在前文介绍指定位置插入结点操作时,已经进行了实现,此处直接进行使用。

我们不难分析得到,删除指定位置的结点的时间复杂度是O(n)。

三. 其他操作

作为一种常见的数据结构,除了对自身结点元素的一些操作,还有一些对链表状态的获取,比如链表的长度,链表是否为空等,这里给大家介绍一下双向链表的一些其他操作。

1. 链表的大小(元素结点的个数)

2. 判断链表是否为空

3. 获取链表元素组成的数组

4. 清空链表

四. 结语

至此,我们已经连续用两篇文章给大家介绍了链表的相关知识。

在上一篇文章中,我们主要介绍了链表的基础知识和单链表的常规操作, 同时辅以图示来说明各种操作情况。在本篇文章中,主要是从Java编程角度作为切入点,来进一步讲解双向链表的一些操作。 特别是本篇文章中的大量代码实践,需要大家能够理清逻辑关系,希望你可以动手练起来哦。

5分钟学会数据结构中的线性链表

深入浅出Spring原理及实战「缓存Cache开发系列」

从零开始学Java之查找算法有哪些?

SQLYog使用教程

更多技术类干货/IT程序员资讯,关注@千锋教育

标签: #java实现一个双向链表 #用java实现双向链表 #双向链表java实现 #双向链表的实现 #双向链表的实现原理