一.单向链表(递归)
MyLinkList类
1 package List;
2
3 // 单向链表
4 public class MyLinkList {
5 private Node root; // 根结点
6 private int size; // 结点个数
7 private int index; // 脚标
8 private Object[] reData; // 保存数据的数组
9
10 // 构造方法
11 public MyLinkList() {
12 this.root = new Node("head");
13 System.out.println("创建了带头指针的链表");
14 }
15
16 public MyLinkList(Object data) {
17 if (data == null)
18 System.out.println("参数错误");
19 this.root = new Node(data);
20 this.size++;
21 System.out.println("创建成功" + data);
22 }
23
24 // 是否是空表
25 public boolean isEmpty() {
26 return this.size == 0;
27 }
28
29 // 返回长度
30 public int size() {
31 return this.size;
32 }
33
34 // 清空链表
35 public void clear(){
36 this.root = null;
37 this.size = 0;
38 }
39
40 // 判断两个链表是否相等
41 public boolean equals(Object obj){
42 // 常规判断
43 if(obj == null)
44 return false;
45 if(obj == this)
46 return true;
47
48 // 是MyLinkList类
49 if(obj instanceof MyLinkList){
50 MyLinkList linkList = (MyLinkList)obj;
51
52 // 根结点相同
53 if(!this.root.data.equals(linkList.root.data)){
54 System.out.println("根节点不相同");
55 return false;
56 }
57 // 长度相同
58 if(this.size != linkList.size) {
59 System.out.println("长度不同");
60 return false;
61 }
62
63 // 各个结点相同
64 if(this.size==1){ // 只含有根结点
65 return true;
66 }
67 return this.root.next.equals(linkList.root.next);
68 }
69
70 // 不是MyLinkList类
71 return false;
72
73 }
74
75 // 添加单个数据
76 public boolean addData(Object data) {
77 if (data == null) {
78 System.out.println("参数错误");
79 return false;
80 }
81
82 // 把data封装成带指针域的结点
83 Node node = new Node(data);
84
85 if (this.root.next == null)
86 this.root.next = node;
87 else
88 this.root.next.addNode(node);
89 System.out.println("添加成功" + data);
90 this.size++;
91 return true;
92 }
93
94 // 添加多个数据
95 public boolean addDatas(Object[] datas) {
96 if (datas == null) {
97 System.out.println("参数错误");
98 return false;
99 }
100
101 // 循环添加结点
102 for (int index = 0; index < datas.length; ++index) {
103 Node data = new Node(datas[index]);// 封装结点
104 this.root.addNode(data);
105 this.size++;
106 }
107 return true;
108 }
109
110 // 查找数据是否存在
111 public boolean contains(Object data) {
112 if (data == null || this.isEmpty())
113 return false;
114 return this.root.containsNode(data);
115 }
116
117 // 查找指定位置下的数据
118 public Object get(int index) {
119 // 参数错误
120 if (this.isEmpty() || index < 0 || index > this.size)
121 return null;
122
123 if (this.root.data.equals("head")) { // 带头指针
124 if (index == 1) // 返回第一个有效数据
125 return this.root.next.data;
126 else {
127 this.index = 0;
128 return this.root.next.getNode(index);
129 }
130 } else { // 不带头指针
131 if (index == 1) // 返回第一个有效数据
132 return this.root.data;
133 else {
134 this.index = 1;
135 return this.root.next.getNode(index);
136 }
137
138 }
139 }
140
141 // 删除数据
142 public boolean deleteData(Object data) {
143 if (data == null || this.isEmpty()) {
144 return false;
145 }
146 // 是根结点
147 if (this.root.data.equals(data)) {
148 this.root = this.root.next;
149 this.size--;
150 return true;
151 }
152
153 // 不是根节点
154 else
155 return this.root.deleteNode(data);
156 }
157
158 // 打印所有数据
159 public void print() {
160 if (this.isEmpty())
161 System.out.print("空表--------");
162 else
163 this.root.printNode();
164 System.out.println("");
165 }
166
167 // 返回数组数据
168 public Object[] toArray() {
169 if (this.isEmpty())
170 return null;
171
172 // 数组保存
173 this.index = 0; // 数组下标
174 if (this.root.data.equals("head")) // 链表带头指针
175 reData = new Object[++this.size];
176 else
177 reData = new Object[this.size];
178 this.root.toArray();
179 return reData;
180 }
181
182 // 结点类(内部)
183 class Node {
184 Object data; // 数据域
185 Node next; // 指针域
186
187 // 构造方法
188 public Node(Object data) {
189 this.data = data;
190 }
191
192 // 添加结点
193 public void addNode(Node node) {
194 if (this.next == null)
195 this.next = node;
196 else
197 this.next.addNode(node);
198 }
199
200 // 打印结点数据
201 public void printNode() {
202 System.out.print(this.data + " ");
203 if (this.next != null)
204 this.next.printNode();
205 }
206
207 // 删除结点
208 public boolean deleteNode(Object data) {
209 if (this.next == null) {
210 System.out.println("删除失败" + data);
211 return false;
212 }
213 if (this.next.data.equals(data)) {
214 System.out.println("删除成功" + this.next.data);
215 MyLinkList.this.size--;
216 this.next = this.next.next;
217 return true;
218 }
219 return this.next.deleteNode(data);
220 }
221
222 // 返回数组
223 public void toArray() {
224 MyLinkList.this.reData[MyLinkList.this.index++] = this.data;
225 if (this.next != null)
226 this.next.toArray();
227 }
228
229 // 查找指定结点
230 public Object getNode(int index) {
231 if (++MyLinkList.this.index == index)
232 return this.data;
233 return this.next.getNode(index);
234 }
235
236 // 查找结点
237 public boolean containsNode(Object data) {
238 if (this.data == data)
239 return true;
240 if (this.next != null)
241 return this.next.containsNode(data);
242 return false;
243 }
244
245 // 重写equals()
246 public boolean equals(Node node){
247 // 数据域是否相同
248 if(!this.data.equals(node.data)) {
249 System.out.println("数据域不同this:"+this.data+" linkList:"+node.data);
250 return false;
251 }
252 // 还有下个结点
253 if(this.next!=null)
254 return this.next.equals(node.next);
255 // 没有下个结点且到目前为止所有结点数据域相同
256 return true;
257
258 }
259 }
260 }
MyLinkList
TestMyLinkList类
1 package List;
2
3 // 单向链表测试
4 public class TestMyLinkList {
5
6 public static void main(String[] args) {
7 // 创建一个链表
8 MyLinkList linkList = new MyLinkList(5);
9
10 // 初始化一个链表
11 for (int index = 1; index < 10; ++index) {
12 int num = (int) (Math.random() * 11);
13 linkList.addData(num);
14 }
15
16 // 打印链表的所有数据
17 linkList.print();
18
19 // 删除结点
20 linkList.deleteData(5);
21 linkList.print();
22 linkList.deleteData(10);
23 linkList.print();
24
25 System.out.println("第2个结点数据:" + linkList.get(2));
26 // 数组化
27 Object[] data = new Object[linkList.size()];
28 data = linkList.toArray();
29 for (Object index : data)
30 System.out.print(index + " ");
31 System.out.println("");
32 System.out.println("-------------------");
33 // 创建一个链表
34 MyLinkList linkList2 = new MyLinkList();
35
36 // 待添加数据的数组
37 Object[] datas = { 5, "123", 26 };
38 linkList2.addDatas(datas);
39 System.out.println("包含'5'吗" + linkList2.contains(5));
40 linkList2.print();
41 System.out.println("----------------------------");
42 // 创建一个链表
43 MyLinkList linkList1 = new MyLinkList();
44 linkList1.addDatas(datas);
45 linkList1.print();
46 System.out.println("是否相等"+linkList2.equals(linkList1));
47 }
48
49 }
TestMyLinkList
打印
1 添加成功5
2 添加成功1
3 添加成功6
4 添加成功6
5 添加成功6
6 添加成功1
7 添加成功5
8 添加成功2
9 添加成功10
10 5 5 1 6 6 6 1 5 2 10
11 5 1 6 6 6 1 5 2 10
12 删除成功10
13 5 1 6 6 6 1 5 2
14 第2个结点数据:1
15 5 1 6 6 6 1 5 2
16 -------------------
17 包含'5'吗true
18 head 5 123 26
19 ----------------------------
20 head 5 123 26
21 是否相等true
TestMyLinkList-console
总结:1.避免空指针异常(NullPointException):先判断引用是否为null,后使用。
参考:
2018-7-19
二、双向链表(循环、头插法)
DoubleLink类
1 package List;
2
3 // 双向链表(循坏、头插法)
4 public class DoubleLink {
5 private Node root; // 表头
6 private int size; // 长度
7
8 // 结点类
9 private class Node {
10 Object data; // 数据域
11 Node prev; // 前趋
12 Node next; // 后继
13
14 // 构造方法
15 public Node(Object data, Node prev, Node next) {
16 this.data = data;
17 this.prev = prev;
18 this.next = next;
19 }
20
21 public Node(Object data) {
22 this.data = data;
23 }
24 }
25
26 // 构造方法
27 public DoubleLink() {
28 this.root = new Node(null, null, null);
29 this.root.prev = this.root.next = this.root;
30 this.size = 0;
31 }
32
33 // 是否是空表
34 public boolean isEmpty() {
35 return this.size == 0;
36 }
37
38 // 返回长度
39 public int size() {
40 return this.size;
41 }
42
43 // 添加数据
44 public boolean addData(Object data) {
45 // 空引用
46 if (data == null)
47 return false;
48
49 this.size++; // 增加长度
50 Node node = new Node(data); // 封装结点
51 // 添加结点
52
53 if (this.isEmpty()) {
54 this.root.next = node;
55 this.root.prev = node;
56
57 node.next = this.root;
58 node.prev = this.root;
59 return true;
60 }
61
62 // 头插法
63 node.next = this.root.next; // 将新结点的后继指向头结点的后继
64 node.prev = this.root; // 将新结点的前驱指向头结点
65 this.root.next.prev = node; // 头结点的后继结点的前驱指向新结点
66 this.root.next = node; // 头结点的后继节点指向新结点
67 return true;
68 }
69
70 // 查找第index结点
71 private Node getNode(int index) {
72 Node oldNode = this.root;
73 int foot = 0; // 脚标
74 if (index <= this.size / 2) { // 正查找
75 System.out.print("正查");
76 while (true) {
77 if (foot++ == index)
78 break;
79 oldNode = oldNode.next;
80 }
81 } else {
82 int LIndex = this.size + 1 - index;
83 System.out.print("反查");
84 while (true) {
85 if (foot++ == LIndex)
86 break;
87 oldNode = oldNode.prev;
88 }
89 }
90 System.out.print(oldNode.data);
91 return oldNode;
92 }
93
94 // 查找结点
95 private Node getNode(Object data) {
96 Node oldNode = this.root.next;
97 while (true) {
98 if (oldNode.data.equals(data))
99 return oldNode;
100 if (oldNode.next.data == null)
101 return null;
102 oldNode = oldNode.next;
103 }
104
105 }
106
107 // 删除结点
108 private void removeNode(Node node) {
109 node.next.prev = node.prev; // 结点的后继结点的前驱指向结点的前驱
110 node.prev.next = node.next; // 结点的前驱结点的后继指向结点的后继
111 node = null;
112 }
113
114 // 前插法
115 private boolean addNode(Node oldNode, Node newNode) {
116 oldNode.prev.next = newNode;
117 newNode.prev = oldNode.prev;
118 oldNode.prev = newNode;
119 newNode.next = oldNode;
120 return true;
121 }
122
123 // 在index结点前插入新结点
124 public boolean addData(Object data, int index) {
125 if (data == null)
126 return false;
127 if (index <= 0 || index > this.size)
128 return false;
129
130 Node newNode = new Node(data); // 封装结点
131
132 // 查找结点
133 Node oldNode = getNode(index);
134 this.size++; // 增加长度
135 // 更改指针域
136 return addNode(oldNode, newNode);
137 }
138
139 // 得到第index个结点的数据
140 public Object get(int index) {
141 if (this.isEmpty())
142 return null;
143 if (index <= 0 || index > this.size)
144 return null;
145
146 // 查找结点
147 return getNode(index).data;
148 }
149
150 // 查找数据是否存在
151 public boolean contains(Object data) {
152 if (data == null)
153 return false;
154 if (this.isEmpty())
155 return false;
156
157 // 查找结点
158 if (getNode(data) == null)
159 return false;
160 else
161 return true;
162 }
163
164 // 删除指定数据
165 public boolean remove(Object data) {
166 if (data == null)
167 return false;
168 if (this.isEmpty())
169 return false;
170
171 // 查找结点
172 Node node = getNode(data);
173 if (node == null)
174 return false;
175
176 // 删除结点
177 removeNode(node);
178 this.size--; // 长度减一
179 return true;
180 }
181
182 // 删除第index个结点
183 public boolean removeIndex(int index) {
184 if (this.isEmpty())
185 return false;
186 if (index <= 0 || index > this.size)
187 return false;
188
189 // 查找结点
190 Node node = getNode(index);
191 // 删除结点
192 removeNode(node);
193 this.size--; // 长度减一
194 return true;
195 }
196
197 // equals()
198 public boolean equals(Object obj) {
199 if (obj == null)
200 return false;
201
202 // 是DoubleLink类
203 if (obj instanceof DoubleLink) {
204 // 对象下转型为DoubleLink类
205 DoubleLink link = (DoubleLink) obj;
206
207 // 比较长度
208 if (this.size != link.size)
209 return false;
210
211 Node thisNode = this.root.next;
212 Node linkNode = link.root.next;
213 // 比较每个结点的后继的数据域是否相同
214 while (true) {
215 if (thisNode.data == null) // 只有头结点数据域为空
216 break;
217
218 if (!thisNode.data.equals(linkNode.data)) // 结点数据域不相同
219 return false;
220
221 thisNode = thisNode.next;
222 linkNode = linkNode.next;
223 }
224 }
225 return true;
226 }
227
228 // 获得所有数据
229 public Object[] toArray() {
230 if (isEmpty())
231 return null;
232
233 Object[] datas = new Object[this.size];
234 int index = 0; // 数组脚标
235 Node node = this.root.prev; // 当前结点
236 while (true) {
237 if (node.data == null) // 只有头结点数据域为空
238 break;
239 datas[index++] = node.data;
240 node = node.prev;
241 }
242
243 return datas;
244 }
245
246 // 打印信息
247 public void print() {
248 if (isEmpty())
249 System.out.println("空表");
250
251 else {
252 Node node = this.root.next;
253 while (true) {
254 if (node.data == null)
255 break;
256 System.out.print(node.data + " ");
257 node = node.next;
258 }
259 System.out.println();
260 }
261 }
262
263 }
DoubleLink
TestDoubleLink类
1 package List;
2
3 // 双向链表测试类
4 public class TestDoubleLink {
5
6 public static void main(String[] args) {
7 // TODO Auto-generated method stub
8
9 // 初始化一个双向链表
10 DoubleLink link1 = new DoubleLink();
11 link1.print();
12
13 // 添加数据
14 System.out.println("头插法添加10 5 12 null");
15 System.out.print("添加结果:"+link1.addData(10)+" ");
16 System.out.print(link1.addData(5)+" ");
17 System.out.print(link1.addData(12)+" ");
18 System.out.println(link1.addData(null));
19 link1.print();
20
21 // 在指定位置前插入数据
22 System.out.println("\n在第2为前插入一个40,在第4位前插入一个50");
23 System.out.println("插入结果:"+link1.addData(40, 2)+" "+link1.addData(50,4));
24 link1.print();
25
26 // 检查是否指定数据
27 System.out.println("\n检查是否含有数据:50 30");
28 System.out.println("检查结果:"+link1.contains(50)+" "+link1.contains(30));
29 link1.print();
30
31 // 删除指定数据
32 System.out.println("\n删除指定数据:50 0");
33 System.out.println("删除结果:"+link1.remove(50)+" "+link1.remove(0));
34 link1.print();
35
36 // 删除指定位置上的数据
37 System.out.println("\n删除指定位置上的数据:第3位 第10位");
38 System.out.println("删除结果:"+link1.removeIndex(3)+" "+link1.removeIndex(10));
39 link1.print();
40
41
42 // 比较两个链表是否相同
43 DoubleLink link2 = new DoubleLink();
44 DoubleLink link3 = new DoubleLink();
45 link2.addData(10);
46 link2.addData(40);
47 link2.addData(12);
48 link3.addData(12);
49 link3.addData(40);
50 link3.addData(10);
51 System.out.println("\n比较两个链表是否相同");
52 System.out.print("link1:");
53 link1.print();
54 System.out.print("link2:");
55 link2.print();
56 System.out.print("link3:");
57 link3.print();
58 System.out.println("link1和link2: "+link1.equals(link2)+"\nlink1和link3:"+link1.equals(link3)+"\nlink1和null:"+link1.equals(null));
59
60 }
61
62 }
TestDoubleLink
打印
1 空表
2 头插法添加10 5 12 null
3 添加结果:true true true false
4 12 5 10
5
6 在第2为前插入一个40,在第4位前插入一个50
7 反查反查插入结果:true true
8 12 40 5 50 10
9
10 检查是否含有数据:50 30
11 检查结果:true false
12 12 40 5 50 10
13
14 删除指定数据:50 0
15 删除结果:true false
16 12 40 5 10
17
18 删除指定位置上的数据:第3位 第10位
19 反查删除结果:true false
20 12 40 10
21
22 比较两个链表是否相同
23 link1:12 40 10
24 link2:12 40 10
25 link3:10 40 12
26 link1和link2: true
27 link1和link3:false
28 link1和null:false
TestDoubleLink-console
总结:1.避免查找错误:先执行查找函数,再改变链表长度。
参考:
2018-7-20