数据结构知识点总结14-(第七章.查找)

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html

......

数据结构知识点总结11-(第六章.图)-图的基本概念

数据结构知识点总结12-(第六章.图)-图的存储结构及图的遍历

数据结构知识点总结13-(第六章.图)-图的应用

......

第七章、查找

本章重点

查找:在数据集合中寻找满足某种条件的数据元素的过程称为查找。

查找的结果分为两种:查找成功 ,即在数据集合中找到了满足条件的数据元素;查找失败,即没有找到满足条件的元素。

平均查找长度:在查找过程中,一次查找的长度是指该次查找中需要比较的次数,而平均查找长度则是指所有查找过程中进行关键字比较次数的平均值。

其数学定义为∑ni=1 PiCi公式中,n是查找表的长度;Pi是查找某个数据元素的概率,一般认为每个数据元素的查找概率相等;Ci是查找到第i个数据元素所需进行的比较次数。平均查找长度是衡量查找算法效率的最主要指标。

顺序表查找成功的平均查找长度为:(n+1)/2,查找不成功时,与表中各关键字的比较次数为n+1次,从而顺序查找不成功的平均查找长度为n+1。

本章的重点:

掌握平均查找长度的计算。

掌握二叉排序树的定义、操作,平衡二叉树的定义。

掌握二分查找。

掌握哈希函数的构造方法,解决冲突的方法。

了解B树和B+树,平衡二叉树的定义。

二分查找

二分查找仅适用于有序的顺序表。

二分查找代码:

int Binary_Search(SeqList L, ElemType key){
    int low = 0; high = L.Len-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 high = mid + 1;
    }
    return -1;
}

二分过程:

有序表{7,10,13,16,19,29,32,33,37,41,43}

则查找关键字11的过程如下:

二叉排序树

二叉排序树也称为二叉查找树、排序二叉树,它的定义是:或者是一颗空树,或者是具有以下性质的二叉树:

1 )若左子树非空,则左子树上所有结点的值均小于根结点的值。

2 )若右子树非空,则右子树上所有结点的值均大于根结点的值。

3 )左右子树也分别是一颗二叉排序树。

根据定义可以看出,左子数结点值 < 根结点 < 右子树结点值,所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列。

二叉排序树不会出现值域相同的结点,因为在查找插入时如果值域相同,就不会插入了。

//二叉排序树的查找算法
BSTNode *BST_Search(BiTree T, ElemType key){
    while(T != NULL && key != T->data){
        if(key < T->data)
	    T->lchild;
            else
	    T->rchild;
    }
    return T;
}

//二叉排序树插入操作算法
int BSTInsert(BiTree &root, KeyType val) {
	if (root == NULL) {
		T = (BiTree)malloc(sizeof(BSTNode));
		T->key=k;
		T->rchild = T->lchild=NULL;
		return 1;
	}
	if (val == T->val)
		return 0;
	if (val < T ->val)
		return BSTInsert (T -> lchild, val);
	else
		return BSTInsert (T -> rchild, val);
}

二叉排序树的删除:

在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须先把被删除结点从存储二叉排序树的链表上摘下来,将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。

删除操作的实现过程按照以下三种情况进行处理:

(1 )如果被删除结点z 是叶节点,则直接删除,不会破坏二叉排序树的性质。

(2)如果结点z只有一颗左子树或者右子树,则让z的子树成为z父结点的子树,替代z的位置。

(3)若结点z有左右两棵子树,则令z的直接后继(或者直接前驱)替代 z,然后从二叉排序树中删去这个直接后继(或者直接前驱),这样就变成了第一种或者第二种情况。

平衡二叉树

对于高度为H的二叉排序树,其插入和删除操作都是O(H)。但最坏的情况下,即构造二叉排序树的输入序列是有序的,则会形成一个倾斜的单支树,此时二叉排序树 的性能显著变坏,树的高度也增加为元素的个数N。

二叉排序树查找算法的平均查找长度取决于树的高度,即与二叉树的形态有关。如果二叉排序树是一个只有左(右)孩子的单支树(类似于有序的单链表),其平均长度和单链表相同为O(n),如果二叉排序树的左右子树的高度之差的绝对值不超过1,这样的二叉排序树被称为平衡二叉树它的平均查找长度达到O(log2n)。

