在軟件開發中,不可不免的會使用到hash表,hash表的優點這里就不說了,以下介紹一個hash表的C實現,
uthash是用宏實現的,使用的時候非常方便,只用包含uthash.h即可。
Uthash的三個數據結構:
typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; unsigned expand_mult; } UT_hash_bucket;
UT_hash_bucket作用提供根據hash進行索引。
typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ unsigned ideal_chain_maxlen; unsigned nonideal_items; unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; char bloom_nbits; #endif } UT_hash_table;
UT_hash_table可以看做hash表的表頭。
typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle;
UT_hash_handle,用戶自定義數據必須包含的結構。
三種數據結構的關系如下:
說明:
每一個節點(用戶自定義的)必須包含一個UT_hash_handle hh
key:用戶自定義,可以是int, string和指針。
hh_prev: 指向前一個UT_hash_handle
hh_next: 指向下一個UT_hash_handle
hashv:根據key計算出的hash值
prev: 指向前一個數據節點(Hash沖突時)
next: 指向下一個數據節點(Hash沖突時)
hho: 數據節點中hh於用戶節點首地址的差。
uthash使用代碼例子
#include "uthash.h" #include <stdlib.h> /* malloc */ #include <stdio.h> /* printf */ #include <time.h> typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; srand((unsigned int)time(NULL)); /* create elements */ for(i=0;i<10;i++) { if ( (user = (example_user_t*)malloc(sizeof(example_user_t))) == NULL) exit(-1); user->id = rand()%100; user->cookie = i*i; HASH_ADD_INT(users,id,user); } for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; }