散列表平均查找长度

散列表(Hash Table)是一种用于存储和查找键值对的数据结构,也被称为哈希表、散列映射或字典。它通过将键转换成一个索引来加快查找速度,进而提高了数据处理的效率。

装填因子(Load Factor)是指散列表中已被占用桶(包含一个或多个键值对)的数量与散列表总桶数的比例。它是衡量散列表负载情况的重要指标,通常用于评估散列表的性能和可扩展性。
当装填因子接近 1 时,说明散列表已经非常拥挤,在这种情况下,如果再插入新的键值对,就可能导致碰撞概率增加,并且查询效率也会降低。因此,需要及时采取一些措施,如扩容,以保持散列表的高效性。
通常建议在装填因子达到某个阈值时进行扩容,具体阈值的选择与散列表大小、散列算法等因素有关,一般建议取值为 0.7 到 0.8 之间。
在散列表中,装填因子

的计算方式为:已占用桶数 / 总桶数。

平均查找长度(Average Search Length,ASL)是指在散列表中查找一个键的平均比较次数,也可以称为平均探测长度。它是衡量散列表性能的重要指标之一。
在散列表中查找一个键时,需要经历两个步骤:首先根据散列函数将该键映射到某个桶中,然后在该桶中对键进行比较,直到找到目标键或者确定目标键不存在。
因此,如果一个散列表有 n 个键值对,并且在查找目标键时需要比较 k 次才能找到或者确定不存在,则平均查找长度为:ASL = (k1 + k2 + ... + ki) / n,其中 ki 表示查找第 i 个键时需要的比较次数。

在散列表中,查找成功的平均查找长度(Average Search Length of Successful Search,ASL-S)是指在散列表中查找某个已存在键的平均比较次数。它通常用于评估散列表查找性能的好坏。
假设散列表中有 n 个键值对,在查找某个已存在键时需要比较 k 次才找到,则查找成功的平均查找长度为:
ASL-S = (k1 + k2 + ... + ki) / n
其中 ki 表示查找第 i 个已存在的键时需要的比较次数。
可以看出,查找成功的平均查找长度越小,说明散列表在查找已存在键时效率越高。因此,尽可能地减少散列冲突和提高散列表的装填因子等方法都可以有效地降低查找成功的平均查找长度,提高散列表查找性能。

在散列表中,查找失败的平均查找长度

常考Average Search Length of Unsuccessful Search,ASL-U)是指在散列表中查找某个不存在键的平均比较次数。它也是评估散列表性能的一个重要参数。
假设散列表中有 n 个键值对,在查找某个不存在键时需要比较 k 次才确定不存在,则查找失败的平均查找长度为:
ASL-U = (k1 + k2 + ... + ki) / n
其中 ki 表示查找第 i 个不存在的键时需要的比较次数。
可以看出,查找失败的平均查找长度越小,说明在散列表中查找不存在键的效率越高。常见的提高散列表查找效率的方法包括:合理设计散列函数、使用开放地址法解决冲突、设置合适的装填因子等。

常考的处理冲突的平均查找长度

 如上图所示,这是一道通过线性探测法解决冲突求查找失败的平均查找长度问题。

