各种结构的查找

查找的概念

线性表的定义:

查找表:是由一组记录组成的表或文件,而每个记录由若千个数据项组成,并假设每个记录都有一个能唯- -标识该记录的关键字。
在这里插入图片描述
内查找和外查找:

若整个查找过程都在内存进行,则称之为内查找;反之,若查找过程中需要访问外存,则称之为外查找。

查找方法的性能指标:
查找运算时间主要花费在关键字比较上,通常把查找过程中执行的关键字平均比较次数(也称为平均查找长度)作为衡量一个查找算法效率优劣的标准。
ASL越大,其时间性能越差。平均查找长度ASL (Average Search Length)定义为:
在这里插入图片描述
其中,n是查找表中记录的个数。p;是查找第i个记录的概率,一般地,认为每个记录的查找概率相等,即p;=1/n (1≤i≤n),c;是找到第i个记录所需进行的比较次数。

通俗来讲,即将所有结点都查找一遍的次数之和÷查找结点的个数

平均查找长度分为
◎成功情况下的平均查找长度
◎不成功情况(失败)下的平均查找长度。

线性表的查找

线性表查找的主要方法有以下3种:

顺序查找

思路:从表的一端开始,顺序扫描线性表,依次将扫描到的关键字和给定值k相比较:
在这里插入图片描述
若当前扫描到的关键字与k相等,则查找成功;若扫描结束后仍未找到关键字等于k的记录,则查找失败。

➊成功情况下的平均查找长度ASL
查找到表中第i个记录R[i-1]时,需比较i次。因此成功时的顺序查找的平均查找长度为:

在这里插入图片描述
查找成功时的平均比较次数约为表长的一半。

❷不成功情况下的平均查找长度ASL
查找不成功情况时需要和表中所有元素都比较一次,所以,不成功时的平均查找长度为n。

可以看到顺序查找的时间复杂度为O(n)。

二分查找

折半查找也称为二分查找,要求线性表中的记录必须己按关键字值有序(递增或递减)排列。

在这里插入图片描述
二分查找过程可用二叉树来描述:
◎把当前查找区间的中间位置上的记录作为根;
◎左子表和右子表中的记录分别作为根的左子树和右子树。

这样的二叉树称为判定树或比较树。

在这里插入图片描述
外部节点即查找失败对应的节点,是虚拟的
n个关键字:内部节点为n个,外部节点为n+1个

例:对于给定11个数据元素的有序表{2,3,10,15,20,25,28,29,30,35,40}, 采用二分查找,试问:
假设查找表中每个元素的概率相同,求查找成功时的平均查找长度和查找不成功时的平均查找长度。

成功二分查找:恰好是走了一条从判定树的根到被查记录的路径,经历比较的关键字次数恰为该记录在树中的层数。

在这里插入图片描述
查找成功时,会找到图中某个内部结点:
在这里插入图片描述
则成功时的平均查找长度:
在这里插入图片描述
不成功二分查找:比较过程经历了一条从判定树根到某个外部节点的路径,所需的关键字比较次数是该路径上内部节点的总数。
在这里插入图片描述
查找不成功时,会找到图中某个外部结点:
在这里插入图片描述
则不成功时的平均查找长度:

在这里插入图片描述
这里要注意的是:查找的是外部结点,即将查找所有外部结点次数÷外部结点数

在等概率假设下,二分查找成功时的平均查找长度为:
在这里插入图片描述
对于n个元素,二分查找,成功时最多的关键字比较次数为:log₂(n+1) ;不成功时关键字比较次数为:log₂(n+1) 。(这里查找的最大次数即树的高度:h=log₂(n+1) )

二分查找的时间复杂度为O(log₂n)。

分块查找

1、索引存储结构
索引存储结构=数据表+索引表
索引表中的每一项称为索引项,索引项的一般形式是:
(关键字,地址)
关键字唯一标识一个节点,地址作为指向该关键字对应节点的指针,也可以是相对地址。
在这里插入图片描述
2、分块查找
在这里插入图片描述
每一块中的关键字不一当有序,但前一块的最大关键字必须小于后一块的最小关键字,即要求整个表是分块有序的。

例,设有一个线性表,其中包含25个记录,其关键字序列为:8, 14, 6,9, 10, 22, 34,18,19, 31, 40, 38, 54, 66,46,71, 78, 68, 80, 85,100,94,88,96, 87
分块:将n=25个记录分为b=5块,每块中有s=5个记录。
数据特性:
在这里插入图片描述

