数据结构-查找

数据结构-查找 2021/8/12 23:00

查找表:用于查找的数据结构称为查找表,它由同一类型的数据元素组成
查找表的数据结构(顺序表)
typedef int ElemType;

typedef struct { //查找表的数据结构(顺序表)
	ElemType* elem;//动态数组基址
	int TableLen;//表的长度
}SSTable;

顺序查找

//顺序查找(O(n))
int Search_Seq(SSTable ST, ElemType key) {
	int i;
	for (i = 0; i < ST.TableLen && ST.elem[i] != key; ++i);
	//查找成功则返回下标,失败返回-1
	return i == ST.TableLen ? -1 : i;
}

折半查找/二分查找

//折半查找/二分查找(仅适用于有序的顺序表,需要存储结构随机访问)
int Binary_Search(SSTable L, ElemType key) {
	int low = 0, high = L.TableLen-1,mid;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (key > L.elem[mid])
			low = mid + 1;
		else if (key < L.elem[mid])
			high = mid - 1;
		else if (key == L.elem[mid])
			return mid;
	}
	return -1;
}
/*
折半查找判定树:右子树的元素数量要么相等,要么比左子树多一个(mid向下取整)
成功结点n个失败结点n+1个
时间复杂度(O(logN))
*/

分块查找/索引顺序查找

/*分块查找/索引顺序查找(在索引表中确定待查记录所属的分块(顺序、折半确定都可以),在块内顺序查找)
索引表中保存每个分块的最大关键字和分块的储存区间

用折半查找查索引,若索引表不包含目标关键字,则最终索引low>high,要在low所指分块中查找

设n个记录,均匀分为b块,每块s个记录,顺序查找索引表,当s=根号(n)时,ASL最小
*/
//索引表
typedef struct {
	ElemType maxValue;
	int low, high;
};
//顺序表储存实际元素
ElemType List[100];

B树

B树/多路平衡查找树
B树中所有结点的孩子的个数的最大值称为B树的阶(包含标志查找失败的叶子结点)
一棵m阶的B树或为空树,或为满足如下特性的m叉树
1)树中每个结点至多有m棵子树,即至多含有m-1个关键字
2)若根结点不是终端结点,则至少有两棵子树
3)除根结点外的所有非叶结点至少有m/2棵子树,即至少含有[m/2]-1(向上取整)个关键字
4)所有的叶结点都出现在同一层次上,并且不带信息
(可以视为外部结点或类似于折半查找判定树的查找失败结点,
实际上这些结点不存在,指向这些结点的指针为空)
<对任一结点,所有子树的高度相同>
大部分学校算B树的高度不包括叶子结点
n个关键字的B树必有n+1个叶子结点(可以看成n个关键字把-无穷到+无穷分为了n+1个部分)

//5叉查找树的定义
struct Node {
	ElemType keys[4]; //最多4个关键字
	struct Node* child[5];//最多5个孩子
	int num;//结点中有几个关键字
};
B树的插入:
1.新元素一定是插入到最底层“终端结点”,用“查找”来确定位置
2.在插入key后,若导致原结点关键字数超过上限,则从中间位置[m/2](向上取整)将其中的关键字分为两部分
左部分包含的关键字放在原结点中,右部分包含的关键字放到新结点中,中间位置[m/2](向上取整)的结点插入原结点的父结点。
若此时导致其父结点的关键字个数超过了上限,则继续进行这种分裂操作,直至这个过程传到根节点位置,进而导致B数高度增1
B树的删除
对非终端结点的删除操作可以转化为终端结点的删除:
若被删除关键字在非终端结点,则用直接前驱或直接后继来替代被删除的关键字
对终端结点的删除:
1.删除后所在结点的关键字个数不低于下限,则可以直接删除移动
2.删除后低于该结点关键字个数下限:
1)兄弟够借。若该结点删除后,结点关键字个数低于要求,在兄弟结点关键字充裕的情况下(兄弟结点删除一个关键字后个数仍符合要求)
用兄弟结点顶替父结点,将父节点插入该结点
2)兄弟不够借。在兄弟关键字不充裕的情况下,将该结点、兄弟结点和他们的父关键字合并。
此时应注意父关键字被拉下来合并后,之前父关键字所在结点可能关键字个数低于要求,此时应重复上诉过程。

B+树

B+树 类似于分块查找
m阶B+树满足以下条件:
1)每个分支结点最多有m棵子树(孩子结点)
2)非叶根结点(当前叶结点不是根结点)至少有两棵子树,其他每个分支结点至少有[m/2]/(向上取整)棵子树
3)结点的子树个数与关键字个数相等!!!!易考点和B树相区别!!!!!!
4)所有叶结点包含全部关键字及指向相应记录的指针,叶结点中将关键字按大小顺序排列,并且相邻结点按大小顺序相互链接起来。
5)所有分支结点仅包含它的各个子结点中关键字的最大值及指向其子结点的指针
B+树中不论是否成功与否,都要走到最后一层

B+树和B树相比的优点:
B+树只有叶子结点处才有完整的数据(即包含关键字又包含关键字对应的其他数据),非叶子结点只有关键字,而B树每个结点都包含了关键字及其对应的数据
在内存中,数据以块的形式储存,进行分析的时候要将磁盘中的数据以块的形式向内存中传输,而这个过程是慢速的
因此B+树非叶子结点只保存关键字的形式可以使得一个块中包含的关键字个数更多,能快速的找到数据所在块。
关系型数据库如mysql就是用B+树实现的

散列查找

散列查找
散列表/哈希表:数据元素的关键字与其存储地址直接相关,典型的空间换时间的算法
装填因子a=表中记录数/散列表长度
常见散列函数:
1.除留取余法:散列表表长为m,取一个不大于但最接近或等于m的质数p,目的:让不同关键字的冲突尽可能的少
2.直接定址法:适合关键字分布基本连续的情况。若关键字分布不连续,空位较多,则可能造成存储空间的浪费
3.数字分析法:选取数码分布较为均匀的若干位作为散列地址(如手机号后四位,不能取前四位)
4.平方取中法:这种取中方法得到的散列地址和关键字的每位都有关系,因此使得散列地址分布较为均匀,适用于关键字的每位取值都不够均匀或均小于散列地址所需的位数

处理冲突的方法:
1.拉链法/链地址法:在插入新元素时,保持关键字有序,可微微提高查找效率
2.开放定址法:指可存放新表项的空闲地址既向它的同义词表项开放又向它的非同义词表项开放。
1)线性探测法:发生冲突时,每次往后探测相邻的下一个单元是否为空(空位置的判断也要算作一次比较)
注意:采用开放定址法时,删除结点不能简单地将被删除结点的位置置空,否则将截断在它之后填入散列表的同义词结点的查找路径,可以做一个删除标记,进行逻辑删除
可能会出现看起来很满,其实很空的情况
2)平方探测法/二次探测法:d=0,1,-1,4,-4……
非重点小坑:散列表长度m必须是可以表示成4j+3的素数,才能探测到所有位置
3)伪随机序列法:d=某个伪随机序列
以上关于开放定址法的三种小方法其实就是对随机序列的取值不同而已
3.再散列法:除了原始的散列函数外,多准备几个散列函数,当散列函数冲突时,用下一个散列函数计算一个新地址,直到不冲突为止。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Handsome Wong

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

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

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

打赏作者

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

抵扣说明:

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

余额充值