理解Linux双向链表

理解Linux双向链表


原文:

http://blog.csdn.net/leisure512/article/details/5188986

我截取其中一部分,并加了图解。


Linux内核中双向链表hlist_head,它的定义:

struct hlist_head {
    struct hlist_node *first;

};


struct hlist_node {
    struct hlist_node *next, **pprev;

};


显然,这个双向链表不是真正的双向链表,因为表头只有一个first域,为什么这样设计?代码中的注释解释:为了节约内存,特别适合作为Hash表的冲突链,但Hash表很大时,那么表头节约下来的内存就相当客观了,虽然每个表头只节约一个指针。


同时,表头的不一致性也会带来链表操作上的困难,显然就是在表头和首数据节点之间插入节点时需要特别处理,这也就是为什么会设计二级指针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;
}


解释:指针n指向新节点,指针next指向将要在它之前插入新节点的那个节点。

看上面的代码,就可以看到二级指针pprev的威力了!有没有看到,当next就是第一个数据节点时,这里的插入也就是在表头和首数据节点之间插入一个节点,但是并不需要特别处理!而是统一使用*(n->pprev)来访问前驱的指针域(在普通节点中是next,而在表头中是first)。这太经典了!


我详细解释下面的代码:

static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next)
{
   
n->pprev=next->pprev;    1
   
n->next=next;                   2
   
next->pprev=&n->next;    3
    *(
n->pprev)=n;                  4
}


你可能感兴趣的:(linux,struct,linux内核)