diff --git a/README.md b/README.md index 783c3b4..e963864 100644 --- a/README.md +++ b/README.md @@ -1 +1,92 @@ -#HashMap +#HashMap + +###1.本库使用了C语言实现了一个基本的hashmap +包含的功能有如下几点: +/********************************************************************* + * 入口参数: hashmap的无类型指针 + * 出口参数: 无 + * 返回值 : int 永远返回0,可以不判断 + * 函数功能: 打印hashmap中所有的元素,主要用于调试和检查散列分布 + * + *********************************************************************/ +int XipHashmapPrint( void * hashmap); + +/********************************************************************* + * 入口参数: 无 + * 出口参数: 无 + * 返回值 : 创建的hashmap的指针,强制转换成了void *类型,方便调用 + * 函数功能: 以默认方式创建一个hashmap,默认的初始容量是16,加载因子是0.75f + * + *********************************************************************/ +void * XipHashmapNew(); + +/********************************************************************* + * 入口参数: int opacity 初始容量, float factor 加载因子 + * 出口参数: 无 + * 返回值 : 创建的hashmap的指针,强制转换成了void *类型,方便调用 + * 函数功能: 按照传入的信息进行初始hashmap创建, + * 如果opacity为0,则为默认值16,如果factor为0,则默认为0.75f + * + *********************************************************************/ +void * XipHashmapInit( int opacity , float factor); + +/********************************************************************* + * 入口参数: hashmap指针 + * 出口参数: 无 + * 返回值 : int , 永远返回0可以不判断 + * 函数功能: 按照传入的信息进行初始hashmap创建, + * 如果opacity为0,则为默认值16,如果factor为0,则默认为0.75f + * + *********************************************************************/ +int XipHashmapDestory( void * in_map); + +/********************************************************************* + * 入口参数: hashmap指针, char * key, void * value + * 出口参数: 无 + * 返回值 : 返回 void * oldvalue 的指针,如果为新增则返回NULL + * 如果put失败则返回XIP_HASHMAP_PUT_ERR + * 函数功能: 根据key和value放入到hashmap中,如果map中已经存在该key的值 + * 则替换成最新的value,同时返回旧value指针 + * 如果put之后,达到了临界值,则重新创建hashmap + *********************************************************************/ +void * XipHashmapPut( void * in_map, char * key, void * value); + +/********************************************************************* + * 入口参数: hashmap指针, char * key + * 出口参数: 无 + * 返回值 : 返回 void * value 的指针 + * 函数功能: 根据key值从hashmap中取得value的指针返回 + *********************************************************************/ +void * XipHashmapGet( void * TxipHashmap, char * key); + +/********************************************************************* + * 入口参数: hashmap指针, char * key + * 出口参数: 无 + * 返回值 : int 返回值XIP_HASHMAP_EXIST_TURE(1), XIP_HASHMAP_EXIST_FALSE(0) + * 函数功能: 根据key值从hashmap中查找是否存在,存在返回真,不存在返回假 + *********************************************************************/ +int XipHashmapExists( void * TxipHashmap, char * key); + +/********************************************************************* + * 入口参数: hashmap指针, char * key + * 出口参数: 无 + * 返回值 : void * value + * 函数功能: 根据key值从hashmap中删除key对应的node节点,如果删除成功, + * 则返回删除节点的value的地址,未找到节点则返回NULL + *********************************************************************/ +void * XipHashmapRemove( void * TxipHashmap, char * key); + + +###2.哈希算法 +哈希算法使用了JAVA的JDK中默认的simple BKDR hash algorithm +有需要的也可以替换成暴雪的One-Way-Hash或者PHP中的time33之类的 + +###3.编译方法 +我是在cygwin环境下编写的,linux下要改一下makefile中的cc -shared命令, unix类似,可以生成动态库 +当然也可以直接把代码copy + +test_hash.c可是执行mk来编译 + + +###4.注意事项 +使用的时候,调用程序请注意包含头文件hashmap.h来声明调用函数原型 ,否则可能会导致core dump diff --git a/kmaplib/HashMap.c b/kmaplib/HashMap.c new file mode 100644 index 0000000..4ae8816 --- /dev/null +++ b/kmaplib/HashMap.c @@ -0,0 +1,489 @@ +/************************************************** + * : HashMap.c + * : icesky + * 汾 : 1.0.0 + * : 2016.07.28 + * : + * οjavahashmapʵֻ,ʵC + * hashmapʵֹּ֣֧: + * 1.½ + * 2. + * 3./ + * 4.ȡ + * 5.ɾ + * 6.жǷ + * 7.ӡ + * + * ޸ļ¼ : + *************************************************/ +#include +#include +#include +#include +#include "hashmap.h" + +#define hmap_malloc(size) malloc(size) +#define HMAPFREE(x) free(x);x=NULL; +#define XIP_HASHMAP_REBUILD_ERR (void *)-1 + +#define MAXIMUM_CAPACITY 1 << 30 /*1 073 741 824 */ +#define DEFAULT_CAPACITY 1 << 4 /*16*/ +#define DEFAULT_FACTOR 0.75f +#define INTER_MAX_VALUE 1<<31 /*intֵ*/ + +/*hashmap nodeṹ */ +typedef struct st_xip_hashmap_node +{ + char * key; + union + { + void *ptr; /*עptrûзڴ,ָֻ*/ + int num; /*ihashmapʹ*/ + }value; + struct st_xip_hashmap_node *next; + unsigned int hash; +} TxipHashmapNode; + +/*hashmap ṹ*/ +typedef struct +{ + TxipHashmapNode ** table; /*T*/ + unsigned int length; /*ͰС*/ + unsigned int size; /*ʵʴС*/ + unsigned int threshold; /*ٽֵ*/ + float factor; /*,ĬΪ0.75(0-1)*/ +} TxipHashmap; + + +#define HMAPLOG(...) AppLog(__FILE__,__LINE__,__VA_ARGS__) +static void AppLog(char *file, long line, char *level, char *fmtstr, ...) +{ + va_list ap; + char tmpstr[501]; + char loglevel[11]; + FILE *fp; + + memset(tmpstr, 0x0, sizeof(tmpstr)); + + va_start(ap, fmtstr); + + vsprintf(tmpstr, fmtstr, ap); + va_end(ap); + + printf("[%s][%s][%03d]", level, file, line); + printf("[%s]\n", tmpstr); + + return ; +} + +/*** static ***/ +/*½T*/ +static TxipHashmapNode ** create_T_table( int opacity); +/*½hashmapڵ*/ +static TxipHashmapNode * create_hashmap_node( char * key, void * value, TxipHashmapNode * next); +/*ؽhashmap*/ +static int rebuild_hash( TxipHashmap * hashmap); +/*hash㷨*/ +static unsigned int XipHash(char * key); + +/********************************************************************* + * ڲ: hashmapָ + * ڲ: + * ֵ : int Զ0Բж + * : ӡhashmapеԪ,ҪڵԺͼɢзֲ + * + *********************************************************************/ +int XipHashmapPrint( void * hashmap) +{ + TxipHashmap * map = ( TxipHashmap *)hashmap; + HMAPLOG("I", "HashMap:length[%d],size[%d],threshold[%d];ֲ:", map->length, map->size, map->threshold); + + int i = 0; + int idx = 0; + + TxipHashmapNode * e = NULL; + TxipHashmapNode * next = NULL; + + /** ӡ־ **/ + if( map != NULL) + { + for ( idx = 0; idx < map->length; idx++) + { + for( e = map->table[idx]; e != NULL; ) + { + next = e->next; + HMAPLOG("I", "Node[%d]:hash[%d],key[%s],value[%s]", idx, e->hash, e->key, e->value.ptr); + e = next; + } + } + } + + /** ӡֲͼ **/ + if( map != NULL) + { + for( idx = 0; idx < map->length; idx++) + { + i = 0; + for( e= map->table[idx] ; e!= NULL; ) + { + next = e->next; + i++; + e = next; + } + HMAPLOG("I","%08ld:%*d", idx, i, i); + } + } + + return 0; +} + +/********************************************************************* + * ڲ: + * ڲ: + * ֵ : hashmapָ,ǿתvoid *, + * : ĬϷʽһhashmap,Ĭϵijʼ16,0.75f + * + *********************************************************************/ +void * XipHashmapNew() +{ + return XipHashmapInit( 0, 0.00); +} + +/********************************************************************* + * ڲ: int opacity ʼ, float factor + * ڲ: + * ֵ : hashmapָ,ǿתvoid *, + * : մϢгʼhashmap, + * opacityΪ0,ΪĬֵ16,factorΪ0,ĬΪ0.75f + * + *********************************************************************/ +void * XipHashmapInit( int opacity, float factor) +{ + TxipHashmap * map = ( TxipHashmap *)hmap_malloc(sizeof( TxipHashmap)); + + if ( opacity < DEFAULT_CAPACITY ) + opacity = DEFAULT_CAPACITY; + if( opacity > MAXIMUM_CAPACITY) + opacity = MAXIMUM_CAPACITY; + if ( factor >= -0.005 && factor <=0.005 ) + factor = DEFAULT_FACTOR; + + if( opacity <= 1) + { + HMAPLOG("E","ʼ1!!!"); + return NULL; + } + if( factor < 0.00 || factor > 1.00) + { + HMAPLOG("E","ȡֵΪ[0.00-1.00],μΪ[%.2f]", factor); + return NULL; + } + + map->table = create_T_table( opacity); + if( map->table == NULL) + { + HMAPLOG("E","hashֵTʧ!!!"); + return NULL; + } + + map->length = opacity; + map->size = 0; + map->factor = factor; + map->threshold = (unsigned int)( factor * opacity); + + return (void *)map; +} + +/********************************************************************* + * ڲ: hashmapָ + * ڲ: + * ֵ : int , Զ0Բж + * : մϢгʼhashmap, + * opacityΪ0,ΪĬֵ16,factorΪ0,ĬΪ0.75f + * + *********************************************************************/ +int XipHashmapDestory( void * hashmap) +{ + TxipHashmap * map = (TxipHashmap *) hashmap; + register unsigned int idx; + TxipHashmapNode * e = NULL; + TxipHashmapNode * next = NULL; + + /** ͷhashmap node ڴ **/ + if( map != NULL) + { + for ( idx = 0; idx < map->length; idx++) + { + for( e = map->table[idx]; e != NULL; ) + { + next = e->next; + HMAPFREE(e); + e = next; + } + } + } + + /** ͷhashmapT **/ + HMAPFREE( map->table); + map->table = NULL; + + return 0; +} + +/********************************************************************* + * ڲ: hashmapָ, char * key, void * value + * ڲ: + * ֵ : void * oldvalue ָ,Ϊ򷵻NULL + * putʧ򷵻XIP_HASHMAP_PUT_ERR + * : keyvalue뵽hashmap,mapѾڸkeyֵ + * 滻µvalue,ͬʱؾvalueָ + * put֮󣬴ﵽٽֵ,´hashmap + *********************************************************************/ +void * XipHashmapPut( void * hashmap, char * key, void * value) +{ + TxipHashmap * map = (TxipHashmap *)hashmap; + + void * oldvalue = NULL; + TxipHashmapNode *e = NULL; + unsigned int hcode = XipHash(key); + unsigned int idx = hcode % map->length; + + /*ҵkey,൱set*/ + for ( e = map->table[idx]; e != NULL ; e = e->next) + { + /*οjavahashmapʵ,ȱȽhash,ٱȽstrcmp*/ + if ( hcode == e->hash && (key == e->key || strcmp( key, e->key) == 0)) + { + oldvalue = e->value.ptr; + e->value.ptr = value; + return oldvalue; /*ԭvalueظ*/ + } + } + + /*½node*/ + map->table[idx] = create_hashmap_node( key, value, map->table[idx]); + if( map->table[idx] == NULL) + { + HMAPLOG("E","½hashnodeڵ쳣!!!"); + return XIP_HASHMAP_PUT_ERR; /*ع̶ֵ*/ + } + + /*޸hashmap*/ + e = map->table[idx]; + e->hash = hcode; + map->size++; + + /*ٽֵؽhash*/ + if( map->size > map->threshold) + { + if( rebuild_hash(map) != 0) + { + HMAPLOG("E","ؽhash!!!"); + return XIP_HASHMAP_PUT_ERR; /*ع̶ֵ*/ + } + } + + return NULL; +} + +/********************************************************************* + * ڲ: hashmapָ, char * key + * ڲ: + * ֵ : void * value ָ + * : keyֵhashmapȡvalueָ뷵 + *********************************************************************/ +void * XipHashmapGet( void * hashmap, char *key) +{ + TxipHashmap * map = (TxipHashmap *) hashmap; + unsigned int hcode = XipHash(key); + unsigned int idx = hcode % map->length; + + TxipHashmapNode * e = NULL; + + for ( e = map->table[idx]; e != NULL ; e = e->next) + { + /*οjavahashmapʵ,ȱȽhash,ٱȽstrcmp, key == e->keyihashmapõ,չ*/ + if ( hcode == e->hash && (key == e->key || strcmp( key, e->key) == 0)) + { + return e->value.ptr; + } + } + return NULL; +} + +/********************************************************************* + * ڲ: hashmapָ, char * key + * ڲ: + * ֵ : int ֵXIP_HASHMAP_EXIST_TURE(1), XIP_HASHMAP_EXIST_FALSE(0) + * : keyֵhashmapвǷ,ڷ,ڷؼ + *********************************************************************/ +int XipHashmapExists( void * hashmap, char *key) +{ + TxipHashmap * map = (TxipHashmap *) hashmap; + unsigned int hcode = XipHash(key); + unsigned int idx = hcode % map->length; + + TxipHashmapNode * e = NULL; + + for ( e = map->table[idx]; e != NULL ; e = e->next) + { + /*οjavahashmapʵ,ȱȽhash,ٱȽstrcmp*/ + if ( hcode == e->hash && (key == e->key || strcmp( key, e->key) == 0)) + { + return 1; + } + } + + return 0; +} + +/********************************************************************* + * ڲ: hashmapָ, char * key + * ڲ: + * ֵ : void * value + * : keyֵhashmapɾkeyӦnodeڵ,ɾɹ + * 򷵻ɾڵvalueĵַ,δҵڵ򷵻NULL + *********************************************************************/ +void * XipHashmapRemove( void * hashmap, char *key) +{ + TxipHashmap * map = (TxipHashmap *) hashmap; + unsigned int hcode = XipHash(key); + unsigned int idx = hcode % map->length; + + void * oldvalue = NULL; + TxipHashmapNode * e = NULL; + TxipHashmapNode * prev = NULL; + + for ( e = map->table[idx]; e != NULL ; prev = e, e = e->next) + { + /*οjavahashmapʵ,ȱȽhash,ٱȽstrcmp*/ + if ( hcode == e->hash && (key == e->key || strcmp( key, e->key) == 0)) + { + if( prev == NULL) + map->table[idx] = e->next; + else + prev->next = e->next; + + oldvalue = e->value.ptr; + + HMAPFREE(e); + map->size--; + return oldvalue; + } + } + + return NULL; +} + +static TxipHashmapNode ** create_T_table( int opacity) +{ + register unsigned int i=0; + + TxipHashmapNode ** table = (TxipHashmapNode **)hmap_malloc( sizeof(TxipHashmapNode*) *opacity); + if( table == NULL) + { + return NULL; + } + + /*ʼ*/ + for ( i = 0; i < opacity; i++) + table[i] = NULL; + + return table; +} + +static TxipHashmapNode * create_hashmap_node( char * key, void * value, TxipHashmapNode * next) +{ + TxipHashmapNode * node = ( TxipHashmapNode *) hmap_malloc( sizeof(TxipHashmapNode)); + if ( node == NULL) + { + return NULL; + } + + node->key = key; + node->value.ptr = value; + node->next = next; + + return node; +} +static int rebuild_hash( TxipHashmap * map) +{ + register unsigned int i = 0; + unsigned int idx = 0; + + /*ﵽ,rebuild*/ + if( map->length == MAXIMUM_CAPACITY) + { + map->threshold = INTER_MAX_VALUE; + return 0; + } + + unsigned int length = map->length*2; + if( length > MAXIMUM_CAPACITY) + length = MAXIMUM_CAPACITY; + + TxipHashmapNode *e=NULL; + TxipHashmapNode *next=NULL; + + TxipHashmapNode ** newtable = create_T_table( length); + if ( newtable == NULL) + { + return -5; + } + + for( i = 0; i < map->length; i++) + { + /**/ + e = *(map->table + i); + if( e != NULL) + { + do + { + next = e->next; + + idx = e->hash % length; + + e->next = newtable[idx]; /*newtable[idx]ֵѾ,ὫֵΪnewtable[idx]->idx*/ + + newtable[idx] = e; + + e = next; + }while( e != NULL); + } + } + + /*ͷoldtable*/ + HMAPFREE(map->table); + map->table = newtable; + map->length = length; + map->threshold = (unsigned int)(map->factor * length); + + return 0; + +} + +/******************************************************** + * hash㷨,˴ʹõ simple BKDR hash algorithm + * ΪJAVAJDKʹõ㷨 + * ҲʹPHPʹõtime33㷨(DJP hash algorithm + * ʹñѩ˾ĵOne-Way-Hash,ųhash㷨 + * + * ֮ûʹƼ㷨,ΪҰѻ. + * 㿴ط,ͼŻ㷨Ļ,ʹҽ + * 㷨г. + * ȵϵͳƿ׷ݵʱ,˸ + * 㷨֤һɢ.o(_)o + * icesky.2016.07.08 + *********************************************************/ +static unsigned int XipHash(char * key) +{ + register uint32_t h = 0; + uint32_t seed = 131; //31 131 1313 13131 + + while ( *key != '\0' ) + { + h = h * seed + ( *key++ ); + } + + return (h & 0x7FFFFFFF); +} diff --git a/kmaplib/OBJS b/kmaplib/OBJS new file mode 100644 index 0000000..5ae14b1 --- /dev/null +++ b/kmaplib/OBJS @@ -0,0 +1,3 @@ +TARGET = libkmaplib.so + +OBJ += HashMap.o diff --git a/kmaplib/hashmap.h b/kmaplib/hashmap.h new file mode 100644 index 0000000..cbeddc0 --- /dev/null +++ b/kmaplib/hashmap.h @@ -0,0 +1,82 @@ +#ifndef __XIPHASHMAP__ +#define __XIPHASHMAP__ + +#define XIP_HASHMAP_EXIST_TURE 1 /*- */ +#define XIP_HASHMAP_EXIST_FALSE 0 /*- */ +#define XIP_HASHMAP_PUT_ERR (void *)1 /*put쳣*/ + +/********************************************************************* + * ڲ: hashmapָ + * ڲ: + * ֵ : int Զ0Բж + * : ӡhashmapеԪ,ҪڵԺͼɢзֲ + * + *********************************************************************/ +int XipHashmapPrint( void * hashmap); + +/********************************************************************* + * ڲ: + * ڲ: + * ֵ : hashmapָ,ǿתvoid *, + * : ĬϷʽһhashmap,Ĭϵijʼ16,0.75f + * + *********************************************************************/ +void * XipHashmapNew(); + +/********************************************************************* + * ڲ: int opacity ʼ, float factor + * ڲ: + * ֵ : hashmapָ,ǿתvoid *, + * : մϢгʼhashmap, + * opacityΪ0,ΪĬֵ16,factorΪ0,ĬΪ0.75f + * + *********************************************************************/ +void * XipHashmapInit( int opacity , float factor); + +/********************************************************************* + * ڲ: hashmapָ + * ڲ: + * ֵ : int , Զ0Բж + * : մϢгʼhashmap, + * opacityΪ0,ΪĬֵ16,factorΪ0,ĬΪ0.75f + * + *********************************************************************/ +int XipHashmapDestory( void * in_map); + +/********************************************************************* + * ڲ: hashmapָ, char * key, void * value + * ڲ: + * ֵ : void * oldvalue ָ,Ϊ򷵻NULL + * putʧ򷵻XIP_HASHMAP_PUT_ERR + * : keyvalue뵽hashmap,mapѾڸkeyֵ + * 滻µvalue,ͬʱؾvalueָ + * put֮󣬴ﵽٽֵ,´hashmap + *********************************************************************/ +void * XipHashmapPut( void * in_map, char * key, void * value); + +/********************************************************************* + * ڲ: hashmapָ, char * key + * ڲ: + * ֵ : void * value ָ + * : keyֵhashmapȡvalueָ뷵 + *********************************************************************/ +void * XipHashmapGet( void * TxipHashmap, char * key); + +/********************************************************************* + * ڲ: hashmapָ, char * key + * ڲ: + * ֵ : int ֵXIP_HASHMAP_EXIST_TURE(1), XIP_HASHMAP_EXIST_FALSE(0) + * : keyֵhashmapвǷ,ڷ,ڷؼ + *********************************************************************/ +int XipHashmapExists( void * TxipHashmap, char * key); + +/********************************************************************* + * ڲ: hashmapָ, char * key + * ڲ: + * ֵ : void * value + * : keyֵhashmapɾkeyӦnodeڵ,ɾɹ + * 򷵻ɾڵvalueĵַ,δҵڵ򷵻NULL + *********************************************************************/ +void * XipHashmapRemove( void * TxipHashmap, char * key); + +#endif diff --git a/kmaplib/makefile b/kmaplib/makefile new file mode 100644 index 0000000..b862ea6 --- /dev/null +++ b/kmaplib/makefile @@ -0,0 +1,7 @@ +include OBJS + +$(TARGET):$(OBJ) + cc -shared -o $@ $< + +clean: + rm -f *.o diff --git a/kmaplib/mk b/kmaplib/mk new file mode 100644 index 0000000..270ae4e --- /dev/null +++ b/kmaplib/mk @@ -0,0 +1 @@ +cc -o test_hash test_hash.c -I./ ./libkmaplib.so diff --git a/kmaplib/test_hash.c b/kmaplib/test_hash.c new file mode 100644 index 0000000..bd78429 --- /dev/null +++ b/kmaplib/test_hash.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +int main() +{ + char *name[] = { + "chenmanwen", "yangqinghua", "chenxin", "yanzi", "yangjian", "zhangrenfang", + "panzi", "zhangqiang", "webssky", "jcseg", "friso", "robbe", "lionsoul", + "tankwar", "jteach" + }; + + void * hashmap = XipHashmapNew(); + + int i = 0; + int length = 15; + for ( i = 0; i < length ; i++) + { + printf("put(%15s, %15s);\n", name[i], name[i]); + XipHashmapPut( hashmap, name[i], name[i]); + } + + XipHashmapPrint(hashmap); + XipHashmapPut( hashmap, "panzi", "iceskyiceskyicesky"); + XipHashmapPrint(hashmap); + + for ( i = 0; i< length; i++) + printf("get(%15s): %15s\n", name[i], (char *)XipHashmapGet(hashmap, name[i])); + + XipHashmapPrint(hashmap); + + printf("remove(%15s): %15s\n", "lionsoul", (char *)XipHashmapRemove(hashmap, "lionsoul")); + + XipHashmapPrint(hashmap); + + XipHashmapDestory(hashmap); + + return 0; +} +