首页 > 其他分享 >线性结构查找(顺序、折半、分块)

线性结构查找(顺序、折半、分块)

时间:2024-08-10 22:25:58浏览次数:14  
标签:折半 结点 顺序 分块 元素 关键字 查找

对于线性结构的查找,应掌握其查找的过程、构造判定树、分析平均查找长度等。

一、顺序查找

顺序查找又称线性查找,它对顺序表和链表都是适用的。对于顺序表,可通过数组下标递增来顺序扫描每个元素;对于链表,可通过指针 next 来依次扫描每个元素。
顺序查找通常分为对一般的无序线性表的顺序查找和对按关键字有序的线性表的顺序查找。
顺序查找缺点 :当 n 较大时,平均查找长度较大,效率低;
顺序查找优点 :对数据元素的存储没有要求,顺序存储或链式存储皆可。对表中记录的有序性也没有要求,无论记录是否按关键字有序,均可应用。同时还需注意,对线性的链表只能进行顺序查找。

1. 一般线性表的顺序查找

1)无序顺序查找的基本思想

① 从线性表的一端开始,逐个检查关键字是否满足给定的条件;
② 若查找到某个元素的关键字满足给定条件,则查找成功,返回该元素在线性表中的位置;
③ 若已经查找到表的另一端,但还没有查找到符合给定条件的元素,则返回查找失败的信息。

2)无序顺序查找的算法代码

typedef struct{	//查找表的数据结构:顺序表
    ElemType *elem;	//动态数组基址
    int TableLen;	//表的长度
}SSTable;
int Search_Seq(SSTable ST, ElemType key){
    ST.elem[0] = key;	//“哨兵”,其关键字赋值为要查找的元素值
    for(int i = ST.TableLen; ST.elem[i] != key; --i);	//从后往前找
    return i;	//查找成功则返回元素下标,查找失败则返回哨兵的位置,即0
}

【引入“哨兵”可以避免很多不必要的判断语句,从而提高程序效率。】

3)无序顺序查找成功与失败的平均查找长度

平均查找长度:在查找过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字的比较次数的平均值。平均查找长度是衡量查找算法效率的最主要的指标。

对于有 n 个无序元素的线性表,假设每个元素的查找概率相等:
① 查找成功时,ASL成功 = (1 + 2 + … + n) / n = (n + 1) / 2
② 查找不成功时,与表中各关键字的比较次数显然是 n + 1 次,即 ASL不成功n + 1

为什么查找不成功时,比较次数是 n + 1,而非 n ?

答:是因为我们在含有 n 个元素的表的表头(或表尾)加入了一个“哨兵”,从而表长变为 n + 1。将“哨兵”的关键字赋值为要查找的元素值,故在加入了“哨兵”的表中查找元素一定会成功(与关键字比较次数最多为 n + 1 次),并返回元素查找成功时所在表中的位置。若返回的位置的值为 0(“哨兵”在表尾:为 n),可以得出查找失败。加入“哨兵”的好处是不需要考虑判断数组下标越界的问题,如果没有“哨兵”,则会产生更多的比较次数。

【通常,查找表中记录的查找概率并不相等。若能预先得知每个记录的查找概率,则应先对记录的查找概率进行排序,使表中记录按查找概率由大至小重新排列。】

2. 有序线性表的顺序查找

1)有序顺序查找的基本思想

若在查找之前就已经知道表的关键字是有序的,则查找失败时可以不用再比较到表的另一端就能返回查找失败的信息,从而 降低顺序查找失败的平均查找长度

假设表 L 是按关键字从小到大排列的,查找的顺序是从前往后,待查找元素的关键字为 key 。当查找到第 i 个元素时,发现第 i 个元素对应的关键字小于 key,但第 i + 1 个元素对应的关键字大于 key,这时就可返回查找失败的信息。因为第 i 个元素之后的元素的关键字均大于 key,所以表中不存在关键字为 key 的元素。

2)有序顺序查找成功与失败的平均查找长度

