c语言 泛型链表,c语言是怎么实现泛型链表

c语言是如何实现泛型链表

最近有看一点Linux内核源码,发现内核里大量使用了list_head结构体。百度查了一下,原来内核利用这个结构体实现了泛型。

自认为对链表已经很熟悉的我,决定自己实现一下。

下面以Node和list_head为例。

100857125.png

上图就是循环链大致思路了。(画的不好)

我们通过list_head对链表进行移动操作。

这里存在几个问题:

首先通过list_head得到的指针,它指向的list_head的结构体,但我们其实想要使用的是Node结构体。

再有,我们要设计一个泛型的链表,那么,我就不可以在实现链表时有任何对Node的操作。

解决办法:

1、通过计算,找到node结构体的首地址。(我们通过一个宏来实现)

1 #define list_entry(ptr, type, member) \

2 ((type *)((char *)(ptr) - (char *)(&(((type *)0)->member))))

这个宏看起来可能点乱,但我们把思路缕清就不乱了。

100857126.png

我们只知道entry的指针,如何求出Node的指针呢?

如果我们可以知道entry的相对位置,那么

Node的实际位置  = entry的实际位置 - entry的相对位置。

entry的相对位置 =  (&(((Node *)0)->entry))   又蒙了么?  这里,我们先将 0转换为(Node *)类型的指针,再用这个指针指向entry,最后取它的地址。这时我们就得到了entry的相对位置。

宏中把他们强转成char * 是为了进行减法。最后再强转成Node类型,这时我就得到了Node的指针。

2、让用户自己定义特定数据的操作,我们只提供一个函数接口(我们通过函数指针来实现)

在我们的链表里,只涉及到了list_head 里的内容,所以,不能对Node进行操作。参数也都是list_head的指针。这就需要用户在使用时,通过上面的宏来完成从list_head 到 Node的转换。在稍后例子中会了解到。

源码

dclist_head.h

1 /*************************************************************************2 > File Name: dlist_head.h3 > Author: gaozy4 > Mail: 44523253@qq.com5 > Created Time: 2016年12月24日 星期六 10时11分22秒6 ************************************************************************/

7

8 /*

9 *这是我自己实现的一个泛型循环链表10 *使用者只需要把dclist_head_t 这个结构体加入到自己的结构体中就可以使用这个链表了。11 *在使用时,需要使用者创建一个头节点,之后使用init函数初始化。(当然,你也可以自己对他进行初始化操作)12 *它很重要,否则无法使用这个链表。13 *链表给使用者提供了四个函数14 *init 刚刚已经说过了,我们用它初始化链表15 *append 这是一个向链表中添加节点的函数,需要我们传入链表的头和新节点的dclist_head_t部分的指针16 *treaverse 正如火函数名一样,它的作用是遍历链表,它需要我们提供一个函数指针17 *这个指针的作用是对节点进行操作,参数是一个dclist_head_t 类型的指针,我们同过list_entry这个宏获取18 *使用者自定义的数据类型。19 *dc_remove这个函数用来释放链表,类似treaverse函数,需要我们自己实现删除j节点函数。20 *它会释放链表中的所有节点,只有头结点例外,头需要我们自己释放21 */

22

23 #ifndef DLIST_HEAD24 #define DLIST_HEAD

25

26 #define list_entry(ptr, type, member) \

27 ((type *)((char *)(ptr) - (char *)(&(((type *)0)->member))))28

29 typedef structdclist_head {30 struct dclist_head *prev;31 struct dclist_head *next;32 } dclist_head_t;33

34 void init(dclist_head_t *head);35 void append(dclist_head_t *head, dclist_head_t *node);36 void treaverse(dclist_head_t *head, void (*pfun)(dclist_head_t *node) );37 void dc_remove(dclist_head_t *head, void (*pfun)(dclist_head_t *node) );38

39 #endif

dclist_head.c

1 /*************************************************************************2 > File Name: dclist_head.c3 > Author: gaozy4 > Mail: 44523253@qq.com5 > Created Time: 2016年12月24日 星期六 10时19分49秒6 ************************************************************************/

7

8 #include

9 #include

10

11 #include "dclist_head.h"

12

13

14 void init(dclist_head_t *head)15 {16 if ( head !=NULL ) {17 head->prev =NULL;18 head->next =NULL;19 }20 }21

22 void append(dclist_head_t *head, dclist_head_t *node)23 {24 if ( head ==NULL ) {25 printf("error\n");26 exit(1);27 }28

29 if ( head->prev == NULL && head->next ==NULL ) {30 head->prev =node;31 head->next =node;32 node->prev =head;33 node->next =head;34 } else{35 dclist_head_t *tmp = head->prev;36 tmp->next =node;37 node->prev =tmp;38 node->next =head;39 head->prev =node;40 }41 }42

43 void treaverse(dclist_head_t *head, void (*pfun)(dclist_head_t *node) )44 {45 if ( head == NULL || head->next ==NULL )46 return;47

48 dclist_head_t *tmp = head->next;49 while ( tmp !=head ) {50 pfun(tmp);51 tmp = tmp->next;52 }53 }54

55 void dc_remove(dclist_head_t *head, void (*pfun)(dclist_head_t *node) )56 {57 treaverse(head, pfun);58 }

测试代码

main.c

1 /*************************************************************************2 > File Name: main.c3 > Author: gaozy4 > Mail: 44523253@qq.com5 > Created Time: 2016年12月24日 星期六 11时11分25秒6 ************************************************************************/

7

8 #include

9 #include

10

11 #include "dclist_head.h"

12

13 typedef struct{14 intid;15 dclist_head_t entry;16 } student_t;17

18 void print(dclist_head_t *ptr)19 {20 student_t *stu =list_entry(ptr, student_t, entry);21 if ( stu ==NULL )22 return;23 printf("student id = %d\n", stu->id);24 }25

26 void free_node(dclist_head_t *ptr)27 {28 if (ptr ==NULL )29 return;30

31 student_t *node =list_entry(ptr, student_t, entry);32 free(node);33 }34

35 student_t* make_node(intid)36 {37 student_t *stu = (student_t *)malloc(sizeof(student_t));38 if ( stu !=NULL ) {39 stu->id =id;40 }41

42 returnstu;43 }44

45 int main(void)46 {47 dclist_head_t list;48

49 init(&list);50

51 inti;52 student_t *stu;53 for ( i=0; i<5; i++) {54 stu =make_node(i);55 if ( stu !=NULL )56 append(&list, &stu->entry);57 }58

59

60 treaverse(&list, print);61 dc_remove(&list, free_node);62

63

64 return 0;65 }

水平有限,还请大神多多指点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值