c中的双向链表实现

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 }

运行程序的结果:

 

 

 

 

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值