Linux散列表(一)——操作函数

散列表(又名哈希表)仅仅需要一个包含单一指针的链表头。它是双向链表的变体。它不同于双链表——表头和结点使用相同的结构体——散列表对表头和结点有不同的定义。如下:

 

struct hlist_head {
        struct hlist_node *first;
};
struct hlist_node {
        struct hlist_node *next, **pprev;
};

散列表的实现一般采用hlist_head数组,每个hlist_head挂一个双向hlist_node链表,大致如下图。其中pprev它指向前一个结点的next指针。

 

《Linux散列表(一)——操作函数》

1、初始化

1.1、初始化头

 

#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)

《Linux散列表(一)——操作函数》

 

1.2、初始化结点

 

static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
	h->next = NULL;
	h->pprev = NULL;
}

《Linux散列表(一)——操作函数》

 

2、逻辑判断

 

static inline int hlist_unhashed(const struct hlist_node *h)
{
	return !h->pprev;
}
static inline int hlist_empty(const struct hlist_head *h)
{
	return !h->first;
}

 

3、删除结点

3.1、内部API

 

static inline void __hlist_del(struct hlist_node *n)
{
	struct hlist_node *next = n->next;//(1)
	struct hlist_node **pprev = n->pprev;//(2)
	*pprev = next;//(3)
	if (next)
		next->pprev = pprev;//(4)
}

《Linux散列表(一)——操作函数》

 

3.2、外部API

 

static inline void hlist_del(struct hlist_node *n)
{
	__hlist_del(n);//(1)
	n->next = LIST_POISON1;//(2)
	n->pprev = LIST_POISON2;//(3)
}

《Linux散列表(一)——操作函数》

 

 

static inline void hlist_del_init(struct hlist_node *n)
{
	if (!hlist_unhashed(n)) {
		__hlist_del(n);//(1)
		INIT_HLIST_NODE(n);//(2)
	}
}

《Linux散列表(一)——操作函数》

 

4、添加结点

4.1、表头添加结点

 

static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)(0)
{
	struct hlist_node *first = h->first;//(1)
	n->next = first;//(2)
	if (first)
		first->pprev = &n->next;//(3)
	h->first = n;//(4)
	n->pprev = &h->first;//(5)
}

《Linux散列表(一)——操作函数》

 

 

在此基础上再次插入一个结点

《Linux散列表(一)——操作函数》

4.2、指定结点之前添加结点

 

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

《Linux散列表(一)——操作函数》

 

4.3、指定结点之后添加结点

 

static inline void hlist_add_after(struct hlist_node *n,
					struct hlist_node *next)//(0)
{
	next->next = n->next;//(1)
	n->next = next;//(2)
	next->pprev = &n->next;//(3)

	if(next->next)
		next->next->pprev  = &next->next;//(4)
}

《Linux散列表(一)——操作函数》

 

 

/* after that we'll appear to be on some hlist and hlist_del will work */
static inline void hlist_add_fake(struct hlist_node *n)
{
	n->pprev = &n->next;
}

 

 

5、移动散列表

 

/*
 * Move a list from one list head to another. Fixup the pprev
 * reference of the first entry if it exists.
 */
static inline void hlist_move_list(struct hlist_head *old,
				   struct hlist_head *new)
{
	new->first = old->first;//(1)
	if (new->first)
		new->first->pprev = &new->first;//(2)
	old->first = NULL;//(3)
}

《Linux散列表(一)——操作函数》

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/fuhaots2009/p/3458896.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