数据结构——查找

2023-11-05

一、查找的基本概念

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

查找表(查找结构) —— 用于查找的数据集合称为查找表,它由同一类型的数据元素(或记录)组成

关键字 —— 数据元素中唯一标识该元素的某个数据项的值,使用基于关键字的查找,查找结果应该是唯一的。

查找长度——在查找运算中,需要对比关键字的次数称为查找长度

平均查找长度(ASL,Average Search Length)——所有查找过程中进行关键字的比较次数的平均值

静态查找表:只作查找操作的查找表。

动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。

二、顺序查找

代码如下:

#include<stdio.h>
typedef int ElemType;
typedef struct//查找表的数据结构(顺序表)
{
	ElemType* elem;//动态数据基址
	int TableLen;//表的长度
}; SSTable;
//顺序查找
int search_seq(SSTable ST, ElemType Key)
{
	int i;
	for (i = 0; i < ST.TableLen && ST.elem[i] != Key; ++i)
	{
		return i = ST.TableLen ? -1 : i;//查找成功返回元素下表,失败返回-1
	}
}

三、有序表查找

3.1 折半查找

折半查找,又称“二分查找”,仅适用于有序的顺序表。

mid=(low+high)/2

3.2 差值查找

mid=low+(high-low)*(key-a[low])/(a[high]-a[low])

四、线索索引查找

4.1 分块查找

分块有序,把数据集的记录分成若干块,并且这些块需要满足:块内无序、块间有序

4.2 倒排索引

倒排索引:其中记录号表储存具有相同次关键字的所有记录的记录号(可以是指向记录的指针或者是该记录的主关键词)

五、二叉树排序

二叉排序树,又称二叉查找树(Binary Search Tree)一颗二叉树或者是空二叉树,或者是具有如下性质的二又树:

子树上所有结点的关键字均小于根结点的关键字:

子树上所有结点的关键字均大于根结点的关键字。

左子树结点值< 根结点值< 右子树结点值

左子树和右子树又各是一棵二叉排序树。

进行中序遍历,可以得到一个递增的有序序列。

4.1 二叉排序树的查找

下面为二叉排序树的查找操作(代码如下):

//二叉排序树结点
typedef struct BSTNode
{
	int key;
	struct BSTNode* lchild, * rchild;
}BSTNode, * BSTree;
//在二叉排序树中查找值为 key 的结点
BSTNode* BST_Search(BSTree T, int key)
{
	while (T != NULL && key != T->key) //若树空或等于根结点值,则结束循环
	{
		if (key < T->key) T = T->lchild; //小于,则在左子树上查找
		else T = T->rchild;//大于,则在右子树上查找
	}
	return T;
}

采用递归版本的二叉查找算法如下:

//在二叉排序树中查找值为 key 的结点 (递归实现)
BSTNode* BSTSearch(BSTree T, int key)
{
	if (T == NULL)
		return NULL;//查找失败
	if (key == T->key)
		return T;//查找成功
	else if (key < T->key)
		return BSTSearch(T->lchild,key); //在左子树中找
	else
		return BSTSearch(T->rchild,key); //在右子树中找
}

4.2 二叉排序树的删除

先搜索找到目标结点:

1、若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质。

2、若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置。

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

使用z的后继代替z时: 采用z的右子树中最左下结点(该节点一定没有左子树))

使用z的前驱代替z时: 采用z的左子树中最右下结点(该节点一定没有右子树))

六、平衡二叉树

平衡二叉树(Balanced BinaryTree),简称平衡树 (AVL)——树        上任一结点的左子树和右子树的
高度之差不超过1。

结点的平衡因子 = 左子树高 - 右子树高。

6.1 调整最小不平衡子树(LL)

(1)LL平衡旋转(右单旋转)。由于在结点A的左孩子(L)的左子树(L)上插入了新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要一次向右的旋转操作。将A的左孩子B向右上旋转代替A成为根结点,将A结点向右下旋转成为B的右子树的根结点,而B的原右子树则作为A结点的左子树。

