C语言双向链表讲解
一、双向链表的概念
双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。
在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。
双向链表结构示意图
表头为空,表头的后继节点为"节点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();
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结果显示