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的使用步骤:
- 需要自定义一个结构体
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。所有函数都会用到他。
- 定义几个操作函数
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));
- 如果想要修改,查到了直接改就行,很简单所以没封装成函数。
- 接下来是主函数
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详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南
- 2024-11-23JAVA项目部署入门:新手必读指南
- 2024-11-23Java项目部署入门:新手必看指南
- 2024-11-23Java项目部署入门:新手必读指南
- 2024-11-23Java项目开发入门:新手必读指南
- 2024-11-23JAVA项目开发入门:从零开始的实用教程
- 2024-11-23Java项目开发入门:新手必读指南