排序与查找--散列和冲突解决方案(python)

1.散列

概念:散列表(Hashing)又叫哈希表。查找算法复杂度为O(1),常数级别。

查找快的原因:因为事先知道数据项在数据集的什么位置,直接到那个位置去看看数据是否存在即可。

散列表(哈希表)

  • 散列表是一种数据集。
  • 散列表中的每一个存储位置,称为( slot),可以用来保存数据项,每个槽有一个唯一的名称(槽号)

例如:如下图所示,一个包含11个槽的散列表,槽的名称分别为0~10。在插入数据项之前,每个槽的值都是None,表示空槽。
在这里插入图片描述
散列函数(hash function):数据项关于槽号的函数,比如y=2x,一样,数据项=2×槽号,数据项为2时,槽号为1。

有一种常用的散列方法是"求余数",将数据项除以散列表的大小,得到的余数作为槽号

例如:将数据项:94,26,93,17,77,31保存到散列表中,请设计一个散列函数,数据项为参数,返回整数0~10,作为槽的名称。

:h(item)=item%11,item为数据项,item%11为槽号

在这里插入图片描述
要查找数据项是否在表中,只需要用散列函数根据数据项计算出槽号,然后查找槽号里有没有数据项即可。

可能有两个数据项计算出来放在同一个槽中,这叫做冲突,冲突怎么解决呢?一会儿再看。

2.完美散列函数

概念:给定一组数据项,如果一个散列函数能把每个数据项映射到不同的槽中,那么这个散列函数就可以称为"完美散列函数

获得完美散列函数的一种方法:扩大散列表容量,大到所有可能出现的数据项都能占据不同的槽。

好的散列函数的特性

  • 冲突最少(近似完美)
  • 计算难度低(额外开销少)
  • 充分分散数据项(节约空间)

python自带的散列函数库:hashlib:
在这里插入图片描述
update()可对任意长数据部分计算
在这里插入图片描述

3.散列函数设计

3.1折叠法

基本步骤
例如:

对电话号码62767255
将数据项按照位数分为若干段,
可以两位两位分为4段(62、76、72、55)
再将几段数字相加,
得到散列值相加(62+76+72+55=265)
最后对散列表大小求余,
散列表包括11个槽,那么就是265%11=1所以
h(62767255)=1

隔数反转:(微调)
(62,76,72,56)隔数反转为(62,67,72, 65

3.2平方取中法

例如

首先将数据项做平方运算,
对44进行散列首先44*44=1936
然后取平方数的中间两位,
然后取中间的93
再对散列表的大小求余
对散列表大小11求余,93%11=5

3.3非数字项

如下图,ord函数把字符串中每个字符转为ASCII码(ord(“c”=99)),再将整数累加,对散列表大小求余。
在这里插入图片描述
代码:
在这里插入图片描述
变位词:abc 和 bac

如何防止所有变位词返回同一个槽
如下图,字符串所在位置乘以ord值再相加求余。
在这里插入图片描述

4.冲突解决方案

冲突两个数据项被散列映射到一个槽

4.1线性探测

解决方法:寻找空槽(开放定址),逐个槽寻找(线性探测)

聚集:线性探测法的一个缺点是有聚集 clustering)的趋势
即如果同一个槽冲突的数据项较多的话,这些数据项就会在槽附近聚集起来。从而连锁式影响其它数据项的插入。

解决方法:再散列,即不是逐个槽寻找,可以空3个槽寻找。叫做跳跃式探测。

跳跃式探测的再散列通式是∶rehash(pos)=(pos+skip)% sizeoftable

skip取值不能被散列表大小整除,否则会产生周期,让很多空槽永远无法被探测到。(可把散列表大小设为素数

4.2数据项链

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

铃音.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值