Java-----Java实现双向链表

双向链表

1.双向链表简介

双向链表和单向链表略微有些区别,  需要将每个节点划分为3个部分, 一个部分存储数据, 一个部分存储前一个节点的地址, 一个数据存储后面的节点位置

Java-----Java实现双向链表

 

2.双向链表的算法实现

创建一个类Node, 用于描述每个节点, Node中表示数据的为data(Object)类型, 表示前一个简单的为pre(Node类型), 后一个节点为next(Node类型)

Java-----Java实现双向链表

 

2.1 add()方法

2.1.1 尾节点和尾指针

(1) 尾节点

和单向链表一样, 在往里面添加数据的时候, 通过Node将数据进行封装, 所以每次新添加一个节点就要创建一个Node对象, 然后要将这个节点和该链表中的其它链表产生关联, 在之前的单向链表中, 提到了一个首节点的概念, 有了首节点, 能够很方便的对整个链表进行操作,但是这例要普及另一个概念-----尾节点.

尾节点和首节点的概念相似, 首节点是链表中的第一个节点, 而尾节点就是链表中的最后一个节点

Java-----Java实现双向链表

 

如上图所示, Last为尾节点, 因为是非循环链表, 所以尾节点的next指向尾null

(2) 尾指针

尾指针是指向尾节点的一个指针, 但是Java中并没有指针的概念, 但是可以定义一个Node类型变量

l(字母L, 不是1), 用作记录最后一个节点的位置

Java-----Java实现双向链表

 

2.1.2 算法分析

有了尾节点和尾指针, 添加操作就会非常的简单, 因为尾节点的next指向是null的, 所以只需要判断这个Node节点的next指向是否为null, 如果为null, 那么就让该节点的next指向每次添加时新new的Node节点

Java-----Java实现双向链表

 

2.1.3 代码实现

首先定义头节点和尾节点

 Java-----Java实现双向链表

然后定义尾指针l, 指向end尾节点

Java-----Java实现双向链表

 

每次add()时, 都要创建一个新的Node节点, 新的Node节点的pre为添加之前的尾节点, 新节点将作为尾节点, 所以next为null,

Java-----Java实现双向链表

 

接下来在添加节点的时候,  要先判断尾指针是否为null, 因为在进行添加操作时, 首先做的操作时将尾节点赋值给了尾指针(Node l = end), 然后将新的Node节点newNode赋值给了尾节点end, 这证明了如果l尾指针为null, 那么证明Node节点没有被new过, 所以此时头节点head和尾节点end都不存在, 这个时候就将新的Node节点newNode, 赋值给head节点, 这样才方便链表的后续操作

Java-----Java实现双向链表

 

当尾指针存在的情况下, 就将尾指针的next指向这个newNode

Java-----Java实现双向链表

2.2 size()get()方法

2.1已经实现了add()方法, 但是数据到底有没有存入进去, 需要遍历一下链表查看,

Java-----Java实现双向链表

遍历的时候需要使用size()方法和get()方法, 所以接下来实现这两个方法

 

2.2.1 size()方法

size方法实现比较简单, 只需要定义一个全局的计数变量size

Java-----Java实现双向链表 

每次add()时将计数自增1, 每次remove()时计数器自减1即可.

Java-----Java实现双向链表

 

先暂时执行自增, 当后面实现remove()方法时,再进行自减

 

2.2.2 get()方法

get()方法是获取链表中某个节点数据的方法, 一般情况下通过下标来获取, 所以这个方法需要一个返回值为Object, 一个参数为index

因为后续还要会有set和remove方法, 都要通过下标找到相应的节点, 所以这里可以先封装两个方法, 分别是下标越界的检查 和 Node节点的查找

Java-----Java实现双向链表

Java-----Java实现双向链表

 

有了以上两个方法, 那么在get方法中, 只需要检查一下标是否越界, 然后再将下标index传入到node()方法中获取到Node节点, 最后将该节点的data数据返回即可

Java-----Java实现双向链表

 

2.2.3 node()方法的实现

(1) 算法分析

单向链表由于每个Node节点只知道后面的Node节点是谁而不知道前面的Node节点是谁, 所以只能从头到尾逐次遍历查找, 但是双向链表的特点就是每个Node节点不仅知道下一个Node节点是谁,还知道前面一个Node节点是谁, 所以在查找的时候就可以根据需要查找的下标index的大小决定从前开始遍历还是从后开始遍历

Java-----Java实现双向链表

 

(3) 代码实现

Java-----Java实现双向链表

 

此时size()和get()方法已经实现, 进行方法测试

Java-----Java实现双向链表

 

 

2.3 set()方法

2.3.1 方法设计

   set()方法能够根据下标index修改Node节点中的data数据为新数据newData, 并且将修改之前的结果返回, 所以set()方法的需要两个参数, 一个参数是需要修改的Node节点的下标, 另一个参数是新数据newData, 返回值类型为data的类型Object

Java-----Java实现双向链表

 

2.3.2方法分析

如果要修改某个节点的数据, 首先要找到这个Node节点, 然后将这个节点中的data数据替换为newData

 

2.3.3 代码实现

Java-----Java实现双向链表

 

2.4 remove()方法

2.4.1 方法设计

删除方法需要知道要删除的Node节点的索引, 所以需要一个参数为下标index, 删除后返回所删除的节点中的data, 所以需要一个Object类型的返回值

Java-----Java实现双向链表

 

 

2.4.2 算法分析

在链表的删除操作中, 首节点head和尾节点end是一定要存在,

所以有以下几种情况

当删除head时, 就要让head的next所指向的Node节点作为head,

当删除end时, 就要让end的pre所指向的节点为end

当删除的不是head和node时, 只要将当前节点的pre所指向的Node的next指向当前节点的next所指向的节点即可

 

2.4.3 方法实现

Java-----Java实现双向链表

 

3. 将数据类型改为泛型

在Java中常使用的集合, 数据的类型都是泛型, 所以这里将所有数据类型改为泛型

首先定义泛型T

Java-----Java实现双向链表

 

然后全局将Object替换为T

Java-----Java实现双向链表

 

Node前加上泛型, Node<T>

Java-----Java实现双向链表

 

此时再往里面添加非泛型定义的数据时, 就会报错

Java-----Java实现双向链表

 

其实, 以上就是Java中LinkedList的部分源码!!!