整本书的知识点,点击右方链接:整本书笔记知识点
-
查找表:用于查找的数据元素集合。查找表由同一类型的数据元素(或记录)构成
对查找表经常进行的操作
查找表是否存在某元素
从查找表中检索某特定元素的属性
在查找表中插入一个元素
在查找表中删除一个元素
-
静态查找表:只做查找表是否存在某元素,从查找表中检索某特定元素的属性操作的称为静态查找表
在查找过程中只是对数据元素进行查找
-
动态查找表:在查找表中插入一个元素,在查找表中删除一个元素操作的称为动态查找表
在实施查找的同时,插入找不到的元素,或从查找表中删除已查到的某个元素,即允许表中元素变化
-
关键字: 是数据元素中的某个数据项。唯一能标识数据元素(或记录)的关键字,即每个元素的关键字值互不相同,这种关键字称为主关键字;若查找表中某些元素的关键字值相同,称这种关键字为次关键字
-
查找:在查找表搜索关键字等于给定值的数据元素(或记录)。若表中存在这样的记录,则称查找成功;若表中不存在关键字等于给定值的记录,则称查找不成功。若按主关键字查找,查找结果是唯一的;若按次关键字查找,结果可能是多个记录,即结果可能不唯一
7.2.1、顺序查找
顺序查找的查找过程为:从表的一端开始,依次将记录的关键字和给定值进行比较,若某个记录的关键字和给定值相等,则查找成功;反之,若扫描整个表后,仍未找到关键字和给定值相等的记录,则查找失败
顺序查找方法既适用于线性表的顺序存储结构(线性表),又适用于线性表的链式存储结构(线性链表)
下面只介绍以顺序表作为存储结构时实现的顺序查找算法
在此定义下,顺序查找算法便与第2章的算法2.2 一样。在此假设元素从 ST.R[1] 开始顺序向后存放,ST.R[0]设置为哨兵,查找时从表的最后开始比较,如下面算法所示
ST.R[0] 称为 “哨兵”。引入它的目的是使循环不用判断数组是否会越界,从而提高程序的效率
平均查找长度为:
时间复杂度为:O(n)
- 优点:对数据元素的存储没有要求,顺序存储或链式存储皆可,数据元素也不一定必须有序
- 缺点:当n较大时,平均查找长度较大,效率低
7.2.2、折半查找
当静态查找表的关键字有序时,可以用折半查找来实现
折半查找也称二分查找,它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构, 而且表中元素按关键字有序排列
基本思想:key 值与中间元素比较,相等则成功;key 大则比较右半边;key 小则比较左半边
分别用low和high来表示当前查找区间的下界和 上界,mid为区间的中间位置
折半查找的判定树:
折半查找判定树过程:
折半查找在查找不成功和给定值进行比较的关键字的比较次数最多为 [log2n]+1次,即判定树的最大层次数
还可以按照值来做出折半查找的判定树:
折半查找的存取结构必须具有随机存取的特性。仅适合于线性表的顺序存储结构,不适合链式存储结构,且要求元素有序
平均查找长度:
当n较大时,可有以下近似结果
时间复杂度为:O(log2n)
折半查找在查找不成功和给定值进行比较的关键字个数最多为 [log2n]+1,即判定树的最大层次数
则下题比较次数最多的是 5
7.2.3、分块查找
分块查找又称为索引顺序查找,这是一种性能介于顺序查找和折半查找之间的一种查找方法
-
分块查找,又称为索引顺序查找,吸取了顺序查找和折半查找各自的优点,既有动态结构,又适于快速查找
-
基本思想:将查找表分为若干个子块,块内元素可以无序,块间元素有序
块间有序含义: 若a<b,则第 b 块中所有记录的关键字均大于第 a 块中的最大关键字
建立“索引表”,每个结点含有最大关键字域和指向本块第一个结点的指针,且按关键字有序
分块查找的过程分为两步:
(1)索引查找:在索引表中确定待查记录所在的块;(可顺序、可折半)
(2)块内查找:在块内顺序查找
分块查找的平均查找长度为索引查找(Ll)和块内查找(Ls)的平均长度之和
优缺点:
- 优点:插入和删除比较容易,无需进行大量的移动。
- 缺点:要增加一个索引表的存储空间并对初始索引表进行排序运算。
- 适用情况:如果线性表既要快速查找又经常动态变化,则可采用分块查找
三种查找方法的比较
顺序查找、二分(折半)查找和索引查找都是静态查找表,其中二分查找的效率最高。
静态查找表的缺点是当表的插入或删除操作频繁时,为维护表的有序性,需要移动表中很多记录。
这种由移动记录引起的额外时间开销,就会抵消二分查找的优点(二分查找和分块查找只适用于静态查找表)。
若要对动态查找表进行高效率的查找,可以使用树表。
以二叉树或树作为表的组织形式,称为树表。
7.3.1、二叉排序树
1、二叉排序树的定义
二叉排序树又称二叉查找树,它是一种排序和查找都很有用的特殊二叉树。
二叉排序树右称二叉查找树。或者为空树,或者是具有以下性质:
(1)若它的左子树不为空,则左子树所有节点的值小于根结点,
(2)若它的右子树不为空,则根结点的值小于所有右子树结点的值
(3)它的左右子树叶分别为二叉排序树
总结起来就是根据结点的值有:左子树<根结点<右子树
中序遍历一颗二叉排序树可以得到一个结点值递增的有序序列
2、二叉排序树的查找
二叉排序树有一些基本的应用,可以用于查找,查找的长度与树的深度有关。其平均查找长度的数量级与log2N 相同(N为结点个数)
注意:二叉排序树中没有值相同的节点
查询过程比较简单,首先将关键字和根节点的关键字比较,如果相等则返回节点的位置(指针);否则,如果小于根节点的关键字,则去左子树中继续查找;如果大于根节点的关键字,则去右子树中查找;如果找到叶子节点也没找到,则返回NULL。
一个序列的排序二叉树有多种构造情况。下面考虑两种极端情况:深度最小和深度最大的二叉排序树。
关键字序列(45,24,53,12,37,93),假设6个记录的查找概率相等都为1/6
容易看出这是一棵完全二叉树,该数的深度(最大层次)为3,它的平均查找长度为:
ASL = 1/6(1+2+2+3+3+3)= 14/6
再来看该关键字序列构成深度最大的二叉排序树
这是一棵单支树,其深度为6,它的平均查找长度为:
ASL = 1/6(1+2+3+4+5+6)= 21/6
在随机情况下,该数的平均查找长度总是介于这两种情况之间,即14/6 < log26 < 21/6。二叉排序树的平均查找长度和log2N是等数量级的。
3、二叉排序树的插入
二叉排序数插入过程的基本过程是查找,所以时间复杂度同查找一样,是O(log2n)
a.插入过程比较简单,首先判断当前要插入的值是否已经存在二叉排序树中,如果已经存在,则直接返回;如果不存在,则转b;
b.当前要插入的值不存在,则应找到适当的位置,将其插入。注意插入的新节点一定是叶子节点;
4、二叉排序树的创建
二叉树创建就是从根节点按关键字序列插入的过程
5、二叉排序树的删除
删除二叉排序树中任意一个结点,需要分成以下三种情况讨论:
(1)删除的是叶子结点
这种情况最简单,由于删除叶子结点不会破坏整棵树的结构,只需要修改其双亲结点的指针即可。
(2)删除的结点只有左子树或只有右子树。
这种情况只需要将其左子树或右子树往上推,替代要删除结点的位置,显然,作此修改也不会破坏二叉排序树的结构。
(3)删除的结点左右子树都不为空
这种情况稍微复杂一点,为了不保持二叉排序树的结构,有两种思路,一种就是从要删除结点的左子树中选取最大的结点进行替代之(前驱),另一种就是从要删除的结点的右子树中选取最小的结点替代之(后继)
7.3.2、平衡二叉树(AVL树)
它或者是颗空树,或者是具有下列性质的二叉树:
- 它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。
- 若将二叉树节点的平衡因子BF定义为该节点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有节点的平衡因子只可能为-1,0,1.
- 只要二叉树上有一个节点的平衡因子的绝对值大于1,那么这颗平衡二叉树就失去了平衡。
因为AVL树上任何结点的左右孩子子树的深度之差都不超过1,则可以证明它的深度和 log2n是同数量级的(其中n为结点个数)。
由此,其查找的时间复杂度为O(log2n)
**最小不平衡树:**是指离插入结点最近且以平衡因子的绝对值大于1的结点作为根的子树。
书上的LL,RR什么的挺麻烦的,看这个两分钟的视频应该就很清楚。
小姐姐声音太甜啦啊哈哈哈哈哈哈哈哈哈
平衡二叉树的动态插入讲解
视频中讲解的那三个点就是最小不平衡树,即是指离插入结点最近且以平衡因子的绝对值大于1的结点作为根的子树。
7.3.3、B-树
六分钟视频讲解b-树基本规则
对于一棵m阶B-tree,每个结点至多可以拥有m个子结点。
即遍观整棵树,子节点最多的个数是m,那么这棵树就是m阶树。
具体描述可以看超链接:
图解B-树
B-树详解
7.3.4、B+树
图解B+树
7.4.1、散列表的基本概念
散列表也叫哈希表
在元素的存储位置和其关键字之间建立某种直接关系,那么在进行查找时,就无需做比较或做很少次的比较,按照这种关系直接由关键字找到相应的记录。这就是散列查找法的思想,它通过对元素的关键字值进行某种运算,直接求出元素的地址,即使用关键字到地址的直接转换方法,而不需要反复比较。因此,散列查找法又叫杂凑法或散列法。
- 散列函数和散列地址:在记录的存储位置p和其关键字key之间建立一个确定的对应关系H,使 p= H(key) ,称这个对应关系H为散列函数,p为散列地址。
- 散列表:采用散列技术将记录存放在一块连续有限的存储空间中,这块连续存储空间称为散列表或哈希表。通常散列表的存储空间是一个一维数组,散列地址是数组的下标。
- 冲突和同义词:对不同的关键字可能得到同一散列地址,即 key1≠key2, 而H(key1) =H( key2),这种现象称为冲突。具有相同函数值的关键字对该散列函数来说称作同义词,key1 与 key2 互称为同义词。
7.4.2、散列函数的构造方法
构造散列函数的方法很多,通常要考虑以下因素:
- 散列表的长度
- 关键字的长度
- 关键字的分布情况
- 计算散列函数所需的时间
- 记录的查找频率
构造一个好的散列函数需要遵循以下两条原则:
- 函数计算要简单,每一关键字只能有一个散列地址与之对应。
- 函数的值域需在表长的范围内,计算出的散列地址的分布应均匀,尽可能减少冲突。
1、数字分析法
如果关键字时位数较多的数字,比如11位的手机号”130****1234”,其中前三位是接入号;中间四位是HLR识别号,表示用户号的归属地;后四为才是真正的用户号。如下图所示。
如果现在要存储某家公司的登记表,若用手机号作为关键字,极有可能前7位都是相同的,选择后四位成为散列地址就是不错的选择。若容易出现冲突,对抽取出来的数字再进行反转、右环位移等。总的目的就是为了提供一个散列函数,能够合理地将关键字分配到散列表的各个位置。
数字分析法通过适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布比较均匀,就可以考虑用这个方法。
2、平方取中法
这个方法计算很简单,假设关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227,用做散列地址。
平方取中法比较适合不知道关键字的分布,而位数又不是很大的情况。
3、折叠法
折叠法是将关键字从左到右分割成位数相等的几部分(注意最后一部分位数不够时可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位(舍去进位)作为散列地址。
比如关键字是9876543210,散列表表长为三位,将它分为四组,987|654|321|0,然后将它们叠加求和987 + 654 + 321 + 0 = 1962,去掉进位得到散列地址962。
折叠法事先不需要知道关键字的分布,适合关键字位数较多的情况。
4、除留余数法
此方法为最常用的构造散列函数方法。对于散列表长为m的散列函数公式为: H(key) = key%p
%是取模(求余数)的意思。事实上,这方法不仅可以对关键字直接取模 ,也可以再折叠、平方取中后再取模。
很显然,本方法的关键在于选择合适的p,p如果选不好,就可能会容易产生冲突。
根据前辈们的经验,若散列表的表长为m,通常p为小于表长的最大质数或不包含小于20质因子的合数。
质数:又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;
质因子(或质因数)在数论里是指能整除给定正整数的质数。
7.4.3、处理冲突的方法
处理冲突的实际含义是:为产生冲突的地址寻找下一个哈希地址(散列地址)
1、开放地址法
所谓的开放地址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
通常把寻找下一个空位的过程称为探测
它的公示为:Hi = (H(key)+di)%m i =1,2,3…,k(k≤m-1)
其中di 为增量序列,根据 di 取值的不同,可以分为以下3中探测方法
①、线性探测法
di = 1,2,3,…,m-1
②、二次探测法
di = 12 ,-12 ,22 ,-22 ,32 ,……,+k2 ,-k2 (k≤m/2)
最后一个key = 34,H(key) = 10,与22所在的位置冲突,可是22后面没有空位置了,反而它的前面有一个空位置,尽管可以不断地求余后得到结果,但效率很差。因此可以改进di = 12 ,-12 ,22 ,-22 ,32 ,……,+k2 ,-k2 (k≤m/2),这样就等于是可以双向寻找到可能的空位置。对于34来说,取di = -1即可找到空位置了。另外,增加平方运算的目的是为了不让关键字都聚集在某一块区域。称这种方法为二次探测法。
③、伪随机探测法
在冲突时,对于位移量di采用随机函数计算得到,称之为随机探测法。
既然是随机,那么查找的时候不也随机生成di 吗?如何取得相同的地址呢?这里的随机其实是伪随机数。伪随机数就是说,如果设置随机种子相同,则不断调用随机函数可以生成不会重复的数列,在查找时,用同样的随机种子,它每次得到的数列是想通的,相同的di 当然可以得到相同的散列地址。
可以看出,上述三种处理方法各有优缺点。线性探测法的优点是:只要散列表未填满,总能找到一个不发生冲突的地址。缺点是:会产生“二次聚集”现象。而二次探测法和伪随机探测法的优点是:可以避免“二次聚集”现象。缺点也很显然:不能保证一定找到不发生冲突的地址。
2、链地址法
此时,已经不存在什么冲突换地址的问题,无论有多少个冲突,都只是在当前位置给单链表增加结点的问题。
链地址法对于可能会造成很多冲突的散列函数来说,提供了绝不会出现找不到地址的保证。当然,这也就带来了查找时需要遍历单链表的性能损耗
7.4.4、散列表的查找
查找过程中需和给定值进行比较的关键字的个数取决于三个因素:散列函数、处理冲突的方法和散列表的装填因子
散列表的装填因子α定义为:
α标志散列表的装满程度。直观地看,α越小,发生冲突的可能性就越小;反之,α越大,表中已填入的记录越多,再填记录时,发生冲突的可能性就越大,则查找时,给定值需与之进行比较的关键字的个数也就越多。
线性表的查找:主要包括顺序查找、折半查找和分块查找,三者比较:
二叉排序树和折半查找的比较
散列查找法主要研究两方面的问题:如何构造散列函数,以及如何处理冲突
- 构造散列函数的方法很多,除留余数法是最常用的构造散列函数的方法。它不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。
- 处理冲突的方法通常分为两大类:开放地址法和链地址法,二者的差别类似于顺序表和单链表的差别
(1)对n个元素的表做顺序查找时,若查找每个元素的概率相同,则平均查找长度为( )。
A.(n-1)/2 B. n/2 C.(n+1)/2 D.n
解释:总查找次数N=1+2+3+…+n=n(n+1)/2,则平均查找长度为N/n=(n+1)/2
(2)适用于折半查找的表的存储方式及元素排列要求为( )。
A.链接方式存储,元素无序 B.链接方式存储,元素有序
C.顺序方式存储,元素无序 D.顺序方式存储,元素有序
解释:折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
(3)如果要求一个线性表既能较快的查找,又能适应动态变化的要求,最好采用( )查找法。
A.顺序查找 B.折半查找
C.分块查找 D.哈希查找
解释:分块查找的优点是:在表中插入和删除数据元素时,只要找到该元素对应的块,就可以在该块内进行插入和删除运算。由于块内是无序的,故插入和删除比较容易,无需进行大量移动。如果线性表既要快速查找又经常动态变化,则可采用分块查找。
(4)折半查找有序表(4,6,10,12,20,30,50,70,88,100)。若查找表中元素58,则它将依次与表中( )比较大小,查找结果是失败。
A.20,70,30,50 B.30,88,70,50
C.20,50 D.30,88,50
解释:表中共10个元素,第一次取(1+10)/2=5,与第五个元素20比较,58大于20,再取(6+10)/2=8,与第八个元素70比较,依次类推再与30、50比较,最终查找失败。
(5)对22个记录的有序表作折半查找,当查找失败时,至少需要比较( )次关键字。
A.3 B.4 C.5 D.6
解释:22个记录的有序表,其折半查找的判定树深度为 ëlog222û + 1=5,且该判定树不是满二叉树,即查找失败时至多比较5次,至少比较4次。
(6)折半搜索与二叉排序树的时间性能( )。
A.相同 B.完全不同
C.有时不相同 D.数量级都是O(log2n)
(7)分别以下列序列构造二叉排序树,与用其它三个序列所构造的结果不同的是( )。
A.(100,80, 90, 60, 120,110,130)
B.(100,120,110,130,80, 60, 90)
C.(100,60, 80, 90, 120,110,130)
D.(100,80, 60, 90, 120,130,110)
解释:A、B、C、D四个选项构造二叉排序树都以100为根,易知A、B、D三个序列中第一个比100小的关键字为80,即100的左孩子为80,而C选项中100的左孩子为60,故选C。
(8)在平衡二叉树中插入一个结点后造成了不平衡,设最低的不平衡结点为A,并已知A的左孩子的平衡因子为0右孩子的平衡因子为1,则应作( )型调整以使其平衡。
A.LL B.LR C.RL D.RR
(9)下列关于m阶B-树的说法错误的是( )。
A.根结点至多有m棵子树
B.所有叶子都在同一层次上
C.非叶结点至少有m/2 (m为偶数)或m/2+1(m为奇数)棵子树
D.根结点中的数据是有序的
(10)下面关于B-和B+树的叙述中,不正确的是( )。
A.B-树和B+树都是平衡的多叉树 B.B-树和B+树都可用于文件的索引结构
C.B-树和B+树都能有效地支持顺序检索 D.B-树和B+树都能有效地支持随机检索
(11)m阶B-树是一棵( )。
A.m叉排序树 B.m叉平衡排序树
C.m-1叉平衡排序树 D.m+1叉平衡排序树
(12)下面关于哈希查找的说法,正确的是( )。
A.哈希函数构造的越复杂越好,因为这样随机性好,冲突小
B.除留余数法是所有哈希函数中最好的
C.不存在特别好与坏的哈希函数,要视情况而定
D.哈希表的平均查找长度有时也和记录总数有关
(13)下面关于哈希查找的说法,不正确的是( )。
A.采用链地址法处理冲突时,查找一个元素的时间是相同的
B.采用链地址法处理冲突时,若插入规定总是在链首,则插入任一个元素的时间是相同的
C.用链地址法处理冲突,不会引起二次聚集现象
D.用链地址法处理冲突,适合表长不确定的情况
解释:在同义词构成的单链表中,查找该单链表表中不同元素,所消耗的时间不同。
(14)设哈希表长为14,哈希函数是H(key)=key%11,表中已有数据的关键字为15,38,61,84共四个,现要将关键字为49的元素加到表中,用二次探测法解决冲突,则放入的位置是( )。
A.8 B.3 C.5 D.9
解释:关键字15放入位置4,关键字38放入位置5,关键字61放入位置6,关键字84放入位置7,再添加关键字49,计算得到地址为5,冲突,用二次探测法解决冲突得到新地址为6,仍冲突,再用用二次探测法解决冲突,得到新地址为4,仍冲突,再用用二次探测法解决冲突,得到新地址为9,不冲突,即将关键字49放入位置9。
(15)采用线性探测法处理冲突,可能要探测多个位置,在查找成功的情况下,所探测的这些位置上的关键字 ( )。
A.不一定都是同义词 B.一定都是同义词
C.一定都不是同义词 D.都相同
解释:所探测的这些关键字可能是在处理其它关键字冲突过程中放入该位置的。
以上就是本篇文章【数据结构查找】的全部内容了,欢迎阅览 ! 文章地址:http://dfvalve.xrbh.cn/quote/4600.html 行业 资讯 企业新闻 行情 企业黄页 同类资讯 网站地图 返回首页 迅博思语资讯移动站 http://keant.xrbh.cn/ , 查看更多