内核数据结构--哈希链表
Linux内核中,除了有通用了双向链表list,还有通用的哈希链表hlist。后者定义与前者有些不同。因为通常一个哈希表的表头要占用很大空间,而如果每个表头都用一个双向链表来做的话,就显得太浪费了。只用一个指针可以实现相同的功能,并且可以节省一半的表头存储空间。
双向链表定义如下:
struct list_head {
struct list_head *next, *prev;
};
哈希链表定义如下:
struct hlist_head {
struct hlist_node *first;
}
struct hlist_node {
struct hlist_node *next, **pprev;
}
在Linux内核的 hlist_node 结构中不使用通常的 prev 指针,而使用二级指针 pprev,是因为对每一个哈希表的表项来说,它并不组成循环的链表,这样就不能方便地用统一的形式操作。在双向链表中,表头和节点是同一个数据结构,直接用 prev 没有问题。而在 hlist 中,表头没有 prev,也没有 next,只有一个 first。为了能统一地修改表头的 first 指针,即表头的 first 指针必须能够被引用修改,hlist 就设计了 pprev, 从而在表头插入的操作可以通过一致的“*(node->pprev)”访问和修改前节点的next(或first)指针。
下面是hlist中常用的几个宏:
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
下面只列出hlist_add_before操作函数,其他hlist链表操作函数操作方法类似。这个函数中的参数next不能为空。它在next前面加入了n节点。函数的实现与list中对应函数类似。
static inline void __hlist_del(struct hlist_node *n){
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}static inline void hlist_add_before(struct hlist_node *n,struct hlist_node *next){
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first;
pos && ({ prefetch(pos->next);
1;
});
\
pos = pos->next)
【内核数据结构--哈希链表】
推荐阅读
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 《数据结构与算法之美》——队列
- 芯灵思SinlinxA33开发板Linux内核定时器编程
- 嵌入式(编译内核、根文件系统等)
- 笔记|C语言数据结构——二叉树的顺序存储和二叉树的遍历
- Java深入了解数据结构之栈与队列的详解
- Java集合框架|Java集合框架 数据结构
- 数据结构与算法|【算法】力扣第 266场周赛
- 数据结构和算法|LeetCode 的正确使用方式
- 一个好的算法应该如何评测(数据结构学习1)