即先通过索引表找地址,然后通过地址找到数据表的数据。

分块查找演示:
查找关键字赋值为k=80的记录
在这里插入图片描述
依次将k和索引表中各关键字比较,直到找到第一个关键字大于等于k的元素,所以我们可以看到k若存在,一定在第4块中。然后通过索引表的地址找到第4块,最后在第4块中进行查找。

查找方法:
◎索引表(有序) :可以顺序查找块,也可以二分查找块。
◎数据表(无序) :只能顺序查找块中元素。

可以看到,在索引表的查找有两种方法:
若以二分法来确定元素所在的块:
(n代表元素个数,s代表每块中元素个数,b(n/s)代表有几块)
ASL总=ASL索引+ASL数据
=log₂(b+1)-1+(s+1)/2

若以顺序查找来确定元素所在的块:
ASL总=ASL索引+ASL数据
=(b+1)/2+(s+1)/2
=(n/s+s)/2+1
显然当s=n½时,ASL总最小为n½+1,即当s=n½时,用顺序查找确定块中元素个数效果最佳。

二叉排序树

二叉排序树(简称BST)又称二叉查找(搜索)树,其定义为:二叉排序树或者是空树,或者是满足如下性质(BST性质) 的二叉树:
➊若它的左子树非空,则左子树上所有节点值(指关键字值)均小于根
节点值;
❷若它的右子树非空,则右子树上所有节点值均大于根节点值;
❸左、右子树本身又各是一棵二叉排序树。
注意:二叉排序树中没有相同关键字的节点。
从它的特性可以看出:
根节点的最左下节点是关键字的最小节点;根节点的最右下节点是关键字的最大节点

1、二叉排序树上的查找

二叉排序树可看做是一个有序表,所以在二叉排序树上进行查找,和二分查找类似,也是一个逐步缩小查找范围的过程。
在这里插入图片描述
[例]已知一组关键字为{25,18,46, 2, 53,39, 32, 4,74, 67,60,11}。
按表中的元素顺序依次插入到一棵初始为空的二叉排序树中,画出该二叉排序树。
求在等概率的情况下查找成功的平均查找长度和查找不成功的平均查找长度。
在这里插入图片描述
所谓创建过程就是将大于根节点的往右子树放,小于的往左子树放

查找成功:
在这里插入图片描述
查找失败:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200612005942834.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLm

2、二叉排序树的节点删除

(1)被删除的节点是叶子节点:直接删去该节点。
在这里插入图片描述
在这里插入图片描述
其双亲节点中相应指针域的值改为“空”

(2) 被删除的节点只有左子树或者只有右子树,用其左子树或者右子树替换它(节点替换)
在这里插入图片描述在这里插入图片描述
其双亲节点的相应指针域的值改为:“指向被删除节点的左子树或右子树”。

(3)被删除的节点既有左子树,也有右子树

在这里插入图片描述
在这里插入图片描述
20 30 32 35 40 50 80 85 88 90
以其**中序前趋值替换之(值替换)**即40,然后再删除该前趋节点。前趋是左子树中最大的节点。
也可以用其后继替换之即80,然后再删除该后继节点。后继是右子树中最小的节点。

平衡二叉树

1、什么是平衡二叉树

若一棵二叉树中 每个节点的左、右子树的高度至多相差1,则称.此二叉树为平衡二叉树(AVL)
平衡因子:该节点左子树的高度减去右子树的高度。
若一棵二叉树中所有节点的平衡因子的绝对值小于或等于1,该二叉树称为平衡二叉树。
一般情况下,一颗平衡二叉树总是二叉排序树

2、平衡二叉树的插入调整

平衡二叉树中插入新节点方式与二叉排序树相似,只是插入后可能破坏了平衡二叉树的平衡性,解决方法是调整。调整操作可归纳为4种情况。
我们记A为第一个节点,B为第二个节点,C为第三个节点。
在这里插入图片描述
(1) LL型调整

在这里插入图片描述(2) RR型调整

在这里插入图片描述
在这里插入图片描述
可以看到LL和RR调整是对称的,它们的调整方法是:从插入方向往根节点求平衡因子,当平衡因子出现2时(即A出现变化),将它前面的结点(B)往上拎成为它的双亲结点

