uthash简介
文章目錄
- C語言hash總結
- 一、 uthash的使用
- Key類型為int時
- 使用注意事項總結
- 二、 完整的例子
- 2.1 key為int
- 2.2 key為字符數組
- 2.3 key為字符
C語言hash總結
本文內容基本來自對官網的翻譯,若有不準確的地方,望指正。
?uthash 是C的比較優秀的開源代碼,已經集成到最新的GCC。它實現了常見的hash操作函數,例如查找、插入、刪除等待。該套開源代碼采用宏的方式實現hash函數的相關功能,支持C語言的任意數據結構最為key值,甚至可以采用多個值作為key,無論是自定義的struct還是基本數據類型,需要注意的是不同類型的key其操作接口方式略有不同。使用uthash代碼時只需要包含頭文件"uthash.h"即可。由于該代碼采用宏的方式實現,所有的實現代碼都在uthash.h文件中,因此只需要在自己的代碼中包含該頭文件即可。
一、 uthash的使用
? 首先,需要定義一個結構體:
struct MyStruct {int id; /* key */char name[10];UT_hash_handle hh; /* makes this structure hashable */ };其中,
-
id是鍵(key),也可以是其他的數據結構,不同的數據結構對應hash操作可能不一樣
-
name是值(value),其類型根據實際情況定義
-
hh是內部使用的hash處理句柄,在使用過程中,只需要在結構體中定義一個UT_hash_handle類型的變量即可,不需要為該句柄變量賦值,但必須在該結構體中定義該變量。
然后,你只需要愉快的調用uthash所定義的api就可以愉快的使用hash啦。然我們舉個例子吧。
Key類型為int時
- 定義一個key為int類型的hash結構體
- 注意:定義一個hash結構的空指針g_users,用于指向保存數據的hash表,必須初始化為空,在后面的查、插等操作中,uthash內部會根據其是否為空而進行不同的操作。
2. 封裝自己的查找接口
? 由于uthash要求鍵(key)必須唯一,而uthash內部未對key值得唯一性進行很好的處理,因此它要求外部在插入操作時要確保其key值不在當前的hash表中。若插入相同的key值到一個hash中,會被當做一種錯誤。
? 3. 封裝實現刪除接口
void DeleteUser(int ikey) {struct MyStruct *s = NULL;HASH_FIND_INT(g_users, &ikey, s);if (s==NULL) {HASH_DEL(g_users, s); // HASH_DEL 只將結構體從hash表中移除,并未釋放結構體內容free(s); } }? 4. 統計hash表中的元素個數
unsigned int numUsers; numUsers = HASH_COUNT(g_users); printf("there are %u items\n", numUsers);? 5. 遍歷元素
struct MyStruct *s, *tmp; HASH_ITER(hh, g_users, s, tmp) {printf("user ikey %d: value %s\n", s->key, s->value);/* ... it is safe to delete and free s here */ }? 還有另外一種刪除方法(更加推薦前一種,不易出錯)
struct MyStruct *s; for(s = g_users; s != NULL; s = s->hh.next) {printf("user ikey %d: value %s\n", s->key, s->value); }? 6. 清空hash表
void DeleteHash() {struct MyStruct *currentUser, *tmp;HASH_ITER(hh, g_users, currentUser, tmp) {HASH_DEL(g_users, currentUser); free(currentUser); } }使用注意事項總結
-
在定義hash結構體時不要忘記定義UT_hash_handle的變量
-
需確保key值唯一,如果插入key-value對時,key值已經存在,再插入的時候就會出錯
-
不同的key值,其增加和查找調用的接口函數不一樣。一般情況下,不通類型的key,其插入和查找接口函數是不一樣的,刪除、遍歷、元素統計接口是通用的,特殊情況下,字符數組和字符串作為key值時,其插入接口函數不一樣,但是查找接口是一樣的
-
以上舉的例子中,g_users是全局變量。但是如果函數如AddUser想將hash結構體的指針g_users作為參數傳入。則有以下問題
/* bad */ void AddUser(struct Mytruct *users, int key, char *name) {...HASH_ADD_INT(users, key, s); } /* good */ void AddUser(struct Mytruct **users, int key, char *name) { ...HASH_ADD_INT( *users, key, s ); }官方給出的解釋如下:The reason it’s necessary to deal with a pointer to the hash pointer is simple: the hash macros modify it (in other words, they modify the pointer itself not just what it points to). 就是這個指針的值會變化。
二、 完整的例子
2.1 key為int
#include <stdio.h> /* gets */ #include <stdlib.h> /* atoi, malloc */ #include <string.h> /* strcpy */ #include "uthash.h"struct my_struct {int id; /* key */char name[10];UT_hash_handle hh; /* makes this structure hashable */ };struct my_struct *users = NULL;void add_user(int user_id, char *name) {struct my_struct *s;HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */if (s==NULL) {s = (struct my_struct *)malloc(sizeof *s);s->id = user_id;HASH_ADD_INT( users, id, s ); /* id: name of key field */}strcpy(s->name, name); }struct my_struct *find_user(int user_id) {struct my_struct *s;HASH_FIND_INT( users, &user_id, s ); /* s: output pointer */return s; }void delete_user(struct my_struct *user) {HASH_DEL(users, user); /* user: pointer to deletee */free(user); }void delete_all() {struct my_struct *current_user, *tmp;HASH_ITER(hh, users, current_user, tmp) {HASH_DEL(users, current_user); /* delete it (users advances to next) */free(current_user); /* free it */} }void print_users() {struct my_struct *s;for(s=users; s != NULL; s=(struct my_struct*)(s->hh.next)) {printf("user id %d: name %s\n", s->id, s->name);} }int name_sort(struct my_struct *a, struct my_struct *b) {return strcmp(a->name,b->name); }int id_sort(struct my_struct *a, struct my_struct *b) {return (a->id - b->id); }void sort_by_name() {HASH_SORT(users, name_sort); }void sort_by_id() {HASH_SORT(users, id_sort); }int main(int argc, char *argv[]) {char in[10];int id=1, running=1;struct my_struct *s;unsigned num_users;while (running) {printf(" 1. add user\n");printf(" 2. add/rename user by id\n");printf(" 3. find user\n");printf(" 4. delete user\n");printf(" 5. delete all users\n");printf(" 6. sort items by name\n");printf(" 7. sort items by id\n");printf(" 8. print users\n");printf(" 9. count users\n");printf("10. quit\n");gets(in);switch(atoi(in)) {case 1:printf("name?\n");add_user(id++, gets(in));break;case 2:printf("id?\n");gets(in); id = atoi(in);printf("name?\n");add_user(id, gets(in));break;case 3:printf("id?\n");s = find_user(atoi(gets(in)));printf("user: %s\n", s ? s->name : "unknown");break;case 4:printf("id?\n");s = find_user(atoi(gets(in)));if (s) delete_user(s);else printf("id unknown\n");break;case 5:delete_all();break;case 6:sort_by_name();break;case 7:sort_by_id();break;case 8:print_users();break;case 9:num_users=HASH_COUNT(users);printf("there are %u users\n", num_users);break;case 10:running=0;break;}}delete_all(); /* free any structures */return 0; }2.2 key為字符數組
#include <string.h> /* strcpy */ #include <stdlib.h> /* malloc */ #include <stdio.h> /* printf */ #include "uthash.h"struct my_struct {char name[10]; /* key (string is WITHIN the structure) */int id;UT_hash_handle hh; /* makes this structure hashable */ };int main(int argc, char *argv[]) {const char *names[] = { "joe", "bob", "betty", NULL };struct my_struct *s, *tmp, *users = NULL;for (int i = 0; names[i]; ++i) {s = (struct my_struct *)malloc(sizeof *s);strcpy(s->name, names[i]);s->id = i;HASH_ADD_STR(users, name, s);}HASH_FIND_STR( users, "betty", s);if (s) printf("betty's id is %d\n", s->id);/* free the hash table contents */HASH_ITER(hh, users, s, tmp) {HASH_DEL(users, s);free(s);}return 0; }2.3 key為字符
#include <string.h> /* strcpy */ #include <stdlib.h> /* malloc */ #include <stdio.h> /* printf */ #include "uthash.h"struct my_struct {const char *name; /* key */int id;UT_hash_handle hh; /* makes this structure hashable */ };int main(int argc, char *argv[]) {const char **n, *names[] = { "joe", "bob", "betty", NULL };struct my_struct *s, *tmp, *users = NULL;int i=0;for (n = names; *n != NULL; n++) {s = (struct my_struct*)malloc(sizeof(struct my_struct));s->name = *n;s->id = i++;HASH_ADD_KEYPTR(hh, users, s->name, strlen(s->name), s);}HASH_FIND_STR(users, "betty", s);if (s) printf("betty's id is %d\n", s->id);/* free the hash table contents */HASH_ITER(hh, users, s, tmp) {HASH_DEL(users, s);free(s);}return 0; }參考鏈接:
https://github.com/troydhanson/uthash
http://troydhanson.github.io/uthash/
http://troydhanson.github.io/uthash/userguide.html
?
總結
- 上一篇: 浔阳江头夜送客,枫叶荻花秋瑟瑟——pyt
- 下一篇: rssi室内定位算法原理_基于RSSI的