uthash简介
文章目錄
- C語言hash總結(jié)
- 一、 uthash的使用
- Key類型為int時(shí)
- 使用注意事項(xiàng)總結(jié)
- 二、 完整的例子
- 2.1 key為int
- 2.2 key為字符數(shù)組
- 2.3 key為字符
C語言hash總結(jié)
本文內(nèi)容基本來自對(duì)官網(wǎng)的翻譯,若有不準(zhǔn)確的地方,望指正。
?uthash 是C的比較優(yōu)秀的開源代碼,已經(jīng)集成到最新的GCC。它實(shí)現(xiàn)了常見的hash操作函數(shù),例如查找、插入、刪除等待。該套開源代碼采用宏的方式實(shí)現(xiàn)hash函數(shù)的相關(guān)功能,支持C語言的任意數(shù)據(jù)結(jié)構(gòu)最為key值,甚至可以采用多個(gè)值作為key,無論是自定義的struct還是基本數(shù)據(jù)類型,需要注意的是不同類型的key其操作接口方式略有不同。使用uthash代碼時(shí)只需要包含頭文件"uthash.h"即可。由于該代碼采用宏的方式實(shí)現(xiàn),所有的實(shí)現(xiàn)代碼都在uthash.h文件中,因此只需要在自己的代碼中包含該頭文件即可。
一、 uthash的使用
? 首先,需要定義一個(gè)結(jié)構(gòu)體:
struct MyStruct {int id; /* key */char name[10];UT_hash_handle hh; /* makes this structure hashable */ };其中,
-
id是鍵(key),也可以是其他的數(shù)據(jù)結(jié)構(gòu),不同的數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)hash操作可能不一樣
-
name是值(value),其類型根據(jù)實(shí)際情況定義
-
hh是內(nèi)部使用的hash處理句柄,在使用過程中,只需要在結(jié)構(gòu)體中定義一個(gè)UT_hash_handle類型的變量即可,不需要為該句柄變量賦值,但必須在該結(jié)構(gòu)體中定義該變量。
然后,你只需要愉快的調(diào)用uthash所定義的api就可以愉快的使用hash啦。然我們舉個(gè)例子吧。
Key類型為int時(shí)
- 定義一個(gè)key為int類型的hash結(jié)構(gòu)體
- 注意:定義一個(gè)hash結(jié)構(gòu)的空指針g_users,用于指向保存數(shù)據(jù)的hash表,必須初始化為空,在后面的查、插等操作中,uthash內(nèi)部會(huì)根據(jù)其是否為空而進(jìn)行不同的操作。
2. 封裝自己的查找接口
? 由于uthash要求鍵(key)必須唯一,而uthash內(nèi)部未對(duì)key值得唯一性進(jìn)行很好的處理,因此它要求外部在插入操作時(shí)要確保其key值不在當(dāng)前的hash表中。若插入相同的key值到一個(gè)hash中,會(huì)被當(dāng)做一種錯(cuò)誤。
? 3. 封裝實(shí)現(xiàn)刪除接口
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 只將結(jié)構(gòu)體從hash表中移除,并未釋放結(jié)構(gòu)體內(nèi)容free(s); } }? 4. 統(tǒng)計(jì)hash表中的元素個(gè)數(shù)
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 */ }? 還有另外一種刪除方法(更加推薦前一種,不易出錯(cuò))
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); } }使用注意事項(xiàng)總結(jié)
-
在定義hash結(jié)構(gòu)體時(shí)不要忘記定義UT_hash_handle的變量
-
需確保key值唯一,如果插入key-value對(duì)時(shí),key值已經(jīng)存在,再插入的時(shí)候就會(huì)出錯(cuò)
-
不同的key值,其增加和查找調(diào)用的接口函數(shù)不一樣。一般情況下,不通類型的key,其插入和查找接口函數(shù)是不一樣的,刪除、遍歷、元素統(tǒng)計(jì)接口是通用的,特殊情況下,字符數(shù)組和字符串作為key值時(shí),其插入接口函數(shù)不一樣,但是查找接口是一樣的
-
以上舉的例子中,g_users是全局變量。但是如果函數(shù)如AddUser想將hash結(jié)構(gòu)體的指針g_users作為參數(shù)傳入。則有以下問題
/* 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). 就是這個(gè)指針的值會(huì)變化。
二、 完整的例子
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為字符數(shù)組
#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
?
總結(jié)
- 上一篇: 浔阳江头夜送客,枫叶荻花秋瑟瑟——pyt
- 下一篇: rssi室内定位算法原理_基于RSSI的