在插入和删除二叉树节点时,要保证任意节点的左右子树的高度差的绝对值不超过1,将这样的二叉树称为平衡二叉树 ,简称平衡树**(** AVL 。定义节点左子树和右子树的高度差为该节点的平衡因子,则平衡二叉树节点的平衡因子只能是-1,0,1。

平衡二叉树的插入

平衡二叉树的插入:二叉排序树保证平衡的基本思想:每当在二叉排序树中插入(或删除)一个节点时,首先要检查其在插入路径上的节点是否因此次操作导致了不平衡。如果导致了不平衡,则先找到插入路径上距离插入节点最近的平衡因子绝对值大于1的节点A,再对以A为根的子树,在保持二叉排序树特性的前提下调整各节点的位置关系,使之重新达到平衡。

注意:每次调整的对象都是最小不平衡子树,即在插入路径上距离插入节点最近的平衡因子的绝对值大于1的结点作为根的子树。

平衡二叉树插入节点后失衡的类型有LL、RR、LR、RL。

LL型:节点A(最小失衡节点)的左孩子L的左子树L上插入了新节点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要一次向右的旋转操作。

RR型:由于在结点A的右孩子R的右子树R上插入了新的结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要一次向左的旋转操作。

LR型:由于在A的左孩子L的右子树R上插入新节点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转然后右旋转。

RL型:由于在A的右孩子R的左子树L上插入新节点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转后左旋转。

举例2:

LL型:

RR型:

LR型:

RL型:

其他示意图:

平衡二叉树的删除

AVL树的删除和二叉查找树一样,分为四种情况:

1)删除叶子节点。

2)删除的节点只有左儿子。

3)删除的节点只有右儿子

4)删除的节点既有左儿子,又有右儿子。

注意:

插入节点时,只需要根据插入节点往上查找第一个不平衡子树进行旋转调整即可。

删除节点时,可能存在由于调整最小不平衡树而导致的更大的不平衡术,因此要继续往上查找不平衡子树直到根节点。

(1)删除叶子节点

直接删除该叶子节点,删除之后可能导致父节点平衡因子变化,所以要从父节点开始向上查找出其中的失衡子树,按照LL、RR、LR、RL型进行处理,处理完之后继续向上检索直到根节点。

(2)删除的节点只有左儿子

假设删除的节点为D,则用D的左儿子替换掉D;从D的父节点开始查找失衡子树,然后按照LL、RR、LR、RL四种情况处理,处理完继续向上查找,直到根节点。

(3)删除的节点只有右儿子,与(2)处理方式类似。

(4)删除的节点既有左儿子,又有右儿子。

假设删除的节点为D,则找到D的前驱节点(左子树的最右节点)或后继节点(右子树的最左节点),假设为C,则用C替代D,然后删除C。删除C后将导致C的父节点平衡因子发生改变,因此要从C的父节点采用类似的处理方式,向上检索,直到根节点。

平衡二叉树的平均查找长度为O(log2n)。

B树和B+树

B树

B树又称为多路平衡查找树B树中所有结点的孩子结点数的最大值称为B树的阶 ,通常用m表示。一个m阶B树或者为空树,或者为满足如下特性的m叉树

1 )树中每个结点至多有m 棵子树(即至多含有m-1个关键字)。

2)若根节点不是终端结点,则至少含有两颗子树。

3)除根节点之外的所有非叶节点至少有(m+1)/2棵子树,即至少含有(m+1)/2 − 1个关键字。

4)所有非叶节点的结构如下。

其中ki为关键字,Pi为指向子树的指针。n为关键字个数。

5)所有叶结点都出现在同一层次上,并且不带信息(实际上这些结点不存在,指向这些结点的指针为空)。

B树是所有结点的平衡因子均等于0的多路平衡查找树。

其他推论:

1)如果根节点没有关键字就没有子树,此时B树为空,如果根节点有关键字,则其子树必然大于等于两棵,因为子树个数等于关键字个数加1.

2)结点中关键字从左到右递增有序,关键字两侧均有指向子树的指针,左边指针所指子树的关键字均小于该关键字,右边指针指向子树的所有关键字均大于该关键字。

下图为:一棵三阶B树示意图。

(1)B树的查找

B树的查找与而二叉查找树很相似,只是不是二路分支,而是多路分支。B树的查找包含两个操:1、在B树中找结点,2、在结点内找关键字。由于B树常存储在磁盘上,因此前一个查找操作在磁盘上进行,后一个查找操作在内存中进行。

(2)B树的插入

B树的插入可能会导致整个B树不满足定义要求,插入后检查被插入的关键字个数是否大于m-1,如果大于,则必须对结点进行分裂操作。

(3)B树的删除

B树的删除操作要保证删除之后结点的关键字个数大于(m+1)/2 -- 1.

因此在删除关键字之后,涉及到结点合并的问题。

当被删关键字k不在终端结点时,可以用k的前驱或后继k'来替代k,然后再响应的节点中删除k',关键字k'必定落在某个中断结点中,则转换成了被删关键字在终端节点的情况。