(3) LR型调整
在这里插入图片描述
(4)RL型调整
在这里插入图片描述在这里插入图片描述
可以看出LR调整和RL调整是对称的,它们的调整方法是:从插入方向往根节点求平衡因子,当平衡因子出现2时(即A出现变化),将它前面两个的结点(C)往上拎成为它的双亲结点。然后就是LR调整和RL调整的区别:
C的原左子树作为B的右子树,原右子树作为A的左子树(LR)
C的原左子树作为A的右子树,原右子树作为B的左子树(RL)
其实就是将C空出来的子树补给A和B

平衡二叉树的构造:
[例9]输入关键字序列{16, 3, 7,11, 9,26,18, 14,15}, 给出构造一棵AVL树的步骤。
在这里插入图片描述
。。。。。。。。

在这里插入图片描述
其实平衡二叉树的构造就是边加元素,边进行调整

3、平衡二叉树的查找

在平衡二叉树上进行查找的过程和在二叉排序树上进行查找的过程完全相同,因此在平衡二叉树上进行查找关键字的比较次数不会超过平衡二叉树的高度。
构造一系列的平衡二叉树T1,T2,T3…其中,Tn表示高度为h且节点数尽可能少的平衡二叉树,下图所示的T1,T2,T3,T4和Th。
在这里插入图片描述
这是节点个数最少的平衡二叉树

设N(h)为T,的节点数,从图中可以看出有下列关系成立:
N(1)=1,N(2)=2,N(h)=N(h-1)+N(h-2)+1
当h>1时,此关系类似于定义Fibonacci数的关系:
F(1)=1,F(2)=1, F(h)=F(h-1)+F(h-2)

通过检查两个序列的前几项就可发现两者之间的对应关系:
N(h)=F(h+2)-1
在这里插入图片描述在这里插入图片描述
含有n个节点的平衡二叉树的平均查找长度为O(logn)。

B-树和B+树

B-树

1、B-树的定 义

在这里插入图片描述
一棵m阶B-树或者是一棵空树,或者是满足要求的m叉树:
➊树中每个节点至多有m个孩子节点(即至多有m-1个关键字)
最多关键字个数Max=m-1。

一棵m阶B-树或者是一棵空树,或者是满足要求的m叉树:
❷除根节点外,其他非叶子节子点至少有(m/2)个孩子节点 (即至少有
(m/2)-1= (m-1)/2个关键字) ;
最少关键字个数Min=m/2-1

一棵m阶B-树或者是一棵空树,或者是满足要求的m叉树:
❸若根节点不是叶子节点,则根节点至少有两个孩子节点;
一棵m阶B-树或者是一棵空树,或者是满足要求的m叉树:

❹每个节点的结构如下,
节点中按关键字大小顺序排列:
在这里插入图片描述其中,n为该结点中关键字个数,kn为该结点的关键字,pn为该结点的孩子指针,pn所指子树上结点的关键字均大于kn小于kn+1

一棵m阶B-树或者是一棵空树,或者是满足要求的m叉树:
❺所有外部节点都在同一层上。B-树是所有节点的平衡因子均等于0的多路查找树。
在计算B-树的高度时,需要计入最底层的外部节点

2、B-树的查找

将k与根节点中的key[i]进行比较:
➊若k=key[i],则查找成功;
❷若k<key[1],则沿着指针ptr[0]所指的子树继续查找;
❸若key[i]<k<key[i+1],则沿着指针ptr[i]所指的子树继续查找;
❹若k>key[n],则沿着指针ptr[n]所指的子树继续查找。
在这里插入图片描述

3、B-树的插入

在某个叶子节点中插入关键字分两种情况:
➊插入节点有空位置,即关键字个数n<m-1:直接把关键字k有序插入到该节点的合适位置上。
❷插入节点没有空位置,即原关键字个数n=m-1,则分裂。

在这里插入图片描述
◎如果没有双亲节点,新建一个双亲节点,树的高度增加一层。
◎如果有双亲节点,将ki插入到双亲节点中。
◎若插入双亲节点后关键字个数也超过Max,继续分裂。
在插入时,注意结点关键字个数是否超过Max

[例9]关键字序列为:{1,2,6,7,11,4,8,13,10,5,17,9,16,20,3,12,14,18,19,15}。创建一棵5阶B-树。

在这里插入图片描述
在这里插入图片描述
此时插入11,结点关键字个数变成5,故需分裂,将插入后的序列按升序排列,从中间位置把关键字分为2份,中间位置的关键字放到双亲结点(若没有则新建一个)中。
在这里插入图片描述
在这里插入图片描述
。。。。。。。。

