数据结构_study(七)

查找

查找表:同一类型的数据元素构成的集合
关键字(键值):数据元素中某个数据项的值,用来标识数据元素
主关键字:唯一标识一个记录的关键字
次关键字:可以标识多个数据元素的关键字

查找:根据给定的某个值,在查找表中确定一个(关键字=给定值的)数据元素
查找成功,返回数据元素,查找失败返回空

静态查找表:只作查找操作的查找表,查找特定数据元素,检索特定数据元素和属性
动态查找表:查找过程中,插入不存在的元素,删除已存在的元素

查找结构:面向查找操作的数据结构,集合

顺序表查找

集合构造成线性表,对线性表查找,静态查找表

顺序查找(线性查找):
从表中的第一个或最后一个记录开始,
逐个比较关键字和给定值;相等则查找成功,返回记录;

哨兵,避免每次比较i<=n;i++;

时间复杂度 O(n)
最好情况 O(1)、最坏情况 O(n)、平均情况 O((n+1)/2)

有序表查找

有序排序之后的线性表查找

折半查找

前提:顺序存储线性表中的记录的关键码有序

二分(折半)查找:取中间记录作为比较对象,
相等则查找成功,
给定值小于中间记录的关键字,在左半区继续查找
给定值大于中间记录的关键字,在右半区继续查找
重复直到查找成功或查找完成

中间记录:mid=(low+high)/2

n个结点的完全二叉树深度:log2n向下取整+1
最好情况O(1),最差情况O(log2n向下取整+1)
时间复杂度 O(logn)

对于频繁插入删除的数据集,维护排序会产生工作量
在这里插入图片描述

插值查找

在二叉查找基础上修改取中间元素的做法

插值计算公式:mid= low+ (high-low)* (key-a[low])/(a[high]-a[low]);

对表长较大,且关键字分布比较均匀的查找表 合适

斐波那契查找

在 斐波那契 数组中查找

避免mid溢出数组,填充待排序数组

1、key=a[mid],查找成功
2、key<a[mid];k–;新范围[low,mid-1],范围个数F[k-1]-1个
3、key>a[mid];k=k-2;新范围[mid+1,high],范围个数F[k-1]-1个

mid:low+F[k-1]-1

时间复杂度 O(log n)
只进行加减操作,减少消耗

在这里插入图片描述

线性索引查找

增删多的数据集

索引:把关键字和对应的记录关联的过程
一个索引由若干索引项构成
索引项包含关键字和对应的记录在存储器的位置

根据结构分为:
线性索引:索引项集合组织为线性结构,索引表
树形索引
多级索引

线性索引分为以下3种

稠密索引

稠密索引:在线性索引中,将数据集中每个记录对应一个索引项,索引项按关键码有序排列

索引有序,可以使用折半,插值,斐波那契数列查找关键字

索引项和记录个数相同,空间代价大
在这里插入图片描述

分块索引

数据集的记录分成若干块,
块内无序:每一块内的记录不要求有序
块间有序:eg:第二块所有记录的关键字均大于第一块中所有记录的关键字

分块索引表
1、最大关键码:每一块中最大关键字
2、存储块中的记录个数
3、指向块首数据元素的指针
在这里插入图片描述
分块索引 查找
1、分块索引表中查找关键字所在的块
2、块首指针找块,块中顺序查找关键码

n个记录,分为m块,每块有t条,n=m*t

查找索引表平均查找长度(m+1)/2
查找块平均查找长度(t+1)/2
分块索引:(m+1)/2+(t+1)/2=(n/t+t)/2+1

倒排索引

倒排索引:属性值确定记录的位置

索引项的通用结构
1、次关键码(记录的属性)
2、记录号表:具有相同次关键字(属性)的所有记录号

生成索引表之后可以不用读取记录,节省查找时间
记录号不定长,插入删除维护困难

二叉排序树

无序数据查找效率低
有序数据插入删除效率低

动态查找:查找时插入和删除

二叉排序树(二叉查找树):空树,或者以下性质
1、左子树<根<右子树
2、左右子树也分别为二叉排序树

中序遍历可以得到有序序列

