linux内核之哈希链表解析

本文深入分析了Linux内核2.6.32.63版本中的哈希链表结构。与普通链表不同,Linux内核的哈希链表采用单指针表头,节点包含next和pprev两个指针,pprev并不直接指向前一个节点,而是指向前一个节点的next指针,以此简化操作。哈希链表的头节点结构不同于普通节点,主要是为了节省空间和统一操作。文中还介绍了链表的初始化、插入、删除等操作函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文只是对linux内核中的链表进行分析。内核版本是linux-2.6.32.63。文件在:linux内核/linux-2.6.32.63/include/linux/list.h。本文对list.h文件进行简要分析,有必要的地方还会以图进行说明。

linux内核中的哈希链表和其他链表不一样。他是头指针用单个的链表,只有next指针,但其他链表节点是有next和prev两个指针的双链表。

由上图可以知道hash链表中存在两种结构体,一种是hash表头,一种是hash节点。

hash表头:struct hlist_head{ struct hlist_node *first;};表头里面只存放一个hlist_node的指针,指向链表

hash节点:struct hlist_node{struct hlist_node *next; struct hlist_node **pprev;};有两个指针,所以链表是双链表。但和一般的双链表又有点不一样,next自然是指向链表的下一个节点,但pprev则不是指向当前节点的前一个节点,而是指向当前节点的前一个节点的next指针。所以ppre是二级指针。为什么要设计成这样呢?因为为了统一操作,如果设计的和我们平时使用的双链表的话(prev指向的是前一个节点),那头节点和链表节点之间的操作就要重新定义一套(因为头结点结构体和链表节点结构体是不一样的)。所以干脆直接指向前一个节点的next指针,next的类型是hlist_node*,first的类型也是hlist_node*。这样就统一了链表操作函数了。

还有个问题:为什么头结点要设计的和链表节点不一样呢?官方解释是为了节约空间,因为一般来说哈希表中有非常多的表项,即可能有上千个表项,也即是有上千个hlist_head。如果头结点不用pprev则可以节约非常大的空间。我个人认为还有种解释是头结点的pprev(如果有这个指针)用处不大。因为所有的操作都是要通过哈希函数来算出值在哈希表中的位置,然后再有链表中查找。哈希链表本来就是个处理碰撞现象的,说明链表中的关键字通过哈希函数后能得到一样的值。所以你不知道在链表中的哪个位置,那头结点有pprev的话你也没必要从后面开始查找(也许从前面查找开些,也许是从后面)。也就是说对于头节点来说这个指针可有可无。

代码分析:

/*
 * Double linked lists with a single pointer list head.
 * Mostly useful for hash tables where the two pointer list head is
 * too wasteful.
 * You lose the ability to access the tail in O(1).
 */
// 哈希节点,这是个表头,注意只有一个first指针。这是为了有多个哈希链表时,可以减少空间上的浪费
struct hlist_head {
struct hlist_node *first;
};
// 这个哈希链表和其他链表不一样,单指针表头双循环链表。所以头节点和其他节点不一样。
// 下面是链表节点有两个指针,next是指向下一个节点,pprev则是指向前一个节点的next,表头则是first。
// 所以pprev是二级指针
struct hli

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值