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();
View Code
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 }
View Code

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 }
View Code

2.34結果顯示


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM