C语言双向链表讲解
上图对应如下代码:
pnode->prev = pindex->prev;
pnode->pNext = pindex;
pindex->prev->pNext = pnode;
pindex->prev = pnode;
上图对应如下代码:
pnode->prev = phead;
pnode->pNext = phead->pNext;
phead->pNext->prev = pnode;
phead->pNext = pnode;
上图对应如下代码:
pnode->pNext = phead;
pnode->prev = phead->prev;
phead->prev->pNext = pnode;
phead->prev = pnode;
上图对应如下代码:
pindex->pNext->prev = pindex->prev;
pindex->prev->pNext = pindex->pNext;
一、双向链表的概念
双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。
在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。
双向链表结构示意图
表头为空,表头的后继节点为"节点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语言实现双向链表
2.1 头文件
1 #pragma once
2 //新建双向链表。成功返回链表头,否则,返回NULL
3 extern int create_dLink();
4 //撤销双向链表,成功返回0,否则返回-1
5 extern int destory_dLink();
6 //双向列表是否为空,为空返回1,否则返回0
7 extern int is_empty_dLink();
8 //双向链表的大小
9 extern int dLink_size();
10 //获取索引index位置的元素,成功返回节点指针,否则返回NULL
11 extern void* dLink_get(int index);
12 //获取双向链表中第一个元素,成功返回节点指针,否则返回NULL
13 extern void* dLink_getFirst();
14 //获取双向链表中最后一个元素,成功返回节点指针,否则返回NULL
15 extern void* dLink_getTail();
16 /*
17 链表中增加
18 */
19 //在Index位置插值value,成功返回0,否则返回-1;
20 extern int dLink_insert(int index,void * pVal);
21 //在表头插入值
22 extern int dLink_insert_head(void *pVal);
23 //在表尾插入值
24 extern int dLink_insert_tail(void *pVal);
25 /*
26 链表中删除
27 */
28 //在index处删除
29 extern int dLink_delete(int index);
30 //删除第一个节点
31 extern int dLink_delete_first();
32 //闪电湖第二个节点
33 extern int dLink_delete_tail();
2.2 .c
1 #include<stdio.h> 2 #include "double_link.h" 3 #include<malloc.h> 4 5 //双向链表节点 6 typedef struct My_node 7 { 8 struct My_node *prev; 9 struct My_node *pNext; 10 void * p; 11 }my_node; 12 //b表头不存放元素值 13 my_node *phead = NULL; 14 //节点的个数 15 int node_count = 0; 16 //创建节点,成功返回节点指针,否则,返回NULL 17 my_node* create_node(void *pVal) 18 { 19 my_node *pnode = NULL; 20 pnode = (my_node*)malloc(sizeof(My_node)); 21 if (!pnode) 22 { 23 printf("create pnode error\n"); 24 return NULL; 25 } 26 //默认的,pnode的前一节点和后一节点都指向他自己 27 pnode->prev = pnode->pNext = pnode; 28 //节点的值为pVal 29 pnode->p = pVal; 30 return pnode; 31 } 32 33 //新建双向链表 成功返回0 否则返回-1 34 int create_dLink() 35 { 36 phead = create_node(NULL); 37 if (!phead) 38 return -1; 39 //设置节点的个数 40 node_count = 0; 41 return 0; 42 } 43 44 int destory_dLink() 45 { 46 if (!phead) 47 { 48 printf("%s failed! dlink is null!\n", __func__); 49 return -1; 50 } 51 My_node*pnode = phead->pNext; 52 my_node* ptmp = NULL; 53 if (pnode!=phead) 54 { 55 ptmp = pnode; 56 pnode = pnode->pNext; 57 free(pnode); 58 } 59 free(phead); 60 phead = NULL; 61 node_count = 0; 62 return 0; 63 } 64 65 int is_empty_dLink() 66 { 67 return node_count==0; 68 } 69 70 int dLink_size() 71 { 72 return node_count; 73 }
74 //获取双向链表中第Index位置的节点 75 my_node* get_node(int index) 76 { 77 if (index<0 || index >= node_count) 78 { 79 printf("%s failed ! index out of bound\n", __func__); 80 return NULL; 81 } 82 //正向查找 83 if (index <= (node_count / 2)) 84 { 85 int i = 0; 86 my_node *pnode = phead->pNext; 87 while ((i++)<index) 88 { 89 pnode = pnode->pNext; 90 } 91 return pnode; 92 } 93 //反向查找 94 int j = 0; 95 int rindex = node_count - index - 1; 96 my_node *rnode = phead->prev; 97 while ((j++)<rindex) 98 { 99 rnode = rnode->prev; 100 } 101 return rnode; 102 } 103 void * dLink_get(int index) 104 { 105 my_node *pindex = get_node(index); 106 if (!pindex) 107 { 108 printf("%s failed!\n", __func__); 109 return NULL; 110 } 111 return pindex->p; 112 } 113 114 //获取第一个节点 115 void * dLink_getFirst() 116 { 117 return get_node(0) ; 118 } 119 //获取最后一个节点 120 void * dLink_getTail() 121 { 122 return get_node(node_count-1); 123 } 124 //将值插入到index位置,成功返回0;否则 返回-1 125 int dLink_insert(int index, void * pVal) 126 { 127 //插入表头 128 if (index == 0) 129 return dLink_insert_head(pVal); 130 //获取要插入位置对应的节点 131 my_node* pindex = get_node(index); 132 if (!pindex) 133 return -1; 134 //创建节点 135 my_node* pnode = create_node(pVal); 136 if (!pnode) 137 return -1; 138 pnode->prev = pindex->prev; 139 pnode->pNext = pindex; 140 pindex->prev->pNext = pnode; 141 pindex->prev = pnode; 142 node_count++; 143 return 0; 144 } 145 //数值插入表头 146 int dLink_insert_head(void * pVal) 147 { 148 my_node* pnode = create_node(pVal); 149 if (!pnode) 150 return -1; 151 pnode->prev = phead; 152 pnode->pNext = phead->pNext; 153 154 phead->pNext->prev = pnode; 155 phead->pNext = pnode; 156 node_count++; 157 return 0; 158 } 159 160 int dLink_insert_tail(void * pVal) 161 { 162 my_node* pnode = create_node(pVal); 163 if (!pnode) 164 return -1; 165 pnode->pNext = phead; 166 pnode->prev = phead->prev; 167 phead->prev->pNext = pnode; 168 phead->prev = pnode; 169 return 0; 170 } 171 172 int dLink_delete(int index) 173 { 174 my_node* pindex = get_node(index); 175 if (!pindex) 176 { 177 printf("%s failed! the index in out of bound\n",__func__); 178 return -1; 179 } 180 pindex->pNext->prev = pindex->prev; 181 pindex->prev->pNext = pindex->pNext; 182 free(pindex); 183 node_count--; 184 return 0; 185 } 186 187 int dLink_delete_first() 188 { 189 return dLink_delete(0); 190 } 191 192 int dLink_delete_tail() 193 { 194 return dLink_delete(node_count-1); 195 }
2.3 test测试代码
1 #include<stdio.h>
2 #include"double_link.h"
3 //1.双向链表操作数为int
4 void int_test()
5 {
6 int arr[10] = {11,55,67,90,21,45,23,59,79,10};
7 printf("xxxxxxxxxxxxxxxxx\n");
8 create_dLink(); //创建链表
9 dLink_insert(0, &arr[0]); //双向链表表头插入
10 dLink_insert(0, &arr[1]); //双向链表表头插入
11 dLink_insert(0, &arr[2]); //双向链表表头插入
12 dLink_insert(0, &arr[3]); //双向链表表头插入
13 dLink_insert(0, &arr[4]); //双向链表表头插入
14 dLink_insert(0, &arr[5]); //双向链表表头插入
15 printf("is_empty_dLink()=%d\n",is_empty_dLink()); //双向链表是否为空
16 printf("dLink_size()=%d\n", dLink_size()); //双向链表的大小
17 //遍历双向链表
18 int i ;
19 int * p ;
20 int sz = dLink_size();
21 for ( i = 0; i < sz; i++)
22 {
23 p = (int*)dLink_get(i);
24 printf("dLink_get(%d)=%d\n",i,*p);
25 }
26 destory_dLink();
27 }
28
29 //2.操作数为字符串
30 void string_test()
31 {
32 char* str[] = {"one","two","three","four","five"};
33 create_dLink(); //创建链表
34 dLink_insert(0, str[0]); //双向链表表头插入
35 dLink_insert(0, str[1]); //双向链表表头插入
36 dLink_insert(0, str[2]); //双向链表表头插入
37 printf("is_empty_dLink()=%d\n", is_empty_dLink()); //双向链表是否为空
38 printf("dLink_size()=%d\n", dLink_size()); //双向链表的大小
39 //遍历双向链表
40 int i ;
41 char * p ;
42 int sz = dLink_size();
43 for (i = 0; i < sz; i++)
44 {
45 p = (char*)dLink_get(i);
46 printf("dLink_get(%d)=%s\n", i, p);
47 }
48 destory_dLink();
49 }
50 //3.双向链表为结构体
51 typedef struct MyStruct
52 {
53 int id;
54 char name[20];
55 } stu;
56 stu arr_stu[] =
57 {
58 {1000,"lii"},
59 { 1001,"mike" },
60 { 1002,"lucky" },
61 { 1003,"eric" },
62 };
63 #define arr_stu_size ((sizeof(arr_stu))/(sizeof(arr_stu[0])))
64 void stuc_test()
65 {
66 create_dLink(); //创建链表
67 dLink_insert(0, &arr_stu[0]); //双向链表表头插入
68 dLink_insert(0, &arr_stu[1]); //双向链表表头插入
69 dLink_insert(0, &arr_stu[2]); //双向链表表头插入
70 printf("is_empty_dLink()=%d\n", is_empty_dLink()); //双向链表是否为空
71 printf("dLink_size()=%d\n", dLink_size()); //双向链表的大小
72 //遍历双向链表
73 int i ;
74 stu * p ;
75 int sz = dLink_size();
76 for (i = 0; i < sz; i++)
77 {
78 p = (stu*)dLink_get(i);
79 printf("dLink_get(%d)=[%d,%s]\n", i, p->id,p->name);
80 }
81 destory_dLink();
82 }
83 int main()
84 {
85 int_test();
86 string_test();
87 stuc_test();
88
89 return 0;
90 }
2.34结果显示