数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现
概要
线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列。本章先介绍线性表的几个基本组成部分:数组、单向链表、双向链表;随后给出双向链表的C、C++和Java三种语言的实现。内容包括:
数组
单向链表
双向链表
1. C实现双链表
2. C++实现双链表
3. Java实现双链表
数组
数组有上界和下界,数组的元素在上下界内是连续的。
数组的特点是:数据是连续的;随机访问速度快。
数组中稍微复杂一点的是多维数组和动态数组。对于C语言而言,多维数组本质上也是通过一维数组实现的。至于动态数组,是指数组的容量能动态增长的数组;对于C语言而言,若要提供动态数组,需要手动实现;而对于C++而言,STL提供了Vector;对于Java而言,Collection集合中提供了ArrayList和Vector。
单向链表
单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。
表头为空,表头的后继节点是"节点10"(数据为10的节点),"节点10"的后继节点是"节点20"(数据为10的节点),...
单链表删除节点
删除"节点30"
删除之前:"节点20" 的后继节点为"节点30",而"节点30" 的后继节点为"节点40"。
删除之后:"节点20" 的后继节点为"节点40"。
单链表添加节点
在"节点10"与"节点20"之间添加"节点15"
添加之前:"节点10" 的后继节点为"节点20"。
添加之后:"节点10" 的后继节点为"节点15",而"节点15" 的后继节点为"节点20"。
单链表的特点是:节点的链接方向是单向的;相对于数组来说,单链表的的随机访问速度较慢,但是单链表删除/添加数据的效率很高。
双向链表
双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
表头为空,表头的后继节点为"节点10"(数据为10的节点);"节点10"的后继节点是"节点20"(数据为10的节点),"节点20"的前继节点是"节点10";"节点20"的后继节点是"节点30","节点30"的前继节点是"节点20";...;末尾节点的后继节点是表头。
双链表删除节点
删除"节点30"
删除之前:"节点20"的后继节点为"节点30","节点30" 的前继节点为"节点20"。"节点30"的后继节点为"节点40","节点40" 的前继节点为"节点30"。
删除之后:"节点20"的后继节点为"节点40","节点40" 的前继节点为"节点20"。
双链表添加节点
在"节点10"与"节点20"之间添加"节点15"
添加之前:"节点10"的后继节点为"节点20","节点20" 的前继节点为"节点10"。
添加之后:"节点10"的后继节点为"节点15","节点15" 的前继节点为"节点10"。"节点15"的后继节点为"节点20","节点20" 的前继节点为"节点15"。
下面介绍双链表的实现,分别介绍C/C++/Java三种实现。
实现代码
双向链表头文件(double_link.h)
1 #ifndef _DOUBLE_LINK_H
2 #define _DOUBLE_LINK_H
3
4 // 新建“双向链表”。成功,返回表头;否则,返回NULL
5 extern int create_dlink();
6 // 撤销“双向链表”。成功,返回0;否则,返回-1
7 extern int destroy_dlink();
8
9 // “双向链表是否为空”。为空的话返回1;否则,返回0。
10 extern int dlink_is_empty();
11 // 返回“双向链表的大小”
12 extern int dlink_size();
13
14 // 获取“双向链表中第index位置的元素”。成功,返回节点指针;否则,返回NULL。
15 extern void* dlink_get(int index);
16 // 获取“双向链表中第1个元素”。成功,返回节点指针;否则,返回NULL。
17 extern void* dlink_get_first();
18 // 获取“双向链表中最后1个元素”。成功,返回节点指针;否则,返回NULL。
19 extern void* dlink_get_last();
20
21 // 将“value”插入到index位置。成功,返回0;否则,返回-1。
22 extern int dlink_insert(int index, void *pval);
23 // 将“value”插入到表头位置。成功,返回0;否则,返回-1。
24 extern int dlink_insert_first(void *pval);
25 // 将“value”插入到末尾位置。成功,返回0;否则,返回-1。
26 extern int dlink_append_last(void *pval);
27
28 // 删除“双向链表中index位置的节点”。成功,返回0;否则,返回-1
29 extern int dlink_delete(int index);
30 // 删除第一个节点。成功,返回0;否则,返回-1
31 extern int dlink_delete_first();
32 // 删除组后一个节点。成功,返回0;否则,返回-1
33 extern int dlink_delete_last();
34
35 #endif
双向链表实现文件(double_link.c)
1 #include <stdio.h>
2 #include <malloc.h>
3
4 /**
5 * C 语言实现的双向链表,能存储任意数据。
6 *
7 * @author skywang
8 * @date 2013/11/07
9 */
10 // 双向链表节点
11 typedef struct tag_node
12 {
13 struct tag_node *prev;
14 struct tag_node *next;
15 void* p;
16 }node;
17
18 // 表头。注意,表头不存放元素值!!!
19 static node *phead=NULL;
20 // 节点个数。
21 static int count=0;
22
23 // 新建“节点”。成功,返回节点指针;否则,返回NULL。
24 static node* create_node(void *pval)
25 {
26 node *pnode=NULL;
27 pnode = (node *)malloc(sizeof(node));
28 if (!pnode)
29 {
30 printf("create node error!\n");
31 return NULL;
32 }
33 // 默认的,pnode的前一节点和后一节点都指向它自身
34 pnode->prev = pnode->next = pnode;
35 // 节点的值为pval
36 pnode->p = pval;
37
38 return pnode;
39 }
40
41 // 新建“双向链表”。成功,返回0;否则,返回-1。
42 int create_dlink()
43 {
44 // 创建表头
45 phead = create_node(NULL);
46 if (!phead)
47 return -1;
48
49 // 设置“节点个数”为0
50 count = 0;
51
52 return 0;
53 }
54
55 // “双向链表是否为空”
56 int dlink_is_empty()
57 {
58 return count == 0;
59 }
60
61 // 返回“双向链表的大小”
62 int dlink_size() {
63 return count;
64 }
65
66 // 获取“双向链表中第index位置的节点”
67 static node* get_node(int index)
68 {
69 if (index<0 || index>=count)
70 {
71 printf("%s failed! index out of bound!\n", __func__);
72 return NULL;
73 }
74
75 // 正向查找
76 if (index <= (count/2))
77 {
78 int i=0;
79 node *pnode=phead->next;
80 while ((i++) < index)
81 pnode = pnode->next;
82
83 return pnode;
84 }
85
86 // 反向查找
87 int j=0;
88 int rindex = count - index - 1;
89 node *rnode=phead->prev;
90 while ((j++) < rindex)
91 rnode = rnode->prev;
92
93 return rnode;
94 }
95
96 // 获取“第一个节点”
97 static node* get_first_node()
98 {
99 return get_node(0);
100 }
101
102 // 获取“最后一个节点”
103 static node* get_last_node()
104 {
105 return get_node(count-1);
106 }
107
108 // 获取“双向链表中第index位置的元素”。成功,返回节点值;否则,返回-1。
109 void* dlink_get(int index)
110 {
111 node *pindex=get_node(index);
112 if (!pindex)
113 {
114 printf("%s failed!\n", __func__);
115 return NULL;
116 }
117
118 return pindex->p;
119
120 }
121
122 // 获取“双向链表中第1个元素的值”
123 void* dlink_get_first()
124 {
125 return dlink_get(0);
126 }
127
128 // 获取“双向链表中最后1个元素的值”
129 void* dlink_get_last()
130 {
131 return dlink_get(count-1);
132 }
133
134 // 将“pval”插入到index位置。成功,返回0;否则,返回-1。
135 int dlink_insert(int index, void* pval)
136 {
137 // 插入表头
138 if (index==0)
139 return dlink_insert_first(pval);
140
141 // 获取要插入的位置对应的节点
142 node *pindex=get_node(index);
143 if (!pindex)
144 return -1;
145
146 // 创建“节点”
147 node *pnode=create_node(pval);
148 if (!pnode)
149 return -1;
150
151 pnode->prev = pindex->prev;
152 pnode->next = pindex;
153 pindex->prev->next = pnode;
154 pindex->prev = pnode;
155 // 节点个数+1
156 count++;
157
158 return 0;
159 }
160
161 // 将“pval”插入到表头位置
162 int dlink_insert_first(void *pval)
163 {
164 node *pnode=create_node(pval);
165 if (!pnode)
166 return -1;
167
168 pnode->prev = phead;
169 pnode->next = phead->next;
170 phead->next->prev = pnode;
171 phead->next = pnode;
172 count++;
173 return 0;
174 }
175
176 // 将“pval”插入到末尾位置
177 int dlink_append_last(void *pval)
178 {
179 node *pnode=create_node(pval);
180 if (!pnode)
181 return -1;
182
183 pnode->next = phead;
184 pnode->prev = phead->prev;
185 phead->prev->next = pnode;
186 phead->prev = pnode;
187 count++;
188 return 0;
189 }
190
191 // 删除“双向链表中index位置的节点”。成功,返回0;否则,返回-1。
192 int dlink_delete(int index)
193 {
194 node *pindex=get_node(index);
195 if (!pindex)
196 {
197 printf("%s failed! the index in out of bound!\n", __func__);
198 return -1;
199 }
200
201 pindex->next->prev = pindex->prev;
202 pindex->prev->next = pindex->next;
203 free(pindex);
204 count--;
205
206 return 0;
207 }
208
209 // 删除第一个节点
210 int dlink_delete_first()
211 {
212 return dlink_delete(0);
213 }
214
215 // 删除组后一个节点
216 int dlink_delete_last()
217 {
218 return dlink_delete(count-1);
219 }
220
221 // 撤销“双向链表”。成功,返回0;否则,返回-1。
222 int destroy_dlink()
223 {
224 if (!phead)
225 {
226 printf("%s failed! dlink is null!\n", __func__);
227 return -1;
228 }
229
230 node *pnode=phead->next;
231 node *ptmp=NULL;
232 while(pnode != phead)
233 {
234 ptmp = pnode;
235 pnode = pnode->next;
236 free(ptmp);
237 }
238
239 free(phead);
240 phead = NULL;
241 count = 0;
242
243 return 0;
244 }
双向链表测试程序(dlink_test.c)
1 #include <stdio.h>
2 #include "double_link.h"
3
4 /**
5 * C 语言实现的双向链表的测试程序。
6 *
7 * (01) int_test()
8 * 演示向双向链表操作“int数据”。
9 * (02) string_test()
10 * 演示向双向链表操作“字符串数据”。
11 * (03) object_test()
12 * 演示向双向链表操作“对象”。
13 *
14 * @author skywang
15 * @date 2013/11/07
16 */
17
18 // 双向链表操作int数据
19 void int_test()
20 {
21 int iarr[4] = {10, 20, 30, 40};
22
23 printf("\n----%s----\n", __func__);
24 create_dlink(); // 创建双向链表
25
26 dlink_insert(0, &iarr[0]); // 向双向链表的表头插入数据
27 dlink_insert(0, &iarr[1]); // 向双向链表的表头插入数据
28 dlink_insert(0, &iarr[2]); // 向双向链表的表头插入数据
29
30 printf("dlink_is_empty()=%d\n", dlink_is_empty()); // 双向链表是否为空
31 printf("dlink_size()=%d\n", dlink_size()); // 双向链表的大小
32
33 // 打印双向链表中的全部数据
34 int i;
35 int *p;
36 int sz = dlink_size();
37 for (i=0; i<sz; i++)
38 {
39 p = (int *)dlink_get(i);
40 printf("dlink_get(%d)=%d\n", i, *p);
41 }
42
43 destroy_dlink();
44 }
45
46 void string_test()
47 {
48 char* sarr[4] = {"ten", "twenty", "thirty", "forty"};
49
50 printf("\n----%s----\n", __func__);
51 create_dlink(); // 创建双向链表
52
53 dlink_insert(0, sarr[0]); // 向双向链表的表头插入数据
54 dlink_insert(0, sarr[1]); // 向双向链表的表头插入数据
55 dlink_insert(0, sarr[2]); // 向双向链表的表头插入数据
56
57 printf("dlink_is_empty()=%d\n", dlink_is_empty()); // 双向链表是否为空
58 printf("dlink_size()=%d\n", dlink_size()); // 双向链表的大小
59
60 // 打印双向链表中的全部数据
61 int i;
62 char *p;
63 int sz = dlink_size();
64 for (i=0; i<sz; i++)
65 {
66 p = (char *)dlink_get(i);
67 printf("dlink_get(%d)=%s\n", i, p);
68 }
69
70 destroy_dlink();
71 }
72
73 typedef struct tag_stu
74 {
75 int id;
76 char name[20];
77 }stu;
78
79 static stu arr_stu[] =
80 {
81 {10, "sky"},
82 {20, "jody"},
83 {30, "vic"},
84 {40, "dan"},
85 };
86 #define ARR_STU_SIZE ( (sizeof(arr_stu)) / (sizeof(arr_stu[0])) )
87
88 void object_test()
89 {
90 printf("\n----%s----\n", __func__);
91 create_dlink(); // 创建双向链表
92
93 dlink_insert(0, &arr_stu[0]); // 向双向链表的表头插入数据
94 dlink_insert(0, &arr_stu[1]); // 向双向链表的表头插入数据
95 dlink_insert(0, &arr_stu[2]); // 向双向链表的表头插入数据
96
97 printf("dlink_is_empty()=%d\n", dlink_is_empty()); // 双向链表是否为空
98 printf("dlink_size()=%d\n", dlink_size()); // 双向链表的大小
99
100 // 打印双向链表中的全部数据
101 int i;
102 int sz = dlink_size();
103 stu *p;
104 for (i=0; i<sz; i++)
105 {
106 p = (stu *)dlink_get(i);
107 printf("dlink_get(%d)=[%d, %s]\n", i, p->id, p->name);
108 }
109
110 destroy_dlink();
111 }
112
113 int main()
114 {
115 int_test(); // 演示向双向链表操作“int数据”。
116 string_test(); // 演示向双向链表操作“字符串数据”。
117 object_test(); // 演示向双向链表操作“对象”。
118
119 return 0;
120 }
运行结果
----int_test----
dlink_is_empty()=0
dlink_size()=3
dlink_get(0)=30
dlink_get(1)=20
dlink_get(2)=10
----string_test----
dlink_is_empty()=0
dlink_size()=3
dlink_get(0)=thirty
dlink_get(1)=twenty
dlink_get(2)=ten
----object_test----
dlink_is_empty()=0
dlink_size()=3
dlink_get(0)=[30, vic]
dlink_get(1)=[20, jody]
dlink_get(2)=[10, sky]
实现代码
双向链表文件(DoubleLink.h)
1 #ifndef DOUBLE_LINK_HXX
2 #define DOUBLE_LINK_HXX
3
4 #include <iostream>
5 using namespace std;
6
7 template<class T>
8 struct DNode
9 {
10 public:
11 T value;
12 DNode *prev;
13 DNode *next;
14 public:
15 DNode() { }
16 DNode(T t, DNode *prev, DNode *next) {
17 this->value = t;
18 this->prev = prev;
19 this->next = next;
20 }
21 };
22
23 template<class T>
24 class DoubleLink
25 {
26 public:
27 DoubleLink();
28 ~DoubleLink();
29
30 int size();
31 int is_empty();
32
33 T get(int index);
34 T get_first();
35 T get_last();
36
37 int insert(int index, T t);
38 int insert_first(T t);
39 int append_last(T t);
40
41 int del(int index);
42 int delete_first();
43 int delete_last();
44
45 private:
46 int count;
47 DNode<T> *phead;
48 private:
49 DNode<T> *get_node(int index);
50 };
51
52 template<class T>
53 DoubleLink<T>::DoubleLink() : count(0)
54 {
55 // 创建“表头”。注意:表头没有存储数据!
56 phead = new DNode<T>();
57 phead->prev = phead->next = phead;
58 // 设置链表计数为0
59 //count = 0;
60 }
61
62 // 析构函数
63 template<class T>
64 DoubleLink<T>::~DoubleLink()
65 {
66 // 删除所有的节点
67 DNode<T>* ptmp;
68 DNode<T>* pnode = phead->next;
69 while (pnode != phead)
70 {
71 ptmp = pnode;
72 pnode=pnode->next;
73 delete ptmp;
74 }
75
76 // 删除"表头"
77 delete phead;
78 phead = NULL;
79 }
80
81 // 返回节点数目
82 template<class T>
83 int DoubleLink<T>::size()
84 {
85 return count;
86 }
87
88 // 返回链表是否为空
89 template<class T>
90 int DoubleLink<T>::is_empty()
91 {
92 return count==0;
93 }
94
95 // 获取第index位置的节点
96 template<class T>
97 DNode<T>* DoubleLink<T>::get_node(int index)
98 {
99 // 判断参数有效性
100 if (index<0 || index>=count)
101 {
102 cout << "get node failed! the index in out of bound!" << endl;
103 return NULL;
104 }
105
106 // 正向查找
107 if (index <= count/2)
108 {
109 int i=0;
110 DNode<T>* pindex = phead->next;
111 while (i++ < index) {
112 pindex = pindex->next;
113 }
114
115 return pindex;
116 }
117
118 // 反向查找
119 int j=0;
120 int rindex = count - index -1;
121 DNode<T>* prindex = phead->prev;
122 while (j++ < rindex) {
123 prindex = prindex->prev;
124 }
125
126 return prindex;
127 }
128
129 // 获取第index位置的节点的值
130 template<class T>
131 T DoubleLink<T>::get(int index)
132 {
133 return get_node(index)->value;
134 }
135
136 // 获取第1个节点的值
137 template<class T>
138 T DoubleLink<T>::get_first()
139 {
140 return get_node(0)->value;
141 }
142
143 // 获取最后一个节点的值
144 template<class T>
145 T DoubleLink<T>::get_last()
146 {
147 return get_node(count-1)->value;
148 }
149
150 // 将节点插入到第index位置之前
151 template<class T>
152 int DoubleLink<T>::insert(int index, T t)
153 {
154 if (index == 0)
155 return insert_first(t);
156
157 DNode<T>* pindex = get_node(index);
158 DNode<T>* pnode = new DNode<T>(t, pindex->prev, pindex);
159 pindex->prev->next = pnode;
160 pindex->prev = pnode;
161 count++;
162
163 return 0;
164 }
165
166 // 将节点插入第一个节点处。
167 template<class T>
168 int DoubleLink<T>::insert_first(T t)
169 {
170 DNode<T>* pnode = new DNode<T>(t, phead, phead->next);
171 phead->next->prev = pnode;
172 phead->next = pnode;
173 count++;
174
175 return 0;
176 }
177
178 // 将节点追加到链表的末尾
179 template<class T>
180 int DoubleLink<T>::append_last(T t)
181 {
182 DNode<T>* pnode = new DNode<T>(t, phead->prev, phead);
183 phead->prev->next = pnode;
184 phead->prev = pnode;
185 count++;
186
187 return 0;
188 }
189
190 // 删除index位置的节点
191 template<class T>
192 int DoubleLink<T>::del(int index)
193 {
194 DNode<T>* pindex = get_node(index);
195 pindex->next->prev = pindex->prev;
196 pindex->prev->next = pindex->next;
197 delete pindex;
198 count--;
199
200 return 0;
201 }
202
203 // 删除第一个节点
204 template<class T>
205 int DoubleLink<T>::delete_first()
206 {
207 return del(0);
208 }
209
210 // 删除最后一个节点
211 template<class T>
212 int DoubleLink<T>::delete_last()
213 {
214 return del(count-1);
215 }
216
217 #endif
双向链表测试文件(DlinkTest.cpp)
1 #include <iostream>
2 #include "DoubleLink.h"
3 using namespace std;
4
5 // 双向链表操作int数据
6 void int_test()
7 {
8 int iarr[4] = {10, 20, 30, 40};
9
10 cout << "\n----int_test----" << endl;
11 // 创建双向链表
12 DoubleLink<int>* pdlink = new DoubleLink<int>();
13
14 pdlink->insert(0, 20); // 将 20 插入到第一个位置
15 pdlink->append_last(10); // 将 10 追加到链表末尾
16 pdlink->insert_first(30); // 将 30 插入到第一个位置
17
18 // 双向链表是否为空
19 cout << "is_empty()=" << pdlink->is_empty() <<endl;
20 // 双向链表的大小
21 cout << "size()=" << pdlink->size() <<endl;
22
23 // 打印双向链表中的全部数据
24 int sz = pdlink->size();
25 for (int i=0; i<sz; i++)
26 cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl;
27 }
28
29 void string_test()
30 {
31 string sarr[4] = {"ten", "twenty", "thirty", "forty"};
32
33 cout << "\n----string_test----" << endl;
34 // 创建双向链表
35 DoubleLink<string>* pdlink = new DoubleLink<string>();
36
37 pdlink->insert(0, sarr[1]); // 将 sarr中第2个元素 插入到第一个位置
38 pdlink->append_last(sarr[0]); // 将 sarr中第1个元素 追加到链表末尾
39 pdlink->insert_first(sarr[2]); // 将 sarr中第3个元素 插入到第一个位置
40
41 // 双向链表是否为空
42 cout << "is_empty()=" << pdlink->is_empty() <<endl;
43 // 双向链表的大小
44 cout << "size()=" << pdlink->size() <<endl;
45
46 // 打印双向链表中的全部数据
47 int sz = pdlink->size();
48 for (int i=0; i<sz; i++)
49 cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl;
50 }
51
52 struct stu
53 {
54 int id;
55 char name[20];
56 };
57
58 static stu arr_stu[] =
59 {
60 {10, "sky"},
61 {20, "jody"},
62 {30, "vic"},
63 {40, "dan"},
64 };
65 #define ARR_STU_SIZE ( (sizeof(arr_stu)) / (sizeof(arr_stu[0])) )
66
67 void object_test()
68 {
69 cout << "\n----object_test----" << endl;
70 // 创建双向链表
71 DoubleLink<stu>* pdlink = new DoubleLink<stu>();
72
73 pdlink->insert(0, arr_stu[1]); // 将 arr_stu中第2个元素 插入到第一个位置
74 pdlink->append_last(arr_stu[0]); // 将 arr_stu中第1个元素 追加到链表末尾
75 pdlink->insert_first(arr_stu[2]); // 将 arr_stu中第3个元素 插入到第一个位置
76
77 // 双向链表是否为空
78 cout << "is_empty()=" << pdlink->is_empty() <<endl;
79 // 双向链表的大小
80 cout << "size()=" << pdlink->size() <<endl;
81
82 // 打印双向链表中的全部数据
83 int sz = pdlink->size();
84 struct stu p;
85 for (int i=0; i<sz; i++)
86 {
87 p = pdlink->get(i);
88 cout << "pdlink("<<i<<")=[" << p.id << ", " << p.name <<"]" <<endl;
89 }
90 }
91
92
93 int main()
94 {
95 int_test(); // 演示向双向链表操作“int数据”。
96 string_test(); // 演示向双向链表操作“字符串数据”。
97 object_test(); // 演示向双向链表操作“对象”。
98
99 return 0;
100 }
示例说明
在上面的示例中,我将双向链表的"声明"和"实现"都放在头文件中。而编程规范告诫我们:将类的声明和实现分离,在头文件(.h文件或.hpp)中尽量只包含声明,而在实现文件(.cpp文件)中负责实现!
那么为什么要这么做呢?这是因为,在双向链表的实现中,采用了模板;而C++编译器不支持对模板的分离式编译!简单点说,如果在DoubleLink.h中声明,而在DoubleLink.cpp中进行实现的话;当我们在其他类中创建DoubleLink的对象时,会编译出错。具体原因,可以参考"为什么C++编译器不能支持对模板的分离式编译"。
运行结果
----int_test----
is_empty()=0
size()=3
pdlink(0)=30
pdlink(1)=20
pdlink(2)=10
----string_test----
is_empty()=0
size()=3
pdlink(0)=thirty
pdlink(1)=twenty
pdlink(2)=ten
----object_test----
is_empty()=0
size()=3
pdlink(0)=[30, vic]
pdlink(1)=[20, jody]
pdlink(2)=[10, sky]
实现代码
双链表类(DoubleLink.java)
1 /**
2 * Java 实现的双向链表。
3 * 注:java自带的集合包中有实现双向链表,路径是:java.util.LinkedList
4 *
5 * @author skywang
6 * @date 2013/11/07
7 */
8 public class DoubleLink<T> {
9
10 // 表头
11 private DNode<T> mHead;
12 // 节点个数
13 private int mCount;
14
15 // 双向链表“节点”对应的结构体
16 private class DNode<T> {
17 public DNode prev;
18 public DNode next;
19 public T value;
20
21 public DNode(T value, DNode prev, DNode next) {
22 this.value = value;
23 this.prev = prev;
24 this.next = next;
25 }
26 }
27
28 // 构造函数
29 public DoubleLink() {
30 // 创建“表头”。注意:表头没有存储数据!
31 mHead = new DNode<T>(null, null, null);
32 mHead.prev = mHead.next = mHead;
33 // 初始化“节点个数”为0
34 mCount = 0;
35 }
36
37 // 返回节点数目
38 public int size() {
39 return mCount;
40 }
41
42 // 返回链表是否为空
43 public boolean isEmpty() {
44 return mCount==0;
45 }
46
47 // 获取第index位置的节点
48 private DNode<T> getNode(int index) {
49 if (index<0 || index>=mCount)
50 throw new IndexOutOfBoundsException();
51
52 // 正向查找
53 if (index <= mCount/2) {
54 DNode<T> node = mHead.next;
55 for (int i=0; i<index; i++)
56 node = node.next;
57
58 return node;
59 }
60
61 // 反向查找
62 DNode<T> rnode = mHead.prev;
63 int rindex = mCount - index -1;
64 for (int j=0; j<rindex; j++)
65 rnode = rnode.prev;
66
67 return rnode;
68 }
69
70 // 获取第index位置的节点的值
71 public T get(int index) {
72 return getNode(index).value;
73 }
74
75 // 获取第1个节点的值
76 public T getFirst() {
77 return getNode(0).value;
78 }
79
80 // 获取最后一个节点的值
81 public T getLast() {
82 return getNode(mCount-1).value;
83 }
84
85 // 将节点插入到第index位置之前
86 public void insert(int index, T t) {
87 if (index==0) {
88 DNode<T> node = new DNode<T>(t, mHead, mHead.next);
89 mHead.next.prev = node;
90 mHead.next = node;
91 mCount++;
92 return ;
93 }
94
95 DNode<T> inode = getNode(index);
96 DNode<T> tnode = new DNode<T>(t, inode.prev, inode);
97 inode.prev.next = tnode;
98 inode.next = tnode;
99 mCount++;
100 return ;
101 }
102
103 // 将节点插入第一个节点处。
104 public void insertFirst(T t) {
105 insert(0, t);
106 }
107
108 // 将节点追加到链表的末尾
109 public void appendLast(T t) {
110 DNode<T> node = new DNode<T>(t, mHead.prev, mHead);
111 mHead.prev.next = node;
112 mHead.prev = node;
113 mCount++;
114 }
115
116 // 删除index位置的节点
117 public void del(int index) {
118 DNode<T> inode = getNode(index);
119 inode.prev.next = inode.next;
120 inode.next.prev = inode.prev;
121 inode = null;
122 mCount--;
123 }
124
125 // 删除第一个节点
126 public void deleteFirst() {
127 del(0);
128 }
129
130 // 删除最后一个节点
131 public void deleteLast() {
132 del(mCount-1);
133 }
134 }
测试程序(DlinkTest.java)
1 /**
2 * Java 实现的双向链表。
3 * 注:java自带的集合包中有实现双向链表,路径是:java.util.LinkedList
4 *
5 * @author skywang
6 * @date 2013/11/07
7 */
8
9 public class DlinkTest {
10
11 // 双向链表操作int数据
12 private static void int_test() {
13 int[] iarr = {10, 20, 30, 40};
14
15 System.out.println("\n----int_test----");
16 // 创建双向链表
17 DoubleLink<Integer> dlink = new DoubleLink<Integer>();
18
19 dlink.insert(0, 20); // 将 20 插入到第一个位置
20 dlink.appendLast(10); // 将 10 追加到链表末尾
21 dlink.insertFirst(30); // 将 30 插入到第一个位置
22
23 // 双向链表是否为空
24 System.out.printf("isEmpty()=%b\n", dlink.isEmpty());
25 // 双向链表的大小
26 System.out.printf("size()=%d\n", dlink.size());
27
28 // 打印出全部的节点
29 for (int i=0; i<dlink.size(); i++)
30 System.out.println("dlink("+i+")="+ dlink.get(i));
31 }
32
33
34 private static void string_test() {
35 String[] sarr = {"ten", "twenty", "thirty", "forty"};
36
37 System.out.println("\n----string_test----");
38 // 创建双向链表
39 DoubleLink<String> dlink = new DoubleLink<String>();
40
41 dlink.insert(0, sarr[1]); // 将 sarr中第2个元素 插入到第一个位置
42 dlink.appendLast(sarr[0]); // 将 sarr中第1个元素 追加到链表末尾
43 dlink.insertFirst(sarr[2]); // 将 sarr中第3个元素 插入到第一个位置
44
45 // 双向链表是否为空
46 System.out.printf("isEmpty()=%b\n", dlink.isEmpty());
47 // 双向链表的大小
48 System.out.printf("size()=%d\n", dlink.size());
49
50 // 打印出全部的节点
51 for (int i=0; i<dlink.size(); i++)
52 System.out.println("dlink("+i+")="+ dlink.get(i));
53 }
54
55
56 // 内部类
57 private static class Student {
58 private int id;
59 private String name;
60
61 public Student(int id, String name) {
62 this.id = id;
63 this.name = name;
64 }
65
66 @Override
67 public String toString() {
68 return "["+id+", "+name+"]";
69 }
70 }
71
72 private static Student[] students = new Student[]{
73 new Student(10, "sky"),
74 new Student(20, "jody"),
75 new Student(30, "vic"),
76 new Student(40, "dan"),
77 };
78
79 private static void object_test() {
80 System.out.println("\n----object_test----");
81 // 创建双向链表
82 DoubleLink<Student> dlink = new DoubleLink<Student>();
83
84 dlink.insert(0, students[1]); // 将 students中第2个元素 插入到第一个位置
85 dlink.appendLast(students[0]); // 将 students中第1个元素 追加到链表末尾
86 dlink.insertFirst(students[2]); // 将 students中第3个元素 插入到第一个位置
87
88 // 双向链表是否为空
89 System.out.printf("isEmpty()=%b\n", dlink.isEmpty());
90 // 双向链表的大小
91 System.out.printf("size()=%d\n", dlink.size());
92
93 // 打印出全部的节点
94 for (int i=0; i<dlink.size(); i++) {
95 System.out.println("dlink("+i+")="+ dlink.get(i));
96 }
97 }
98
99
100 public static void main(String[] args) {
101 int_test(); // 演示向双向链表操作“int数据”。
102 string_test(); // 演示向双向链表操作“字符串数据”。
103 object_test(); // 演示向双向链表操作“对象”。
104 }
105 }
运行结果
----int_test----
isEmpty()=false
size()=3
dlink(0)=30
dlink(1)=20
dlink(2)=10
----string_test----
isEmpty()=false
size()=3
dlink(0)=thirty
dlink(1)=twenty
dlink(2)=ten
----object_test----
isEmpty()=false
size()=3
dlink(0)=[30, vic]
dlink(1)=[20, jody]
dlink(2)=[10, sky]