6.2 调整最小不平衡子树(RR)

(2)RR平衡旋转(左单旋转)。由于在结点A的右孩子(R)的子树(R)上插入了新结点,A的平衡因子由-1减至-2导致以A为根的子树失去平衡,需要一次向左的旋转操作。将A的右孩子B向左上旋转代替A成为根结点,)将A结点向左下旋转成为B的左子树的根结点,而B的原左子树则作为A结点的右子树。

6.3 调整最小不平衡子树(LR)

 (3)LR平衡旋转(先左后右双旋转)。由于在A的左孩子(L)的右子树(R)上插入新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转后右旋转。先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,然后再把该C结点向右上旋转提升到A结点的位置。

6.4 调整最小不平衡子树(RL)

  (4)RL平衡旋转(先右后左双旋转)。由于在A的右孩子 (R)的左子树(L)上插入新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转后左旋转。先将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置,然后再把该C结点向左上旋转提升到A结点的位置。

6.5 四种情况小结

 只有左孩子才能右上旋, 只有右孩子才能左上旋。

6.6 平衡二叉树的删除

平衡二叉树的删除操作:

1、删除结点后,要保持二又排序树的特性不变(左<中<右 )

2、若删除结点导致不平衡,则需要调整平衡

平衡二叉树的删除操作具体步骤

1. 删除结点 (方法同“二叉排序树”)

2. 一路向北找到最小不平衡子树,找不到就完结撒花

3. 找最小不平衡子树下,“个头”最高的儿子、孙子

4. 根据孙子的位置,调整平衡 (LL/RR/LR/RL)

5. 如果不平衡向上传导,继续2

七、红黑树

红黑树是二叉排序树的一种:左子树结点值 < 根结点值< 右子树结点值

7.1 红黑树的特性

1. 每个结点或是红色,或是黑色的

2. 根节点是黑色的

3. 叶结点 (外部结点、NULL结点、失败结点) 均是黑色的

4. 不存在两个相邻的红结点 (即红结点的父节点和孩子结点均是黑色)

5. 对每个结点,从该节点到任一叶结点的简单路径上,所含黑结点的数目相同

记忆口诀:左根右,根叶黑,不红红,黑路同。

性质1: 从根节点到叶结点的最长路径不大于最短路径的2倍

性质2: 有n个内部节点的红黑树高度 h\leqslant log_{2}(n+1)

红黑树的定义方式

7.2 红黑树的插入

1、先查找,确定插入位置(原理同二叉排序树),插入新结点

2、新结点是——染为黑色

3、新结点非根一一染为红色

        3.1 若插入新结点后依然满足红黑树定义,则插入结束

        3.2 若插入新结点后不满足红黑树定义,需要调整,使其重新满足红黑树定义

黑叔: 旋转+染色。

1. LL型:右单旋,父换爷+染色

2. RR型: 左单旋,父换爷+染色

3. LR型:左、右双旋,儿换爷+染色

4. RL型:右、左双旋,儿换爷+染色

红叔: 染色+变新。

叔父爷染色,爷变为新结点

 7.3 红黑树的删除

1. 红黑树删除操作的时间复杂度 = O(log_{2}n)

2. 在红黑树中删除结点的处理方式和 “二叉排序树的删除” 一样

3. 按2删除结点后,可能破坏“红黑树特性”,此时需要调整结点颜色、位置,使其再次满足 “红黑树特性”

八、B树

策略: m叉查找树中,规定除了根节点外,任何结点至少有 [m/2] 个分叉,即至少含有 [m/2]-1 个关键字。

m叉查找树中,规定对于任何一个结点,其所有子树的高度都要相同。

8.1 B树的概念

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

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

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

3)   除根结点外的所有非叶结点至少有「m/2] 棵子树,即至少含有[m/2]-1个关键字。

