通用双向链表的设计(参考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

下载代码

目录
相关文章
|
存储 安全 Ubuntu
从Linux到Windows:阿里云服务器系统镜像适配场景与选择参考
阿里云为用户提供了丰富多样的服务器操作系统选择,以满足不同场景下的应用需求。目前,云服务器的操作系统镜像主要分为公共镜像、自定义镜像、共享镜像、镜像市场和社区镜像五大类。以下是对这些镜像类型的详细介绍及选择云服务器系统时需要考虑的因素,以供参考。
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
496 0
linux内核中的几种链表
linux内核中的几种链表
|
Linux 网络安全 开发工具
linux实验参考1
linux实验参考1
199 0
|
Linux
Linux内核链表的使用
Linux内核链表的使用
381 0
|
缓存 C语言 数据安全/隐私保护
|
关系型数据库 MySQL 数据库
|
存储 算法 Java
【C语言】网吧管理系统-链表项目设计
C语言 & 网吧管理系统
308 0
|
存储 Linux C++
一文搞懂 Linux 内核链表(深度分析)
hello 大家好,今天给大家介绍一下linux 内核链表的分析,在写这篇文章前,笔者自己以前也只是停留在应用层面,没有深究其中的细节,很多也是理解的不是很透彻。写完此文后,发现对链表的理解更加深刻了。很多现代计算机的思想在内核里面都有体现。
575 0
|
Ubuntu Linux 开发工具
Linux部分操作命令,可以学习参考
2.1、终端基本提示符 终端提示符: ubuntu @ubuntu-linux:~$ ubuntu:用户名(当前登录的用户) 分隔符:@: 示当前的工作路径表示符:~ 用户权限符:$ 、 # 普通用户表示符:$ 超级用户(root)表示符:# 根(起始位置)表示符:/ 用户目录(文件夹):/home/xxxx用户名文件夹 2.2、Linux基本命令 mkdir 目录名:在当前工作路径下创建目录