比如在下图的4阶B树种,删除关键字80,用其前驱78替代,然后在中断结点种删除78.

因此B树的删除只要讨论关键字在终端节点(最底层的关键字结点)即可,有以下三种情况:

1)直接删除关键字,删除后满足B树的定义。2)兄弟够借。3)兄弟不够借。以四阶B树为例:

B+树

B+ 树通常用于数据库和操作系统的文件系统中。

一棵m阶的B+树需要满足以下条件:

1)每个分支结点,最多有m棵子树。

2)非叶根结点至少有两棵子树,其他分支结点至少有ceil(m/2)棵子树。

3)结点的子树个数与关键字个数相等。

4)所有叶结点包含全部关键字及指向相应记录的指针,叶结点中将关键字按大小顺序排列,并且相邻叶结点互相链接起来。

5)所有分支结点(可视为索引)中仅包含它的各个子结点中关键字的最大值及指向其子结点的指针。

m阶的B+树与m阶的B树主要差异如下:

1)在B+树中,具有n个关键字的结点含有n棵子树,即每个关键字对应一棵子树;而在B树种,具有n个关键字的结点含有n+1棵子树。

2)在B+树种,根结点的关键字个数范围1<=n<=m,在B树中,根结点的关键字范围1<=n<=m-1

3)在B+树中,叶结点包含信息,所有非叶节点起索引作用,非叶结点的每个索引项只含有对应子树最大关键字和指向该子树的指针,不含有该关键字对应记录的存储地址。

4)在B+树中,叶结点包含了全部关键字,即在非叶结点中出现的关键字也会出现在叶节点中,而在B树种,叶节点包含的关键字和其他结点包含的关键字是不重复的。

如图所示的一棵4阶B+树,通常在B+树种有两个头指针,一个指向根结点,另一个指向关键字最小的叶结点。因此可以对B+树进行两种查找运算:一种从最小关键字开始顺序查找,另一种从根节点开始多路查找。

B+树的查找、插入和删除和B树基本类似,只是在查找过程中,非叶结点上的关键字值等于给定值时并不终止,而是继续向下查找,直到叶节点上的该关键字为止。所以在B+树种查找时,无论查找成功与否,每次查找都是一条从根节点到叶结点的路径。

散列表

前述的线性表和树表 的查找种,都是基于**"比较"** 的思想,查找的效率取决于比较的次数。而散列表又称为哈希表,是基于哈希的思想查找效率取决于哈希函数和解决冲突的方法。

散列函数 :一个把查找表中的关键字映射成该关键字对应的地址的函数,这里的地址可以是数组下标、索引或内存地址等,散列函数又称为哈希函数,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table)。

哈希函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突一方面应设计好的哈希函数尽量减少这种冲突,另一方面,由于这种冲突不可避免,所以还要设计好的处理冲突的方法。

理想情况下,对散列表进行查找的时间复杂度为O(1)。

哈希函数的构造方法:

(1 )直接定址法

取关键字或关键字的某个线性函数值为哈希地址。即H(key) = key 或 H(key) = a*key+b (a,b为常数)。 用数组结合直接定址,在做相关算法题时非常常见。

(2 )除留余数法

取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址(p为素数)

H(key)=key MOD p,p<=m (最简单,最常用)p的选取很重要

(3)若关键字是以r为基的数(如:以10为基的十进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。

(4)平方取中法

取关键字平方后的中间几位为哈希地址。(较常用的一种)

(5)随机数法

选择一个随机函数,取关键字的随机函数值为它的哈希地址。即H(key)=random(key),其中random为随机函数。适用于关键字长度不等时。

总结:实际中根据情况不同选用的哈希函数不同,通常,考虑因素如下:

(1)计算哈希函数所需时间(包括硬件指令的因素)

(2)关键字的长度

(3)哈希表的大小

(4)关键字的分布情况

(5)记录的查找频率

处理冲突的方法:

(1)处理冲突的方法-开放定址法(封闭散列)

其基本思想是:当关键字key的哈希地址p = H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,...,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。这种方法有一个通用的再散列函数形式:

Hi =(H(key)+ di)% m i=1,2,...,n

其中H(key)为哈希函数,m 为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种:

1)线性探测再散列

di = 1,2,3,...,m-1

这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

2)二次探测再散列(平方探测)

di=12,-12,22,-22,...,k2,-k2 ( k <= m/2 )

这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

3)伪随机序列法

当di等于伪随机序列时,称为伪随机序列法。

4)再散列法。