可以下图所示的 判定树 来描述有序线性表的查找过程。
① 树中的圆形结点表示有序线性表中存在的元素;
② 树中的矩形结点称为失败结点(若有 n 个结点,则有 n + 1 个查找失败结点),它描述的是那些不在表中的数据值的集合。
若查找到失败结点, 则说明查找不成功。

① 在有序线性表的顺序查找中,查找成功的平均查找长度和一般线性表的顺序查找一样。
② 查找失败时,查找指针一定走到了某个失败结点。这些失败结点是我们虚构的空结点,实际上是不存在的,所以到达失败结点时所查找的长度等于它上面的一个圆形结点的所在层数。
假设每个元素的查找概率相等,则查找不成功的平均查找长度为:
ASL不成功 = (1 + 2 + … + n + n) / (n + 1) = (n / 2) + (n / (n + 1))

【注:有序线性表的顺序查找和折半查找的思想是不一样的,且有序线性表的顺序查找中的线性表可以是链式存储结构。】

3. 有关线性查找的例题

① 顺序查找适合于存储结构为( A )的线性表。
A. 顺序存储结构或链式存储结构
B. 散列存储结构
C. 索引存储结构
D. 压缩存储结构

② 由 n 个数据元素组成的两个表:一个递增有序,一个无序。采用顺序查找算法,对有序表从头开始查找,发现当前元素已不小于待查元素时,停止查找,确定查找不成功,已知查找任意一个元素的概率是相同的,则在两种表中成功查找( B )。
A. 平均时间后者小
B. 平均时间两者相同
C. 平均时间前者小
D. 无法确定

③ 对长度为 3 的顺序表进行查找, 若查找第一个元素的概率为1/2,查找第二个元素的概率为1/3,查找第三个元素的概率为1/6,则查找任意一个元素的平均查找长度为( A )。
A. 5/3
B. 2
C. 7/3
D. 4/3

二、折半查找

折半查找又称二分查找,它仅适用于有序的顺序表。因为折半查找需要方便地定位查找区域,所以它要求线性表必须具有随机存取的特性,因此,该查找法仅适合于顺序存储结构,不适合于链式存储结构,且要求元素按关键字有序排列。

1. 折半查找的基本思想

1)首先将给定值 key 与表中中间位置的元素进行比较,若相等,则查找成功,返回该元素的存储位置;
2)若不等,则所需查找的元素只能在中间元素以外的前半部分或后半部分(例如,在查找表升序排列时,若给定值 key 大于中间元素,则所查找的元素只可能在后半部分)。然后缩小范围继续进行同样的查找。
3)如此重复,直到找到为止,或确定表中不存在所需要查找的元素,则查找不成功,返回查找失败的信息。

2. 折半查找的算法代码

int Binary_Search(SSTable L, ElemType key){
    int low = 0, high = L.TableLen - 1, mid;
    while(low <= high){
        mid = (low + high) / 2;	//取中间位置
        if(L.elem[mid] == key){return mid;}	//查找成功,返回所在位置
        else if(L.elem[mid] > key){high = mid - 1;}	//从前半部分继续查找
        else{low = mid + 1;}	//从后半部分继续查找
    }
    return -1;	//查找失败,返回-1
}

当折半查找算法选取中间结点时,既可以采用向下取整,也可以采用向上取整。但每次查找的取整方式必须相同。

3. 折半查找成功与失败的平均查找长度

折半查找的过程可用下图所示的二叉树来描述,称为 判定树
1)树中每个圆形结点表示一个记录,结点中的值为该记录的关键字值;
2)树中的叶结点都是矩形的,它表示查找不成功的情况。
从判定树可以看出,查找成功时的查找长度为从根结点到目的结点的路径上的结点数,而查找不成功时的查找长度为从根结点到对应失败结点的父结点的路径上的结点数。
每个结点值均大于其左子结点值,且均小于其右子结点值。若有序序列有 n 个元素,则对应的判定树有 n 个圆形的非叶结点和 n + 1 个矩形的叶结点。显然,判定树是一棵 平衡二叉树

