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

原创 2013年12月04日 20:16:53

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

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

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)

1.2、初始化结点

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

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)
}

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)
}

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

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)
}

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

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)
}

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)
}

/* 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散列表(二)——宏

散列表宏承接了双向链表宏的风范,好使好用! 1、获取元素(结构体)基址 #define hlist_entry(ptr, type, member) container_of(ptr,type,mem...

【算法导论】十一章散列表11.1-4大数组实现直接寻址方式的字典操作

算法导论第三版,第十一章散列表 习题11.1-4 大数组实现直接寻址方式的字典操作。...

开散列表的查找、插入、删除操作的完整C代码

/*开散列表的插入、查找、删除算法的实现*/ #include #include #define M 13 //表长定为13 typedef int KeyType; typedef str...

散列表查找(哈希表)的基本操作 (完整代码)

表和二叉树的排序,是利用元素之间的关系,逐个查找,或按一定的规律查找。 而散列表(哈希表),元素之间没有关系,它是利用了元素与存储地址之间的关系。 说白了,就是利用散列函数建立 元素->地址 的映...

哈希表(散列表)的基本操作

大家好,近几天没有更新文章,今天在下介绍一个非常使用的哈希表(散列表) 首先要说的是:哈希表又叫散列表(哈希只是英文hash的音译,散列才是标准的翻译) 好吧,下面是源代码,如果有错误,...

散列表分离链接法初始化、插入、删去等操作(c)

#include #include struct ListNode; struct HashTb1; typedef unsigned int Index; typedef struct Lis...

散列表碰撞的链接法解决之双向链表删除操作的代价

浣熊今天读到《算法导论》的第十一章散列表,看到中文书的第135页(英文P224~225)时,被其中的一个知识点难住,想了许久终于有了答案,故撰此文与大家分享     在散列表发生碰撞问题的时候,其中...

散列表开放定址法的初始化、插入、打印等函数(c)

/* *散列表开放定址法的一些操作。 */ #include #include typedef unsigned int Index; typedef Index Position; ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux散列表(一)——操作函数
举报原因:
原因补充:

(最多只允许输入30个字)