知识点
[记录本章包含哪些内容]
未攻克
[记录还不会的知识点]
笔记
由于文件丢失,故以下内容仅为之前未曾看过的内容😒
#todoB树章节暂未掌握 #todo题未掌握
散列表
- 散列函数(哈希函数):一个把查找表中关键字映射成该关键字对应的地址的函数,记为 Hash (key)=Addr (这里的地址可以是数组下标、索引或内存地址等)
- 冲突:散列函数将两个或两个以上的不同关键字映射到同一地址
- 散列表(也称哈希表):根绝关键字而直接进行访问的数据结构。散列表建立了关键字和存储地址之间的一种直接映射关系
- 时间复杂度:最好情况下,对散列表进行查找的时间复杂度为 O ( 1 ) O(1) O(1),即与表中元素的个数无关
构造散列函数的注意事项:
- 散列函数的定义域必须包含全部关键字,而值域的范围则依赖于散列表的大小
- 散列函数计算出的地址应尽可能均匀的分布在整个地址空间,尽可能的减少冲突
- 散列函数应尽量简单,能在较短的时间内计算出任意一个关键字对应的散列地址
- 采用何种构造散列函数的方法取决于关键字合集的情况
常用的散列函数构造:
- 直接定址法
- 直接取关键字的某个线性函数值为散列地址,散列函数为: H ( k e y ) = k e y H(key)=key H(key)=key 或 H ( k e y ) = a ∗ k e y + b H(key)=a*key+b H(key)=a∗key+b,a 和 b 为常数
- 优点:方法计算简单,且不会产生冲突
- 适合关键字的分布基本连续的情况,若关键字分布不连续,空位较多,则会造成存储空间的浪费,且需要连续的空间
- 除留余数法
- 最简单、最常用的方法
- 假定散列表表长为 m m m,取一个不大于 m m m 但最接近或等于 m m m 的质数 p p p,利用以下公式把关键字转换成散列地址。散列函数为: H ( k e y ) = k e y % p H(key)=key \% p H(key)=key%p
- 除留余数法的关键是选好 p p p,使得每个关键字通过该函数转换后等概率的映射到散列空间上的任意一个地址,从而减少冲突的可能性
- 数字分析法
- 若关键字是 r r r 进制数,而 r r r 个数码在各位上出现的频率不一定相同,可能在某些位上分布均匀一些,每种数码出现的机会均等;而在某些位上分布不均匀,只有某几种数码经常出现,此时应选取数码分布较为均匀的若干位作为散列地址
- 适合已知的关键字集合,若更换了关键字,则需要重新构造新的散列函数
- 平方取中法
- 该方法取关键字的平均值的中间几位作为散列地址,具体取多少位根据实际情况而定
- 该方法得到的散列地址与关键字的每位都有关系,因此使得散列地址分布比较均匀
- 适合:关键字的每位取值都不够均匀或均小于散列地址所需的位数
解决冲突的方法
- 为产生冲突的关键字寻找下一个“空”的 Hash 地址
- 用 H i H_i Hi 表示处理冲突中第 i i i 次探测得到的散列地址
- 假设得到的另一个散列地址 H 1 H_1 H1 仍然发生冲突,只得继续求下一个地址 H 2 H_2 H2,以此类推,直到 H k H_k Hk 不发生冲突为止,则 H k H_k Hk 为关键字在表中的地址
- 开放地址法
- 采用开放地址法时,不能随便物理删除表中已有元素,否则会截断其它同义词元素的查找路径,因此,删除一个时,先做一个删除标记,进行逻辑删除。副作用为:执行多次删除后,表面上看起来散列表很满,实际上有许多位置未利用
线性探测法
- 有冲突,存储位置已经被占用,就去到下一个地方存储,直到有空的位置
- 优点:只要哈希表未被填满,保证能找到一个空地址单元存放有冲突的元素
- 缺点:可能使第 i i i 个哈希地址的同义词存入第 i + 1 i+1 i+1 个地址,这样本应存入第 i + 1 i+1 i+1 个哈希地址的元素变成了第 i + 2 i+2 i+2 个哈希地址的同义词,…,产生“聚集”现象,降低查找率
平方探测法
- 减少“聚集”现象,
- 使用数学递推公式: H i = ( H ( k e y ) + d i ) % m H_i = (H(key)+d_i) \% m Hi=(H(key)+di)%m, m m m 表示散列表表长, d i d_i di 为增量序列, d = 1 2 , − 1 2 , 2 2 , − 2 2 . . . . d=1^2 , -1^2,2^2,-2^2.... d=12,−12,22,−22....
- 有冲突时,去加入增量之后的位置看看有没有位置
- 拉链法(链接法)
- 基本思想:相同哈希地址的记录链成一单链表,m 个哈希地址就设 m 个单链表,然后用一个数组将 m 个单链表的表头指针存储起来,形成一个动态的结构
💡step1:取数据元素的关键字 key,计算其哈希地址,若该地址对应的链表为空,则将该元素插入此链表,否则执行 step2 解决冲突。
💡step2:根据选择的冲突处理方法,计算关键字 key 的下一个存储地址,若该地址对应的链表不为空,则利用链表的头插法或尾插法将该元素插入此链表。
散列表的查找性能分析
- 散列表的查找效率取决于:散列函数、处理冲突的方法和装填因子
- 装填因子:散列表的装填因子一般记为 α α α,定义为一个表的装满程度,即 α = 表中记录数 n / 散列表长度 m α=表中记录数n / 散列表长度m α=表中记录数n/散列表长度m
- 散列表的平均查找长度依赖于散列表的装填因子 α α α,而不直接依赖于 n n n 或 m m m
- α α α 越大,表示装填的记录越"满",发生冲突的可能性越大;查找时比较次数就越多;反之发生冲突的的可能性越小
小节选择题答案
序号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
答案 | D | D | D | C | A | A | A | C | C | D | A | AB |
序号 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | |
答案 | AC | C | D | D | D | A |
考题多为已知散列表长度、元素个数及散列函数和解决冲突方法后,求 ASL 或查找成功/查找失败的平均长度 #todo这类题型看视频讲解
- 图中空余题均为此类型。18 题及以后为真题
- 会受堆积现象直接影响的是:平均查找长度
- B
- 只能在顺序存储结构上进行的查找方法是:折半查找法
- 顺序查找可以是顺序存储或链式存储
- 折半查找只能是顺序存储且要求关键字有序
- 树形查找要求采用树的存储结构,既可以采用顺序存储也可以采用链式存储
- 散列查找重的链地址法解决冲突时,采用的时顺序存储与链式存储相结合的方式
- D
- K K K 个关键字在依次填入的过程中,只有第一个不会发生冲突,所以探测次数为 1 + 2 + 3 + . . . + K = K ( K + 1 ) / 2 1+2+3+...+K=K(K+1)/2 1+2+3+...+K=K(K+1)/2
- D
- 聚集是因选取不当的处理冲突的方法,而导致不同关键字的元素对对同一散列地址进行争夺的现象。用线性探测法时,容易引起聚集现象
- C #todo暂未理解
- “下一个空位”可以大于或小于但不等于原散列地址,因为原来的地址已经放了一个关键字了
- D
- 由散列函数计算知:14,1,27,29 散列后的地址都是 1,故有 4 个记录
14-16
✔️ 解决
14. A
-
C
-
B
20-21
- 查找成功的平均查找长度:查找成功查的是元素
- 查找失败的平均查找长度:查找失败查的是位置
- C #todo删除后查找失败的平均长度
- 删除关键字后,查找失败的平均查找长度
- 删除后,打一个标志位,相当于还有一个数在