哈希表(散列表)
2015-08-12 16:21
127 查看
哈希表是最基础的数据结构之一,利用键值对存储并检索数据的一种非线性结构。
在其它各种结构线性表、树等数据结构中,记录在结构中的位置是随机的,和记录关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的“比较”的基础上。在顺序查找时,比较的结果为“==”与“!=”两种可能;在折半查找、二叉排序树查找和B-树查找时,比较的结果为“<”、”=”和“>”3种可能。查找的效率依赖于查找过程中所进行的比较次数。
理想的情况是希望不经过比较,一次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。因而在查找时,只要根据这个对应关系f找到给定值K的像f(k)。若结构中存在关键字和K相等的记录,则必定在f(k)的存储位置上,由此,不需要进行比较便可直接取得所查记录。在此,我们称这个对应的关系f为哈希(Hash)函数,按这个思想建立的表为哈希表。
然而,在一般情况下,冲突只能尽可能地少,而不能完全避免。因为,哈希函数是从关键字集合到地址集合的映像。通常,关键字集合集合比较大,它的元素包括所有可能的关键字。而地址集合元素仅为哈希表中的地址值。假设表长为n,则地址为0到n-1。例如,在C语言的编译程序中可对源程序中的标识符建立一张哈希表。在设定哈希函数时考虑的关键字集合应包含所有可能产生的关键字;假设标识符定义为以字母为首的8位字母或数字,则关键字(标识符)的集合大小(-----PS:数字大,打印不了····) ,而在一个源程序中出现的标识符合是有限的,设表长为1000足矣。地址集合中的元素为0~999。因此,在一般情况下,哈希函数是一个压缩映像,这就不可避免产生冲突。因此,在建造哈希表时不仅要设定一个”好“的哈希函数,而且要设定一种处理冲突的方法。
综上所述,可如下描述哈希表:根据设定的哈希函数H(key)和处理冲突的方法将一组关键字映像到一个有限的连续地址集上,并以关键字在地址集中的”像“作为记录在表中存储位置,这种表便称为哈希表,这一映像过程称为哈希造表或散列,所得存储位置称哈希地址或者散列地址。
若对于关键字集合中的任一个关键字,哈希函数映像到地址集合中任何一个地址的概率是相等的,则称此类哈希函数为均匀的哈希函数。换句话说,就是使关键字经过哈希函数得到一个“随机的地址“,以便使一组关键字的哈希地址均匀分布在整个地址区间中,从而减少冲突。
1.直接定址法
取关键字或关键字的某个线性函数值为哈希地址。即:
H(key)=key或H(key)=a*key+b;
其中a和b为常数(这种哈希函数叫做自身函数)。
由于直接定址所得地址集合和关键字集合的大小相同。因此,对于不同的关键字不会发生冲突。但实际中使用这种哈希函数的情况很少。
2.数字分析法
假设关键字是以r为基的数(如:以10为基的十进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。
3.平方取中法
取关键字平方后的中间几位为哈希地址。
4.折叠法
将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。
5.除留余数法
取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。即H(key)=key MOD p,(p<=m),这是一种最简单,也是最常用的构造哈希函数的方法。它不仅可以对关键字直接取模(MOD),也可在折叠、平方取中等运算之后取模。
6.随机数法
选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random为随机函数。通常,当关键字长度不等时采用此法构造哈希函数较切当。
总结:
实际工作中需视不同情况采用不同的哈希函数,通常,考虑的因素有:
(1)计算哈希函数所需时间(包括硬件指令的因素);
(2)关键字的长度;
(3)哈希表的大小;
(4)关键字的分布情况;
(5)记录的查找频率。
处理冲突的方法(冲突只能减少,不能避免):
1.开放定址法
2.再哈希法
3.链地址法
4.建立一个公共溢出区
在其它各种结构线性表、树等数据结构中,记录在结构中的位置是随机的,和记录关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的“比较”的基础上。在顺序查找时,比较的结果为“==”与“!=”两种可能;在折半查找、二叉排序树查找和B-树查找时,比较的结果为“<”、”=”和“>”3种可能。查找的效率依赖于查找过程中所进行的比较次数。
理想的情况是希望不经过比较,一次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。因而在查找时,只要根据这个对应关系f找到给定值K的像f(k)。若结构中存在关键字和K相等的记录,则必定在f(k)的存储位置上,由此,不需要进行比较便可直接取得所查记录。在此,我们称这个对应的关系f为哈希(Hash)函数,按这个思想建立的表为哈希表。
然而,在一般情况下,冲突只能尽可能地少,而不能完全避免。因为,哈希函数是从关键字集合到地址集合的映像。通常,关键字集合集合比较大,它的元素包括所有可能的关键字。而地址集合元素仅为哈希表中的地址值。假设表长为n,则地址为0到n-1。例如,在C语言的编译程序中可对源程序中的标识符建立一张哈希表。在设定哈希函数时考虑的关键字集合应包含所有可能产生的关键字;假设标识符定义为以字母为首的8位字母或数字,则关键字(标识符)的集合大小(-----PS:数字大,打印不了····) ,而在一个源程序中出现的标识符合是有限的,设表长为1000足矣。地址集合中的元素为0~999。因此,在一般情况下,哈希函数是一个压缩映像,这就不可避免产生冲突。因此,在建造哈希表时不仅要设定一个”好“的哈希函数,而且要设定一种处理冲突的方法。
综上所述,可如下描述哈希表:根据设定的哈希函数H(key)和处理冲突的方法将一组关键字映像到一个有限的连续地址集上,并以关键字在地址集中的”像“作为记录在表中存储位置,这种表便称为哈希表,这一映像过程称为哈希造表或散列,所得存储位置称哈希地址或者散列地址。
哈希函数的构造方法:
若对于关键字集合中的任一个关键字,哈希函数映像到地址集合中任何一个地址的概率是相等的,则称此类哈希函数为均匀的哈希函数。换句话说,就是使关键字经过哈希函数得到一个“随机的地址“,以便使一组关键字的哈希地址均匀分布在整个地址区间中,从而减少冲突。
1.直接定址法
取关键字或关键字的某个线性函数值为哈希地址。即:
H(key)=key或H(key)=a*key+b;
其中a和b为常数(这种哈希函数叫做自身函数)。
由于直接定址所得地址集合和关键字集合的大小相同。因此,对于不同的关键字不会发生冲突。但实际中使用这种哈希函数的情况很少。
2.数字分析法
假设关键字是以r为基的数(如:以10为基的十进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。
3.平方取中法
取关键字平方后的中间几位为哈希地址。
4.折叠法
将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。
5.除留余数法
取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。即H(key)=key MOD p,(p<=m),这是一种最简单,也是最常用的构造哈希函数的方法。它不仅可以对关键字直接取模(MOD),也可在折叠、平方取中等运算之后取模。
6.随机数法
选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random为随机函数。通常,当关键字长度不等时采用此法构造哈希函数较切当。
总结:
实际工作中需视不同情况采用不同的哈希函数,通常,考虑的因素有:
(1)计算哈希函数所需时间(包括硬件指令的因素);
(2)关键字的长度;
(3)哈希表的大小;
(4)关键字的分布情况;
(5)记录的查找频率。
处理冲突的方法(冲突只能减少,不能避免):
1.开放定址法
2.再哈希法
3.链地址法
4.建立一个公共溢出区
相关文章推荐
- 字符输入,输出问题
- C#中的泛型
- SQLite 日期 & 时间
- Linux系统排查4——网络篇
- C++/CLI托管
- 自定义GridView六宫格
- Java FileInputStream/FileOutputStream的应用 文件读取和写入
- 鼠标放到图片上实现动态的效果
- 解决混淆报错问题-打包签名出现问题的解决方法
- 数据结构Java实现01----算法概述
- 关于C#反射(转载)
- ie6-7 overflow:hidden失效问题的解决方法
- 一个看股票的小工具
- IOS开发在线文档 记录下
- android 调用系统出现activity销毁
- 国王的烦恼---nyoj
- DUBBO配置规则详解
- 有关win32信号量和事件在多线程使用的小例子
- Groovy插件安装
- SAS硬盘与SATA硬盘有什么区别