数据结构:双向链表

目录:

​1、简介​

​2、简单使用​

  ​​1、创建节点​

  ​​2、创建链表对象​

  ​​3、判断是否为空的方法​

  ​​4、判断该节点是否已经存在的方法​

  ​​5、将节点添加到链表尾部​

  ​​6、将节点添加到链表中,保持从小到大的顺序​

    ​​7、修改节点​

  ​​8、删除节点​

  ​​9、全部源码​





1、简介

在说双向链表之前,肯定要先说一下单向链表,因为双向链表是在单向链表的基础上进行修改。​​【单链表】​

那么我们这里简单的画一个单链表的图:

数据结构:双向链表_链表



单链表每个节点都有一个next属性,都指向了下一个节点,这就形成了一个链表的结构,那么这次记录的双向链表,表如其名,我们的单链表只是每个节点只有一个next属性指向其他节点,而我们的双向链表不仅仅有next属性,还有pre属性。


数据结构:双向链表_双向链表_02



这个图应该还是挺清晰的哈,双向链表在原单向链表的基础上增加了一个pre属性,指向了当前节点的前一个结点。



2、简单使用




1)创建节点


数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


 1 /*节点*/
2 /*英雄类-水浒传*/
3 class HeroNode2 {
4
5 public int no;
6 public String name;
7 public String nickName;
8
9 public HeroNode2 next;
10 public HeroNode2 pre;
11
12 public HeroNode2() {
13 }
14
15 public HeroNode2(int no, String name, String nickName) {
16 this.no = no;
17 this.name = name;
18 this.nickName = nickName;
19 }
20
21 @Override
22 public String toString() {
23 return "HeroNode2{" +
24 "no=" + no +
25 ", name='" + name + '\'' +
26 ", nickName='" + nickName + '\'' +
27 '}';
28 }
29 }

英雄节点

 节点中no、name、nickName为基础字段,为该节点存储的数据,pre和next分别指向前一个节点和后一个节点


2、创建链表对象


数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


1 /*双向链表*/
2 class DoubleLinkedList {
3
4 /*头节点*/
5 private HeroNode2 head = new HeroNode2();
6 }

链表对象


创建一个链表对象来存放操作双向链表的方法



3、判断是否为空的方法

 如果头节点的next为空,那么就说明该链表中没有数据

数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


/*判断链表是否为空*/
public boolean isEmpty() {
return head.next == null;
}

判断链表是否为空(存放到DoubleLinkedList中)



4、判断该节点是否已经存在的方法

数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


 1  /*判断该节点是否已经存在与链表中*/
2 public boolean isExits(HeroNode2 heroNode) {
3 if (isEmpty()) {
4 return false;
5 }
6 HeroNode2 tmp = head.next;
7 while (true) {
8 if (tmp == heroNode) {
9 return true;
10 }
11 if (tmp == null) {
12 return false;
13 }
14 tmp = tmp.next;
15 }
16 }

判断该节点是否已经存在(存放在DoubleLinkedList中)

 首先判断是否为空,如果为空,那肯定不存在,如果不为空,那么就遍历链表进行判断



5、将节点添加到链表的底部


数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


 1 /*将节点添加到链表的底部*/
2 public boolean addHeroNode(HeroNode2 heroNode) {
3 /*如果为空,那么直接添加到链表的底部*/
4 if (isEmpty()) {
5 head.next = heroNode;
6 heroNode.pre = head;
7 return true;
8 }
9 /*判断是否已经存在于链表中*/
10 if (isExits(heroNode)) {
11 System.err.println(heroNode + "已经存在于链表中不能添加");
12 return false;
13 }
14 HeroNode2 tmp = head.next;
15 while (true) {
16 if (tmp.next == null) {
17 tmp.next = heroNode;
18 heroNode.pre = tmp;
19 return true;
20 } else {
21 tmp = tmp.next;
22 }
23 }
24 }

将节点添加到链表的底部(存放在DoubleLinkedList中)

先判断是否为空,如果为空那么就直接放置到头结点的next中,然后把头结点放置到节点的pre中。

如果不为空,那么就遍历,只要遍历到尾部,例如尾部节点为end,我们需要加进去的节点为node,那么只需要将node赋值给end.next,然后将end赋值给node.pre,那么end的next往后的一条线和node.pre往前的一条线就连成了。

数据结构:双向链表_双向链表_13



 6、将节点添加到链表,保持从小到大的顺序

数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


 1 /*将节点添加到链表中,保持从小到大的顺序*/
