uthash详解

2022/7/24 6:24:08

本文主要是介绍uthash详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

库函数

//新增元素
HASH_ADD_INT(head, keyfield_name, item_ptr);
HASH_ADD_STR(head, keyfield_name, item_ptr);
HASH_ADD_PTR(head, keyfield_name, item_ptr);
//查找元素
HASH_FIND_INT(head, key_ptr, item_ptr);
HASH_FIND_STR(head, key_ptr, item_ptr);
HASH_FIND_PTR(head, key_ptr, item_ptr);
//删除元素
HASH_DEL(head, item_ptr);
//返回长度
HASH_COUNT(head);
//释放堆区内存
HASH_CLEAR(hh_name, head);
//排序,cmp_func书写规则和qsort一样。
HASH_SORT(head, cmp_func);

参数介绍:
head: 哈希表变量,是一个结构体指针
keyfield_name: 结构体内键的定义名称
item_ptr: 新增节点的指针
key_ptr: 键变量的指针
hh_name: UT_hash_handle变量的定义名称

正文

上面列出了常用的库函数(都是便利版本,如果想要更高的灵活性请参考原文链接uthash)
正常来说,上面这些就足够刷题使用了。

下面是uthash的使用步骤:

  1. 需要自定义一个结构体
typedef struct
{
	int key;
	char name[20];
	uint8_t age;
	UT_hash_handle hh;
} HashMap;
static HashMap *head = NULL;

这里必须的只有两个,一个是UT_hash_handle hh;,映射就是通过这个宏实现的,变量名称最好定义为hh,否则上面介绍的便利版本宏函数全部用不了(便利版本内部默认使用hh导致)。当然定义成别的名称也不是不行,函数就得用通用版本,参数更多也更难记,总不能既要有要还要吧~
另一个就是key变量,便利版本支持三种类型:int,char *,void *,查找会用到该字段。
最后声明一个全局变量head,他就是hash表的入口,初始化必须是NULL。所有函数都会用到他。

  1. 定义几个操作函数
HashMap *Find(const int key)
{
	HashMap *node = NULL;
	HASH_FIND_INT(head, &key, node);	//如果是int,要取地址,str或ptr不需要
	return node;
}

void Add(const int key, const char *name, const uint8_t age)
{
	HashMap *node = Find(key);
	if (!node)
	{
		node = (HashMap *)malloc(sizeof(HashMap));
		node->key = key;
		node->age = age;
		strcpy_s(node->name, sizeof(node->name), name);
		HASH_ADD_INT(head, key, node);	//注意,这里key其实是结构体主键的定义名称,而不是变量。
	}
}

void Delete(const int key)
{
	HashMap *node = Find(key);
	if (node)
	{
		HASH_DEL(head, node);
		free(node);		//最好free一下,毕竟节点删掉了。
	}
}

为什么要定义这些呢?
很简单,为了代码可读,为了少写点代码字数(C大概是所有现代语言里最繁琐的一种了),具体看下文主函数的内容就知道了。
接下来简单说下。

  • Find是查找hash表,找到了就返回结构体指针,找不到返回NULL;
  • Add是给hash表新增元素,必须包含结构体所有字段;
  • Delete是删除某个元素
  • 如果有别的需求,比如不用key来找,用name来找,那么修改下Find函数即可(但是性能肯定会下降很多,O(1)->O(N));
  • 如果想要修改,查到了直接改就行,很简单所以没封装成函数。
  1. 接下来是主函数
int main()
{
	Add(0, "zhang san", 18);	//这里一条就可以加一个映射关系
	Add(1, "li si", 21);
	Add(2, "wang wu", 31);
	for (int i = 0; i < HASH_COUNT(head); i++)
	{
		printf("name: %s    age: %d\n", Find(i)->name, Find(i)->age);
	}
	HASH_CLEAR(hh, head);	//必须,千万别忘了写
	return 0;
}

打印结果为:

name: zhang san    age: 18
name: li si    age: 21
name: wang wu    age: 31

这里要特别注意,最后必须要调用HASH_CLEAR(hh, head);,否则堆内存未被释放,在线编程会导致内存错误或结果不正确。
到这里,库函数和简单演示都结束了~

后记

这个hash库可以做很多事情,因为他使用自定义结构体做节点,结构体里可以塞各种变量,主键和结构体会产生映射关系。
如果只有主键,那么就是个set;
如果除了主键还有其他结构体元素,那他就是个map;
如果Add函数不查重,那么他就是multi版本的set和map;
默认情况下是无序的,如果sort一下,他就是有序的。
这么看来,它就把C++里的8种set和map都覆盖了呢~



这篇关于uthash详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程