查找的相关定义
查找定义:根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。
查找表:按照操作可以分为两大种:静态查找表和动态查找表。
其中:
静态查找表:只作查找操作的查找表。
动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。
几种查找结构
一、顺序表查找
:又叫线性查找,从表中第一个开始逐次查找。
最好的情况第一个位置就找到,时间复杂度为O(1)
最坏的情况最后一个位置找到,时间复杂度为O(n)
平均的查找次数为:(n+1)/2
综上:
时间复杂度为O(n)
二、有序表查找
:即线性表中的元素是有序排列。
1. 折半查找(二分查找):时间复杂度O(logn)
2. 插值查找:是在二分查找上的改进,时间复杂度O(logn)
利用到了插值的计算公式:
(key-a[low])/(a[high]-a[low])
key:要查找的关键字
a[high]、a[low]:查找表中最大最小记录的关键字
适用于表长较大,关键字分布比较均匀的查找表。
3. 斐波那契查找:时间复杂度O(logn)
但平均性能优于二分查找
三、线性索引查找
索引:把一个关键字与它对应的记录下个关联的过程
线性索引:把索引项集合组织为线性结构,也称为索引表。
三种线性索引:
稠密索引:可采用折半查找提高效率
分块索引:块内无序,块间有序
倒排索引
四、二叉排序树
又称为二叉查找树,有可能是空树,若不为空,则具有以下性质:
若它的左子树不为空,则左子树上所有的结点的值均小于它的根结点的值
若它的右子树不为空,则右子树上所有的结点的值均大于它的根结点的值
它的左右子树也分别为二叉排序树
时间复杂度:
最坏的时间复杂度:O(n)
好的时间复杂度:O(logn)
示例:集合{62,88,58,47,35,73,51,99,37,93},构造二叉排序树
五、平衡二叉树
:又叫AVL树
是一种二叉排序树
特点:其中每一个结点的左子树和右子树的高度差至多等于1
构建平衡二叉树:
每当插入一个结点时,先检查是否因插入而破坏了树的平衡性,
若是则找出最小不平衡子树,
在保持二叉排序树的特性前提下,调整最小不平衡子树中各结点之间的连接关系,
进行相应的旋转,使之成为新的平衡子树。
其中:
最小不平衡子树:距离插入结点最近的,且平衡因子的绝对值大于1的节点为根的子树。
六、散列表查找(哈希表)
存储位置=f(关键字)
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key).
对应关系f称为散列函数,又称为哈希(Hash)函数
常用的散列函数构造方法:
1.直接定地址法:适用于知道关键字的分布情况,是和查找表较小且连续的情况。
2. 数字分析法:适合处理关键字位数较多的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀,可以考虑此方法。
3.平方取中法:比较适合不知道关键字分布,而位数又不多的情况。
4.折叠法:事先不需要知道关键字的分布,适合关键字位数较多的情况。
5.除留余数法:最常用。
6.随机数法:当关键字长度不等时,采用此方法。
处理哈希冲突:
一、开放定址法:
对于给定的关键字集合,依次根据哈希函数就是其存储的地址,当发现当前计算出的存储位置上已有数据存在,则根据公式接着寻找下一个空的位置,知道找到为止,并将此关键字存入。
根据使用的公式不同,分为以下三种方法:
线性探测法:
f(key)=(f(key)+d)%m (d=1,2,3,...,m-1)
二次探测法
f(key)=(f(key)+d)%m (d=1^2,-1^2,2^2,-2^2,…,q^2,-q^2,q<=m/2)
随机探测法
f(key)=(f(key)+d)%m (d是一个随机数列)
二、再散列函数法
准备多个散列函数,当发生存储地址冲突的时候,就换一个散列函数计算。
三、链地址法
当发生冲突时,将发生冲突的记录存储在单链表中
四、公共溢出区法
为所有冲突的关键字建立一个公共溢出区来存放。