hash表的简单说明以及例子

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值