1、之前在培训公司学习了用C语言实现双向链表的知识,现在有空重新写一遍。首先定义一下头文件list.h。
1 #ifndef __LIST_H__
2 #define __LIST_H__
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 //双向循环列表
9 struct list
10 {
11 struct list *prev, *next;
12 void *dat;
13 int size;
14 };
15
16 //比较函数类型
17 typedef int (*cmp_t)(void *dat1, void *dat2);
18
19 //打印函数类型
20 typedef void (*print_t)(void *dat);
21
22 struct list *list_create(int size);
23 int list_addtail(struct list *head, void *dat);
24 int list_addhead(struct list *head, void *dat);
25 struct list *list_find(struct list *head, void *dat, cmp_t cmp);
26 void list_delnode(struct list *head, void *dat, cmp_t cmp);
27 void list_print(struct list *head, print_t print);
28 void list_destroy(struct list **entry);
29
30 #endif /* __LIST_H__ */
在头文件中,主要是定义了一个结构体的链表list,里面定义了指向前prev跟指向后的next指针,还有保存数据的变量dat及大小size。其他都是函数的声明。
2、接下来看一下list.c的函数具体实现。
1 #include "list.h"
2
3 //分配一个头结点
4 struct list *list_create(int size)
5 {
6 struct list *head = NULL;
7 head = calloc(1, sizeof(*head));
8 if (NULL == head)
9 {
10 perror("calloc head");
11 return NULL;
12 }
13 head->prev = head->next = head;
14 head->size = size;
15 return head;
16 }
17
18 //把一个结点加入链表尾
19 int list_addtail(struct list *head, void *dat)
20 {
21 struct list *tmp, *new;
22
23 //分配新的结点
24 new = calloc(1, sizeof(*new));
25 if(new == NULL)
26 {
27 perror("calloc new");
28 return -1;
29 }
30
31 //为结点分配数据的空间
32 new->dat = calloc(1, head->size);
33 if(new->dat == NULL)
34 {
35 perror("calloc dat");
36 free(new);
37 return -1;
38 }
39 memcpy(new->dat, dat, head->size);
40
41 //把新结点加入链表中
42 new->next = head;
43 new->prev = head->prev;
44 head->prev->next = new;
45 head->prev = new;
46 return 0;
47 }
48
49
50 //把一个结点加入链表头
51 int list_addhead(struct list *head, void *dat)
52 {
53 struct list *tmp, *new;
54
55 //分配新的结点
56 new = calloc(1, sizeof(*new));
57 if(new == NULL)
58 {
59 perror("calloc new");
60 return -1;
61 }
62
63 //为结点分配数据的空间
64 new->dat = calloc(1, head->size);
65 if(new->dat == NULL)
66 {
67 perror("calloc dat");
68 free(new);
69 return -1;
70 }
71 memcpy(new->dat, dat, head->size);
72
73 //把新结点加入链表中
74 new->prev = head;
75 new->next = head->next;
76 head->next->prev = new;
77 head->next = new;
78 return 0;
79 }
80
81 //在链表中查找某个结点
82 struct list *list_find(struct list *head, void *dat, cmp_t cmp)
83 {
84 struct list *tmp;
85 for (tmp = head->next; tmp != head; tmp = tmp->next)
86 {
87 if (!cmp(tmp->dat, dat))
88 {
89 return tmp;
90 }
91 }
92 return NULL;
93 }
94
95 //删除某个指定的结点
96 void list_delnode(struct list *head, void *dat, cmp_t cmp)
97 {
98 struct list *tmp;
99 tmp = list_find(head, dat, cmp);
100 if (tmp != NULL)
101 {
102 tmp->prev->next = tmp->next;
103 tmp->next->prev = tmp->prev;
104 free(tmp->dat);
105 free(tmp);
106 }
107 }
108
109 //打印链表的内容
110 void list_print(struct list *head, print_t print)
111 {
112 struct list *tmp;
113 for (tmp = head->next; tmp != head; tmp = tmp->next)
114 {
115 print(tmp->dat);
116 }
117 printf("\n");
118 }
119
120 //销毁链表,释放链表占据的所有空间
121 void list_destroy(struct list **entry)
122 {
123 struct list *head, *tmp, *next;
124
125 if (entry != NULL)
126 {
127 head = *entry;
128 for (tmp = head->next; tmp != head; tmp = next)
129 {
130 next = tmp->next;
131 free(tmp->dat);
132 free(tmp);
133 }
134 free(head);
135 *entry = NULL;
136 }
137
138 }
首先是定义头结点 *list_create(int size),在这个函数里面会分配内存空间,并且让前后指针都指向头head。
3、通过测试test.c来测试一下刚才写的双向链表。
1 #include <stdio.h>
2 #include "list.h"
3
4 //此程序用于测试双向循环链表
5 int ar[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
6 void print_int(void *dat);
7 int cmp_int(void *dat1, void *dat2);
8
9 int main(void)
10 {
11 int i = 0;
12 struct list *tmp;
13 struct list *head = list_create(sizeof(int));
14 if (NULL == head)
15 {
16 return -1;
17 }
18
19 for (i; i < 10; i++)
20 {
21 list_addtail(head, &ar[i]);
22 }
23
24 list_print(head, print_int);
25 tmp = list_find(head, &ar[3], cmp_int);
26 if (tmp != NULL)
27 {
28 print_int(tmp->dat);
29 printf("\n");
30 }
31
32 list_delnode(head, &ar[4], cmp_int);
33 list_print(head, print_int);
34
35 ar[4] = 100;
36 list_delnode(head, &ar[4], cmp_int);
37 list_print(head, print_int);
38
39 list_destroy(&head);
40 return 0;
41
42
43 }
44
45 void print_int(void *dat)
46 {
47 printf("%d ", *(int *)dat);
48 }
49
50 int cmp_int(void *dat1, void *dat2)
51 {
52 return *(int *)dat1 - *(int *)dat2;
53 }
运行程序的结果: