数组、单链表和双链表介绍 以及 双向链表的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/