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都覆盖了呢~
标签:node,head,HASH,name,详解,key,uthash,ptr 来源: https://www.cnblogs.com/mrzono/p/16513591.html