struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
从上面结构可以看到,散列链表对链表头和链表节点有不同的定义。
散列链表的头结构只维护了指向链表第一个结点的指针;而散列链表结点则维护了下个结点的指针和一个二级指针。
这个二级指针到底是什么呢,带着问题,我们先看两个结构的初始化API
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next = NULL;
h->pprev = NULL;
}
可以看到初始化API平平无奇...
再看一下add方法:
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
从这里就可以看到pprev保存的是前一个结点的next指针的地址。
具体情况大概就是上面这个图描述的样子。
此种设计,用结点地址代替指针可以大大减少内存的开销