您的位置:首页 > 编程语言 > C语言/C++

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);
};

#endif
main.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了。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux hash hashmap