http://blog.csdn.net/feixiaoxing/article/details/6885657 这一篇写的很赞
数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。hash表可以解决以上两个不足之处。
假如你要在图书馆里找一本《电路原理》,这本书首先它在工科类下面,再在工科类的电子信息这个分类里面,你首先要找到工科,再找到电子信息类,然后再找《电路原理》。好了,hashEntry_s相当于这个分类表,它的key就是你要查的类别,data就是你要查的书本,hashtable就是那张存放类别的大表。
struct hashEntry_s{
void *key;
void *data;
struct hashEntry_s *next;
};
struct hashTable_s{
struct hashEntry_s **hashlist;
};
typedef struct hashTable_s hashTable_t;
首先要生成这样hash表
HASHSIZE 最好是素数,这样可以减少冲突的概率。
hashlist指向各个分类
#define HASHSIZE 67
hashTable_t *createHashTable(void)
{
hashTable_t *table;
int i,len,primesize;
table = malloc(sizeof(hashTable_t));
if(NULL == table){
printf("error in createtable");
return NULL;
}
len = sizeof(struct hashEntry_s *)*HASHSIZE;
table->hashlist = malloc(len);
if(table->hashlist == NULL){
printf("error in createtable\n");
exit(1);
}
for(i=0;i<HASHSIZE;i++)
table->hashlist[i]=NULL;
return table;
}
hash表中的标签。就相当于在图书观的那张表中,工科类被编号1234一样。hash表中也要将key做一个标签,通过key可以快速定位table中的hashlist,进而快速提取数据。
hash算法有很多,可参考http://hi.baidu.com/hytjfxk/blog/item/46f6feceafbe622392457e0a.html
我截取其中一个比较简单的算法作为我的hash算法,它将字符串转换成了响应的整数。
unsigned long getHashValue(char *string)
{
unsigned long ret=0;
long n;
unsigned long v;
int r;
if(NULL == string){
return 0;
}
/*
unsigned char b[16];
MD5(c,strlen(c),b);
return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
*/
n=0x100;
while (*string) {
v=n|(*string);
n+=0x100;
r= (int)((v>>2)^v)&0x0f;
ret=(ret<<r)|(ret>>(32-r));
ret&=0xFFFFFFFFL;
ret^=v*v;
string++;
// printf("while is over\n");
}
return((ret>>16)^ret);
}
由于我们table的大小为HASHSIZE,所以要将key放入表中的话,得到的hash值还需整除HASHSIZE。
将标签和数据插入表中(int insertHash(void *key,void *data,hashTable_t *tab)),比如我要《电路原理》这部书放置在电子信息工程这张表里,key是电路原理,data是电路原理的内容,table是电子信息工程。 hashlist是表中一个个分类。
/*检查key是否已经存在于表中*/
int UpdateHashList(void *key,void *data,struct hashEntry_s *hashlist,hashTable_t *tab)
{
if(hashlist !=NULL){
struct hashEntry_s *pos;
for(pos=hashlist;pos != NULL;pos=pos->next){
if(strcmp(key,pos->key)==0){
pos->key = key;
pos->data =data;
return 0;
}
}
}
return -1;
}
int insertHash(void *key,void *data,hashTable_t *tab)
{
int index;
index =getHashValue((char *)key)%HASHSIZE;
// printf("index:%d\n",index);
if(UpdateHashList(key,data,tab->hashlist[index],tab)<0){
struct hashEntry_s *l;
l= hashEntryNew(key,data);
if(tab->hashlist[index] == NULL){
tab->hashlist[index] = l;
printf("insert data:%s\n",(char *)tab->hashlist[index]->data);
}else{
struct hashEntry_s *pos;
for(pos = tab->hashlist[index];pos->next !=NULL;pos->next){
pos= l;
}
}
}
return 0;
}
得到元素数据(void *getHashData(void *key,hashTable_t *tab))。假如要取《电路原理》的信息,那么key即为电路原理,tab是电子信息工程那张表。
void *getHashData(void *key,hashTable_t *tab)
{
int index;
char *get_data;
index = getHashValue((char *)key)%HASHSIZE;
printf("get index :%d\n",index);
struct hashEntry_s *pos;
for(pos = tab->hashlist[index];pos !=NULL;pos = pos->next){
if(strcmp(key,pos->key) == 0){
return pos->data;
}
}
return NULL;
}
删除表信息
int removeHash(void *key,hashTable_t *tab)
{
int index;
index = getHashValue((char *)key)%HASHSIZE;
struct hashEntry_s *pos;
for(pos=tab->hashlist[index];pos != NULL;pos=pos->next,index++){
if(strcmp(key,pos->key) == 0){
pos->key = NULL;
pos->data = NULL;
if(pos->next != NULL){
pos =pos->next;
}else{
tab->hashlist[index] =NULL;
}
return 0;
}
return -1;
}
printf("remove over!\n");
return -1;
}
按照上面的思路,假如你要从图书馆这个大表开始查的话,得建两张hash表,一张是图书馆,一张是电子信息。查的时候,图书馆表中的key是电子信息,电子信息表中的key是电路原理。
下面是把上面代码整个起来做的一个简单测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define HASHSIZE 67
struct hashEntry_s{
void *key;
void *data;
struct hashEntry_s *next;
};
struct hashTable_s{
struct hashEntry_s **hashlist;
};
typedef struct hashTable_s hashTable_t;
unsigned long getHashValue(char *string)
{
unsigned long ret=0;
long n;
unsigned long v;
int r;
if(NULL == string){
return 0;
}
/*
unsigned char b[16];
MD5(c,strlen(c),b);
return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));
*/
n=0x100;
while (*string) {
v=n|(*string);
n+=0x100;
r= (int)((v>>2)^v)&0x0f;
ret=(ret<<r)|(ret>>(32-r));
ret&=0xFFFFFFFFL;
ret^=v*v;
string++;
// printf("while is over\n");
}
return((ret>>16)^ret);
}
hashTable_t *createHashTable(void)
{
hashTable_t *table;
int i,len,primesize;
table = malloc(sizeof(hashTable_t));
if(NULL == table){
printf("error in createtable");
return NULL;
}
len = sizeof(struct hashEntry_s *)*HASHSIZE;
table->hashlist = malloc(len);
if(table->hashlist == NULL){
printf("error in createtable\n");
exit(1);
}
for(i=0;i<HASHSIZE;i++)
table->hashlist[i]=NULL;
return table;
}
inline struct hashEntry_s *hashEntryNew(void *key, void *data)
{
struct hashEntry_s *new = malloc(sizeof(struct hashEntry_s));
memset(new,0,sizeof(struct hashEntry_s));
new->key = key;
new->data = data;
new->next = NULL;
return new;
}
int UpdateHashList(void *key,void *data,struct hashEntry_s *hashlist,hashTable_t *tab)
{
if(hashlist !=NULL){
struct hashEntry_s *pos;
for(pos=hashlist;pos != NULL;pos=pos->next){
if(strcmp(key,pos->key)==0){
pos->key = key;
pos->data =data;
return 0;
}
}
}
return -1;
}
int insertHash(void *key,void *data,hashTable_t *tab)
{
int index;
index =getHashValue((char *)key)%HASHSIZE;
// printf("index:%d\n",index);
if(UpdateHashList(key,data,tab->hashlist[index],tab)<0){
struct hashEntry_s *l;
l= hashEntryNew(key,data);
if(tab->hashlist[index] == NULL){
tab->hashlist[index] = l;
printf("insert data:%s\n",(char *)tab->hashlist[index]->data);
}else{
struct hashEntry_s *pos;
for(pos = tab->hashlist[index];pos->next !=NULL;pos->next){
pos= l;
}
}
}
return 0;
}
void *getHashData(void *key,hashTable_t *tab)
{
int index;
char *get_data;
index = getHashValue((char *)key)%HASHSIZE;
printf("get index :%d\n",index);
struct hashEntry_s *pos;
for(pos = tab->hashlist[index];pos !=NULL;pos = pos->next){
if(strcmp(key,pos->key) == 0){
return pos->data;
}
}
return NULL;
}
int removeHash(void *key,hashTable_t *tab)
{
int index;
index = getHashValue((char *)key)%HASHSIZE;
struct hashEntry_s *pos;
for(pos=tab->hashlist[index];pos != NULL;pos=pos->next,index++){
if(strcmp(key,pos->key) == 0){
pos->key = NULL;
pos->data = NULL;
if(pos->next != NULL){
pos =pos->next;
}else{
tab->hashlist[index] =NULL;
}
return 0;
}
return -1;
}
printf("remove over!\n");
return -1;
}
int main(void)
{
hashTable_t *table_a;
int i=0;
char *data ="hello";
char *getdata ="world" ;
char *key ="1";
table_a = createHashTable();
if(table_a == NULL){
printf("error!\n");
return -1;
}
insertHash(key,data,table_a);
getdata = getHashData(key,table_a);
if(getdata == NULL ){
printf("wo cao !!!\n");
return -1;
}
printf("get hash data :%s\n",getdata);
char *data2="next!";
insertHash(key,data2,table_a);
getdata = getHashData(key,table_a);
if(getdata == NULL ){
printf("empty !!!\n");
return -1;
}
printf("get hash data :%s\n",getdata);
removeHash(key,table_a);
getdata = getHashData(key,table_a);
if(getdata == NULL ){
printf("empty !!!\n");
return -1;
}
printf("get data remove:%s\n",getdata);
free(table_a);
return 0;
}