查找-基于树的查找和散列


基于树的查找


1、二叉树排序


二叉排序树(Binary Search Tree,BST),又称为二叉查找树,是一种高效的数据结构。它是满足:1、若它的左子树不为空,则左子树上的所有结点的值均小于根结点的值。2、若它的右子树不为空,则右子树上所有结点的值均大于根结点的值。3、它的左、右子树也都是二叉排序树。

对一颗二叉排序树进行中序遍历,而已得到一个递增的有序序列


二叉排序树的查找

由于二叉排序树可以看成是一个有序表,所以在二叉排序树上进行查找类似于折半查找,即逐步缩小查找范围的过程。具体:1、若给定值等于根节点的关键字,则查找成功;2、若给定值大于根结点的关键字,则继续在左子树上进行查找;3、若给定值小于根结点的关键字,则继续在右子树上进行查找。


二叉排序树的插入

首先查找待插入的记录是否在树中,如果存在则不允许插入重复关键字;如果直到找到叶子结点仍没有发现重复关键字,则把待插结点作为新的叶子结点插入。具体的,若二叉排序树为空树,则新插入的结点为新的根结点;否则,新插入的结点必为一个新的叶子结点,其插入位置有查找不成功的位置确定。


二叉排序树的建立

二叉排序树的建立是基于插入算法进行的,根据给定的关键字顺序依次插入得到的。

二叉排序树的形态完全由输入顺序决定,相同的关键字不同的输入顺序会产生不同的二叉排序树。


二叉排序树的删除

由于二叉排序树要求关键字之间满足一定的大小关系,这就使得从树中删除一个结点的算法相对复杂。具体的,首先在二叉排序树中查找待删结点,如果不存在则不作任何操作;否则,分以下三种情况进行讨论。

I、待删结点是叶子结点;

此种情况只需将待删结点的父亲结点的相应孩子域悬空。

II、待删结点只有左子树或只有右子树;

此种情况只需将待删结点的父亲结点的相应孩子域置为该孩子对应的左子树或右子树。

III、待删结点既有左子树也有右子树。

首先确定替换待删结点的位置为左子树中最右下角的那个结点或右子树上最左下角的那个结点。接下来删除替换结点,其实,仔细分析后,替换结点的删除恰好就是我们讨论的前两种情况。替换结点或者恰好即使个叶子结点,或者就是值带了左子树或只带了右子树的情况。


二叉排序树的性能分析

二叉排序树的查找最差的情况与顺序查找相同,ASL=(n+1)/2;最好的情况与折半查找相同,ASL可以达到对数级别log2(n)。对于二叉排序树的插入和删除来说,只需修改某些结点的指针域,不需要大量移动其他记录,动态查找的效率很高。


2、平衡二叉树


平衡二叉树(AVL,发明者Adelson-Velskii和Landis的首字母)或者是一棵空树;或者是一棵二叉排序树并且具有:1、二叉排序树中任何一个结点的左子树和右子树高度相差的绝对值最多为1;2、它的左、右子树也分别是平衡二叉树。


平衡因子(Balance Factor):用BF(Node)表示结点Node的平衡因子,显然,BF(Node)=Node的右子树高度-Node左子树高度。


满足条件的一棵平衡二叉树,如果含有n个结点,则它的高度为O(log2(n)),因而在其上进行各种操作,例如查找、插入和删除等,都只需O(log2(n))的时间代价


平衡二叉树的插入

首先在AVL树中查找新结点应插入的位置,将新结点插入,查找需要调整的最小子树,记录新结点的双亲结点,即新插入的结点为孩子结点,然后修改双亲结点的平衡因子。如果双亲结点平衡因子为0,则插入成功,AVL树的平衡性质没有被破坏,直接返回;如果双亲结点的平衡因子为1或-1,则孩子结点和双亲结点都向根结点移动一步,修改双亲结点的平衡因子,继续判断,循环执行,直至双亲结点为空时,返回;如果双亲结点的平衡因子为2或-2,则找到了失衡的最小子树,通过旋转调整该子树,使其恢复平衡,然后返回。

在一棵平衡二叉树中插入一个新结点时,情况类似于二叉排序树的插入,新结点将出现在查找失败的位置,即作为一个新的叶子结点插入该位置。此时,整棵树可能会发生以下4中失衡:LL型、RR型、LR型、RL型。


平衡二叉树的删除

AVL树的删除是个比较复杂的过程,首先在AVL树中确定要删除结点的位置,删除结点算法思想与二叉排序树中删除结点的算法思想类似,关键在于删除后修改平衡因子并找出失衡子树。删除一个结点后,修改其双亲的平衡因子,判断以其双亲为根结点的子树是否失衡,如果失衡,直接向根结点追溯,循环执行;直到所有结点的平衡因子都符合定义,然后返回,保证整棵树的平衡性质。可以使用一个标志flag来记录是否修改,当flag=1,表示继续回溯修改;否则,flag=0,表示停止回溯。