在这里插入图片描述在这里插入图片描述
当插入关键字15后,分裂,将13放入双亲结点,其余关键字分为两份。可以看到此时双亲结点个数超过Max,故将双亲结点分裂,将10放入一个新的双亲结点,其余的关键字分为两份。

4、B-树的删除

删除关键字k分两种情况:
◎在叶子节点层上删除关键字k。
◎在非叶子节点层上删除关键字k。
在进行删除时,注意结点关键字是否小于Min=(m/2)-1

  1. 在非叶子节点上删除关键字k转换为在叶子节点.上删除关键字“k”
    在这里插入图片描述
    在这里插入图片描述
    可以看到删除13后,非叶子结点关键字个数小于Min,将删除结点所指子树(左子树)中最大关键字12代替删除结点的位置。
    当删除结点所指子树为右子树时,将该子树中最小关键字代替删除结点的位置。

  2. 在B-树的叶子节点b上删除关键字共有以下3种情况:
    ➊假如b节点的关键字个数大于Min,说明删去该关键字后该节点仍满足B-树的定义,则可直接删去该关键字。
    在这里插入图片描述
    ❷假如b节点的关键字个数等于Min,说明删去关键字后该节点将不满足B-树的定义。若可以从兄弟节点借。
    在这里插入图片描述
    从这里可以看到,删除15后,左兄弟结点关键字个数小于Min,此时从右兄弟结点最小的关键字18上移到双亲结点,然后将双亲结点中小于上移结点的那个关键字17下移到要删除结点中。
    当进行删除操作后,若右兄弟结点关键字个数小于Min,此时从左兄弟结点最大的关键字上移到双亲结点,然后将双亲结点中大于上移结点的那个关键字下移到要删除结点中。

    ❸假如b节点的关键字个数等于Min,说明删去关键字后该节点将不满足B-树的定义。若不能从兄弟节点借。
    在这里插入图片描述
    此时要把删除关键字的结点与其左(或右)兄弟结点以及双亲结点中分割二者的关键字17合并为一个结点,若此时双亲结点中关键字个数小于Min,则对双亲结点进行同样的操作。

[例9] 对于前例生成的B-树,给出删除8,16,15,4等4个关键字的过程。
在这里插入图片描述
在这里插入图片描述
可以看掉删除结点16后,非叶子结点不满足条件,将16所指子树(右)中最小的关键字与它替换 。
在这里插入图片描述
在这里插入图片描述
将15删除后,叶子结点不满足条件,可以看到可以向兄弟结点借关键字。将右子树最小关键字18上移到双亲结点,然后将小于18的关键字17下移
在这里插入图片描述
在这里插入图片描述
这里可以看到,删除4后,叶子结点不满足条件,此时不能向兄弟结点借关键字。则将这两个兄弟结点和将它们分开的双亲结点中的关键字合并为一个。
此时发现,双亲结点也不满足条件了,继续判断、操作。

B+树

在这里插入图片描述
B+树的定义:一棵m阶B+树满足下列要求:
➊每个分支节点至多有m棵子树(这里m=4)。
❷根节点或者没有子树,或者至少有两棵子树。
❸除根节点外,其他每个分支节点至少有|(m/2)棵子树。
❹有n棵子树的节点恰好有n个关键字。
❺所有叶子节点包含全部关键字及指向相应记录的指针,而且叶子节点按关键字大小顺序链接。并将所有叶子节点链接起来。
❻所有分支节点(可看成是索引的索引)中仅包含它的各个子节点(即下级索引的索引块)中最大关键字及指向子节点的指针。

哈希表的查找

1. 哈希表的基本概念

1、哈希表适合情况

在这里插入图片描述
在这里插入图片描述
查找学号为201001025的学生姓名:
①计算:地址d= 201001025- 201001001=24
②和24处的学号比较,相等,返回姓名“王五”
可以看到时间复杂度为O(1)

2、几个概念

➊哈希函数和哈希地址
在这里插入图片描述
哈希函数:把关键字为ki的对象存放在相应的哈希地址中

❷哈希冲突
对于两个关键字分别为ki和kj (i≠j) 的记录,有ki≠kj, 但h(ki)=h(kj)。把这种现象叫做哈希冲突(同义词冲突)
在哈希表存储结构的存储中,哈希冲突是很难避免的! ! !

3、哈希表设计