当di = Hash2(key)时,称为再散列法,又称为双散列法。需要使用两个散列函数,当使用第一个散列函数得到的地址发生冲突时,则利用第二个散列函数计算该关键字的地址增量,它的具体函数形式如下:

Hi = (H(key) + i*Hash2(key)) % m

eg:关键字序列{19,14,23,01,68,20,84,27,55,11,10,79}按散列函数H(key) = key%13和线性探测处理冲突构造所得得散列表L如图所示:

给定值84的查找过程为:首先求得散列地址H(84) = 6,因为L[6]不空且L[6]!=84,需要找冲突的下一个地址H1=(6+1) % 16 = 7,L[7]不空,且L[7]!=84,则找冲突的第二个地址H2 = (6+2)%16 = 8,L[8]不空,且L[8]=84,查找成功。

给定值38的查找过程:求散列地址H(38)=12,L[12]不空且L[12]!=38,则找下一地址H1=(12+1) % 16 = 13,此时L[13]是空记录,故表中不存在关键字为38的记录。

查找各关键字的比较次数为:

平均查找长度ASL = (1*6 + 2 + 3*3 + 4 + 9)/12 = 2.5

(2)处理冲突的方法-拉链法(开放散列)

这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

eg:已知一组关键字(32,40,36,53,16,46,71,27,42,24,49,64),哈希表长度为13,哈希函数为:H(key)= key % 13,则用链地址法处理冲突的结果如图8.27所示:

本例的平均查找长度 ASL = (1*7+2*4+3*1)/12=1.5

(3)处理冲突的方法-建立公共溢出区

这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表

散列表的查找效率取决于三个因素:散列函数、处理冲突的方法和装填因子。装填因子定义为一个表的装满程度,其等于表中记录数和散列表长度的比值。散列表的平均查找长度依赖于装填因子,而不直接依赖于表记录数或散列表长度,装填因子越大表示装填的记录越满,发生冲突的可能性就大,反之发生冲突的可能性就小。

分块查找

分块查找是折半查找和顺序查找的一种改进方法,分块查找由于只要求索引表是有序 的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。

索引表用二分查,块内用顺序查。

贵大考研13年的考题23题考到了。

13年的考题,选择题考察3道题。数据结构选择题一共10道。

相关考题

1、在任意一颗非空二叉树T1中,删除某节点v之后形成二叉排序树T2,再将v插入T2形成二叉排序树T3。则关于T1和T3的叙述中,正确的是:

I:若v是T1的叶节点,则T1与T3不同。

II:若v是T1的叶节点,则T1与T3相同。

III:若v不是T1的叶节点,则T1与T3不同。

IV:若v不是T1的叶节点,则T1与t3相同。

A:仅I、III,B仅I,IV, C:仅II、III, D:仅II、IV。

解析C:因为插入一个节点必然在叶子节点插入,因此如果之前删除的不是叶子节点,则之后的树形将发生变化。

2、在如下图所示的平衡二叉树中插入关键字48后得到一颗新的平衡二叉树,在新平衡二叉树中,关键字37所在结点的左右子结点中保存的关键字分别是:()

A:13,48 B:24,48 C:24,53 D:24,90

解析C:插入48后,RL型旋转。

3、n个叶子结点的哈夫曼树中,非叶子结点个数是()。

A:n-1,B:n C:2*n-1 D:2*n.

解析A:特例法。举例子推出来。

由哈夫曼树的构造过程可以可知,哈夫曼树只有度为0和2的结点,在非空二叉树中有n0=n2+1。

4、下图所示的是一棵()。

A. 4阶B树 B. 4阶B+树

C. 3阶B树 D. 3阶B+树

解析:关键字数目比子树数目少1,所以不是B+树,而是B树。又因为m阶B树结点关键字最多为m-1,有一个结点关键字个数为4,因此是4阶的B树。

下一篇将介绍数据结构排序章节

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html

......

数据结构知识点总结11-(第六章.图)-图的基本概念

数据结构知识点总结12-(第六章.图)-图的存储结构及图的遍历

数据结构知识点总结13-(第六章.图)-图的应用

......

相关推荐
yyt_cdeyyds9 分钟前
FIFO和LRU算法实现操作系统中主存管理
算法
daiyang123...32 分钟前
测试岗位应该学什么
数据结构
alphaTao36 分钟前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
kitesxian1 小时前
Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)
数据结构·算法·leetcode
做人不要太理性1 小时前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
VertexGeek1 小时前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
石小石Orz1 小时前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
jiao_mrswang2 小时前
leetcode-18-四数之和
算法·leetcode·职场和发展
qystca2 小时前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法
薯条不要番茄酱2 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea