一、雙向鏈表的概念
雙向鏈表基於單鏈表。單鏈表是單向的,有一個頭結點,一個尾結點,要訪問任何結點,都必須知道頭結點,不能逆着進行。而雙鏈表添加了一個指針域,通過兩個指針域,分別指向結點的前結點和后結點。這樣的話,可以通過雙鏈表的任何結點,訪問到它的前結點和后結點。
在雙向鏈表中,結點除含有數據域外,還有兩個鏈域,一個存儲直接后繼結點的地址,一般稱為右鏈域;一個存儲直接前驅結點地址,一般稱之為左鏈域。
雙向鏈表結構示意圖
表頭為空,表頭的后繼節點為"節點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結果顯示