4)   关键字由小到大按顺序排列

5)   所有的叶结点都出现在同一层次上,并且不带信息(可以视为外部结点或类似于折半查找判定树的查找失败结点,实际上这些结点不存在,指向这些结点的指针为空)。

m阶B树的核心特性:

1)  根节点的子树数∈[2, m],关键字数∈[1, m-1]。
     其他结点的子树数∈[ [m/2], m];关键字数∈ [[m/2]-1, m-1])

2)对任一结点,其所有子树高度都相同

3)关键字的值:子树0<关键字1<子树1<关键字2<子树2<....(类比二叉查找树左<中<右)

      含n个关键字的m叉B树,log_{m}(n+1)\leqslant h\leqslant log_{[m/2]}\frac{n+1}{2}

8.2 B树的插入

核心要求:
① 对m阶B树——除根节点外,结点关键字个数[m/2]-1≤n≤m-1

② 子树0<关键字1<子树1<关键字2<子树2<....

新元素一定是插入到最底层“终端节点”,用“查找”来确定插入位置

在插入key后,若导致原结点关键字数超过上限,则从中间位置([m/2])将其中的关键字分为两部分,左部分包含的关键字放在原结点中,右部分包含的关键字放到新结点中,中间位置([m/2])的结点插入原结点的父结点。若此时导致其父结点的关键字个数也超过了上限,则继续进行这种分裂操作,直至这个过程传到根结点为止,进而导致B树高度增1。

8.3 B树的删除

1、若被删除关键字在终端节点,则直接删除该关键字(要注意节点关键字个数是否低于下限「m/2]- 1)

2、若被删除关键字在非终端节点,则用直接前驱直接后继来替代被删除的关键字

        直接前驱:当前关键字左侧指针所指子树中“最右下”的元素。

        直接后继:当前关键字右侧指针所指子树中“最左下”的元素。

3、若被删除关键字所在结点删除前的关键字个数低于下限且与此结点右(或左)兄弟结点的关键字个数还很宽裕,则需要调整该结点、右(或左)兄弟结点及其双亲结点(父子换位法)。

当右兄弟很宽裕时,用当前结点的后继、后继的后继来填补空缺;当左兄弟很宽裕时,用当前结点的前驱、前驱的前驱来填补空缺。

4、若被删除关键字所在结点删除前的关键字个数低于下限,且此时与该结点相邻的左、右兄弟结点的关键字个数均=[m/2]一1,则将关键字删除后与左(或右〉兄弟结点及双亲结点中的关键字进行合并。

8.4 B+树

一棵m阶的B+树需满足下列条件︰

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

2)  非叶根结点至少有两棵子树,其他每个分支结点至少有「m/2] 棵子树

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

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

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

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

 九、散列表查找(哈希表)

散列表(Hash Table),又称哈希表。是一种数据结构,特点是: 数据元素的关键字与其存储地址直接相关。

查找长度—— 在查找运算中, 需要对比关键字的次数称为查找长度。

9.1 常见的散列函数

一、除留余数法—— H(key)= key % p

散列表表长为m,取一个不大于m但最接近或等于m的质数p

二、直接定址法——H(key) = key 或 H(key) = a*key + b

其中, a和b是常数。这种方法计算最简单,且不会产生冲突。它适合关键字的分布基本连续的情况,若关键字分布不连续,空位较多,则会造成存储空间的浪费。

三、数字分析法——选取数码分布较为均匀的若干位作为散列地址

设关键字是r进制数〈如十进制数),而r个数码在各位上出现的频率不一定相同,可能在某些位上分布均匀一些,每种数码出现的机会均等﹔而在某些位上分布不均匀,只有某几种数码经常出现,此时可选取数码分布较为均匀的若干位作为散列地址。这种方法适合于已知的关键字集合,若更换了关键字,则需要重新构造新的散列函数。