假设每个元素的查找概率相等,则上图所示的判定树中:
ASL成功 = (1 × 1 + 2 × 2 + 3 × 4 + 4 × 4) / 11 = 33 / 11 = 3;
ASL失败 = (3 × 4 + 4 × 8) / 12 = 44 / 12 = 11 / 3。

4. 有关折半查找的例题

① 【2010 统考真题】已知一个长度为16 的顺序表 L,其元素按关键字有序排列,若采用折半查找法查找一个 L 中不存在的元素,则关键字的比较次数最多是( B )。
A. 4
B. 5
C. 6
D. 7

② 【2015 统考真题】下列选项中,不能构成折半查找中关键字比较序列的是( A )。
A. 500, 200, 450, 180
B. 500, 450, 200, 180
C. 180, 500, 200, 450
D. 180, 200, 500, 450

③ 【2017 统考真题】下列二叉树中,可能成为折半查找判定树(不含外部结点)的是( A )。

④ 【2023 统考真题】对含 600 个元素的有序顺序表进行折半查找,关键字间的比较次数最多是( B )。
A. 9
B. 10
C. 30
D. 300

三、分块查找

分块查找又称索引顺序查找,它吸取了顺序查找和折半查找各自的优点,既有动态结构,又适于快速查找。

1. 分块查找的基本思想

将查找表分为若干子块。块内的元素可以无序,但块间的元素是有序的 。即第一个块中的最大关键字小于第二个块中的所有记录的关键字,第二个块中的最大关键字小于第三个块中的所有记录的关键字,以此类推。再建立一个索引表,索引表中的每个元素含有各块的最大关键字和各块中的第一个元素的地址,索引表按关键字有序排列。

分块查找的过程分为两步:
第一步是在索引表中确定待查记录所在的块,可以顺序查找或折半查找索引表;
第二步是在块内顺序查找。

例如,关键码集合为 {88, 24, 72, 61, 21, 6, 32, 11, 8, 31, 22, 83, 78, 54} ,按照关键码值 24, 54, 78, 88,分为 4 个块和索引表,如下图所示:

2. 分块查找成功与失败的平均查找长度

分块查找的平均查找长度为索引查找和块内查找的平均长度之和。
设索引查找和块内查找的平均查找长度分别为 LI 和 LS,则分块查找的平均查找长度为:
ASL = LI + LS

将长度为 n 的查找表均匀地分为 b 块,每块有 s 个记录,在等概率情况下,若在块内和索引表中均采用顺序查找,则平均查找长度为:
ASL = LI + LS = (b + 1) / 2 + (s + 1) / 2 = (s2 + 2s + n) / 2s
此时,若 s = n1/2,则平均查找长度取最小值 n1/2 + 1 。

虽然索引表占用了额外的存储空间,索引查找也增加了一定的系统开销,但由于其分块结构,使得在块内查找时的范围较小,因此与顺序查找相比,分块查找的总体效率提升了不少。

3. 有关分块查找的例题

① 采用分块查找时,数据的组织方式为( B )。
A. 数据分成若干块,每块内数据有序
B. 数据分成若干块,每块内数据不必有序,但块间必须有序,每块内最大(或最小)的数据组成索引块
C. 数据分成若干块,每块内数据有序,每块内最大(或最小)的数据组成索引块
D. 数据分成若干块,每块(除最后一块外)中数据个数需相同

② 对有 2500 个记录的索引顺序表(分块表)进行查找,最理想的块长为( A )。
A. 50
B. 125
C. 500
D. ⌈log22500⌉

③ 设顺序存储的某线性表共有 123 个元素,按分块查找的要求等分为 3 块。若对索引表采用顺序查找法来确定子块,且在确定的子块中也采用顺序查找法,则在等概率情况下,分块查找成功的平均查找长度为( B )。
A. 21
B. 23
C. 41
D. 62

④ 为提高查找效率,对有 65025 个元素的有序顺序表建立索引顺序结构,在最好情况下查找到表中已有元素最多需要执行( C )次关键字比较。
A. 10
B. 14
C. 16
D. 21