哈希表设计主要需要解决哈希冲突。实际中哈希冲突是难以避免的,主要与3个因素有关:
●与装填因子有关。 装填因子a=存储的记录个数/哈希表的大小=n/m,a越小,冲突的可能性就越小; a越大 (最大可取1),
冲突的可能性就越大。通常使最终的控制在0.6~0.9的范围内。
●与所采用的哈希函数有关。好的哈希函数会减少冲突的发生;不好的哈希函数会增加冲突的发生。
●与解决冲突方法有关。 好的哈希冲突解决方法会减少冲突的发生。

2. 哈希函数构造方法

1、直接定址法

直接定址法是以关键字k本身或关键字加上某个数值常量c作为哈希地址的方法。直接定址法的哈希函数h(k)为:
h(k)= k+c
例:h(学号)=学号-201001001

2、除留余数法

在这里插入图片描述
除留余数法的哈希函数h(k)为:
h(k)=k modp (mod为求余运算,p≤m) p最好是质数(素数)。

3、数字分析法

在这里插入图片描述
可以看到每个关键字从左到右的第1,2,3位和第6位取值集中,不宜作为哈希地址。剩余的第4,5,7,8位取值较分散,可根据实际情况取其中若干位作为哈希地址。这样设计的哈希函数将一个大的数据取值范围映射到一个小的数据取值范围。

3. 哈希冲突解决方法

1、 开放定址法

开放定址法:冲突时找–个新的空闲的哈希地址。
怎么找空闲单元?
实例:晚到电影院找座位的情况就是采用开放定址法。

(1) 线性探查法

线性探查法的数学递推描述公式为:
在这里插入图片描述
该方法即当出现冲突时,依次向后查看后面的结点是否为空,若为空,将它放在那里,若不为空,继续向下找为空的结点。
这样它容易出现非同义词冲突:
哈希函数值不相同的两个记录争夺同一个后继哈希地址中堆积(或聚集)现象。
即若干同义词占用哈希表连续的几个位置。

(2) 平方探查法

平方探查法的数学描述公式为:
在这里插入图片描述
查找的位置依次为::d0+1²,d0-1²,d0+2²,d0-2²,…
平方探查法是一种较好的处理冲突的方法,可以避免出现堆积现象。它的缺点是不能探查到哈希表.上的所有单元,但至少能探查到一半单元。

哈希表的创建
[例9 ]假设哈希表长度m=13, 采用除留余数法哈希函数建立如下关键字集合的哈希表: {16,74, 60, 43, 54,90,46,31,29,88,77},共11个关键字。采用线性探查法解决冲突。
n=11,m=13,设计除留余数法的哈希函数为:
h(k)=k mod p
p应为小于等于m的素数,设p=13。
在这里插入图片描述
依次将关键字除余,放入哈希表中,到29时出现哈希冲突,探测表中3不为空,继续下移探测,直到序号为6为空,放入6这个结点中。
在这里插入图片描述
在这里插入图片描述
88,77也是同样的方法放入10,0 结点中。

查找:
➊对于前面构建的哈希表:成功查找ASL计算
成功查找的情况:
查找关键字为29的记录:
h(29)=29%13=3 :16≠29 ;
d0=3, d1=(3+1)=4:43≠29 ;
d2=(4+1)=5 :31≠29 ;
d3=(5+1)=6 : 29=29。成功!
需要4次关键字比较
在这里插入图片描述探查次数恰好等于查找到该记录所需要的关键字比较次数!
在这里插入图片描述
❷对于前面构建的哈希表:不成功查找ASL计算
不成功查找的情况:
查找关键字47的记录:
h(47)=47%13=8:60≠47
d0=8,d1=(8+1)=9:74≠47
d2=(9+1)=10:88≠47
d3=(10+1)=11:此处为空,查找失败!
在这里插入图片描述
查找次数为采用线性探查法找空位置,就意味着查找失败

在这里插入图片描述

2、拉链法

拉链法是把所有的同义词用单链表链接起来的方法。
在这里插入图片描述
对上例的关键字序列,构造采用拉链法解决冲突的哈希表。
在这里插入图片描述
➊拉链法中成功查找的ASL计算
成功查找的情况
查找关键字为16的记录::
h(16)=16%13=3
p指向ha[3]的第1个节点,29≠16;
p指向ha[3]的第2个节点,16= 16。
成功!
2次关键字比较
在这里插入图片描述
❷拉链法不成功查找的ASL计算
不成功查找的情况
查找关键字为47的记录:
h(47)=47%13=8
p指向ha[8]的第1个节点,60≠47;p=NULL。失败!
1次关键字比较
在这里插入图片描述在这里插入图片描述
查找次数为查找到结点指针为NULL,意味着查找失败
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值