数据结构知识点-查找

线性表的查找

顺序查找
顺序表或线性链表表示俄的静态查找表,表内元素之间无序

# 查找顺序表L中值为e的数据元素
int LocateElem(SqList L,ElemType e)
{
	for(i = 0;i < L.length;i++)
	{
		if(L.elem[i] == e)
			return i+1;
	}
	return 0;
}
# 增加哨兵
int Search_Seq(SSTable ST,KeyType Key)
{
	ST.R[0].key = key;
	for(i = ST.length;ST.R[i].key != key;--i);
	
	return i;
}

空间复杂度为:O(1)
时间复杂度:
查找成功的ASL=(1+2+…+n)/n=(n+1)/2
查找不成功的ASL=n+1
顺序查找的特点:1、算法简单,对表结构无任何要求。2、n很大时查找效率很低。

在一维数组A[1…n]中,在进行顺序查找时n个数的排列有序或无序其平均 查找长度ASL相同。
查找概率相等时,ASL相同。
查找概率不等时,如果从前向后查找,则按照查找概率由大到小排列的有序表的ASL,要比无序表的ASL小。

折半查找
适用于采用顺序存储结构的有序表,不适用于链式结构。
折半查找的性能:每次将待查找记录所在区间缩小一半,比顺序查找效率高时间复杂度为O(log2 n)

# 折半查找 非递归算法
int Search_Bin(SSTable ST,KeyType key)
{
	low = 1;high = ST.lenght;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(key==ST.R[mid].key)
			return mid;
		else if (key < ST.R[mid].key)
			high = mid - 1;
		else
			low = mid + 1;
	}
	return 0;
}
# 非递归查找
int Search_Bin(SSTable ST,KeyType key,int low,int high)
{
	if(low > high)
		return 0;
	mid = (low + high)/2;
	if(key == ST.elem[mid].key)
		return mid;
	else if(key < ST.elem[mid].key)
		递归 Search_bin(ST)
	else
		递归
}

折半查找判定树
在判定树中方形结点称为外部结点,圆形结点称为内部结点。
在这里插入图片描述
在这里插入图片描述
查找成功时比较次数:为该结点在判定树上的层次数,不超过树深d=[log 2n ]+1(向下取整)
查找不成功的过程就是走了一条从根结点到外部结点的路径d或者d-1。

分块查找
块间有序,块内无序。
分块有序:分成若干子表,要求每个子表中的树值都比后一块中的树值小,然后将各子表中的最大关键字构成一个索引表,表中还要包含每个子表的起始地质。
在这里插入图片描述
分块查找过程:
1、对索引表使用折半查找法,因为索引表是有序表。
2、确定了待查找关键字所在的子表之后,在子表内采用顺序查找法,因为各个子表内部是无序的。

查找效率:ASL=Lb+Lw,ASLb=log2(n/s+1)+s/2
在这里插入图片描述
优点:插入和删除比较容易,无序移动大量元素。
缺点:要增加一个索引表的存储空间并对初始索引表进行排序运算。
适用情况:如果线性表需要快速查找又经常变动。

树表的查找

二叉排序树
二叉排序树性质:左小右大
1、若左子树非空,则左子树上的所有结点均小于根结点的值
2、若右子树非空,则右子树上的所有结点均大于根结点的值
3、左右子树本身各是一颗二叉排序树。
在这里插入图片描述
右边的树违反了二叉排序树的原则,左子树的右子树比树的根结点大。
中序遍历二叉排序树会得到一个递增的有序序列。

二叉排序树的查找
若查找的关键字等于根结点查找成功,若小于根结点查找左子树,若大于根结点查找右子树。

BSTree SearchBST(BSTree T,KeyType key)
{
	if((!T) || key ==T->data.key)
		return T;
	else if(key < T->data.key)
		return SearchBST(T->lchild,key);
	else
		return SearchBST(T->rchild,key);
}

二叉排序树的插入
若二叉排序树为空,则插入根结点。
若二叉排序树不为空,继续在左、右子树查找,插入元素一定是在叶结点上。

二叉排序树的生成
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二叉排序树的删除:缺右子树用左子女填充,却左子树用右子女填充,在右子树找中序遍历的第一个结点填充。
二叉排序树的删除
1、被删除的是叶子结点
2、被删除的结点只有左子树或者右子树
3、被删除的结点既有左子树又有右子树

1、被删除的是叶子结点
由于要删除的结点既没有左子树也没有右子树,因此删除结点不会破坏二叉排序树的性质
在这里插入图片描述

2、被删除的结点只有左子树或者只有右子树
要删除的结点只有左子树PL或只有右子树PR,这时候只要将P的左子树PL或者P的右子树PR,直接作为其双亲结点f的相应的左子树和右子树即可。
在这里插入图片描述
3、被删除的结点既有左子树又有右子树
要删除的结点P只有左子树PL或者右子树PR
要删除的结点若为双亲结点F的右子树,
则令p的左子树PL成为双亲结点f的右子树,然后令p的右子树PR成为中序遍历下p的直接前驱s的右子树。

令中序下的直接前驱s或直接后继结点代替p结点,同时删除其中序下的前驱s或者后继。

查找的性能

平均查找长度和二叉树的形态有关。
在这里插入图片描述
最好:log2n(形态均匀),最坏:(n+1)/2(单支数)

如何提高二叉排序树的查找效率?
尽量让二叉树的形状均衡,平衡二叉树,左右子树的深度之差的绝对值小于等于1。