标签:折半,结点,顺序,分块,元素,关键字,查找
From: https://blog.csdn.net/weixin_49272453/article/details/140972113

相关文章

  • 树形结构查找(B树、B+树)
    平衡树结构的树高为O(logn),平衡树结构包括两种平衡二叉树结构(分别为AVL树和RBT)以及一种树结构(B-Tree,又称B树,它的度大于2)。AVL树和RBT适合内部存储的应用,而B树适合外部存储的应用。对于B树,应掌握其查找、插入以及删除的操作过程,对于B+树(一种B树的变形树......
  • Java--String类查找方法
    目录1.indexOf(Stringstr)2.indexOf(Stringstr,intfromIndex)3.lastIndexOf(Stringstr)4.lastIndexOf(Stringstr,intfromIndex)5.contains(CharSequences)6.startsWith(Stringprefix)7.endsWith(Stringsuffix)booleanequalsStringtrim在Java中,String类提供了......
  • 黑马Java零基础视频教程精华部分_15_基本查找/顺序查找、二分查找/折半查找、插值查找
    系列文章目录文章目录系列文章目录一、基本查找/顺序查找核心思想:从0索引开始挨个往后查找代码:练习:定义一个方法利用基本查找,查询某个元素在数组中的索引,数组包含重复数据。二、二分查找/折半查找核心思想:属于有序查找算法。用给定值先与中间结点比较,每次排除一半的......
  • DFS查找依赖路径
    背景:有如下场景://定义结构体dep,表示Src依赖DependtypedepModelstruct{Srcstring`json:"src"`//源Dependstring`json:"depend"`//依赖}//示例输入deps:=[]depModel{{"A","B"},{"A......
  • 数据结构 分块 & 莫队
    分块一种优化暴力的思想。通常是将原数据划分成适当块(一般为\(\sqrt{n}\)),对每块数据进行预处理,进而达到比暴力更优的时间复杂度。划分确定块长后,一般需要开两个数组存储每一块的右边界与原数据所属块序号,更加方便后续操作。intsq=sqrt(n);for(inti=1;i<=sq;i++)ed[i]=n/......
  • 清晰易懂二分查找算法 你确定不看吗?
    @目录前言简介一、二分查找算法的原理是什么?1.确定搜索范围:2.计算中间位置:3.比较中间元素:4.调整搜索范围:5.重复迭代:二、二分查找算法的优缺点是什么?优点:缺点:三、java实现二分查找案例总结前言请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i、提示:以下是本篇文......
  • 分块
    写在前面非常简单的分块,使我开心的转圈,稍微看了一下oiwiki就懂了,妈妈再也不用担心我的暴力了正文分块,非常优雅的暴力,本质是上是通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。例如(博客萌新好不容易整的):\[\begin{......
  • 《Advanced RAG》-05-探索语义分块(Semantic Chunking)
    摘要文章首先介绍了语义分块在RAG中的位置和作用,并介绍了常见的基于规则的分块方法。然后,阐述了语义分块的目的是确保每个分块包含尽可能多的独立语义信息。接着,文章分别介绍了三种语义分块方法的原理和实现方法,并对每种方法进行了总结和评估。文章观点语义分块是R......
  • PTA 6-13 折半查找
    6-13折半查找(15分)给一个严格递增数列,函数intSearch_Bin(SSTableT,KeyTypek)用来二分地查找k在数列中的位置。函数接口定义:int Search_Bin(SSTableT,KeyTypek)其中T是有序表,k是查找的值。裁判测试程序样例:#include<iostream>usingnamespacestd;#define......
  • 查找分层股东关系:在 python 中重构嵌套 if
    我想找到公司之间的股东关系。在下面的示例中,“人员1”直接拥有“公司1”50%的股份,那么需要检查“公司1”是否也拥有其他公司的股份。“公司1”拥有“公司2”50%的股份,“公司3”拥有20%的股份。这意味着“人员1”间接拥有“公司2”和“公司3”的部分股份。此......