散列表是什么


散列表是个啥?
想象一下,你有一个巨大的通讯录,里面存着很多人的名字和电话号码。散列表就像这个通讯录,但它用一种特别快的方法来找到人。散列表里有一个“神奇公式”,这个公式可以把人的名字(关键字)转换成一个特定的位置(地址),这样你就能直接找到这个人的电话号码。
散列函数怎么工作的?
散列函数就像是一个翻译官,它把名字翻译成一个数字,这个数字就是电话号码的位置。但是,有时候两个不同的名字可能会被翻译成同一个数字,这就是“冲突”。散列表的目标就是尽量减少这种混乱。
怎么造散列函数?
直接定址法:就像你直接用人的名字的笔画数来找电话号码,简单直接,但如果名字笔画数分布不均匀,有些位置就会空着,浪费空间。
除留余数法:这个方法就像是把名字的笔画数除以一个特别的数字(质数),然后只用余数来找位置。这个特别的数字要选得好,这样每个名字都能均匀地分布在通讯录里。
数字分析法:这个方法适合你已经知道通讯录里所有人的名字笔画数分布情况。你可以选择那些笔画数分布比较均匀的数字来作为位置。
平方取中法:这个方法是先把名字的笔画数平方,然后取中间几位数字来找位置。这样可以让位置分布得更均匀。
散列表的好处
用散列表找电话号码(或者任何东西)通常非常快,因为那个“神奇公式”可以瞬间告诉你电话号码在哪里,时间复杂度是 O(1),意思是不管通讯录有多大,找东西的速度都差不多。

散列表
散列表就像是一个超市的储物柜,每个格子都有一个编号,顾客(数据)可以通过自己的密码(键值)来找到对应的储物柜格子。
处理冲突的方法
但是,如果两个顾客的密码指向同一个储物柜格子,这就麻烦了,这就是所谓的“冲突”。下面是几种解决这种冲突的方法:
开放定址法:
就像超市里如果一个储物柜格子满了,就找下一个空的格子放东西。
线性探测法:
就是按顺序找下一个空格子,如果满了就继续找下一个,直到找到为止。但这样有时候会导致很多顾客挤在一起,找东西就慢了。
平方探测法:
这种方法是跳过几个格子再找,可以避免顾客挤在一起,但不是每个格子都能找到。
再散列法:
就是如果第一个密码对应的格子满了,就换另一个密码再试一次。
伪随机序列法:
用一种看似随机的方法来找空格子。
拉链法:
如果格子满了,就在这个格子上挂一个链子,链子上可以挂很多个储物柜,每个储物柜都有自己的密码。
散列查找及性能分析
查找数据的过程就像是顾客拿着密码去储物柜找东西:
先看密码对应的储物柜有没有东西,如果没有,说明东西没放这儿,查找失败。
如果有东西,就看看是不是自己的东西,是的话就找到了,不是的话就继续找下一个可能的储物柜。
装填因子
装填因子就像是看储物柜的拥挤程度,如果太满了,找东西就慢了。
平均查找长度
平均查找长度就是顾客平均需要找多少个储物柜才能找到自己的东西,这取决于储物柜的拥挤程度和找东西的方法。
 

知识点链接
散列表的基本概念
散列函数:一种将查找表中的关键字映射到特定地址的函数,记为 \text{Hash}(key) = \text{Addr}。地址可以是数组下标、索引或内存地址等。
冲突:当散列函数把两个或更多不同的关键字映射到同一个地址时发生。
散列表:根据关键字直接访问的数据结构,它建立了关键字和存储地址之间的直接映射关系。散列表的查找时间复杂度通常为 O(1)。
散列函数的构造方法
原则:
散列函数的定义域必须包含所有需要存储的关键字。
值域的范围依赖于散列表的大小或地址范围。
地址应均匀分布在整个地址空间中,以减少冲突。
散列函数应简单,便于快速计算。
散列函数的具体方法
直接定址法:
概述:直接取关键字的某个线性函数值为散列地址,如 H(key) = key 或 H(key) = a \times key + b,其中 a 和 b 是常数。
特点:计算简单,不会产生冲突,适合关键字分布连续的情况。若分布不连续,可能导致存储空间浪费。
除留余数法:
概述:假设散列表长度为 m,选择一个接近或等于 m 的质数 p,使用 H(key) = key \mod p 来转换关键字为散列地址。
特点:关键在于选择质数 p,使得每个关键字等概率映射到散列空间的任一地址,减少冲突。
数字分析法:
概述:如果关键字是 r 进制数,某些位上的数码分布可能不均匀。选择数码分布均匀的位作为散列地址。
特点:适用于已知的关键字集合,若关键字更换,需要重新构造散列函数。
平方取中法:
概述:取关键字平方值的中间几位作为散列地址。
特点:散列地址分布比较均匀,适用于关键字的每位取值不够均匀或小于散列地址所需的位数。

处理冲突的方法
散列表在存储数据时,可能会因为不同的键值通过散列函数映射到同一个位置,从而产生冲突。以下是几种常见的解决冲突的方法:
开放定址法:
概念:允许新表项的空闲地址既向它的同义词表项开放,也向非同义词表项开放。
数学递推公式:使用散列函数 H(key) 和表长 m 以及增量序列 d_i 来计算下一个空闲地址。
线性探测法:
概念:当冲突发生时,顺序查看表中的下一个单元,直到找到一个空闲单元或查遍全表。
注意:这种方法可能导致聚集现象,降低查找效率。
平方探测法:
注意:这种方法可以避免“堆积”问题,但不能探测到散列表上的所有单元,但至少能探测到一半单元。
再散列法:
需要使用两个散列函数,当第一个散列函数 H(key) 得到的地址发生冲突时,使用第二个散列函数 Hash(key) 计算地址增量。
伪随机序列法:
使用伪随机数序列来解决冲突。
拉链法:
将所有同义词存储在一个线性链表中,这个链表由其散列地址唯一标识。
适用于经常进行插入和删除的情况。
散列查找及性能分析
查找过程:
检测地址为 Addr 的位置上是否有记录,若无记录则查找失败,若有记录则比较它与 key 的值,若相等则查找成功,否则计算下一个散列地址并继续查找。
特点:
散列表的查找效率取决于散列函数、处理冲突的方法和装填因子。
装填因子:
装填因子定义为表的装满程度,装填因子越大,越容易发生冲突。
平均查找长度:
散列表的平均查找长度依赖于装填因子。
可以在求出散列表的基础上计算出查找成功时和查找失败时的平均查找长度。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值