【背诵笔记】查找

查找

在这里插入图片描述

查找表

用于查找的数据结构。一般为数组或者链表。定义为结构体,用来存储相同的数据。

//定义查找表结构体
typedef struct
{
	int *data;
	int TableLen;
}SSTable;

key是唯一标识值

查找的对象是唯一的,这意味着,在查找的时候不考虑重复值的情况。

ASL

在这里插入图片描述
平均查找长度:所有查找过程中进⾏关键字的⽐较次数的平均值。
1,默认概率是相等的,实际就是比较总次数/元素数。
2,也有一些题会给不同的概率,按公式计算即可。
3,ASL的计算还分为查找成功和查找失败两种。
在这里插入图片描述

在这里插入图片描述

顺序查找

在这里插入图片描述

思路

暴力搜索,从头到尾遍历数组,找到该元素就返回元素下标,否则返回-1。

代码

1,不带哨兵,待排数据存在data[0]-data[n-1],从前向后遍历,需要多一步比较防止数组越界。

//定义查找表结构体
typedef struct
{
	int *data;
	int TableLen;
}SSTable;
//查找
int Search_Seq(SSTable* L, int key) {
	int i;
	for (i = 0; i < L->TableLen && L->data[i] != key; ++i);//需要比较i < L->TableLen ,防止数组越界
	return i == L->TableLen ? -1 : i;
}

2,带哨兵,data[0]存哨兵数据,待排数据存在data[1]-data[n],从后向前遍历,如果没有找到最后会回到哨兵处,返回0;少一步比较

//查找
int Search_Seq(SSTable* L, int key) {
	L->data[0]=key;
	int i;
	for (i = L->TableLen;  L->data[i] != key; --i);//需要比较i < L->TableLen ,防止数组越界
	return i;
}

效率

在这里插入图片描述
查找成功:如果是从前向后遍历,第一个元素遍历1次即可找到,第二个遍历2次,依次类推ASL成功=(n+1)/2
查找失败:从头向后遍历完序列,直到遇到哨兵,对比n+1次。
则顺序查找的时间复杂度为0(n)

链表实现

//定义查找表结构体
typedef struct SSTable//必须先加SSTable,否则next指针无法使用
{
	int data;
	SSTable* next;
}SSTable;
int Search_Seq(SSTable* L, int key) {
	SSTable* p = L->next;
	if (p != NULL) {
		while (p != NULL && p->data != key) {
			p = p->next;
		}
	}
	return p == NULL ? -1 : p->data;//p必须为全局变量,返回的是值不是下标
}

优化:有序序列

思路:从前向后对有序序列查找,如果遇到一个大于key的元素,说明后面所有的元素都大于key,则无需继续查找。

int Search_Seq(SSTable* L, int key) {
	int i;
	for (i = 0; i < L->TableLen && L->data[i] != key; ++i) {
		if (L->data[i] > key)
			return -1;
	}
	return i == L->TableLen ? -1 : i;
}

效率(查找判定树)

在这里插入图片描述
在这里插入图片描述
可见优化主要是在查找失败的时候体现。

优化:概率不相等序列

在这里插入图片描述
1,ASL的计算,对比次数乘以对应的概率
2,查找概率大的放在序列靠前位置,能提升查找成功的效率,但是同时查找失败的效率会降低。

折半查找

在这里插入图片描述

思路

仅适合有序的顺序表(数组);key与序列中间位置元素对比,等于返回key;小于查找左子表,大于查找右子表。直到找到key或者low>high,找不到返回-1。

代码

//定义查找表结构体
typedef struct
{
	int* data;
	int TableLen;
}SSTable;
//折半查找
int Binary_Search(SSTable* L, int key) {
	int low = 0, high = L->TableLen - 1, mid;
	while (low <= high) {
		mid = (low + high) / 2;
		if (L->data[mid] == key)
			return mid;
		else if (L->data[mid] > key)
			high = mid - 1;
		else
			low = mid + 1;
	}
	return -1;
}

效率

查找判定树

构建查找判定树(非叶节点为查找成功情况,叶节点为查找失败情况)
在这里插入图片描述
快速构建方法——根据序列元素的奇偶数。
右子树节点数>左子树节点数=0 or 1
在这里插入图片描述

性质

1,一定是一棵平衡二叉树(折半查找的性质,每次都分为两半来找)
2,判定树,只有最后一层不满,类似于完全二叉树(只是节点优先在右边)
在这里插入图片描述
树高为h,则最多 2 h − 1 2^{h}-1 2h1个节点,最少 2 h − 1 2^{h-1} 2h1个节点(上一层最多 2 h − 1 2^{h-1} 2h1-1个,加一个就是本层最少的节点数)最终可以计算出判定树的树高。
在这里插入图片描述

3,是一棵二叉排序树(左<根<右),且关键字节点数为n,失败节点数为n+1。
4,ASL<=h,则查找的时间复杂度为O( l o g n log^{n} logn)
5,如果换成向上取整,则判定树变为左子树节点数>右子树节点数=0 or 1
在这里插入图片描述

二叉排序树

在这里插入图片描述

代码实现

查找
在这里插入图片描述
插入
在这里插入图片描述
构造
在这里插入图片描述
删除
1,没有子树,直接删除
2,只有左或者右子树,让左右子树根节点代替该节点。
3,有左右子树,按中序遍历,直接前驱(或后继)节点替代该节点,然后删除前驱或后继(代替之前的)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

效率

在这里插入图片描述
在这里插入图片描述

与二分查找(折半)

相同点:二叉排序树与二分查找的查找判定树的查找方式类似。
不同:
1,对于同一个序列,二分查找判定树固定(查找方式始终一样);二叉排序树则可以构造为不同形态
2,逻辑结构不同,二分查找是采用顺序表进行,插入删除要移动大量元素(O(n)),适合静态查找;二叉排序树则是采用指针链表进行,移动删除元素较少,适合动态查找。

平衡二叉树

在这里插入图片描述

在这里插入图片描述

插入节点

插入一个新节点后,整个书上所有节点都可能受到影响。从插入点开始向根节点找到第一个不平衡的节点,也就是最小不平衡子树,对其进行调整。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

效率

只需要记得平衡后平均查找长度是O( l o g n log^{n} logn)。
查找长度与树的深度挂钩。对于二叉树每层节点肯定是大于等于1;则h<=n。小于n这个级别的也只有 l o g n log^{n} logn和常数级。则查找长度最坏是O(n),平均是 l o g n log^{n} logn这个级别的。
在这里插入图片描述

分块查找(索引顺序查找)

在这里插入图片描述

思路

存储结构

实际顺序存储在数组中;按块存储,块内无需,块与块之间有序(后面的块中元素均小于前面的块)
索引表结构体中存储每个块的最大元素,以及块的范围(数组下标)。

//索引表
typedef struct{
	ElemType maxvalue;
	int low,high;
	};
//实际数据
ElemType List[100];

在这里插入图片描述

查找思路

1,对模板元素key,先在索引表中查找,找到第一个大于等于key的元素(顺序查找或者折半查找)。
2,找到了就在该元素对应的块内顺序查找(块中无序)。

对于折半查找而言:
若索引表中有该元素,则在mid指向处找到。
若索引表中没有该元素,则在low>high后,在low指向的块中查找(指向大于该元素的最小元素)
若low最后超出了索引范围,则说明查找失败,索引表所有元素都小于key。

效率(一般不考)

1,给一个序列,手动求ASL
2,给n长度序列,分为b块,每块s个元素,求ASL
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

B树

基本概念

在这里插入图片描述

推导

B树是在m叉查找树基础上发展而来。对于m叉查找树,每个节点内至少1个关键字2个分叉,最多m-1个关键字m个分叉。且在节点内关键字有序排序。
在这里插入图片描述
但是查找树存在两个问题,如果每个节点内的关键字太少,会导致树变高,查找更多层效率低。因此要保证每个节点内的关键字最低数量为⌈m/2⌉-1。
在这里插入图片描述
同时左右子树高度不同(不平衡)也会增加查找的时间。因此要求任意节点左右子树高度相同。

在这里插入图片描述

基本性质

满足以上两个条件的m叉查找树就是B树,也就是m阶B树。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

高度

