一个简单的字符串hash表
2012-08-21 12:38
204 查看
设计一个字符串hash表。
1.总体设计图:
2.为什么要这么设计?
用一个Buckets来保存所有哈希表,用户能看到的只是一个相对于Buckets的偏移量即索引,而这个索引是数组索引还是其他比如二叉排序树的搜索关键字,这就对Buckets的数据结构进行了隐藏;另外各个线程分别对自己的得到的索引值的哈希表进行操作,互不影响,所以支持了多线程。
3.接口设计
对于字符串hash表所支持的操作也即通常的 插入,删除,查找 所以目前对于哈希表仅仅支持这三种操作,由于需要得到索引和释放申请来的索引而创建/释放一个哈希表所以增加了st_create和st_release方法,另外为方便调试,增加打印整个字符串表的操作
代码如下:
4.具体实现
5.设计不足
1.如果代码需要被其他用户调用,最好对索引进行一次变换,以防止用户去释放并非自己获得的索引。
2.对GPL协议文件中的所有字符串进行测试,发现冲突比较严重。
亲,版权所有,转载注明出处:blog.csdn/zhccl/
如果你要使用这些代码,不要删除每个文件开始那段注释就可以了。^_^
1.总体设计图:
2.为什么要这么设计?
用一个Buckets来保存所有哈希表,用户能看到的只是一个相对于Buckets的偏移量即索引,而这个索引是数组索引还是其他比如二叉排序树的搜索关键字,这就对Buckets的数据结构进行了隐藏;另外各个线程分别对自己的得到的索引值的哈希表进行操作,互不影响,所以支持了多线程。
3.接口设计
对于字符串hash表所支持的操作也即通常的 插入,删除,查找 所以目前对于哈希表仅仅支持这三种操作,由于需要得到索引和释放申请来的索引而创建/释放一个哈希表所以增加了st_create和st_release方法,另外为方便调试,增加打印整个字符串表的操作
代码如下:
/** File: strtab.h table is implemented as a chained hash table use the BKDR string hash funcion cc 2012.8.20 blog.csdn/zhccl/ */ #ifndef _STRTAB_ #define _STRTAB_ /** Function st_create() create the hash table returns the index of all hash tables or -1 if create error. use the ID for hiding the datastructure of tables */ int st_create(); /** Function st_insert inserts a char * to the string table index=id inserted only the first time, otherwise ignored returns 1 or 0 if is exist. */ int st_insert(int id,char * str); /** Function st_lookup look up the char * from string table index=id returns 1 or 0 if not found */ int st_lookup(int id,char * str); /** Function st_delete delete the char * from string table index=id returns 1 when deleted or 0 if not found. */ int st_delete(int id,char *str); /** Function st_release the index=id string table returns 1 when released or 0 if not exist. */ int st_release(int id); /** Function st_print just for debug. */ void st_print(int id); #endif
4.具体实现
/** File: strtab.c table is implemented as a chained hash table use the BKDR string hash funcion all function's implement. cc 2012.8.20 */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <assert.h> #define DBUG /*the max size of tables */ #define MAX_INDEX 255 /* the size of hash table */ #define TABLE_SIZE 253 /* node structure */ typedef struct strNode{ char *str; struct strNode *next; }* pstrNode; /* all hash tables */ static pstrNode** Buckets=NULL; /*the BKDR hash funcion */ static unsigned int BKDRHash(char *str){ unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned int hash = 0; while (*str){ hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); } /** a very simple error handle function. */ static void st_error(char *errmsg){ fprintf(stderr,"%s\n",errmsg); exit(0); } int st_create(){ //if the first use the create all tables. if(NULL==Buckets){ if(NULL==(Buckets=(pstrNode **)malloc(MAX_INDEX*sizeof(pstrNode **)))){ st_error("Memory over follow."); } memset(Buckets,0,MAX_INDEX*sizeof(pstrNode **)); } //find a free index of tables,return it for costom storing strings. for(int i=0;i<MAX_INDEX;i++){ if(NULL==Buckets[i]){ if(NULL==(Buckets[i]=(pstrNode *)malloc(TABLE_SIZE*sizeof(pstrNode *)))){ st_error("Memory over follow."); } memset(Buckets[i],0,TABLE_SIZE*sizeof(pstrNode *)); return i; } } //now the tables is full must extend or report error. st_error("The buckets is full."); return -1; } int st_insert(int id,char* srcstr){ assert(NULL!=Buckets[id]); int hash=BKDRHash(srcstr)%TABLE_SIZE; //if the first use Bucetss[i][hash],so srcstr must be the first string. if( NULL== (*(*(Buckets+id)+hash))){ if(NULL==((*(*(Buckets+id)+hash))=(pstrNode)malloc(sizeof(struct strNode)))){ st_error("Memory over follow."); } if( NULL==( (*(*(Buckets+id)+hash))->str=(char *)malloc( (strlen(srcstr)+1) * sizeof(char) ) ) ){ st_error("Memory over follow."); } strcpy((*(*(Buckets+id)+hash))->str,srcstr); (*(*(Buckets+id)+hash))->next=NULL; #ifdef DBUG printf("String:< %s > is inserted at the first time in hash=%d .\n",srcstr,hash); #endif return 1; } else{ //conflict then use chain to resovle. pstrNode pnode=(*(*(Buckets+id)+hash)); while( (pnode!=NULL) && (strcmp(srcstr,pnode->str)!=0) ){ pnode=pnode->next; } //not found,so for the first time , do inserting. if(pnode==NULL){ if(NULL==(pnode=(pstrNode)malloc(sizeof(struct strNode)))){ st_error("Memory over follow."); } if(NULL==(pnode->str=(char *)malloc((strlen(srcstr)+1)*sizeof(char)))){ st_error("Memory over follow."); } strcpy(pnode->str,srcstr); pnode->next=(*(*(Buckets+id)+hash)); (*(*(Buckets+id)+hash))=pnode; #ifdef DBUG printf("String:< %s > is inserted in hash=%d .\n",srcstr,hash); #endif return 1; } //the srcstr is exist,so ignore. else{ #ifdef DBUG printf("String:< %s > is exist.\n",srcstr); #endif return 0; } } } int st_lookup(int id,char * srcstr){ assert(NULL!=Buckets[id]); int hash=BKDRHash(srcstr)%TABLE_SIZE; pstrNode ptemp=*(*(Buckets+id)+hash); while( (NULL!=ptemp) && (strcmp(ptemp->str,srcstr)!=0)){ ptemp=ptemp->next; } #ifdef DBUG if(NULL!=ptemp){ printf("String <%s> has found.\n",ptemp->str); } else{ printf("String <%s> has not found.\n",srcstr); } #endif return NULL==ptemp?0:1; } int st_delete(int id,char *srcstr){ assert(NULL!=Buckets[id]); int hash=BKDRHash(srcstr)%TABLE_SIZE; /** pprenode point to the precocious node and the ptemp point to the node which will be deleted. */ pstrNode ptemp,pprenode; ptemp=pprenode=*(*(Buckets+id)+hash); while( (NULL!=ptemp) && (strcmp(ptemp->str,srcstr)!=0)){ pprenode=ptemp; ptemp=ptemp->next; } //the srcstr is exist. if(NULL!=ptemp){ /** we must test the node which will delete is the only one node or not. if it is the only one,we can't free an item from an array,so we set the item of array[index] NULL will be ok. otherwise we must free the node from the chain. */ /* more than one node */ if(pprenode != ptemp){ /* remove the node from hash table which index=id. */ pprenode->next=ptemp->next; /* free the node : have to handle two pointers. */ free(ptemp->str); ptemp->str=NULL; free(ptemp); ptemp=NULL; } /* only one. */ else{ free(ptemp->str); ptemp->str=NULL; free(ptemp); ptemp=NULL; *(*(Buckets+id)+hash)=NULL; } #ifdef DBUG printf("Delete string < %s > OK.\n",srcstr); #endif return 1; } else{ #ifdef DBUG printf("< %s > is not exist.\n",srcstr); #endif return 0; } } int st_release(int id){ assert(NULL!=Buckets[id]); pstrNode ptemp,pnext; for(int i=0;i<TABLE_SIZE;i++){ ptemp=*(*(Buckets+id)+i); while(NULL != ptemp){ pnext=ptemp->next; #ifdef DBUG printf("The sting < %s > node has freed.\n",ptemp->str); #endif free(ptemp->str); ptemp->str=NULL; free(ptemp); ptemp=NULL; ptemp=pnext; } *(*(Buckets+id)+i)=NULL; } free(Buckets[id]); Buckets[id]=NULL; /** if Buckets[i] is last exist table , after release Buckets[i] we should release the whole Buckets. */ int lastindex; for(lastindex=0;lastindex<MAX_INDEX;lastindex++){ if(NULL!=Buckets[lastindex]){ break; } } if(MAX_INDEX==lastindex){ free(Buckets); Buckets=NULL; } #ifdef DBUG printf("The table index=%d has freed.\n",id); #endif return 1; } void st_print(int id){ assert(NULL!=Buckets[id]); pstrNode ptemp; printf("--------------------------Buckets[%d]-----------------------------\n",id); for(int i=0;i<TABLE_SIZE;i++){ printf("------------------------------TABLE[%d]-------------------------\n",i); int order=1; ptemp=(*(*(Buckets+id)+i)); while( NULL != ptemp){ printf("The index=%-4d string =%-15s\n",order++,ptemp->str); ptemp=ptemp->next; } } }
5.设计不足
1.如果代码需要被其他用户调用,最好对索引进行一次变换,以防止用户去释放并非自己获得的索引。
2.对GPL协议文件中的所有字符串进行测试,发现冲突比较严重。
亲,版权所有,转载注明出处:blog.csdn/zhccl/
如果你要使用这些代码,不要删除每个文件开始那段注释就可以了。^_^
相关文章推荐
- 简单递归____判断一个字符串是否为回文
- C++字节流与二进制字符串相互转换(一个简单的明文加解密程序)
- 一个简单不过却很非常实用的PHP加密字符串方法
- x-template:一个简单高效的字符串模板引擎
- 一个看似简单却复杂的问题:求两个字符串的 左向右匹配 所有的 最长连续的 公共子字符串( 在每个字符串中先后次序相同的) 序列
- 一个简单的Hash表算法 zz
- 一个简单的整型值转大写汉字字符串的小程序
- 刚刚在园里看到的一个简单的做连接字符串的方法.
- C++字节流与二进制字符串相互转换(一个简单的明文加解密程序)
- 笔试题13:采用UDP协议,编写一个简单发送字符串的程序(源码)
- 在情报传递过程中,为了防止情报被截获,往往需要对情报用一定的方式加密,简单的加密算法虽然不足以完全避免情报被破译,但仍然能防止情报被轻易的识别。我们给出一种最简的的加密方法,对给定的一个字符串,把其中
- 输入一个只包含个位数字的简单四则表达式字符串,计算该表达式的值
- 将一个简单对象转为Json字符串.
- SQL中获取一个长字符串中某个字符串出现次数的简单方法
- 请实现一个队列,既可以存放整数,又可以存放字符串。简单的说,队列是一种数据结构,按照先进先出的顺序管理进、出队列的元素
- SQL点滴3—一个简单的字符串分割函数
- 有限状态机的简单使用案例:“将字符串中多于一个的空格变为一个空格输出”
- 一个简单的网页读字符串 SpeechLib
- 一个简单的例子展示makefile推导顺序(@echo输出字符串验证)
- 一个简单的C#倒转字符串程序