I、当BF(A)不为0,如果其左子树或者右子树中有结点被删除,导致其高度缩短,则其平衡因子改为1或者-1,同时,flag=0.由于以A为根的整棵子树的高度未发生变化。因而不会影响到上层结点,所以调整可以结束。

II、当BF(A)不为0,即为1或-1时,但是其较高的子树有结点要被删除,也就是较高的子树的高度被缩短,则其平衡因子修改为0,同时,flag=1,需要继续向上修改。

III、当BF(A)不为0,即为1或-1时,但是其较低的子树有结点要被删除,也就是较低的子树的高度被缩短时,结点A必不平衡。假设其较高子树的根结点为B,则会出现以下三种情况:1、如果BF(B)=0,执行单旋转恢复结点A的平衡,并设置flag=0。2、如果BF(A)=BF(B),执行单旋转恢复平衡,BF(A)=BF(B)=0,flag=1。3、如果BF(A)和BF(B)的平衡因子相反,执行一个双旋转恢复平衡,新的根结点的平衡因子为0,其他的结点做相应的处理,并且flag=1。


3、B树和B+树


B树(Balance tree)是1970年R.Bayer和E.Mccreight提出的,它在文件系统和数据库系统中使用的较多,适用于组织动态的索引结构。它不是二叉树而是树,是一种多路平衡查找树,多路是指树的分支多余二叉;平衡是指所有叶子结点均在同一层上,以避免出现单支树的情况。也称B-树。

B树的阶:树中所有结点的孩子结点的最大值称为B树的阶。通常用m表示,从查找效率来考虑,通常取m>=3。

一个m阶的B树定义:

该树或者是空树,或者是m叉树满足:

1、树中的每个结点至多有m个子结点。

2、除根结点和叶子结点以外,其他每个结点至少有[m/2]个子结点。

3、若根结点不是叶子结点,则根结点至少有两棵子树。

4、所有的叶子结点在同一层,可以有[m/2]-1到m-1个关键字,并且叶子结点所在的层数为树的深度。

5、有k个子结点的分支结点恰好包含k-1个关键字。


B+树是B树的变种。一棵m阶B+树,在结构上与m阶B树相同,但在结构内部的关键字安排不同。

具体:

1、具有n棵子树的结点就含n个关键字,及每个关键字对应一棵子树。

2、结点内关键字仍然按序排列,与B树相同。

3、关键字Ki是它所对应的子树的根结点中的最大或最小关键字。

4、关键字符合二叉排序树的要求,对同一结点内的任意两个关键字Ki和Kj,若Ki<Kj,则Ki小于Kj对应的子树中的所有关键字,与二叉排序树及B树类似。

5、所有的叶子结点中包含了所有的关键字。

6、叶子结点中的关键字对应的子树,实际应用中代表记录块。关键字Ki是它所代表的记录块中的最大或最小的关键字。

7、各叶子结点可以按照关键字的大小次序链接在一起,形成单链表,并设置链头指针。


4、伸展树


它是一种自调整形式的二叉排序树,每次查找、插入或删除之后,通过仔细设计旋转序列,将被访问的结点向上移动到根。这种简单“移动到顶”的启发式策略有利于所进行的各种操作。它会沿着从某个结点到树根之间的路径,通过一系列的旋转把这个结点搬移到树根去。事实上,伸展树是指改进了二叉排序树性能的一组规则,可以在O(log2(n))内完成插入、查找和删除等操作,控制了查找、插入和删除等操作对排序树的修改,从而避免二叉排序树在最差情况下的线性时间代价。


给定一棵二叉排序树,当访问一个内部结点p时,通过一系列重构过程,将结点p移到树的根结点处,即完成一次伸展过程。伸展进行的特殊重构非常重要,因为只进行任意序列的重构,还不足以p移动到树的根部。将p向上移动的特定操作取决与p、其父结点f以及其祖父结点g(若存在)的相对位置。


具体伸展过程还有一组旋转组成,旋转主要有绕单根旋转、一字旋转(也称同构调整)和之字旋转(也称异构调整)


伸展树的插入操作和删除操作与二叉排序树相同了,如果是新插入的结点,那么在找到插入位置插入后还要将插入结点展开到根结点;如果是删除结点,那么在删除该结点后,需要将被删结点的父结点展开到根结点。从操作角度上看,伸展树与平衡二叉树的操作只有略微的差别,但伸展树与结点被访问的频率有关,能够进行更加动态的调整;而平衡二叉排序树的结构只与插入、删除的顺序有关,与插入、删除的频率无关。


对一个具有n个结点的伸展树,进行一组m此操作(插入、删除或查找等操作),当m>=n时,总的时间代价为O(m*log2(n))。伸展树不能保证每一个单个操作是有效率的,即某次插入或删除操作可能花费O(n)时间,但是,能够保证m此操作总共需要O(m*log2(n))时间,即每次访问操作的平均代价为O(log2(n)),这是查找树结构的必要保证。


5、红黑树


