c语言实现hashmap(转载)

//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了。


转载于:https://my.oschina.net/chenliang165/blog/125664

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值