数据结构与算法:搜索(查找)

前面的文章中写的每一种数据结构都定义了一些常用的操作,如:初始化、访问数据元素等等,因此,研究操作的实现(不是操作的定义)即算法与数据结构密不可分。

有两个操作在每个数据结构上一般都要定义,而且是非常重要的:

·确定元素的位置——搜索(查找);

将元素按某种书序排列——排序(分类)。

这篇文章我主要写一下搜索(查找)的一些知识(算法基本思想、效率、优缺点、适用范围等)。

 

一、静态表的查找

二、动态表查找

三、HASH(哈希)查找

 

1.查找:在某一数据集合中查找数据元素是否存在,如果存在,返回其位置,否则,返回失败信息。

2.查找表:被查找数据元素的集合,如果是逻辑结构上定义的操作,那么位置就是逻辑位置;如果有了存储结构,那么位置应该就是物理位置。因此,查找表一般是“数据结构+存储结构”。

3.查找表的种类:

(1)静态查找表;数据集合在查找前后不变(没有插入、删除);

(2)动态查找表:数据集合在查找前后会改变(有插入、删除)。

4.关键码:可以唯一的标识一个数据元素的数据项(属性)。

基于关键码的查找,结果必是唯一的;基于一般属性的查找,结果可能不唯一。

5.查找方法:

查找表不同,查找方法就会不同。有很多不同的查找方法。

6.查找算法的评价:

(1)空间:占用的辅助空间少;

时间:时间少。查找的基本操作是比较,因此 时间主要体现为比较次数。

(2)查找成功:

最大比较次数——MSL(Maximum Serach Length)

平均比较次数——ASL(Average Serach Length)

(3)查找失败:

最大比较次数——MSL

平均比较次数——ASL

 

一、静态表的查找

1. 静态查找表是顺序或链式存储的线性表 ——顺序查找

(1)查找表的要求:只要是线性表即可;

(2)查找方法:不断找前驱或后继。

(3)特点:

1)思想简单,对查找表要求少,适应面广;

2)比较次数较大O(n)——成功、失败。

2.静态查找表是顺序存储的、有序的线性表——折半查找(Fibonacci查找、插值查找)

(1)查找表的要求:顺序存储、有序的线性表

(2)查找方法:

(3)特点:

1)对查找表要求多;

2)比较次数较少O(log以2为底n的对数)。

折半查找的过程可以用一棵二叉树表示,称之为“折半查找的判定树”。

3.静态查找表是二叉树——静态二叉排序树查找

(1)查找表的要求:二叉排序树

(2)查找方法:

X与根比较:相等则输出;X<根:在左子树上找;X>根,在右子树上找。

(3)特点:

类似折半,最大比较次数是树的深度;等概率时,深度为log2(n)二叉排序树最好;不等概率时,概率高的应该靠近根。

4.静态查找表是分块索引表——分块查找(索引顺序查找)

(1)查找表的要求:顺序存储、分块有序;即:每一块中的结点不必有序,但块与块之间必须"按块有序"。

(2)查找方法:

1)先选取各块中的最大关键字构成一个索引表;

2)折半方法确定被查找元素可能所在的块;

3)在块中采用顺序查找,确定元素是否存在;

(3)特点:

1)要建立索引表;

2)效率介于折半和顺序之间。

 

二、动态表查找

查找表本身是在查找过程中动态生成的,即对于给定值 key,若查找表中存在其关键码等于key的元素,则查找成功 返回,否则插入关键码等于key的元素。
动态查找表可以是线性表,也可以是树(二叉排序树)。最常用的动态查找表是二叉排序树。

1.二叉排序树动态查找方法:

若二叉排序树为空,则查找不成功,在二叉排序树中插入 该元素;否则 

(1)若给定值等于根结点的关键字,则查找成功; 

(2)若给定值小于根结点的关键字,则继续在左子树上进 行查找;

(3)若给定值大于根结点的关键字,则继续在右子树上进 行查找。

2.特点:查找效率与构造出的二叉排序树的深度有关。

对于每一棵特定的二叉排序树,均可按照平均查找 长度的定义来求它的ASL值:

其中,pi是查找第i个元素的概率,通常假设为等概率; ci是查找第i个元素的比较次数,这里ci=hi。

显然,由n个关键字构造所得的,不同形态的各棵 二叉排序树的平均查找长度的值不同,甚至可能差 别很大,例如:

对于同一个关键码集合,因为关键码插入的顺序不同,可以得到不同的二叉排序树。

3.平衡二叉树

(1)定义:一棵二叉排序树是平衡的,当且仅当每个结点的左右子树的高度至多相差1。(由G.M.Adelson_Velskii 和E.M.Landis给出的定义——AVL树)

(2)递归定义:

1)空树是二叉排序树;

2)它的左右子树都是二叉排序树,且左右子树 的高度最多相差为1。

(3)平衡因子:

左子树高度-右子树高度,即BF(t)=H(l)-H(r),平衡二叉树中,对任意节点,BF=1、0、-1。

(4)平衡二叉树的特点:

其深度和log以2为底n的对数同数量级,即AVL树的平局查找长度为O(log以2为底n的对数)。

(5)AVL树的构造和调整过程:

1)基本原则:按照二叉排序树的构造方法,构造过程中判断是否为平衡二叉树(平衡因子),是,则继续构造;否则, 按一定的原则(保持是二叉排序树和平衡)将其调整为平衡,然后继续。

2)插入过程中的调整原则:

二叉排序树在插入前平衡,插入一个结点后如果失去平衡,则至少有一个结点的平衡因子变为+2或-2。 若平衡因子=+2,则左分支高于右分支;若平衡因子=-2,则右分支高于左分支;
分为四种情况,分别进行调整:

LL型:在左分支的左子树上插入后,失去平衡,BF=2

LR型:在左分支的右上子树插入后,失去平衡,BF=2

RR型:在右分支的右子树上插入后,失去平衡,BF=-2

RL型:在右分支的左子树上插入后,失去平衡,BF=-2

LL型:

RR型:

对于LL型和RR型,如果失衡,就把它“掰”向另一边,当然,这个动作看上去很容易,但是用代码实现起来还是比较复杂的。

LR型:

 

RL型:

(6)查找过程:同静态二叉排序树是一样的。

(7)效率分析:

查找过程中和给定值进行比较的关键字的个数不超过 平衡树的深度。 

假设深度为h的二叉平衡树上所含结点数的最小值为 Nh,则显然 Nh = N(h-1) + N(h-2) + 1 ,由此可以推导出h约为log(n)(应当是以2为底的)。因此,在平衡树上进行查找的时间复杂度为O(log(n))。

 

三、HASH(哈希)查找

1.哈希技术概述

(1)哈希技术的提出背景:我们前面介绍的各种查找方法,其基本操作是“比较” 即通过比较得到元素的位置。那么,有没有不用“比较”的查找方法?

如果有一个函数,它能够根据要查找的关键字直接计算 出要查找元素的地址,该地址的内容为空,则查找的元素不 存在,否则,查找成功。显然,这样的查找不需要比较!

(2)HASH类问题的描述:

假设问题可能用到的关键字集合为U,|U|=n0,即该集合的元素个数为n0,而一个问题实际用到的关键字集合为S,|S|=n,n<<<<n0,且S是取自U的任意一个子集合,表示为{R1,R2,R3,...Rn},其关键字集合为{K1,K2,...,Kn}; T是解决问题需要的连续空间,它由m个存储单元组成, 表示为T[0..m-1],m>=n。

有一个函数H,其定义域是key∈U,值域是i∈0...m-1,它将关键字映射到存储空间地址上;

H(key)= i      key ∈U,  i∈0...m-1

(3)有关基本概念:

1)HASH函数:将元素按照关键字映射出存储空间地址的 函数,记作:H(key) ;

2)HASH地址:由HSAH函数计算出的数据元素的存储地址;

3)HASH表:存储元素的连续地址空间T;

4)HASH造表:利用HASH函数将元素存储到HASH表中的 过程; 

5)HASH表的填充度(装填因子):

6)冲突:由于HASH函数的定义域是U,而S是U的任意一个小子集,映射地址空间是由S的大小确定的,因此,对于不同的关键字可能得到相同的HASH地址,即: 若 key1≠key2 , 而 H(key1)=H(key2),则称为冲突;

7)同义词: 若 H(key1)=H(key2),则key1和key2互称 为同义词。 

(4)HASH技术的关键:

1)HASH函数的构造;

函数设计目标:使通过哈希函数得到的n个数据元素的哈希地址尽可能均匀地分布在m个连续内存单元上,同时使计算过程 尽可能简单以达到尽可能高的时间效率。

常用的哈希函数构造方法有:除法取余、直接定址法、数字分析法、折叠法、平方取中

除留余法:

特点:

①这是一种最简单、最常用的方法;

②P的选择很重要,选择不好会产生同义词; 

③P一般取位素数或不包含小于20的质数的合数。

2)解决冲突的方法;

解决冲突的策略分为两类:

①闭散列方法(Closed Hashing):同义词放在HASH表中的 其他位置;(Open addressing,又称为开地址法);

a.开放地址法(闭散列):发生冲突后,按一定的原则寻找新的地址:

举个例子:

注意,图中有很多79,并不是真的有那么多79,而是将79从地址1开始逐渐后移,直到后移到有空位的地方为止。

b.再造HASH法(闭散列):

H(i)=RHi(key)

用一系列HASH函数计算地址。

这个方法的意思应该是另外再找一个HASH函数。

②开散列方法(Open Hashing):同义词放在HASH表之外的 空间中;(Separate chaining,又称为拉链法)。

a.链地址法(开散列):

将同义词存放在同一个链表中;

举个例子:

③还有一种方法叫做建立公共溢出区法:

除了HASH表外,开辟一个公共溢出区,一旦冲 突,将同义词放入公共溢出区;
 

 

最后,总结一下:

1.哈希查找的方法

给定关键字k:

(1)用给定的HASH函数计算出k的HASH地址; i=H(key)

(2)若该地址为空,则查找失败; 否则,若 T[i]=k ,则查找成功,返回地址; 否则,按HASH造表时解决冲突的方法计算出新的地址;

(3)重复(2)直到查找成功或失败。
2.性能分析

如果没有冲突:O(1);

有冲突,性能与下列因素有关:

HASH函数、解决冲突的方法,装填因子。

总之,HASH查找是一种很高效的查找方法,也是一种使用范围很广的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值