查找

查找


查找:在一个含有众多数据元素(或记录)的查找表中,找出某个特定的数据元素(或记录)。

术语:

记录:

关键字:

主关键字:

次关键字:

查找表:

动态查找:

静态查找:

内部排序:

外部排序:

稳定性:


静态查找

顺序查找:是用待查找记录与查找表中的记录逐个比较,若找到相等记录,则查找成功,否则查找失败。

性能分析:假设对查找表中的数据元素实施查找的概率相同即Pi=1/n,在查找表中查找第i个元素成功的比较次数Ci=i,查找第i个元素不成功时的比较次数Ci=n,则对查找表实施顺序查找,在查找成功时的ASLsucc=n+1/2

优点:算法简单,对表结构无任何要求。时间复杂度为O(n)。当n较大时,不宜使用。

折半查找:用待查找元素的key与查找表的中间位置的元素的关键字进行比较,若他们的值相等,则查找成功。若查找元素key大于查找表的中间位置元素的关键字的值,则在查找表的中间位置的后端位置,继续使用折半查找。否则在查找表的中间位置的前端范围内,继续使用折半查找。直到查找成功或者失败。

前提:顺序存储且有序二分查找的性能分析:用二叉树来描述二分查找过程。把当前查找区间的中点作为根节点,左子区间和右子区间分别作为根的左右子树,左子区间和右子区间再按类似的方法,由此得到的二叉树称为二分查找的判定树。 因此二叉树第K层结点的查找次数各位K次(根节点为第1层),而第K层结点数最多为2^{k}-1个。假设该二叉树的深度为h,则二分查找成功的平均查找长度为ASL=(n+1)/n   log以2为底(n+1)-1


动态查找

在查找表中实施查找时,对于给定值key,若表中存在关键字值等于key的记录,则查找成功。若失败,将待查找记录按规则插入查找表中。

二叉排序树查找:前提是将查找表组成称为一棵二叉排序树。

二叉排序树:或者是一棵空树,或者是一棵具有如下规则的树:

  • 若它的左子树非空,则左子树上所有结点的关键字均小于根节点的关键字。
  • 若它的右子树非空,则右子树上所有结点的关键字均大于等于根节点的关键字。
  • 左、右子树本身又都是一棵二叉排序树。

思想:首先将待查找记录的key值与二叉排序树的根节点比较,若相等,则查找成功。若带查找记录的key值小于二叉排序树根节点的值,则继续在该结点的左子树上进行查找。否则,继续在该结点的右子树上进行查找。

性能分析:成功查找的次数不会超过二叉树的深度,因而具有n个结点的二叉排序树的深度,最多为log以2为底n的对数。最坏为n。因此,二叉排序树最好的时间复杂度为O(log以2为底n的对数),最坏时间复杂度为O(n),一般情况下,其时间复杂度大致可看成O(log以2为底n的对数)查找效率比顺序查找要好,但比二分查找要差。

平衡二叉树查找

平衡二叉树,又称AVL树,每个结点的左右子树的深度之差的绝对值不超过1,则这样的二叉树称为平衡二叉树。

平衡因子:该结点左子树深度减去右子树深度的值。平衡二叉树的所有结点的平衡因子只能是0,1,-1。

非平衡二叉树的平衡处理:边建边调整

  1. LL型的处理(左左型):以中间节点为中心顺时针旋转
  2. LR型的处理(左右型):先把右边节点加入左边节点的中心,然后顺时针旋转
  3. RR型的处理(右右型):以中间节点为中心逆时针旋转
  4. RL型的处理(右左型):先把左边节点加入右边节点的中心,然后逆时针旋转

性能分析:平衡二叉树本身就是一颗二叉排序树,故它的查找与二叉排序树完全相同,但它的查找性能优于二叉排序树,不会与二叉排序树一样,会出现最坏的时间复杂度O(n),它的时间复杂度与二叉排序树的最好时间复杂度相同,都为O(log以2为底n的对数)。


