zoukankan      html  css  js  c++  java
  • c语言是如何实现泛型链表

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

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

      下面以Node和list_head为例。

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

      我们通过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))))

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

    我们只知道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.h
     3     > Author: gaozy
     4     > Mail: 44523253@qq.com 
     5     > 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_HEAD
    24 #define    DLIST_HEAD
    25 
    26 #define list_entry(ptr, type, member) 
    27     ((type *)((char *)(ptr) - (char *)(&(((type *)0)->member))))
    28 
    29 typedef struct dclist_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.c
     3     > Author: gaozy
     4     > Mail: 44523253@qq.com 
     5     > Created Time: 2016年12月24日 星期六 10时19分49秒
     6  ************************************************************************/
     7 
     8 #include <stdio.h>
     9 #include <stdlib.h>
    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
    ");
    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.c
     3     > Author: gaozy
     4     > Mail: 44523253@qq.com 
     5     > Created Time: 2016年12月24日 星期六 11时11分25秒
     6  ************************************************************************/
     7 
     8 #include <stdio.h>
     9 #include <stdlib.h>
    10 
    11 #include "dclist_head.h"
    12 
    13 typedef struct {
    14     int id;
    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
    ", 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(int id)
    36 {
    37     student_t *stu = (student_t *)malloc(sizeof(student_t));
    38     if ( stu != NULL ) {
    39         stu->id = id;
    40     }
    41 
    42     return stu;
    43 }
    44 
    45 int main(void)
    46 {
    47     dclist_head_t list;
    48 
    49     init(&list);
    50 
    51     int i;
    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 }

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

  • 相关阅读:
    noi 2011 noi嘉年华 动态规划
    最小乘积生成树
    noi 2009 二叉查找树 动态规划
    noi 2010 超级钢琴 划分树
    noi 2011 阿狸的打字机 AC自动机
    noi 2009 变换序列 贪心
    poj 3659 Cell Phone Network 动态规划
    noi 2010 航空管制 贪心
    IDEA14下配置SVN
    在SpringMVC框架下建立Web项目时web.xml到底该写些什么呢?
  • 原文地址:https://www.cnblogs.com/ITgaozy/p/6217328.html
Copyright © 2011-2022 走看看