哈希表(散列表)

本文介绍了散列表的基本概念,包括其工作原理、哈希函数的作用,通过实例展示了散列表的高效查找和空间效率低的问题。还讨论了构造散列函数的方法以及解决哈希冲突的策略,如开放地址法和链地址法,并总结了链地址法的优势和影响查找时间的因素。
摘要由CSDN通过智能技术生成

一.散列表的概念:

什么是散列表?散列表是一种新的存储形式,它既不是杂乱无章的存储,也不是排好序有序的方式存储的,它是根据要存储的数据记录的关键字值计算出应该存储的位置,怎么计算呢?就是根据一个函数计算出来的,这个函数就称为哈希函数,或者散列函数.
单词hash:混杂,平凑的意思.
看似混乱的数据,其实是通过hash函数运算存放的.
所以翻译为散列,杂凑,所以这种这种存储方式我们就称之为散列存储. 或者hash存储,这个函数就称为哈希函数,或者散列函数.而存储的表我们就称之为散列表或者哈希表
基本思想:记录的存储位置与关键字之间存在对应关系
对应关系------hash函数
Loc(i)=H(keyi)-----等号右边就称之为hash函数.等号左边就是对应的存储位置;

二.两个例子理解散列表/哈希表

例1:若将学生信息按如下方式存入计算机:将2001011810211的所有信息存入V[11]单元;将2001011810207的所有信息存入V[07]单元;……………………将2001011810231的所有信息存入V[31]单元;
存储学生的信息,不是根据输入的顺序存储,也不是按照排序从小到大存储,而是按照学号的后两位来存储到对应的内存单元.
例2:数据元素序列(25,23,39,9,14,11),若规定每个元素K的存储地址H(k)=k,请画出存储结构图.

image-20230701163711383.png


如果要查找,学生信息的查找则直接根据末两位查找,如要查找20010111810216的信息,可直接访问V[16];而例2的数据如何查找呢?
根据哈希函数H(k)=k,查找key=9,则访问H(9)=9号地址,若内容为9则成功;
若查不到,则返回一个特殊值,如空指针或空记录.

三.哈希表的优缺点

通过上两个例子的查找我们可以看出散列表(哈希表)的查找效率特别高,(根据关键字的值计算出的存储位置, 第一个是去末两位,第二个是直接对应地址)这个是它的优点,直接对应哈希函数去查找,比折半查找,树的查找效率都要高,可以达到O(1),根据关键字的值直接计算就可以找到,但是它的缺点就是空间效率低,比如例2,一共只有6个元素,但是我们需要的存储空间却是39,假如最大的值更大,那么我们就会空着更多的空间没有利用,所以哈希表其实就是典型的以空间换取时间.这个就是散列表的特点:查找效率高,空间利用率低;

哈希表研究重点:
那么接下来需要研究的就是如何让空间利用率不是太低.

四.几个名词

在开始研究之前我们先介绍一下几个名词:

1. 散列方法和散列函数

散列方法(杂凑法):选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放;
查找时,由同一个函数对给定K值计算地址,将K与地址单元中元素关键码进行对比,确定是否查找成功;
散列函数(杂凑函数,哈希函数):散列方法中使用的转化函数;

2. 散列表(杂凑表,哈希表):

按上述思想构造的表或者说按哈希函数构造的表如下(如上图的表)

3. 冲突:

不同的关键码映射到同一个散列地址,key1不等于key2,但是H(key1)=H(key2).

image-20230701164550290.png


哈希冲突:虽然关键字的值不一样,但是通过哈希函数计算出来的值是相同的,这个就是哈希冲突;其实就是:不同的关键码映射到同一个散列地址

4. 同义词

如上图,同义词就是具有相同函数值的多个关键字.
在散列查找方法中,冲突是不可能避免的,只能尽可能减少.

五.使用散列表要解决好两个问题:

(1) 构造好的散列函数:

所选函数尽可能简单,以便提高转化速度;
    所选函数对关键码计算出的地址,应在散列地址中均匀分布,以减少空间浪费;

(2) 指定一个好的解决冲突的方案:

查找时,如果从散列函数计算出的地址中查不到关键码,则应当依据解决冲突的规则,有规律地查询其他相关单元.