2 public boolean addHeroNodeOrder(HeroNode2 heroNode) {
3 /*如果为空,那么直接添加到尾部*/
4 if (isEmpty()) {
5 head.next = heroNode;
6 heroNode.pre = head;
7 return true;
8 }
9 /*判断该节点是否存在于链表中,如果存在,则不要进行添加*/
10 /*判断是否已经存在于链表中*/
11 if (isExits(heroNode)) {
12 System.err.println(heroNode + "已经存在于链表中不能添加");
13 return false;
14 }
15 /*从第一个元素开始遍历*/
16 HeroNode2 tmp = head.next;
17 while (true) {
18 if (tmp.no > heroNode.no) {
19 /*如果当前节点的no大于需要添加的节点的no,那么就将需要加入的节点放置到当前节点的前一个*/
20 tmp.pre.next = heroNode;
21 heroNode.pre = tmp.pre;
22 tmp.pre = heroNode;
23 heroNode.next = tmp;
24 return true;
25 } else if (tmp.next == null) {
26 /*tmp的下一个为空,说明已经完了,直接加到末尾*/
27 tmp.next = heroNode;
28 heroNode.pre = tmp;
29 return true;
30 } else {
31 tmp = tmp.next;
32 }
33 }
34 }

将节点添加到链表的同时保持顺序(DoubleLinkedList)


首先是判断是否为空,如果为空,那么就直接添加到head后。

然后再判断该节点是否已经存在,如果已经存在,那么则不能添加

然后遍历链表,如果当前当前遍历到的节点为current,然后需要添加的节点为node

如果current的no大于node的no的话,那么我们就需要将node存到current的前面去。

首先让current的pre的next指向node,然后node.pre就等于current.pre,然后至此,current的前一个节点就会指向current,然后我们需要做的就是将current的pre指向我们的node,最后我们需要将node.next指向我们的current。

数据结构:双向链表_删除节点_16



7、修改节点

数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


 1   /*修改节点数据,通过no*/
2 public boolean update(HeroNode2 heroNode2) {
3 if (isEmpty()) {
4 System.err.println("链表为空!");
5 return false;
6 }
7 HeroNode2 tmp = head.next;
8 while (tmp != null) {
9 if (tmp.no == heroNode2.no) {
10 tmp.name = heroNode2.name;
11 tmp.nickName = heroNode2.nickName;
12 return true;
13 } else {
14 tmp = tmp.next;
15 }
16 }
17 return false;
18 }

修改节点(存放在DoubleLinkedList中)


这个没啥逻辑,就是遍历,找到了就修改name和nickName 




 8、删除节点


数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


 1     /*删除节点*/
2 public boolean delByNo(Integer no) {
3 if (isEmpty()) {
4 System.err.println("当前链表为空,无法删除");
5 return false;
6 }
7 HeroNode2 tmp = head.next;
8 /*可能有多个相同no的节点,所以当成立删除时并不停止。*/
9 boolean flag = false;
10 while (tmp != null) {
11 if (tmp.no == no) {
12 /**/
13 tmp.pre.next = tmp.next;
14 tmp.next.pre = tmp.pre;
15 flag = true;
16 }
17 tmp = tmp.next;
18 }
19 return flag;
20 }

删除节点(存放在DoubleLinkedList)



遍历,如果当前节点的no就是我们需要删除的no,假设我们当前节点为current,然后需要删除的no为3

那么就是如果current.no==3的话,那么我们current的pre的next就等于node.next,然后node.next.pre就等于我们current的pre。

数据结构:双向链表_链表_21



9、全部源码


数据结构:双向链表_链表_03数据结构:双向链表_双向链表_04


  1 package t4;