给定一个所要查找的键值k,若开始通过哈希函数定位到下标为0的位置,将98与k比较,不相等(比较一次)说明这个位置查找失败,继续下一个紧邻的下标为1的位置......直到比较到下标为8的位置为空,至此查找失败,这种情况一共比较了9次;若开始通过哈希函数定位到下标为1的位置,将22与k比较,不相等(比较一次)说明这个位置查找失败,继续下一个紧邻的下标为2的位置......直到比较到下标为8的位置为空,至此查找失败,这种情况一共比较了8次;若开始通过哈希函数定位到下标为2的位置,将30与k比较,不相等(比较一次)说明这个位置查找失败,继续下一个紧邻的下标为3的位置......直到比较到下标为8的位置为空,至此查找失败,这种情况一共比较了7次......若开始通过哈希函数定位到下标为6的位置,将6与k比较,不相等(比较一次)说明这个位置查找失败,继续下一个紧邻的下标为7的位置......直到比较到下标为8的位置为空,至此查找失败,这种情况一共比较了3次,综上所述,查找失败的平均查找长度=(9+8+7+6+5+4+3)/7=6。(分母是7是因为通过对7取余,只能定位到下标0到6的位置。

 如上图所示,这是一道通过线性探测法解决冲突求查找成功的平均查找长度问题。

查找成功的平均查找长度=查找每一个存在的关键字比较的次数/关键字总个数。因为22%7=1(比较一次,所需位置是空的,将22放入这个位置),43%7=1(发现下标为1的位置有22,根据线性探测法放到下标为2的位置,比较了两次),15%7=1(发现下标为1和2的位置均有元素,于是放到下标为3的位置,比较了三次)。分母是3的原因是每个元素被成功查找的概率都是1/3。也就是说成功查找22只需要通过哈希函数定位到下标为1的位置,和22比较一次发现相等即成功,成功查找43通过哈希函数也定位到下标为1的位置,比较一次不相等,继续向后寻找,和43比较发现相等即查找成功,比较了两次。则成功查找15比较了3次。所以查找成功的平均查找长度=(1+2+3)/3=2.

可参考王道相关视频

 

 

 

 这是一道通过链接地址法解决冲突求查找平均查找长度问题。

查找成功的平均查找长度=(1*4+2*3+3*1)/8=13/8,查找33,1,13,38只需要通过哈希函数定位下标比较一次即成功(故1*4),查找22,12,27均需要比较两次才成功(故2*3),查找34需要比较三次才能成功。

查找失败的平均查找长度=(3+4+2+1+1+3+1+1+1+1+1)/11=19/11,通过哈希函数定位到下标为0的位置,与33比较,与22比较均不是关键值,再比较一次发现22后面为空,至此查找失败,一共比较了3次;通过哈希函数定位到下标为1的位置,与1比较,与12,与34比较均不是关键值,再比较一次发现34后面为空,至此查找失败,一共比较了4次;通过哈希函数定位到下标为2的位置,与13比较不是关键值,再比较一次发现13后面为空,至此查找失败,一共比较了2次;通过哈希函数定位到下标为3的位置,比较一次发现为空,至此查找失败,一共比较了1次,同理依次类推即得,分母11为所能定位到的所有的初始地址0到10。

 


 

 

### 散列表链地址法的平均查找长度分析 #### 成功查找平均查找长度 对于采用链地址法(即开散列)构建的哈希表,在理想情况下,假设哈希函数能够均匀分布键值,则每个桶中的元素数量服从泊松分布。当进行成功查找操作时,如果目标键确实存在于某个特定位置对应的链表中,那么需要遍历该链表直到找到匹配项。 设n为插入到哈希表中的记录总数,m表示哈希表大小(也就是桶的数量),α=n/m定义为装载因子(load factor)。在最坏的情况下,所有的关键字都映射到了同一个索引处形成一条很长的单向链表;而在最好的情况则是这些数据被良好地分配给了各个不同的槽位上几乎不发生碰撞。因此实际应用中更关注的是期望时间复杂度E[T],它反映了平均性能指标: \[ E(T_{success})=\frac{1}{m}\sum^{m}_{i=0}(L_i+1)=\alpha+\frac{\lambda e^{-\lambda}}{(1-\lambda)} \] 其中\( L_i \)代表第 i 个桶内含有的结点数目,\(\lambda\)近似等于 α 当 m 足够大时[^2]。 #### 失败查找平均查找长度 同样基于上述设定条件考虑未命中情形下的探查过程。此时是从头至尾扫描整个关联序列直至到达链尾仍未能定位所需对象为止。所以理论上讲其预期成本会稍高于前者: \[ E(T_{failure})=\frac{1}{m}\sum^{m}_{i=0}L_i=\alpha+(e^\lambda-1)\cdot (1-\lambda)^{-1} \] 这里 \(T_{failure}\) 表达了从给定 key 不存于任何 bucket 的前提下执行 look-up 所耗费的时间资源量级。 ```python import math def expected_search_cost(alpha): lambda_ = alpha success_cost = alpha + ((lambda_ * math.exp(-lambda_)) / (1 - lambda_) if abs(lambda_-1)>1e-7 else 1) failure_cost = alpha + (((math.exp(lambda_) - 1)/(1-lambda_))if abs(lambda_-1)>1e-7 else float('inf')) return { "Success": round(success_cost, 4), "Failure": round(failure_cost, 4) } # Example usage with a load factor of 0.7 print(expected_search_cost(0.7)) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值