c语言实现hashmap(转载)
2013-04-26 17:23
2031 查看
//hash.h
/* * hashmap.h * */ #ifndef HASHMAP_H #define HASHMAP_H #define HMAP_PRESET_SIZE 2 <<23 // use a power of 2 for faster array access #define HMAP_GROWTH_RATE 2 #define HMAP_MAKE_HASHFN // build a few hash functions #define HMAP_THREAD_SAFE // add "-lrt" to your GCC compile flags #define HMAP_DESTRUCTORS // require destructors for value clean-up #define NEED 1 //需要做成hashCode #define NOTNEED 0 //不需要做成hashCode #ifdef HMAP_MAKE_HASHFN #include <string.h> #endif #ifdef HMAP_THREAD_SAFE #include <semaphore.h> #endif #include <stdint.h> #include <stdbool.h> // it may be a good idea to redefine key and val if the size of either is less // than sizeof(void*). keep in mind that the default hash functions assume that // key and val are void pointers, and will not work properly if they are changed // to other (non-pointer) types. typedef void* key; typedef void* val; typedef int int32; typedef struct key_val_pair key_val_pair; typedef struct hashmap hashmap; // create a hashmap hashmap* mk_hmap(uint32_t (*hash_fn)(key), bool (*eq_fn)(key, key) #ifdef HMAP_DESTRUCTORS , void (*del_fn)(val) #endif ,uint32_t isNeedCalcHashCode ); // create a hashmap ,Specify memory Size Settings hashmap* mk_hmap2(uint32_t (*hash_fn)(key), bool (*eq_fn)(key, key) #ifdef HMAP_DESTRUCTORS , void (*del_fn)(val) #endif ,uint32_t isNeedCalcHashCode ,uint32_t set_size ); // delete the hashmap (and if destructors are enabled, destroy all values) void free_hmap(hashmap*); // add a value (with a given key) to the hashmap // returns true on success and false on failure bool __hmap_add(hashmap* hmap, key in, val out); #define hmap_add(hmap, in, out) __hmap_add(hmap, (key) in, (val) out) // retrieve a value using a given key from the hashmap // returns your value if successful and NULL if not val __hmap_get(hashmap* hmap, key in); #define hmap_get(hmap, obj) __hmap_get(hmap, (key) obj) #ifdef HMAP_MAKE_HASHFN // integer-as-key hash functions uint32_t int_hash_fn(key); bool int_eq_fn(key, key); void int_del_fn(val); // char*-as-key hash functions uint32_t str_hash_fn(key); bool str_eq_fn(key, key); void str_del_fn(val); #endif #endif//hash.c
/* * hashmap.c * */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <semaphore.h> #include "hash.h" struct key_val_pair { key k; val v; }; struct hashmap { key_val_pair* map; uint32_t size; uint32_t capacity; uint32_t (*hash_fn)(key); bool (*eq_fn)(key, key); #ifdef HMAP_DESTRUCTORS void (*del_fn)(val); #endif #ifdef HMAP_THREAD_SAFE sem_t lock; uint32_t isNeedCalcHashCode; #endif }; // hashmaps need a hash function, an equality function, and a destructor hashmap* mk_hmap(uint32_t (*hash_fn)(key), bool (*eq_fn)(key, key) #ifdef HMAP_DESTRUCTORS , void (*del_fn)(val) #endif , uint32_t isNeedCalcHashCode ) { hashmap* hmap = (hashmap*) calloc(sizeof(hashmap),1); //memset(hmap,0,sizeof(hashmap)); hmap->map = (key_val_pair*) calloc(sizeof(key_val_pair) , HMAP_PRESET_SIZE); //memset(hmap->map,0,sizeof(key_val_pair) * HMAP_PRESET_SIZE); hmap->size = 0; hmap->capacity = HMAP_PRESET_SIZE; hmap->hash_fn = hash_fn; hmap->eq_fn = eq_fn; #ifdef HMAP_DESTRUCTORS hmap->del_fn = del_fn; #endif #ifdef HMAP_THREAD_SAFE sem_init(&hmap->lock, 0, 1); #endif hmap->isNeedCalcHashCode = isNeedCalcHashCode; return hmap; } hashmap* mk_hmap2(uint32_t (*hash_fn)(key), bool (*eq_fn)(key, key) #ifdef HMAP_DESTRUCTORS , void (*del_fn)(val) #endif , uint32_t isNeedCalcHashCode , uint32_t set_size ) { hashmap* hmap = (hashmap*) calloc(sizeof(hashmap),1); hmap->map = (key_val_pair*) calloc(sizeof(key_val_pair) , set_size); hmap->size = 0; hmap->capacity = set_size; hmap->hash_fn = hash_fn; hmap->eq_fn = eq_fn; #ifdef HMAP_DESTRUCTORS hmap->del_fn = del_fn; #endif #ifdef HMAP_THREAD_SAFE sem_init(&hmap->lock, 0, 1); #endif hmap->isNeedCalcHashCode = isNeedCalcHashCode; return hmap; } void free_hmap(hashmap* hmap) { #ifdef HMAP_THREAD_SAFE sem_wait(&hmap->lock); #endif #ifdef HMAP_DESTRUCTORS static uint32_t it; for (it=0; it < hmap->size; ++it) { if (hmap->map[it].v != NULL) { hmap->del_fn(hmap->map[it].v); } } #endif free(hmap->map); #ifdef HMAP_THREAD_SAFE sem_post(&hmap->lock); #endif free(hmap); } // open addressed hashmap insertion function static void __oa_hmap_add(key_val_pair* map, uint32_t size, uint32_t (*hash_fn)(key), key in, val out,int32 flag) { static uint32_t hash; //PRINT_INFO("add in=[%s]\n",(char *)in); //PRINT_INFO("flag=%d\n",flag); if(flag){ hash = hash_fn(in) % size; }else{ hash = *((uint32_t *)in) % size; } while (map[hash].v != NULL) { hash = (hash + 1) % size; } map[hash].k = in; //PRINT_INFO("add k in=[%s]\n",(char *)map[hash].k); map[hash].v = out; } bool __hmap_add(hashmap* hmap, key in, val out) { #ifdef HMAP_THREAD_SAFE sem_wait(&hmap->lock); #endif // performace degrades after a certain load if (((float) hmap->size) / hmap->capacity > 0.70) { key_val_pair* temp = (key_val_pair*) malloc(hmap->capacity * HMAP_GROWTH_RATE); //PRINT_INFO("hmap->capacity=%d",hmap->capacity); if (temp != NULL) { hmap->capacity *= HMAP_GROWTH_RATE; } else { #ifdef HMAP_THREAD_SAFE sem_post(&hmap->lock); #endif // we're out of memory return false; } // re-posn all elements static uint32_t it; for (it=0; it < hmap->capacity; ++it) { if (hmap->map[it].v != NULL) { __oa_hmap_add(temp, hmap->capacity, hmap->hash_fn, in, out ,hmap->isNeedCalcHashCode); } } // swap out the old map with the new one free(hmap->map); hmap->map = temp; //PRINT_INFO("hmap->capacity=%d",hmap->capacity); } __oa_hmap_add(hmap->map, hmap->capacity, hmap->hash_fn, in, out , hmap->isNeedCalcHashCode); hmap->size += 1; //PRINT_INFO("hmap->capacity=%d",hmap->capacity); #ifdef HMAP_THREAD_SAFE sem_post(&hmap->lock); #endif return true; } val __hmap_get(hashmap* hmap, key in) { #ifdef HMAP_THREAD_SAFE sem_wait(&hmap->lock); #endif static uint32_t hash; //PRINT_INFO("get in=[%s] aaaa hmap->capacity=%d",(char *)in,hmap->capacity); if(hmap->isNeedCalcHashCode){ hash = hmap->hash_fn(in) % hmap->capacity; }else{ //PRINT_INFO("%d %d",*((uint32_t *)in) , hmap->capacity); hash = *((uint32_t *)in) % hmap->capacity; } //PRINT_INFO("hash=%d",hash); while (hmap->map[hash].v != NULL) { if (hmap->eq_fn(in, hmap->map[hash].k)) { #ifdef HMAP_THREAD_SAFE //PRINT_INFO("HMAP_THREAD_SAFE"); sem_post(&hmap->lock); #endif //PRINT_INFO("get in=[%s] bbbb",(char *)in); return hmap->map[hash].v; } hash = (hash + 1) % hmap->capacity; } #ifdef HMAP_THREAD_SAFE sem_post(&hmap->lock); #endif return NULL; } #ifdef HMAP_MAKE_HASHFN // Robert Jenkins' 32 bit integer hash function uint32_t int_hash_fn(key in) { static uint32_t a; a = *((uint32_t*) in); a = (a+0x7ed55d16) + (a << 12); a = (a^0xc761c23c) ^ (a >> 19); a = (a+0x165667b1) + (a << 5); a = (a+0xd3a2646c) ^ (a << 9); a = (a+0xfd7046c5) + (a << 3); a = (a^0xb55a4f09) ^ (a >> 16); return a; } bool int_eq_fn(key a, key b) { return *((int*) a) == *((int*) b) ? true : false; } void int_del_fn(val q) {}; // Dan Bernstein's string hash function (djb2) uint32_t str_hash_fn(key in) { static uint32_t hash; //static unsigned char c; int c; ////PRINT_INFO("c:%c\n",c); hash = 5381; //c = *(unsigned char*) in++; //while (c != '\0') { while((c = *(unsigned char*)in++)){ // //PRINT_INFO("while\n"); // c = *(unsigned char*) in++; hash = ((hash << 5) + hash) + c; } ////PRINT_INFO("hash:%d\n",hash); return hash; } bool str_eq_fn(key a, key b) { return (strcmp((char*) a, (char*) b) == 0) ? true : false; } void str_del_fn(val q) { free(q); }; #endifmain.c
#include <stdio.h> #include "hash.h" void main() { hashmap *pfilterMap; pfilterMap = mk_hmap(str_hash_fn, str_eq_fn, str_del_fn,NEED); if(!hmap_add(pfilterMap, (void*)"key", (void*)"value")) return; printf( "%s\n", (char*)hmap_get(pfilterMap, (void*)"key") ); free_hmap(pfilterMap); pfilterMap = NULL; }
以上程序解决了:
1、hash冲突
2、hash表个数的限制
3、线程安全
注意问题:
1、key和value全是存储的值地址,所以key和value在hashmap释放之前不能释放。
2、如果2次add的都是同一个key,get出的值是第一次add的时候的值。以后add的找不到了,因为为了解决冲突,把hashcode一样的map,hashcode+1了。
相关文章推荐
- 【转载】C语言itoa()函数和atoi()函数详解(整数转字符C实现)
- 快速幂(C语言实现) 超详细 (转载)
- 简单c语言实现unix shell【转载】
- 转载--HashMap实现原理分析
- 快速幂(C语言实现) 超详细 (转载)
- OTSU算法提取图像阈值的C语言实现[转载】
- C语言实现HashMap
- 一个简单的HashMap C语言实现
- 【转载】Java HashMap工作原理及实现
- 转载的标准文档:C语言实现一个简单的单向链表list
- 快速幂(C语言实现) 超详细 (转载)
- 转载:HashMap的实现原理
- (转载)C语言单链表实现19个功能完全详解
- hashMap 实现原理(解释的清晰,转载一下)
- C语言中的面向对象(2)-C语言的多态实现(转载)
- 【转】用C语言实现将一个文件读入内存中(分享转载)
- 快速幂(C语言实现) 超详细 (转载)
- (转载)ConcurrentHaspLRUHashMap实现初探
- [转载]顺序栈的C语言实现
- (转载)Java中HashMap底层实现原理(JDK1.8)源码分析