概要
线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列。本章先介绍线性表的几个基本组成部分:数组、单向链表、双向链表;随后给出双向链表的C、C++和Java三种语言的实现。内容包括:
数组
单向链表
双向链表
1. C实现双链表
2. C++实现双链表
3. Java实现双链表
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3561803.html
更多内容
数组
数组有上界和下界,数组的元素在上下界内是连续的。
数组的特点是:数据是连续的;随机访问速度快。
数组中稍微复杂一点的是多维数组和动态数组。对于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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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]