1,下限
使每个结点装满,m-1个关键字,m个分叉。
第一层有1个节点,m个分叉
第二层有m个节点, m 2 m^{2} m2个分叉
则第h层有 m h − 1 m^{h-1} mh1个节点
节点求和并乘以m-1(每个节点的关键字个数)得到了关键字数的上限。由不等式求高度上限。
在这里插入图片描述
2,上限
从叶子节点出发求解
在这里插入图片描述
从总的最少关键字个数出发求解
在这里插入图片描述

插入与删除

在这里插入图片描述

插入

1,插入后满了,要执行分裂
在这里插入图片描述
2,新元素插入要沿着指针插在最下层。
在这里插入图片描述

3,插入后满了,分裂时,中间位置节点往上层插;插入的位置就是从左向右遍历,插在第一个大于该元素的元素前面即可。

在这里插入图片描述

在这里插入图片描述
4,插入后父节点满了,则对父节点分裂,直到根节点为止。
在这里插入图片描述
在这里插入图片描述
5,总结
在这里插入图片描述

删除

1,在终端节点内删除,直接删即可。
2,对非终端节点删除后,用直接前驱或后继代替(实际就是对终端节点删除)
在这里插入图片描述
在这里插入图片描述
3,删除后节点内关键字低于下限,从兄弟节点中借调
右兄弟:先把直接后继(父关键字)下移插入到该节点中;然后将右兄弟节点中最小关键字(最左边)上移代替父关键字位置。
在这里插入图片描述
在这里插入图片描述

左兄弟:先把直接后继(父关键字)下移插入到该节点中;然后将左兄弟节点中最大关键字(最右边)上移代替父关键字位置。
在这里插入图片描述

在这里插入图片描述
4,删除后,兄弟不够借;合并兄弟节点以及双亲节点关键字。
在这里插入图片描述
双亲关键词下沉合并后,若导致上层节点(非根节点时)低于下限,则继续合并上层,直到满足要求。
在这里插入图片描述
在这里插入图片描述

B+树

特性

应数据库而出现的一种B树的变形树。
在这里插入图片描述
分块查找和B+树都有索引这个概念,分块查找是在索引表中存放每个分块的区间和最大关键字。B+树索引中只存储下一索引的最大关键字和地址,通过树结构连接到叶子节点,最终通过叶节点指向数据。
在这里插入图片描述
特征
在这里插入图片描述
B+树追求绝对平衡
在这里插入图片描述

B树与B+树

1,主要差异点
在这里插入图片描述
2,查找不同
B+树的查找,最终都会到叶子节点。非叶子节点不会指向数据。因为非叶节点是在外存(磁盘)中存储,每次查找需要存入内存中执行。如果不存储数据的地址,使得每次传入内存空间的节点更多,减少磁盘存取次数(B+树阶更大,更矮,提高查找效率)。
在这里插入图片描述
B树则可能在任何一层查找成功,因为每个节点都存储了数据的地址。

在这里插入图片描述
3,子树不同
在这里插入图片描述
B树,每个节点的n个关键字,被分割成n+1段。
在这里插入图片描述
4,关键字数目不同
B+树有m个分支,对应m个关键字。
在这里插入图片描述
B树有m个分支,对应m-1个关键字。
在这里插入图片描述
6,关键字是否重复
在这里插入图片描述

在这里插入图片描述
6,数据存储结构
最终由叶节点执行数据地址。
在这里插入图片描述
关键字地址分布于各节点
在这里插入图片描述
7,应用
在这里插入图片描述

散列查找(哈希查找)

在这里插入图片描述

概念

1,散列表(哈希表):根据关键字直接进行访问的数据结构,建立关键字与地址的直接关系。
2,散列函数:关键字输入函数,输出地址。将关键字映射到地址上。

存储:关键字输入函数,获得地址,将关键字存入地址中。
查找:输入要查找的关键字,获取地址,在改地址中找关键字,理想情况下查找速度为O(1)。
在这里插入图片描述

查找效率

散列函数

不同的散列函数映射的地址分布状况也不相同,好的散列函数可以均匀分布地址,减少冲突。并尽可能简单,快速计算结果。由此散列函数影响查找效率

冲突处理方法