那么构造散列函数需要考虑的因素有哪些呢?(了解)
1.执行速度(即计算散列函数所需的时间);2,关键字的长度;3,散列表的大小4,关键字的分布情况;5查找频率;
散列表大:空间利用率低,散列表小:冲突的可能性大;所以需要折衷的方法.

六.构造散列函数的6个方法

那么构造散列函数的方法有哪些呢?(两个要求,6个方法)
根据元素集合的特性构造:要求一:n个数据原仅占用n个地址,虽然散列查找是以空间换时间,但仍希望散列的地址空间尽可能小;要求二:无论用什么方法存储,目的都是尽量均匀地存放元素,以避免冲突;
6个方法:1.直接地址法2数字分析法3平方取中法4折叠法5除留余数法6随机数法

我们下面给大家介绍一些第1和第5个方法

1.  直接定址法:

H(key)=a*key+b(a,b为常数),
例子:{100,300,500,700,800,900},哈希函数为Hash(key)=key/100,其实就是a=1/100,b=0;
那么以此函数建立的哈希表为:

image-20230701204656536.png


优点:以关键码Key的某个线性函数值为散列地址,不会产生冲突;
为什么不会产生冲突?y=ax+b线性函数,x唯一,那么y唯一
缺点:要占用连续的地址空间,空间效率低.
直接定址法我们也比较常用,因为简单,同时优点是不会产生冲突,缺点是要占用连续的地址空间,空间效率低.

2.那么接下来我们来介绍一种更加常用的方法----除留余数法

用关键字除以p得到的余数作为关键字的存储位置.
Hash(key)=key%p(p是一个整数) 那么关键是怎么取到合适的除数p?
技巧:设表长为m,取p<=m且为质数
例如{15,23,27,38,53,61,70},散列函数Hash(key)=key%7,那么哈希表为:

image-20230701204831757.png


查找的时候同样用这个哈希函数,比如我们要查找70.用10除以7余数为0,直接去0号位置查找.
以上就是我们常用的散列表的构造方法:直接定址法和除留余数法.

七.处理冲突的方法

讲完了散列表的构造方法,那么我们还有一个问题就是如何解决冲突问题呢?
处理冲突的方法:1.开放地址法(开地址法)2.链地址法(拉链法)3.再散列法(双散列函数法)4.建立一个公共溢出区;
我们只介绍解决冲突的两种方法:开地址法和链地址法;

1.开放地址法

请查看下面的博客

http://t.csdnimg.cn/eoSLO

2.链地址法

请查看下面的博客

http://t.csdnimg.cn/ioenX

八.总结

1.链地址法的优点:

非同义词不会冲突,无”聚集”现象;
链表上节点空间动态申请,更适合于表长不确定的情况.

开地址法非同义词也会产生冲突,比如原来需要存储的地址有元素,我们放入下一个地址,那么下一个地址需要存储的元素本来和这个不是同义词,但是也产生冲突了,这种就叫做聚集现象.
而链地址法不会有这种问题,因为它的同义词都挂在各自的链表上,非同义词之间没有冲突,没有聚集现象;

2.哈希表查找的时间复杂度

不是O(1),如果完全没有冲突,是O(1),但是一般都会有冲突;
结论:哈希表的查找的时间复杂度不是O(1),但是逼近O(1);

3.影响时间复杂度的因素有散列函数和解决冲突的方法;

散列函数是不是能够让元素比较均匀的分布在散列表中.
解决冲突的方法是看看解决的冲突解决的是不是比较好,如果解决冲突解决的比较好,那么它的时间复杂度就会比较小.

4.几点结论:

散列表技术具有很好的平均性能,优于一些传统的技术;
链地址法优于开地址法
除留余数法作散列函数优于其他类型函数

链地址法优于开地址法一个是查找效率,一个是链地址它是动态的,表的长度是动态的,比较容易修改,而且如果做插入和删除的操作也比较方便.所以链地址法优于开地址法.
除留余数法比其他方法好,更均匀一些,通常我们的除数取一个质数,取一个小于等于表长的质数更好.这个就会获得一个比较好的散列效果.


 
  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪星猫宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值