哈希查找(Hash)

基本术语:

Hash方法:在存放记录时,通过相同函数计算存储位置,并按此位置存放,这种方法称为Hash方法

Hash函数:是指在Hash方法中的函数

Hash表:按Hash方法构造出来的表

Hash地址:通过Hash函数计算记录的存储位置,我们把这个存储位置称为Hash地址

冲突(Collision):不同记录的关键字经过Hash函数的计算可能得到同一Hash地址,即key1!=key2时,H(key1)=H(key2),此现象叫做“冲突”

对于Hash方法需要讨论的三个问题:

  1. 装满因子
  2. 对于给定的一个关键码集合,选定一个计算简单且地址分布比较均匀的Hash函数,避免或尽量减少冲突。
  3. 大萨达撒多

所谓装满因子(一般介于0.6-0.9之间)是指:散列表中已存入的元素的个数n与散列表的大小m的比值,即a=n/m。当a越小,发生冲突的可能性就越小,a越大(最大为1)时,发生冲突的可能性就越大。

但是不能为减少冲突的发生,将a变得太小,造成大量存贮空间的浪费,因此必须兼顾存储空间和冲突两个方面。第二是与所构造的散列函数有关,第三是与解决冲突的办法有关。

构造Hash函数应注意以下几个问题:

  • 计算Hash函数所需要的时间
  • 关键字的长度
  • Hash表的大小
  • 关键字的分布情况
  • 记录的查找频率

构造Hash函数的常用办法

(1)直接定址法

此类方法取记录中关键码的某个线性函数值为Hash地址:Hash(key)=a*key+b

其中,ab为常数。这类Hash函数是一对一的映射,一般不产生冲突。但是,它要求Hash地址空间的大小与关键码集合的大小相同,这种要求一般很难实现。

(2)数字分析法

设有n个d位数,每一位可能有r种不同的符号。这r种不同的符号在各位上出现的频率不一定相同。可根据Hash表的大小,选取其中各种符号分布均与的若干位作为Hash地址。

计算各位数字中符号分布均匀度的公式:

(3)除留余数法

设Hash表中允许的地址数为m,取一个不大于m,但最接近或等于m的质数p,或取一个 不含有小于20的质因子的合数作为除数。这样的Hash函数为:Hash(key)= key%p(p<=m)其中:“%”是整数除法取余的运算,要求这时的质数p不是接近2的幂。

(4)平方取中法

先计算构成关键码的表示符的内码的平方,然后按照hash表的大小取中间的若干位作为Hash地址。

(5)折叠法

(6)随机数

为Hash表中的关键字选取一个随机函数值作为其Hash地址。即:H(key)= random(key)

通常在Hash表中的关键字长度不等时,采用此方法构造Hash函数比较合适。

处理冲突的方法

(1)开放地址法:在冲突发生时,产生某个探测序列,按照这个序列,探测在Hash表中的其它存储单元,直到探测到不发生冲突的存储单元为止。可以用以下公式来描述:Hi(key)= (H(key)+di)(i=1,2,3。。。)

一般情况下,地址增量的取值有以下三种:

di=1,2,3,,,m-1 这种情况为线性探测再Hash

di=1^{2},-1^{2}2^{2},-2^{2},,,k^{k}称这种情况为二次探测再Hash

di=为随机函数 称这种情况为伪随机探测再Hash

(2)链地址法

链地址法处理冲突的方法是,将通过Hash函数计算出来的Hash地址相同的关键码通过链表链接起来,链表表头结点组成一个向量。向量的元素个数与关键字个数相同

散列查找的性能分析:理论分析,时间复杂度应为O(1),平均查找长度应为ASL=1,实际上由于冲突的存在,它的平均查找长度将会比1大。

线性探查法的性能分析:平均查找长度ASL=1/2(1+1/(1-a))

拉链法查找的性能分析:平均查找长度ASL=1+a/2


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值