2
3
4 import t2.Test;
5
6 import java.util.Random;
7
8 /**
9 * @author 自在仙
10 * @create 2020年04月19 12:20
11 */
12 public class DoubleLinkedListDemo {
13
14 public static void main(String[] args) {
15 DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
16 HeroNode2 heroNode = new HeroNode2(1, "林冲", "林大哥");
17 HeroNode2 heroNode2 = new HeroNode2(2, "林冲2", "林大哥");
18 HeroNode2 heroNode3 = new HeroNode2(3, "林冲3", "林大哥");
19 HeroNode2 heroNode5 = new HeroNode2(3, "林冲3", "林大哥");
20 HeroNode2 heroNode4 = new HeroNode2(4, "林冲4", "林大哥");
21 doubleLinkedList.addHeroNodeOrder(heroNode4);
22 doubleLinkedList.addHeroNodeOrder(heroNode3);
23 doubleLinkedList.addHeroNodeOrder(heroNode5);
24 doubleLinkedList.addHeroNodeOrder(heroNode);
25 doubleLinkedList.addHeroNodeOrder(heroNode2);
26 /*
27 doubleLinkedList.display();
28
29 doubleLinkedList.delByNo(3);
30
31 System.out.println("-------------");*/
32
33 doubleLinkedList.display();
34
35 }
36 }
37
38 /*双向链表*/
39 class DoubleLinkedList {
40
41 /*头节点*/
42 private HeroNode2 head = new HeroNode2();
43
44 /*判断链表是否为空*/
45 public boolean isEmpty() {
46 return head.next == null;
47 }
48
49 /*将节点添加到链表的底部*/
50 public boolean addHeroNode(HeroNode2 heroNode) {
51 /*如果为空,那么直接添加到链表的底部*/
52 if (isEmpty()) {
53 head.next = heroNode;
54 heroNode.pre = head;
55 return true;
56 }
57 /*判断是否已经存在于链表中*/
58 if (isExits(heroNode)) {
59 System.err.println(heroNode + "已经存在于链表中不能添加");
60 return false;
61 }
62 HeroNode2 tmp = head.next;
63 while (true) {
64 if (tmp.next == null) {
65 tmp.next = heroNode;
66 heroNode.pre = tmp;
67 return true;
68 } else {
69 tmp = tmp.next;
70 }
71 }
72 }
73
74 /*将节点添加到链表中,保持从小到大的顺序*/
75 public boolean addHeroNodeOrder(HeroNode2 heroNode) {
76 /*如果为空,那么直接添加到尾部*/
77 if (isEmpty()) {
78 head.next = heroNode;
79 heroNode.pre = head;
80 return true;
81 }
82 /*判断该节点是否存在于链表中,如果存在,则不要进行添加*/
83 /*判断是否已经存在于链表中*/
84 if (isExits(heroNode)) {
85 System.err.println(heroNode + "已经存在于链表中不能添加");
86 return false;
87 }
88 /*从第一个元素开始遍历*/
89 HeroNode2 tmp = head.next;
90 while (true) {
91 if (tmp.no > heroNode.no) {
92 /*如果当前节点的no大于需要添加的节点的no,那么就将需要加入的节点放置到当前节点的前一个*/
93 tmp.pre.next = heroNode;
94 heroNode.pre = tmp.pre;
95 tmp.pre = heroNode;
96 heroNode.next = tmp;
97 return true;
98 } else if (tmp.next == null) {
99 /*tmp的下一个为空,说明已经完了,直接加到末尾*/
100 tmp.next = heroNode;
101 heroNode.pre = tmp;
102 return true;
103 } else {
104 tmp = tmp.next;
105 }
106 }
107 }
108
109 /*删除节点*/
110 public boolean delByNo(Integer no) {
111 if (isEmpty()) {
112 System.err.println("当前链表为空,无法删除");
113 return false;
114 }
115 HeroNode2 tmp = head.next;
116 /*可能有多个相同no的节点,所以当成立删除时并不停止。*/
117 boolean flag = false;
118 while (tmp != null) {
119 if (tmp.no == no) {
120 /**/
121 tmp.pre.next = tmp.next;
122 tmp.next.pre = tmp.pre;
123 flag = true;
124 }
125 tmp = tmp.next;
126 }
127 return flag;
128 }
129
130 /*修改节点数据,通过no*/
131 public boolean update(HeroNode2 heroNode2) {
132 if (isEmpty()) {
133 System.err.println("链表为空!");
134 return false;
135 }
136 HeroNode2 tmp = head.next;
137 while (tmp != null) {
138 if (tmp.no == heroNode2.no) {
139 tmp.name = heroNode2.name;
140 tmp.nickName = heroNode2.nickName;
141 return true;
142 } else {
143 tmp = tmp.next;
144 }
145 }
146 return false;
147 }
148
149 /*判断该节点是否已经存在与链表中*/
150 public boolean isExits(HeroNode2 heroNode) {
151 if (isEmpty()) {
152 return false;
153 }
154 HeroNode2 tmp = head.next;
155 while (true) {
156 if (tmp == heroNode) {
157 return true;
158 }
159 if (tmp == null) {
160 return false;
161 }
162 tmp = tmp.next;
163 }
164 }
165
166 /*遍历该链表*/
167 public void display() {
168 if (isEmpty()) {
169 System.out.println("当前链表为空");
170 }
171 HeroNode2 temp = head.next;
172 while (temp != null) {
173 System.out.println(temp);
174 temp = temp.next;
175 }
176 }
177
178 }
179
180 /*节点*/
181 /*英雄类-水浒传*/
182 class HeroNode2 {
183
184 public int no;
185 public String name;
186 public String nickName;
187
188 public HeroNode2 next;
189 public HeroNode2 pre;
190
191 public HeroNode2() {
192 }
193
194 public HeroNode2(int no, String name, String nickName) {
195 this.no = no;
196 this.name = name;
197 this.nickName = nickName;
198 }
199
200 @Override
201 public String toString() {
202 return "HeroNode2{" +
203 "no=" + no +
204 ", name='" + name + '\'' +
205 ", nickName='" + nickName + '\'' +
206 '}';
207 }
208 }

所有源码,