数据结构——四十一、分块查找(索引顺序查找)(王道408)

文章目录

前言

分块查找算法是一种结合顺序查找和索引查找的搜索方法。其核心思想是将无序元素分成若干有序块,建立索引表存储各块最大值和区间范围。查找时先通过顺序或折半方式定位索引块,再在该块内进行顺序查找。算法特点包括块内无序、块间有序。查找效率分析表明,当块数为√n时,顺序查找索引表可获得最优ASL(√n+1),而折半查找索引表则使ASL为⌈log₂(b+1)⌉+(s+1)/2。对于动态查找表,采用链式存储能有效提升插入/删除效率。该算法在特定数据分布下能显著提高查找性能。

一.分块查找的算法思想

1.算法思想

  1. 看似没有规律的元素,可以将他们分至一个个小区间,第一个区间内都是≤10的元素,第二个区间是≤20的元素,第三个区间是≤30的,以此类推
  2. 所以我们看虽然这个数组当中的某一小个部分看起来是乱序的,但是当我们把它分成一块一块的小区间之后,会发现各个区间之间其实是有序的
  3. 那我们可以给这个查找表,建立上一级的索引,"索引表"中保存每个分块的最大关键字和分块的存储区间

2.特点

  • 块内无序、块间有序

3.代码定义

c 复制代码
//索引表
typedef struct {
	ElementType maxValue;// 最大的关键字
	int low, high;// 分块的区间范围
}Index;

//顺序表存储实际元素
ElementType List[100];

二.顺序查找查索引

  • 假设要查找的关键字是22
  1. 首先我们可以先查找这个索引表,从索引表的第一个元素开始依次往后找
  2. 那第一个元素10<22,所以肯定是在下一个分块内
  3. 20<22,所以还得往后找,第三个分块30是≥22的,所以如果22存在的话那么肯定是在30所指向的这个分块内
  4. 因此接下来就从这个方块的起始位置6开始查找
  5. 那6号元素不满足,所以往后找一位,接下来7号元素刚好22和我们要找的关键词是相等的,那到此为止就查找成功
  6. 如果这分块内的所有元素都和查找目标不同,那么说明查找失败

三.用折半查找查索引

1.查找成功

  • 假设查找目标为30
  1. 那根据这个折半查找的规则,我们要在索引表的开头和末尾这两个元素之间尝试找到30这个关键字,那么mid等于low加high除以二,所以刚开始mid所指向的这个元素刚好就是30
  2. 30指向的分块是从6开始,所以接下来会从6号元素开始往后依次的对比,那一直找到8号元素的时候查找成功

2.索引查找失败

1.给出关键字在索引表范围内

1.过程
  • 假设查找目标为19
  1. 和之前一样,mid指向low和high的中间位置
  2. 19<30,所以我们应该让high等于mid-1,接下来low加high除以2,那mid就应该是指向0这个位置
  3. 19>10,所以接下来我们应该让low等于mid+1同时mid等于low加high除以2
  4. 19<20,high = mid - 1,现在low已经大于high了,所以按照折半查找的规则,查找应该失败了,但是其实我们的19应该在在low所指向的分块中
  5. 所以接下来应该在low所指的分块当中来查找
  6. 接下来的操作和之前查找成功的操作一致
2.结论
  • 若索引表中不包含目标关键字,则折半查找索引表最终停在 low>high ,要在low所指分块中查找

原理:折半查找失败,最后low大于high,但是在low大于high之前的那一步,肯定是low等于high,所以如果往回退一步的话.mid和low,high肯定是指向同一个位置