四、平方取中法——取关键字的平方值的中间几位作为散列地址。

具体取多少位要视实际情况而定。这种方法得到的散列地址与关键字的每位都有关系,因此使得散列地址分布比较均匀,适用于关键字的每位取值都不够均匀或均小于散列地址所需的位数

9.2 处理冲突的办法

9.2.1 开放定址法

所谓开放定址法,是指可存放新表项的空闲地址既向它的同义词表项开放,又向它的非同义词表项开放。其数学递推公式为︰ H =(H(key)+ di)% m

m表示散列表表长; d 为增量序列; i 可理解为“ 第 i 次发生冲突 ”。

1、线性探测法—— d=0,1,2,3,..., m-1; 即发生冲突时,每次往后探测相邻的下一个单元是否为空

注意: 采用 “开放定址法” 时,删除结点不能简单地将被删结点的空间置为空,否则将截断在它之后填入散列表的同义词结点的查找路径,可以做一个“删除标记”,进行逻辑删除。

缺点:线性探测法很容易造成同义词、非同义词的“聚集 (堆积)”现象,严重影响查找效率

产生原因——冲突后再探测一定是放在某个连续的位置

2. 平方探测法

其中 d_{i}=0^{2}1^{2}-1^{2}2^{2}-2^{2}......

9.2.2 再散列法

再散列法 (再哈希法) : 除了原始的散列函数 H(key)之外,多准备几个散列函数当散列函数冲突时,用下一个散列函数计算一个新地址,直到不冲突为止。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构——查找 的相关文章

