哈希查找之链地址法解决冲突(代码封装实现)
来源:互联网 发布:免费淘宝联盟推广软件 编辑:程序博客网 时间:2024/04/30 11:26
链地址法的基本思想是:将所有哈希地址为i 的元素构成一个称为同义词链的链表,并将链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。
该散列方法首先对关键码集合用某一个散列函数计算它们的存放位置。
若设散列表地址空间的所有位置是从0到m-1,则关键码集合中的所有关键码被划分为m个子集,具有相同地址的关键码归于同一子集。我们称同一子集中的关键码互为同义词。每一个子集称为一个桶。
通常各个桶中的表项通过一个链表链接起来,称之为同义词子表。所有桶号相同的表项都链接在同一个同义词子表中,各链表的表头结点组成一个向量。
进一步的分析:
1、通常,每个桶中的同义词子表都很短,设有n个关键码通过某一个散列函数,存放到散列表中的 m 个桶中。那么每一个桶中的同
义词子表的平均长度为 n / m。这样,以搜索平均长度为 n / m 的同义词子表代替了搜索长度为 n 的顺序表,搜索速度快得多(O(1))。
2、时间复杂度分析:应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上,由于开地址法必须保持大量的空闲空间以确保搜索
效率,如二次探查法要求装填因子,(a = n / m)而表项所占空间又比指针大得多,所以使用链地址法反而比开地址法节省存储空间。
下面给出链地址法的实现,包括建立哈希表,释放哈希表,在哈希表中根据key查找一项,根据key 插入一项,根据key 删除一项等。
使用双向链表实现。
#ifndef _HASH_H_#define _HASH_H_//双向链表的哈希typedef struct hash hash_t;typedef unsigned int (*hashfunc_t)(unsigned int,void*);//哈希函数/*建立哈希表*/hash_t* hash_alloc(unsigned int buckets,hashfunc_t hash_func); /*查找关键字*/void* hash_lookup_entry(hash_t *hash,void* key,unsigned int key_size);/*哈希表中添加记录*/void hash_add_entry(hash_t *hash,void *key,unsigned int key_size, void *value,unsigned int value_size);/*释放哈希表*/void hash_free_entry(hash_t *hash,void *key,unsigned int key_size);#endif
hash.c
#include "hash.h"#include <assert.h>#include "common.h"typedef struct hash_node{ void *key; //任意类型的关键字 void *value;//信息 struct hash_node *prev;//前驱指针 struct hash_node *next;//后继指针}hash_node_t;struct hash{ unsigned int buckets; hashfunc_t hash_func; hash_node_t **nodes;};//得到桶号hash_node_t **hash_get_bucket(hash_t *hash,void *key){ unsigned int bucket=hash->hash_func(hash->buckets,key); if(bucket >= hash->buckets) { fprintf(stderr,"bad buckets lookup\n"); exit(EXIT_FAILURE); } return &(hash->nodes[bucket]);}hash_node_t *hash_get_node_by_key(hash_t *hash,void *key,unsigned int key_size){ hash_node_t **bucket=hash_get_bucket(hash,key); hash_node_t *node=*bucket; if(node==NULL) return NULL; while(node!=NULL && memcmp(node->key,key,key_size)!=0) { node=node->next; } return node;}hash_t* hash_alloc(unsigned int buckets,hashfunc_t hash_func){ hash_t *hash=(hash_t *)malloc(sizeof(hash_t)); hash->buckets=buckets; hash->hash_func=hash_func; int size=buckets * sizeof(hash_node_t*); hash->nodes=(hash_node_t**)malloc(size); memset(hash->nodes,0,size); return hash; }void* hash_lookup_entry(hash_t *hash,void* key,unsigned int key_size){ hash_node_t *node=hash_get_node_by_key(hash,key,key_size); if(node==NULL) return NULL; return node->value;}void hash_add_entry(hash_t *hash,void *key,unsigned int key_size, void *value,unsigned int value_size){ //已经存在 if(hash_lookup_entry(hash,key,key_size)) { fprintf(stderr,"duplicate hash key\n"); return ; } hash_node_t *node=malloc(sizeof(hash_node_t)); node->prev=NULL; node->next=NULL; node->key=malloc(key_size); memcpy(node->key,key,key_size); node->value=malloc(value_size); memcpy(node->value,value,value_size); hash_node_t **bucket=hash_get_bucket(hash,key); if(*bucket == NULL) { *bucket=node; } else { //将新的节点插入到头部 node->next=*bucket; (*bucket)->prev=node; *bucket=node; }}//删除操作void hash_free_entry(hash_t *hash,void *key,unsigned int key_size){ hash_node_t *node=hash_get_node_by_key(hash,key,key_size); if(node==NULL) return ; free(node->key); free(node->value); if(node->prev) node->prev->next=node->next; else { hash_node_t **bucket=hash_get_bucket(hash,key); *bucket=node->next; } if(node->next) node->next->prev=node->prev; free(node);}测试main.c
#include "hash.h"#include "common.h"typedef struct stu{ char sno[5]; char name[32]; int age;}stu_t;typedef struct stu2{ int sno; char name[32]; int age;}stu2_t;//字符串哈希函数unsigned int hash_str(unsigned int buckets,void *key){ char *sno=(char *)key; unsigned int index=0; while(*sno) { index=*sno+4*index; sno++; } return index % buckets;}unsigned int hash_int(unsigned int buckets,void *key){ int *sno=(int *)key; return (*sno) % buckets;}int main(){/* stu_t stu_arr[]= { {"1234","AAAA",20}, {"4568","AAAA",23}, {"6729","AAAA",19} }; hash_t *hash=hash_alloc(256,hash_str); int size=sizeof(stu_arr)/sizeof(stu_arr[0]); int i; for(i=0;i<size;i++) {//插入地址,关键码,关键码的长度,数据项 hash_add_entry(hash,stu_arr[i].sno,strlen(stu_arr[i].sno), &stu_arr[i],sizeof(stu_arr[i])); } //查找 stu_t *s=(stu_t *)hash_lookup_entry(hash,"4568",strlen("4568")); if(s) { printf("%s %s %d\n",s->sno,s->name,s->age); } else printf("Not found\n"); hash_free_entry(hash,"1234",strlen("1234")); s=(stu_t *)hash_lookup_entry(hash,"1234",strlen("1234")); if(s) { printf("%s %s %d\n",s->sno,s->name,s->age); } else printf("Not found\n");*/ stu2_t stu_arr[]= { {1234,"AAAA",20}, {4568,"AAAA",23}, {6729,"AAAA",19} }; hash_t *hash=hash_alloc(256,hash_int); int size=sizeof(stu_arr)/sizeof(stu_arr[0]); int i; for(i=0;i<size;i++) {//插入地址,关键码,关键码的长度,数据项 hash_add_entry(hash,&(stu_arr[i].sno),sizeof(stu_arr[i].sno), &stu_arr[i],sizeof(stu_arr[i])); } //查找 int sno=4568; stu2_t *s=(stu2_t *)hash_lookup_entry(hash,&sno,sizeof(sno)); if(s) { printf("%d %s %d\n",s->sno,s->name,s->age); } else printf("Not found\n"); sno=1234; hash_free_entry(hash,&sno,sizeof(sno)); s=(stu2_t *)hash_lookup_entry(hash,&sno,sizeof(sno)); if(s) { printf("%d %s %d\n",s->sno,s->name,s->age); } else printf("Not found\n"); return 0;}结果:
可以看到因为我们封装的时候使用的是void *,所以支持各种类型的关键字,例如测试中的字符串和整型。
4 0
- 哈希查找之链地址法解决冲突(代码封装实现)
- 散列表(二):冲突处理的方法之链地址法的实现(哈希查找)
- 散列表(二):冲突处理的方法之链地址法的实现(哈希查找)
- 数据结构与算法学习之路:简单的哈希表实现(链地址法解决冲突)
- 哈希表链地址法解决冲突
- 数据结构与算法之哈希冲突解决-链地址法与开放定址法对比
- 一段采用链地址法解决冲突的Hash代码
- 哈希表之开地址法解决冲突
- 一个简单HashTable实现,哈希函数求模取余,链地址解决冲突
- 算法学习 - HashTable开放地址法解决哈希冲突
- 数据结构实验之查找五:平方之哈希表(详解平方法解决哈希表冲突)
- SDUT 3379 数据结构实验之查找七:线性之哈希表(线性探测法解决冲突)
- 用链地址法解决冲突的哈希表
- [ACM] POJ 3349 Snowflake Snow Snowflakes(哈希查找,链式解决冲突)
- 哈希冲突解决之开放寻址法
- hash(开放地址法解决冲突)
- 解决ip地址冲突
- 解决ip地址冲突
- 《侣行》三季合集下载
- RMI AND CORBA简介——java菜鸟成长记
- 触发器类 , 指针函数
- Understanding Linux /proc/id/maps
- 关于幂等的设计
- 哈希查找之链地址法解决冲突(代码封装实现)
- 常用的正则表达式验证
- iOSCore Location地理定位的简单实用
- ubuntu 14.04 改网卡IP为静态IP
- MySQL高级十六——内存优化
- Save could not be completed. Reason: some characters cannot be mapped using “ISO-8859-1“
- com的小笔记--发文于2013-10-24
- listview中实现item播放音乐的进度显示
- didReceiveMemoryWarning