红黑树(red-black tree)是一种自平衡二叉查找树,它是在1972年由Rudolf Bayer发明的,当时被称为“对称二叉B树”,现在的名字是在Leo J.Guibas和Robert Sedgewick于1978年写的一篇论文中命名的。它的操作有着良好的最坏情况运行时间,并且在实践中是高效的,它可以在O(log2(n))时间进行查找、插入和删除等操作。其中每个结点被“染成”红色或黑色。它利用对树中结点红黑着色的要求达到局部平衡。


一棵红黑树是染色二叉排序树,满足:

1、每个结点只有红和黑两种颜色。

2、根结点永远是黑色的。

3、所有的扩充外部叶子结点(空结点被认为是叶子结点)是黑色的。

4、如果一个结点是红色的,那么它的左右的两个子结点的颜色是黑色的(也就是说,不能有两个相邻的红色结点)。

5、对于每个结点而言,从这个结点到叶子结点的任何路径上的黑色结点的数目相同。


在一棵红黑树中,最短的道路是所有结点都是黑色,最长的道路必是红黑相间。所以一条道路其长度最多是其他道路的两倍,因此红黑树实际上是关于高度近似均衡的树。


定理:一棵含有n个内结点的红黑树的树高至多为2*log2(n+1),由这个定理可知,红黑树可在O(log2(n))时间内实现各种操作。但是,在插入和删除之后,红黑属性有可能被破坏。恢复红黑属性需要少量(O(log2(n)))的颜色变更(这在实践中是非常快的)并且不超过三次旋转(对于插入是两次),这保证了插入和删除操作维持在O(log2(n))次,但是它带来了相对复杂的操作。


散列


散列方法是一种计算式查找方法,又叫做hash(哈希、杂凑)法或关键字地址计算,记录在表中的位置与其关键字之间不存在一个确定的关系。


基本思想:首先在记录的关键字key和记录的存储位置p之间建立一个对用关系H,使得p=H(key),H被称为hash函数,p被称为散列地址。当创建hash表时,把关键字为key的记录直接存入地址为H(key)的地址单元中;以后当查找关键字为key的记录时,再利用hash函数p=H(key)计算出该记录的散列地址p,从而达到直接存取记录的目的。因此,散列方法的核心就是有hash函数决定关键字值与散列地址之间的对应关系,通过这种关系来组织存储并进行查找等操作。


散列方式进行查找的问题:1、如何构造恰当的hash函数,使得结点“分布均匀”,尽力少的产生冲突。2、一旦发生冲突,如何处理。


1、hash函数的构造方法


构造原则为简单均匀:1、hash函数本身运算尽量简单,便于计算;2、hash函数值必须在散列地址范围内,且分布均匀,地址冲突尽可能少。

1、除留余数法

2、数字分析法

3、平方取中法

4、分段叠加法

5、基数转换法


在实际应用中,还是应该根据实际情况选择采用恰当的散列方法,并用实际数据测试它的性能,以便做出正确的判断,考虑因素:1、计算hash函数所需的时间;2、关键字的长度;3、散列表的长度;4、关键字分布的情况;5、记录查找的频率。


2、处理冲突的方法


1、开放定址法(再散列法)

基本思想:当关键字key的初始散列地址h0=H(key)出现冲突时,以h0为基础查找下一个地址h1,如果h1仍然冲突,再以h0为基础,产生另一个散列地址h2......直到找出一个不冲突的地址hi,将相应元素存入其中。这种方法有一个通用的再散列形式:hi=(H(key)+di)%mi=1,2,...n

I、线性探测再散列

di=c*i最简单情况 c=1

这种方法的特点是:发生冲突时,顺序查看表中下一个单元,直到找到一个空单元或遍查全表。值得注意的是,由于这里使用的是%运算,因而整个表变成了一个收尾相连的循环表,在查找时类似循环队列,表尾的后边是表头,表头前边是表尾。


II、二次探测再散列

di=1^2,-1^2,2^2,-2^2,……,k^2,-k^2 (k<=m/2)

特点:冲突发生时,分别在表的右、左进行跳跃式探测,较为灵活,不易产生聚集,但缺点是不能探测到整个散列地址空间。


III、随机探测再散列

di=伪随机数

这种方法需要建立一个随机数发生器,并给定一个随机数作为起始点。


2、链地址法

链地址法解决冲突的基本思想是把所有具有地址冲突的关键字链在同一个单链表中。


影响hash表关键字比较次数的因素有三个:哈希函数、处理冲突的方法以及哈希表的装填因子。

哈希表的装填因子:a=哈希表中已存入的元素个数/哈希表的长度


哈希表的ASL

处理冲突的方法ASL(succ)ASL(unsucc)
线性探测法[1+1/(1-a)[/2[1+1/((1-a)^2)]/2
二次线性探测法ln(1-a)/a1/(a-1)
链地址法1+a/2a+e^-a

从表中可看出,哈希表的平均查找长度是与装填因子有关,而与待散列记录的数目n无关。因此,无论记录数目n有多大,关键还是通过调装填因子a控制平均查找长度使其在合理范围之内。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值