此时有可能发生两种情况 k e y 是查找的目标关键字 ; m i d = { < k e y , l o w + + ① > k e y , h i g h − − ② ; \begin{aligned}key是查找的目标关键字;\\mid = \begin{cases}<key,&low++①\\>key,&high--②;\end{cases}\end{aligned} key是查找的目标关键字;mid={<key,>key,low++①high−−②;

在情况1中,low在进行自增1的操作后一定比key大

在情况2中,high自减1而low不变

所以最终low大于high的时候,low这个指针所指向的位置的这个关键字肯定是要大于key

由于在分块查找的时候,我们总是找当前分块索引比目标关键字大的元素,因此可以在low指向分块进行查找

2.目标关键字超出索引范围

  • 折半查找的过程和之前一样,最终结果是low超出了索引表范围,因此查找失败

四.查找效率分析(ASL)

1.一般情况

一般不考

1.分析过程

  1. 共有14个元素,各自被查概率为1/14
  2. 若索引表采用顺序查找,则7:2次、10:3次、13:3次...
  3. 若索引表采用折半查找,则30:4次
    A S L = ∑ i = 1 n P i C i ASL=∑_{i = 1}^{n}P_iC_i ASL=i=1∑nPiCi

查找失败的情况更复杂...一般不考

2.特殊情况

1.分析过程

  • 假设,长度为n的查找表被均匀地分为b块,每块s个元素

2.结论

1.总体结论
  • 设索引查找和块内查找的平均查找长度分别为 L 1 、 L 2 L_{1}、L_{2} L1、L2,则分块查找的平均查找长度为
    A S L = L 1 + L 2 ASL=L_{1}+L_{2} ASL=L1+L2
2.用顺序查找索引表

L I = ( 1 + 2 + ... + b ) b = b + 1 2 , L S = ( 1 + 2 + ... + s ) s = s + 1 2 ; 则 A S L = b + 1 2 + s + 1 2 = s 2 + 2 s + n 2 s 所以当 s = n 时, A S L 最小 = n + 1 ① \begin{aligned}&L_{I}=\frac{(1+2+\dotsc +b)}{b}=\frac{b+1}{2},\\&L_{S}=\frac{(1+2+\dotsc +s)}{s}=\frac{s+1}{2}; \\&则ASL=\frac{b+1}{2}+\frac{s+1}{2}=\frac{s^{2}+2s+n}{2s}\\&所以当s=\sqrt{n}时,ASL_{\text{最小}}=\sqrt{n}+1①\end{aligned} LI=b(1+2+...+b)=2b+1,LS=s(1+2+...+s)=2s+1;则ASL=2b+1+2s+1=2ss2+2s+n所以当s=n 时,ASL最小=n +1①

  • 最优ASL方案 :式子①的意义在于把n个元素分为 n \sqrt{n} n 块,那么而每一个分块内有 n \sqrt{n} n 个元素,在这种情况下,可以保证ASL取得最小的值
3.用折半查找查索引表

则 L I = ⌈ log ⁡ 2 ( b + 1 ) ⌉ , L S = ( 1 + 2 + ⋯ + s ) s = s + 1 2 则ASL = ⌈ log ⁡ 2 ( b + 1 ) ⌉ + s + 1 2 \begin{aligned}&则L_{I}=\left\lceil\log_{2}(b+1)\right\rceil,\\&L_S=\frac{(1+2+\cdots+s)}{s}=\frac{s+1}{2}\\ &则\text{ASL}=\left\lceil\log_{2}(b+1)\right\rceil +\frac{s+1}{2}\end{aligned} 则LI=⌈log2(b+1)⌉,LS=s(1+2+⋯+s)=2s+1则ASL=⌈log2(b+1)⌉+2s+1

五.知识回顾与重要考点

六.拓展思考

  • 若查找表是"动态查找表",有没有更好的实现方式?
    答:现在如果这个查找表当中,经常需要进行元素的啊增加或者删除,比如现在我想要增加一个元素,这个元素的值是8,因为我们必须保证块间是有序的,所以如果我们要插入8这个数据,那我们只能在第一个分块内找一个位置插入.
    那就会导致我们需要把后面的所有元素全部后移一位,就会浪费大量的时间
    那么,解决方式就是链式存储,时间复杂度会显著降低

结语

一更😉
如果想查看更多章节,请点击:一、数据结构专栏导航页

相关推荐
蒙奇D索大2 小时前
【计算机网络】[特殊字符] 408高频考点 | 数据链路层组帧:从字符计数到违规编码,一文学透四大实现方法
网络·笔记·学习·计算机网络·考研
遇印记2 小时前
蓝桥java蜗牛
java·学习·蓝桥杯
xier_ran2 小时前
深度学习:RMSprop 优化算法详解
人工智能·深度学习·算法
地平线开发者2 小时前
不同传感器前中后融合方案简介
算法·自动驾驶
地平线开发者2 小时前
征程 6X 常见 kernel panic 问题
算法·自动驾驶
格鸰爱童话2 小时前
next.js学习——react入门
学习·react.js·node.js
B0URNE2 小时前
【Unity基础详解】Unity3D全程学习路线
学习·unity·游戏引擎
com_4sapi3 小时前
2025 权威认证头部矩阵系统全景对比发布 双榜单交叉验证
大数据·c语言·人工智能·算法·矩阵·机器人