平衡二叉树
任意结点的平衡因子只能取-1、0、1,如果任意一个结点的平衡因子的绝对值大于1,则这颗二叉树就失去了平衡。

平衡二叉树的调整

LL旋转
若在A的左子树的左子树插入结点,使A的平衡因子从1增加到2,需要进行一次顺时针旋转。
RR旋转
若在A的右子树的右子树插入结点,使A的平衡因子从-1增加到-2,需要进行一次逆时针旋转。
LR旋转
若在A的左子树的右子树插入结点,使A的平衡因子从1增加到2,需要先进行逆时针旋转,在进行顺时针旋转。
RL旋转
若在A的右子树的左子树插入结点,使A的平衡因子从-1增加到-2,需要先进行顺时针旋转,在进行逆时针旋转。

红黑树
红黑树,Red-Black tree,变种的AVL树,利用对树中的结点‘红黑着色’的要求,降低了平衡的条件,达到了局部平衡,有着良好的最坏情况运行时间,它可以在O(logn)时间内做查找、插入和删除,n是树中元素的数目。

C++的STL中集合set、多重集合multset、映射map、多重映射multmap使用的就是红黑树。
在Linux内核中,用于组织虚拟区间的数据结构也是红黑树。

红黑树的特征
颜色特征:每个结点为黑色或红色
根特征:根结点永远是黑色
外部特征:扩充外部叶结点都是空的黑色结点
内部特征:红色结点的两个子结点都是黑色的,不允许有两个连续的红色结点
深度特征:对于每个结点,从该结点看到其所有子孙叶结点的路径中所包含的黑色结点的数量必须想用

红黑树:根结点是黑色的,每个空叶子结点是黑色的,如果一个结点是红色的,那么他的子结点必须是黑色的,
从一个结点到该结点的子孙结点的所有路径上包含相同数目的黑结点。
在查找大量数据时候

在这里插入图片描述
哈系表查找
基本思想:记录的存储位置与关键字之间对的对应关系。
优点:查找速度极快O(1),查找效率与元素个数n无关。
在这里插入图片描述
哈希方法(杂凑法)
选取某个函数,依该函数按关键字计算元素存储的位置,并按照此存放。
查找时,由同一个函数对给定值k计算地质,将k与地址单元中元素关键码对比,确定查找是否成功。

哈希函数:哈希方法中使用的转换函数。
冲突:不同关键码映射到同一个哈希地址。
同义词:具有相同函数值的两个关键字。
在这里插入图片描述
如何减少冲突?
冲突是不可避免的,构造一个好的哈希函数,制定一个好的解决冲突方案。

哈希函数的构造方法
根据元素集合的特性,地址空间尽量小,均匀。
1、直接定地址法
Hash(key) = a*key +b
优点:以关键码key的某个线性函数值为哈希地址,不会产生冲突。
缺点:要占用连续地址空间,空间效率低。
在这里插入图片描述
2、数字分析法
3、平方取中法
4、折叠法
5、除留余数法
Hash(key) = key mod p (p是一个整数)
关键:如何选取合适的P
技巧:设表长为m,取p<=m且为质数
6、随即数法

构造哈希函数考虑的因素
执行速度、关键字的长度、哈希表的大小、关键字的分布情况、查找频率

处理冲突的方法
1、开地址法
基本思想
只要有冲突就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希表总能找到。

  • 线性探测法:一但有冲突,就找下一个空地址存入
    在这里插入图片描述
    优点:只要哈希表未被填满,保证能找到一个空地址单元存放有冲突的元素。
    缺点:可能使得第i个哈希地址的同义词存入第i+1个地址,这样本来应该第i+1个变成了第i+2个,产生了聚集现象。
    因此出现了二次探测法

  • 二次探测法

在这里插入图片描述

  • 伪随即探测法
    在这里插入图片描述

开放地址法建立哈希表步骤:
step1:取数据元素的关键字key,计算其哈希函数值(地址)。若该地址对应的存储空间还没被占用,则将元素存入;否则执行step2解决冲突。
step2:根据选择的冲突处理方法,计算关键字key的下一个存储地址。若下一个存储地址仍被占用,则继续执行step2,直到找到能用的存储地址。
2、链地址法
基本思想
相同哈希地址的记录链成一个单链表,m个哈希地址设m个单链表,然后用一个数组将单链表表头指针存储起来,形成一个动态数组。
在这里插入图片描述建立方法:
step1:取数据元素的关键字key,计算其哈希数值。若该地址对应的链表为空,则将该元素地址插入此链表;否则执行step2解决冲突。
step2:根据选择的冲突处理方法,计算关键字key的下一个存储地址。若该地址对应链表不为空,则利用链表的前插法或后插法将该元素插入此链表。

链地址法优点
非同义词不会冲突,无聚集现象
链表上结点空间动态申请,更适合于表长不确定的情况

在这里插入图片描述
哈希表的查找效率
使用平均查找长度ASL来衡量查找算法,ASL取决于哈希函数、处理冲突的方法、哈希表的装填因子。
a越大,表中的记录数月多,说明表装得越满,发生冲突的可能性就越大,查找时比较次数就越多。
在这里插入图片描述
在这里插入图片描述结论:
1、哈希表技术具有很好的平均性能,优于一些传统的技术。
2、链地址法优于开地址法。
3、除留余数法作哈希函数优于其它类型的函数。

在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值