构造二叉排序树可以提高在有序序列中插入删除的速度
查找性能取决于二叉排序树的形状,平衡时间复杂度=完全二叉树深度,不平衡时间复杂度=O(n)

链接方式存储

在这里插入图片描述

查找

比较根结点
关键字<根,查左子树
关键字>根,查右子树
相等返回

插入

查找完成,不存在关键字时插入
在这里插入图片描述

删除

删除结点,并且保持二叉排序树的特性

1、叶子结点直接删除
2、只有左子树/右子树,左子树整个移动到删除结点的位置
3、有左右子树,找到结点的直接前驱或直接后继,替换结点并删除原来的结点
在这里插入图片描述
在这里插入图片描述

平衡二叉AVL树

每个结点的左子树和右子树高度差最多=1二叉排序树

平衡因子 BF:左子树深度-右子树深度
AVL树BF取值-1,0,1
最小不平衡子树:距离插入结点最近,平衡因子绝对值>1的结点为根的子树

每插入一个结点,检查平衡性
不平衡,找出最小不平衡子树,旋转
BF>1右旋,BF<-1左旋
最小不平衡子树根节点和子结点符号不同时,对子节点旋转一次之后再反向旋转

平衡二叉树查找,删除,插入时间复杂度,均为O(logn)
在这里插入图片描述

在这里插入图片描述

多路查找 B树

操作的数据集非常大,不在内存中处理,涉及到访问外部存储设备

多路查找树:一个结点的孩子树多于2个,每一个结点处可以存储多个元素
同一元素出现一次

2-3 树

每个结点都具有2个孩子(2结点)或3个孩子(3结点)的多路查找树
2结点:1个元素和(0个或2个)孩子,左子树<根<右子树
3结点:一大一小2个元素和(0个或3个)孩子。左子树<较小元素<中间元素<较大元素<右子树

特征:叶子都在同一层次

插入:一定是发生在叶子结点上
1、空树,插入2结点
2、插入结点到2结点的叶子,叶子本身只有一个元素,升级为3结点
3、插入结点到3结点的叶子,树中的两元素或插入元素,选择一个向上移动:
在这里插入图片描述

删除:
1、删除元素在3结点,直接删除
2、删除元素在2结点叶子:

  • 待删除元素的双亲是2结点,且拥有一个3结点的右孩子
  • 待删除元素的双亲是2结点,且拥有一个2结点的右孩子
  • 待删除元素的双亲是3结点,拆分双亲
  • 满二叉树,减少层数

3、删除的元素在非叶子的分支结点
在这里插入图片描述

2-3-4 树

在2-3树的基础上加上4结点
4结点:小中大3个元素和(0个或4个)孩子
左子树<最小元素<第二子树<中间元素<第三子树<最大元素<右子树
在这里插入图片描述

B树

平衡多路查找树
B树的阶:结点最大的孩子数目

2-3树是3阶B树
2-3-4树是4阶B树

一个m阶的B树,属性
1、根结点不是叶结点时,至少有2棵子树
2、所有叶子结点位于同一层
3、每一个非根的分支结点都有k-1个元素(关键字)和k个孩子(子树),
每个叶子结点n都有k-1个元素,m/2向上取整<=k<=m
4、所有分支结点包含(n,A0,K1,A1,K2,A2,K3,A3…Kn,An),
Ki为关键字,Ki-1<Ki,i=(1,2,3,…,n-1)
Ai指向子树根结点的指针,i=(0,2,3,…,n)
Ai-1指向的子树所有结点关键字<Ki,i=(1,2,3,…,n-1)
Ai指向的子树所有结点关键字>Ki,i=(1,2,3,…,n-1)
m/2向上取整-1<=n<=m-1

查找:指针查找结点,结点中查找关键字
插入删除和2-3,2-3-4树类似

应用:结点的元素和硬盘存储的页面大小相匹配,每次访问硬盘可以获得最大数量的数据
eg:1个结点包含1000个关键字,高度为2(3层),可以存储超10亿的关键字,只要根节点在内存,找关键字只用读取2次硬盘

缺点:遍历往返结点会在硬盘的页面之间多次访问