理想情况下(没有冲突)查找长度为O(1);如果遇到冲突,就会回到对比元素大小的情况,如果冲突越多,ASL就会变大。ASL=每个元素查找次数/序列长度

在这里插入图片描述

装填因子

装填因子:衡量散列表的利用率;值越大说明装的约满,再插入新元素,或者查找的话冲突可能性越大。计算每一个格子内的元素数量,然后除以格子数。
在这里插入图片描述
衡量效率的因素:散列函数、处理冲突的方法和装填因子。

散列函数

直接定址

在这里插入图片描述

除留余数

在这里插入图片描述
质数的公因子最少,除的时候不会集中分布。比如关键字多为偶数,用偶数除,导致地址都分布在偶数上。用质数则会尽可能的均匀。
在这里插入图片描述
在这里插入图片描述

数字分析法

比如手机号,身份证号,可以用后四位进行计算。结果分布均匀一些。如果用前四位则会造成大量重复。
在这里插入图片描述

平方取中

平方后,中间几位是每一个元素都参与了相乘(影响了结果);由此取中间结果比较均匀。
在这里插入图片描述

空间换时间

散列函数合理尽可能的均匀,则列表越长,冲突概率越低。
在这里插入图片描述

处理冲突的方法

不同的关键字被映射到同一个地址,由此引发了冲突;必须对冲突进行处理。

拉链法

原始数列存储指针,初始都指向NULL;存入数据就通过指针构建链表,如果遇到同义词就依次插入链表中。

在这里插入图片描述

效率

1,查找长度:
如果链表为空,不算元素之间的比较,查找长度为0;如查找21,8中为空直接结束,查找长度为0。
链表不为空从链表第一个元素的对比计算,如查找27,在链表中和14 1 27对比后找到,查找长度为3。查找66,对14 1 27 79对比后查找失败,长度为4。
在这里插入图片描述
2,平均查找长度
ASL=每个元素查找次数/序列长度
在这里插入图片描述

小优化

在这里插入图片描述

开放定址法

开放表中空闲地址给同义词使用;可能造成同义词和非同义词的集中。
主要有三种方法。在这里插入图片描述

线性探测法

每次冲突都像下一个单元探测,1与14冲突,向后探测,插在14后面。
在这里插入图片描述
可能会造成不断向后查找,直到遇到第一个NULL,如79要从1一直找到9才能插入。
在这里插入图片描述
哈希函数和线性探测的范围可能不同,哈希函数确定的初始范围,线性探测是在初始冲突后调整的范围。
在这里插入图片描述

查找

查找的时候,没有被挤占,就很快
在这里插入图片描述

如果被挤占了,则同义词、非同义词也可能都要查找。
在这里插入图片描述
查找失败,要一直比较到NULL处,且空位置的比较也算一次。
在这里插入图片描述
在这里插入图片描述

删除

直接删除,可能造成后面查找出现错误(直接判定为失败)
在这里插入图片描述

在这里插入图片描述
删除后在原位置加一个标记。
在这里插入图片描述
在这里插入图片描述
也可能造成空间的浪费
在这里插入图片描述

效率

在这里插入图片描述
逐个分析[0,12]的查找失败的对比次数。
关键字映射到0处,对比1次失败
关键字映射到1处,要遍历到13才失败
。。。。
求和,除以关键字个数即可。
在这里插入图片描述
在这里插入图片描述

平方探测法

关键字遇到冲突后d按平方加正负取值。如下,本应都存在6处。冲突后按平方探测处理H=(H(key)+d)%m;注意这里是对表长取模,不是对序列数取模。
19:(6+1)%27=7
32:6和7都冲突,再计算H=(6-1)%27=5
在这里插入图片描述

在这里插入图片描述
查找的时候也是按H的计算方法,如71依次查找6 7 5 10 2 最后再15找到。
在这里插入图片描述
表长应该为4J+3的素数
在这里插入图片描述

伪随机数

按伪随机数随机放置;如19和6冲突,取随机数5;往后移5格(6+5=11)到11处。
在这里插入图片描述

删除都要标记

开放定址法删除都要标记。
在这里插入图片描述

再散列法

用多个散列函数进行处理,当函数计算地址冲突的时候,用下一个函数计算新地址。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕南路GISer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值