数据结构之散列表(哈希表)
来源:互联网 发布:游戏编程需要怎么学 编辑:程序博客网 时间:2024/06/05 16:47
今天学的是数据结构的散列查找篇,其他的查找可参见以前的传送门
以前的查找都是基于比较关键字的基础上,所以查找的效率依赖于查找过程中所进行的比较次数。
理想的情况是不经过任何比较,通过计算就能直接得到记录所在的存储地址,散列查找(Hashed Search)是基于上述思想的一种查找方式。
散列法又称为哈希法、杂凑法或关键字地址计算法,是一种重要的存储方式,又是一种查找方式。
按散列法存储方式构造的动态查找表称为散列表(Hash Table)。散列法查找的核心是散列函数,又称为哈希函数。
散列法查找的基本思想
以记录中关键字的值K为自变量,通过确定的散列函数H进行计算,求出对应的函数值H(k),并吧这个函数值作为关键字值为K的记录的存储地址,将该记录(或记录的关键字)存放在这个位置上,查找时仍按这个确定的散列函数H进行计算,获得的将是待查找关键字所在记录的存储地址。这样,每个记录的关键字通过散列函数H计算都将对应得到一个记录的存储地址:
Addr( i )=H (第 i 个记录的关键字Ki) 其中H为确定的散列函数:Addr( i )为计算得到的第i 个记录的存储地址。
散列表查找需要解决好以下两个问题:
1、如何设计较好的散列函数。一个好的散列函数应该计算简单(加快转换速度);并且冲突较少,使散列函数结果值均匀分布在散列表的地址空间中。
2、如何处理冲突
散列函数的构造方法
1、直接定址法
此法的散列函数是线性的,取关键字或关键字的某个线性函数值为散列地址2、除留余数法( 最常用)
取关键字被某个不大于散列表表长m的质数p除后所得余数为散列地址,即对关键字进行取余运算:H( k )=k%p (p<=m)3、数字分析法
设关键字集合中,每个关键字均由m位组成,每位上可能有r种不同的符号。数字分析法根据r种不同的符号在各位上的分布情况,选取某几位,组合成散列地址。所选的位应使各种符号在该位上出现的频率大致相同。(适用于关键字集中的集合,且关键字是事先知道的)4、平方取中法
若已知关键字为数字,但预先不一定能够知道关键字的全部情况,用数字分析法难以确定哪几位分布比较均匀,可先求出关键字的平方,然后取其中若干位作为散列地址。(关键字平方后的结果与关键字中每一位都相关,故不同关键字产生不同散列地址的概率较高。
发生冲突是指由关键字得到的散列地址的位置上已经存有记录。而处理冲突是为该关键字的记录找到一个空的散列地址。在找空的散列地址时,可能还会产生冲突,此时需再找下一个空的散列地址,直到不产生冲突为止。
处理冲突法
1、开放定址法(再散列法)
分为:线性探测法、二次探测法
说白了就是本来的位置已经满了,此时继续以当前位置为起点往后寻找到空位,填入。2、拉链法(链地址法)
即将同一地址的关键字组成链表,放到该地址处3、建立一个公共溢出区
将散列表分为基本表和溢出表两部分,凡是与基本表发生冲突的元素一律填入溢出表
算法实现(完整版)
以除留余数法分配空间,以线性探测法处理冲突。
#include<stdio.h>#include<malloc.h>typedef struct{ int key; char data;}record;int prime(int m){ int i,p,flag; for(p=m;p>=2;p--) { for(i=2,flag=1;i<=p/2&&flag;i++) if(p%i==0) flag=0; if(flag==1) break; } return p;}int hi(int key,int p){ return key%p;}void creat(record**r,int n){ int i; (*r)=(record*)malloc(n*sizeof(record)); printf("input %d number:\n",n); for(i=0;i<n;i++) scanf("%d",&((*r)[i].key));}void hashed(record**ht,record*r,int n,int m,int p){ int i,j; (*ht)=(record*)malloc(m*sizeof(record)); for(i=0;i<m;i++) (*ht)[i].key=0; for(i=0;i<n;i++) { j=hi(r[i].key,p); while((*ht)[j].key!=0) j=(j+1)%m; (*ht)[j].key=r[i].key; }}int search(record*ht,int key,int p,int*k){ int i; *k=1; i=hi(key,p); while(ht[i].key!=0&&ht[i].key!=key) { i++; ++*k; } if(ht[i].key==0) return -1; else return i;}int main(){ record*r,*ht; int key,i,n,m,p,k; char ch; printf("input n and m.(n<=m):"); scanf("%d,%d",&n,&m); creat(&r,n); p=prime(m); printf("the prime is:%d",p); hashed(&ht,r,n,m,p); printf("\nthe hashed is:"); printf("\n location:"); for(i=0;i<m;i++) printf("%3d",i); printf("\nthe value:"); for(i=0;i<m;i++) printf("%3d",ht[i].key); do{ printf("\ninput search value:"); scanf("%d",&key); i=search(ht,key,p,&k); if(i!=-1) { printf("search good,location:%d",i); printf("\n compare time:%d\n",k); } else { printf("search bad"); printf("\n compare time:%d\n",k); } fflush(stdin); ch=getchar(); }while(ch=='y'||ch=='Y'); return 0;}
性能分析
虽然散列表时基于计算式的查找方式但由于冲突的存在,散列法仍需进行关键字比较,故仍需要用平均查找长度来评价散列法的查找性能。影响散列法中关键字的比较次数的因素有三个:散列函数、处理冲突的方法、散列表的装填因子。
散列表的装填因子α=表中已记录数/表长。α可描述散列表的装填状态程度。α越大,冲突越大;α越小,冲突越小。
总结
数据结构是一门神奇的学科,它的思想很丰富,应用也是相当之广泛,有时间我将会多多更新其中的实际应用,数据结构就先告一段落了,开始伟大的自学奋斗模式了。
- 数据结构之哈希表(散列表查找)
- 数据结构之散列表(哈希表)
- 《数据结构》之(散列表)
- 数据结构之散列表
- 数据结构之散列表
- 数据结构之散列表
- 数据结构之散列表
- 一点一点学数据结构之哈希表(散列表)
- 旭说数据结构之散列表(哈希表)
- C++数据结构 之 哈希表(散列表)_Hash Table
- 数据结构:散列表(哈希表)
- 数据结构:哈希表(散列表)
- 《数据结构导论之散列表》
- 数据结构---哈希表/散列表
- 【数据结构】哈希表/散列表
- 数据结构-散列表 哈希表
- HashSet、HashMap,散列表数据结构(哈希表)
- [数据结构]程杰:散列表(哈希表)
- 把java项目上传到github上命令使用
- [Python/MangoDb/MangoEngine] 模拟数据库/增/删/改/查
- asp.NET UpdatePanel实现异步局部刷新
- shell传参并将参数传递给sql文件
- bootstrap-datetimepicker 日期选择控件 通用版
- 数据结构之散列表(哈希表)
- iOS知识汇总
- Android开发倒计秒数的正确用法
- Android距离传感调试与input子系统探究
- 简单的webService实例
- POJ1573 Robot Motion (模拟 | 递归)
- listview实现时间轴显示效果
- 安转luajit 和 cjson模块
- 微服务中的服务发现