【tip】UThash使用技巧总结
2024-01-18 本文已影响0人
papi_k的小茅屋
首先看一个用整型值做key的哈希结构体:
//hh是内部使用的hash处理句柄,在使用过程中,只需要在结构体中定义一个UT_hash_handle类型的变量即可,不需要为该句柄变量赋值,但必须在该结构体中定义该变量。
struct hash_entry {
int id; /* we'll use this field as the key */
char name[10];
UT_hash_handle hh; /* makes this structure hashable */
};
//用于指向保存数据的hash表,必须初始化为空,在后面的查、插等操作中,uthash内部会根据其是否为空而进行不同的操作。
struct hash_entry *head = NULL;
// 查找
struct hash_entry *tmp;
HASH_FIND_INT(head, &key, tmp) //在hash中KEY值唯一,在添加时 需要先查找,没找到就构建一个新的,如果存在 就需要更新新的值
// 添加
// 第二入参的id是上边结构体中的成员变量id,结构体里面成员定义的名字是啥,这里就原样填啥。
HASH_ADD_INT(head, id, tmp);
// 删除
// 删除宏, 从head hash表中删除user结点
HASH_DEL(head, user);
// 清空hash表,利用hash中的迭代器进行删除和打印
void DeleteAll(struct hash_entry *head)
{
struct hash_entry *currentUser, *tmp;
HASH_ITER(hh, head, currentUser, tmp)
{
printf("id:%d,name:%s\n", tmp->id, tmp->name);
HASH_DEL(head, currentUser); /* delete; head advances to next */
free(currentUser); /* optional- if you want to free */
}
}
//如果只想删除所有项目,但不释放它们或进行每个元素的清理,则可以通过一次操作更有效地做到这一点,之后,列表头head将设置为NULL。
HASH_CLEAR(hh, head);
// 或者通过hh.next指针遍历hash表中的所有items。
// 由于hh.prev和hh.next字段的缘故,可以在哈希中向前和向后迭代。可以通过重复跟随这些指针来访问哈希中的所有项目,因此哈希也是双链表。
void print_all(struct hash_entry *head)
{
struct hash_entry *tmp;
for(tmp = head; tmp != NULL; tmp = (struct hash_entry *)tmp->hh.next)
{
printf("id:%d,name:%s\n", tmp->id, tmp->name);
}
}
//统计hash表中的已经存在的元素数
unsigned int numUsers = HASH_COUNT(head);
//排序,与之前总结的qsort、Cmp差不多
// 第二个参数sortFunction是指向比较函数的指针。它必须接受两个指针参数(要比较的项目),并且如果第一个项目分别在第二个项目之前,等于或之后排序,则必须返回小于零,零或大于零的int
//(这与标准C库中的strcmp或qsort使用的约定相同)。
HASH_SORT(head, sortFunction);
int sortFunction(void *a, void *b)
{
/* compare a to b (cast a and b appropriately)
* return (int) -1 if (a < b) 或者 return (int) a-b 升序
* return (int) 0 if (a == b)
* return (int) 1 if (a > b) 或者 return(int)b-a 降序
*/
}
例如:
// 字符串比较
HASH_SORT(head, nameSort);
int nameSort(struct hash_entry *a, struct hash_entry *b)
{
return strcmp(a->name, b->name);
}
// 整数比较
HASH_SORT(head, idSort);
int idSort(struct my_struct *a, struct my_struct *b)
{
return (a->id - b->id);
}
UThash组key方式
// 1.字符数组做key
struct hash_entry {
char name[10]; // 字符数组做key
int id;
UT_hash_handle hh;
};
int test() {
const char *names[] = {"joe", "bob", "betty", NULL};
struct hash_entry *s;
struct hash_entry *next;
struct hash_entry *head = NULL;
for (int i = 0; names[i]; ++i) {
s = (struct hash_entry *)malloc(sizeof(struct hash_entry));
strcpy(s->name, names[i]);
s->id = i;
HASH_ADD_STR(head, name, s); // 当使用字符数组做key,要使用 HASH_ADD_STR 接口添加节点
}
HASH_FIND_STR(head, "betty", s);
if (s) {
printf("betty's id is %d\n", s->id);
}
HASH_ITER(hh, head, s, next) {
HASH_DEL(head, s);
free(s);
}
return 0;
}
// 2.字符指针做key
struct hash_entry {
char *name; // 字符指针做key
int id;
UT_hash_handle hh;
};
int test() {
const char *names[] = {"joe", "bob", "betty", NULL};
struct hash_entry *s;
struct hash_entry *next;
struct hash_entry *head = NULL;
for (int i = 0; names[i]; ++i) {
s = (struct hash_entry *)malloc(sizeof(struct hash_entry));
s->name = names[i];
s->id = i;
HASH_ADD_KEYPTR(hh, head, s->name, strlen(s->name), s); // 当使用字符指针做key,要使用 HASH_ADD_KEYPTR 接口添加节点
}
HASH_FIND_STR(head, "betty", s);
if (s) {
printf("betty's id is %d\n", s->id);
}
HASH_ITER(hh, head, s, next) {
HASH_DEL(head, s);
free(s);
}
return 0;
}
// 3.void *方式组key
// 在uthash中也可使用地址做key进行hash操作,使用地址作为key值时,其类型为void *,这样它就可以支持任意类型的地址了。
struct hash_entry {
void *key; // void *方式组key
int i;
UT_hash_handle hh;
};
struct hash_entry *head = NULL;
char *someaddr = NULL;
int test() {
struct hash_entry *s;
struct hash_entry *tmp = (struct hash_entry*)malloc(sizeof(struct hash_entry);
tmp->key = (void*)someaddr;
tmp->i = 1;
HASH_ADD_PTR(hash, key, tmp); // 当使用void *做key,要使用 HASH_ADD_PTR 接口添加节点
HASH_FIND_PTR(hash, &someaddr, s);
if (s) {
printf("found\n");
}
HASH_DEL(head, tmp);
free(tmp);
return 0;
}
// 4.结构体方式组key
// HASH_ADD 表示添加的键值可以是任意类型,比较通用,比如结构体
typedef struct {
char a;
int b;
} RecordKey;
typedef struct {
RecordKey key; // 结构体方式组key
UT_hash_handle hh;
} Record;
int main(int argc, char *argv[]) {
Record l, *p, *r, *next, *head = NULL;
r = (Record *)malloc(sizeof *r);
/* 结构体键值清零 */
memset(r, 0, sizeof *r);
r->key.a = 'a';
r->key.b = 1;
HASH_ADD(hh, head, key, sizeof(RecordKey), r);
memset(&l, 0, sizeof(Record));
l.key.a = 'a';
l.key.b = 1;
HASH_FIND(hh, head, &l.key, sizeof(RecordKey), p);
if (p) {
printf("found %c %d\n", p->key.a, p->key.b);
}
HASH_ITER(hh, head, p, next) {
HASH_DEL(head, p);
free(p);
}
return 0;
}
yo peace!