通用双向链表的设计(参考Linux系统中的实现)

简介: 通常我们设计设计链表都是将数据域放在里面,这样每次需要使用链表的时候都需要实现一个链表,然后重新实现它的相关操作,这里参考Linux系统中的设计实现了一个通用的双向链表,只需要在你的结构里面有一个这个链表的域,就可以使用链表的相关操作了。

通常我们设计设计链表都是将数据域放在里面,这样每次需要使用链表的时候都需要实现一个链表,然后重新实现它的相关操作,这里参考Linux系统中的设计实现了一个通用的双向链表,只需要在你的结构里面有一个这个链表的域,就可以使用链表的相关操作了。

注意:这个通用的双向链表是参考Linux系统中的实现,它使用了typeof这个功能,所以有些编译器可能不支持。我是再Windows系统中使用MinGW下使用GCC编译的。

////////////////////////////////////////////////////////////////////////////////////////

// list.h

 
#ifndef _list_h
#define _list_h
 
typedef struct _list_head {
    struct _list_head *prev,*next;
} list_head;
 
#define offsetof(TYPE,MEMBER) ( (size_t) &((TYPE*)0)->MEMBER )
 
#define container_of(ptr,type,member) ({\
    const typeof( ((type*)0)->member ) *__mptr = (ptr);\
    (type*)( (char*)__mptr - offsetof(type,member) );})
 
#define list_empty(head) ( head->next==0&&head->prev==0 )
 
/* get the member of list object
 * @ptr        pointer to list_head
 * @type    the type of container which contains list_head field
 * @memeber field name in the container
 * @return    return pointer to the container
 */
#define list_entry(ptr,type,member) container_of(ptr,type,member)
 
/* add a new node after `head`
 */
void list_add(list_head *head,list_head *node);
 
/* delete a node
 */
void list_del(list_head *node);
 
#endif

/////////////////////////////////////////////////////////

// list.c

#include "list.h"
 
/* add a new node after `head`
 */
void list_add(list_head *head,list_head *node) {
    if(list_empty(head)) {
        head->next = head;
        head->prev = head;
    }
    node->next = head->next;
    node->prev = head;
    head->next->prev = node;
    head->next = node;
}
/* delete a node
 */
void list_del(list_head *node) {
    node->prev->next = node->next;
    node->next->prev = node->prev;
}

///////////////////////////////////////////////////////////////////////////////

// test.c

#include <stdio.h>
#include <assert.h>
#include "list.h"
 
typedef struct _task {
    int id;
    list_head next;
} task;
 
#define task_next(t) ( container_of(t->next.next,task,next) )
 
void task_print(task *t) {
    printf("#%d -> ",t->id);
}
 
void task_foreach(task *head,void (*callback)(task *)) {
    task *p = head;
    do {
        callback(p);
        p = task_next(p);
    }
    while (p!=head);
}
 
// use task like a list
void test_list() {
    task t1={1,{0,0}},
        t2={2,{0,0}},
        t3={3,{0,0}},
        t4={4,{0,0}},
        t5={5,{0,0}};
 
    list_add(&t1.next,&t2.next);
    list_add(&t2.next,&t3.next);
    list_add(&t3.next,&t4.next);
    list_add(&t4.next,&t5.next);
 
    task_foreach(&t1,task_print);
}
 
int main(int argc, char *argv[]) {
    test_list();
 
    return 0;
}

编译运行

    gcc test.c list.h list.c -o test
    .\test.exe

下载代码

目录
相关文章
|
机器学习/深度学习 移动开发 Linux
linux通用双向链表
1, 基于linux4.9版本 #include #include #include #if 1 struct list_head { struct list_head *next, *prev; }; ...
863 0
|
Linux 机器学习/深度学习 C语言
linux内核源码“双向链表list_head”续
      上篇博文《linux内核源码“双向链表list_head”》中以一个实例介绍了list_head双向链表的用法,只有实例的代码,并没有list_head链表的代码,考虑到各位好学博友的强烈愿望,今天把list_head的代码即list.h头文件粘贴到此,供各位好学博友使用。
812 0
|
Linux
linux内核源码“双向链表list_head”
摘要:linux内核源码真是好东东,是众多高手思维的结晶,在linux 源代码中有个头文件为list.h 。很多linux 下的源代码都会使用这个头文件,它里面定义了一个结构, 以及定义了和其相关的一组函数,这个结构是这样的: struct list_head{ struct list_head *next, *prev; };         如果您之前学过双向链表,那么当你看到这个结构的时候,会觉得似曾相识。
1197 0
|
Linux C语言 C++
linux下c语言 双向链表
C/C++ code /*sgx 2008-10-30 c语言 双向链表*/#include #include #include #define TRUE 1;#define FALSE 0;typedef int ELEMTYPE;typedef struct DoubleLinkNode{...
734 0
|
8天前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
72 6
|
9天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
37 3
|
9天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
29 2
|
17天前
|
缓存 监控 Linux
|
4天前
|
运维 监控 网络协议
运维工程师日常工作中最常用的20个Linux命令,涵盖文件操作、目录管理、权限设置、系统监控等方面
本文介绍了运维工程师日常工作中最常用的20个Linux命令,涵盖文件操作、目录管理、权限设置、系统监控等方面,旨在帮助读者提高工作效率。从基本的文件查看与编辑,到高级的网络配置与安全管理,这些命令是运维工作中的必备工具。
20 3