随机推荐

  • Spell 基于最长公共子序列的在线日志解析方法

    文章目录 01 日志模板挖掘 02 基于 LCS 的日志解析流程 2 1 日志键匹配查找 2 2 拆分与合并处理 2 2 1 拆分过程 2 2 2 合并过程 03 匹配查找优化 3 1 前缀树预过滤 3 2 倒排索引查找 04 Spell
  • APP弱网测试

    APP弱网测试 一 网络测试的一般流程 step1 首先要考虑网络正常的情况 各个模块的功能正常可用 页面元素 数据显示正常 step2 其次要考虑无网络的情况 APP各个功能在无网络情况下是否可用 APP各个页面之间切换是否正常 发送网络
  • torch.nn.Module和torch.nn.LSTM 相关文档

    torch nn Module和torch nn LSTM 相关文档 搬运官方链接 class torch nn Module 所有网络的基类 你的模型也应该继承这个类 import torch nn as nn import torch
  • fatal error C1034: stdio.h: 不包括路径集 ---LINK : fatal error LNK1104: 无法打开文件“libucrt.lib”【已解决】

    用windows 自带的编译工具 cl exe 编译 链接程序时候报错如下 1 编译报错 1 cpp 1 fatal error C1034 stdio h 不包括路径集 解决方法 新建环境变量 变量名 INCLUDE 变量值 D vs20
  • MQ 消息丢失、重复、积压问题,如何解决?

    MQ是面试中比较高频的问题 下面分享下MQ的常见问题 面试官在面试候选人时 如果发现候选人的简历中写了在项目中使用了 MQ 技术 如 Kafka RabbitMQ RocketMQ 基本都会抛出一个问题 在使用 MQ 的时候 怎么确保消息
  • Objective-C非正式协议和分类的区别

    当一个项目需要使用到一些通用的方法 这些方法需要在多个类中使用 那么我们就可以使用非正式协议来定义这些方法 以便于多个类之间共享这些方法 比如 我们可以定义一个名为 Utilities 的非正式协议 并在其中定义一些通用的方法 比如 Uti
  • 最大熵模型

    1 什么是最大熵原理 例子1 假设随机变量X有5个取值 A B C D E 要估计各个值的概率P A P B P E 这些概率值满足条件P A P B P C P D P E 1 但是满足这个条件的概率分布有无数个 如果没有其他信息 一个可
  • vue项目打包及配置跨域

    一 配置 proxy 跨域 module exports devServer open true 自动启动浏览器 host localhost localhost port 8080 端口号 hotOnly false 热更新 overla
  • python四行代码生成“年月日”格式的日期列表序列

    代码如下 import pandas as pd start 20110101 end 20161231 dates pd date range start end strftime Y m d to list 代码运行结果如下 需要说明的
  • 使用Typora将Markdown内容导出为Word(.docx)

    使用Typora将Markdown内容导出为Word docx 操作步骤 01 下载并安装Typora 自行前往Typora官网下载 傻瓜式安装 此处就不再做多余的解释 02 安装Pandoc 2 1 pandoc官网下载 真不知道怎么从这
  • Mongodb 定义model中的某个属性 保存任意类型

    参考 Mongoose5 0 文档http www mongoosejs net docs schematypes html 一个啥都可以放的 SchemaType 虽然便利 但也会让数据难以维护 Mixed 可以通过 Schema Typ
  • Spring @Scheduled @Async联合实现调度任务

    定时任务之前一直用的是quartz之类 但是注意到Spring中其实也提供了一种简单的调度注释 Scheduled 也就想尝一下鲜 代码示意如下 Component EnableScheduling public class AsyncTa
  • C++ primer plus 第六版 第十一章 复习题

    第十一章 复习题 1 Stonewt Stonewt operator double n const Stonewt result double total stn Lbs per stn n lbs n result stn total
  • RabbitMQ(三)手动Ack确认

    默认情况下 spring boot data amqp 是自动ACK机制 就意味着 MQ 会在消息发送完毕后 自动帮我们去ACK 然后删除消息的信息 这样依赖就存在这样一个问题 如果消费者处理消息需要较长时间 最好的做法是消费端处理完之后手
  • javascript enval()函数与JSON 之间关系

    概念定义 eval 函数可计算某个字符串 并执行其中的的 JavaScript 代码 enval 函数将把最后一个表达式或者语句所包含的值或引用作为返回值 举例说明一 eval javascrit表达式
  • 关于召开“CIE2019第三届中国IT教育论坛”的通知

    各相关高校 伴随着人工智能 智能制造 云计算 虚拟现实 5G等新技术的发展与日益成熟 全球范围内的新科技革命悄然打响 新一轮科技革命正在重塑世界竞争格局 以新技术 新业态 新产业为特点的新经济蓬勃发展 我国急需培养一批集学科 技术和产业思维
  • ubuntu18.04下mysql数据库安装和C语言连接操作

    数据库在应用系统开发中很常见 在众多的数据库中 mysql总是会占有一席之地 本篇说明一下如何在ubuntu18 04上安装mysql数据库 目录 1 更新环境 2 安装mysql数据库系统 3 检测是否安装成功 4 启动 重启 关闭 删除
  • CLion用于STM32开发

    最近想要复现稚晖君的ElectronBot 发现32的代码用的CLion编写的 而且是C和C 混编的 本来想着用keil再写一个 但是有点浪费时间 而且发现CLion学生可以白嫖 反正以后都要学习C 所以现在就装上吧 注 最终的效果只能下载
  • 克服过拟合和提高泛化能力的20条技巧和诀窍

    克服过拟合和提高泛化能力的20条技巧和诀窍 你是如何提升深度学习模型的效果 这是我经常被问到的一个问题 有时候也会换一种问法 我该如何提高模型的准确率呢 或者反过来问 如果我的网络模型效果不好 我该怎么办 通常我的回答是 具体原因我不清楚
  • 数据结构——查找

    一 查找的基本概念 查找 在数据集合中寻找满足某种条件的数据元素的过程称为查找 查找表 查找结构 用于查找的数据集合称为查找表 它由同一类型的数据元素 或记录 组成 关键字 数据元素中唯一标识该元素的某个数据项的值 使用基于关键字的查找 查