本文首先给出了传统链表,即在课本上学过的链表和侵入式链表的实现,而后将两者进行了对比,阐明了侵入式链表的优势,并给出了对应的实现代码与详细的注释。
一句话总结
传统链表是在链表节点中包含数据,而侵入式链表是在数据内部包含链表节点
传统链表
概念: 正如从数据结构课本中学到的那样,传统链表由节点构成,每个节点包含数据和指向序列中下一个节点的指针,以及一个指向前一个节点的指针。其C语言实现如下所示:
struct node {
void *data;
struct node *next;
struct node *pre;
};
引用知乎上的一张图片:
侵入式链表
侵入式链表(Intrusive List)是一种在数据结构内部直接包含链表节点的方法。这与传统链表不同,传统链表通常有一个单独的节点结构,用来存储数据和指向列表中下一个节点的指针。侵入式链表直接在要组成链表的数据结构中嵌入链表节点。
其对应的C语言实现如下所示:
这是Linux内核中定义的典型侵入式链表节点的示例:
struct list_head {
struct list_head *next, *prev;
};
然后你的数据结构会嵌入这个list_head:
struct my_data {
data_type data;
struct list_head list;
};
优势
在说侵入式链表的优势前,先说传统链表的缺陷:
- 一个数据对象只能属于一个链表节点:如果你想在两个节点之间共享一个对象,就需要使用指针或者用deepcopy。
- 每个链表节点中,data元素的类型是指定的,也就是一个链表中,每个节点存储的数据类型必须是相同的。
- 不同的链表,在构建api的时候必须要构建多套函数。
- 难以处理每个节点数据个数不同的情况
由此,侵入式链表的优势为:
- 操作侵入式链表根本不调用任何内存管理。与动态内存相关的时间和大小开销可以最小化。
- 同一个数据对象可以同时插入到多个链表中,对象大小的开销很小。同样,一个链表可以用于多种对象。
- 与语义上等价的指针容器相比,遍历侵入式容器需要更少的内存访问——迭代更快。
以上就是关于linux内核中使用的侵入式链表的讲解,当然,在内核中真正的代码使用了大量的trick这里并没有说明,感兴趣的话可以看相关的文章。