n个关键字的m阶B树查找最坏情况:层数最大 log(m/2向下取整)((n+1)/2)+1
第一层1个
第二层最少2个结点,每个分支结点至少有(m/2向下取整)棵子树
第三层:(m/2向下取整)*2个结点
第k+1层:2 * (m/2向下取整)k-1个结点,叶子结点
n+1>=2 * (m/2向下取整)k-1

B+树

和B树的差异
1、n棵子树的结点中有n个关键字
2、所有的叶子节点包含全部关键字的信息,及指向关键字对应记录的指针,叶子结点本身依关键字大小自小而大的顺序链接
3、除了叶子都是索引,结点中只含有子树中最大或最小关键字

随机查找:根节点出发,到叶子结点才能访问记录
顺序查找:从最左侧叶子结点出发,不经过分支

最适合:从根节点出发,查找第一个信息,再在叶子节点查找符合范围的记录

插入删除都在叶子节点
在这里插入图片描述

散列表查找(哈希表)

不通过比较关键字获取记录

散列:在记录的存储位置和关键字之间建立确定的对应关系f,使得每个关键字key对应一个存储位置=f(key)

散列函数(哈希函数):f

散列表(哈希表):(采用散列技术将记录存储在)一块连续的存储空间

散列过程
1、存储:根据散列函数计算记录的散列地址,按照散列地址存储记录
2、查找记录:根据散列函数计算记录的散列地址,按照散列地址访问记录

记录之间不存在逻辑关系,只与关键字关联

最适合查找与给定值相等的记录
不适合一个关键字对应多个记录,查找范围,获取记录排序

理想状态:每个关键字通过散列计算的地址不一样
冲突:关键字不同,f(key1)=f(key2)地址相同
散列函数的同义词:冲突的两个关键字

散列函数构造

要求:
1、计算简单
2、散列地址分布均匀

参考因素:
1、计算散列地址需要的时间
2、关键字的长度
3、散列表的大小
4、关键字的分布情况
5、记录查找的频率

直接定址

取关键字的某个线性函数值为散列地址
f(key)=a*key+b (a,b为常数)

简单,均匀,不会产生冲突,适合表小且连续
在这里插入图片描述

数字分析

抽取关键字的一部分,对抽取的数字反转、左环位移、右环位移等等操作

适合关键字位数较大,事先知道关键字的分布,且关键字的若干位分布均匀
在这里插入图片描述

平方取中

关键字平方,再取中间几位

适合不知道关键字分布,位数不大的情况

折叠

关键字从左到右分割成位数相等的几部分,叠加求和,按散列表长取后几位

适合不知道关键字分布,位数较大的情况

除留余数

f(key)=key mod p(p<=m)

关键:p取值,不好的取值会导致冲突
通常p为小于或等于表长的最小质数、或不包含小于20质因子的合数

随机数

f(key)=random(key)随机函数
适合关键字长度不等

散列冲突

冲突:关键字不同,f(key1)=f(key2)地址相同

开放定址

线性探索法:发生冲突,找下一个空的散列地址
f(key)=(f(key)+d¡)MOD m(di=1,2,3,…,m-1 )

堆积:不是同义词的key需要争夺一个地址

二次探索法:增加平方运算,为了不让关键字聚集在某一块区域
f(key)=(f(key)+di )MOD m(di=12,-12,22,-22,…, q2,-q2,q≤m/2 )

堆积探索法:对位移量di采用随机函数(伪随机数)
伪随机数:同样的随机种子,得到的数列相同
f(key)=(f(key)+di;)MOD m(di是一个随机数列)

再散列

事先准备多个散列函数
每次发生冲突,换一个散列函数计算
增加计算时间

链地址

同义词子表:关键字为同义词的记录存储在一个单链表中
增加查找单列表的性能损耗
在这里插入图片描述

公共溢出区

冲突的元素存到溢出表中

散列函数计算散列地址和基本表的位置比较,相等则查找成功,不相等去溢出表顺序查找

适合有冲突的数据少
在这里插入图片描述

散列表查找

性能:
1、散列函数是否均匀:出现冲突的频繁程度
2、处理冲突的方法:堆积
3、散列表的装填因子:实际记录个数/散列表长度,越大冲突越多

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值