您的当前位置:首页正文

AVL树研究与实现

2021-02-13 来源:伴沃教育
ISSN 1009-3044 E—mail:xsjl@dnzs.net.crl http://www.dnzs.net.cn Tel:+86—55 1—65690963 65690964 Computer Knowledge and Technology电脑知识与技术 Vo1.9,No.7,March 2013. AVL树研究与实现 解晨 (中山大学,广东广州510275) 摘要:计算机最广为人知的优点之一是其能储存大量的数据,如今随着时代的发展,储存容量更是犹如日进千里一般极速 扩展,大容量的硬盘、u盘早已随处可见。然而,要在巨大的数据中搜索出需要的内容却不是一件容易的事,由此,为了能 减少在搜索储存数据上的开销,各种适应于不同访问搜索背景的数据结构应运而生。树,便是计算机学科中最基本的数 据结构之一,提供了快速的储存和访问性能。该文探究了带有平衡条件的二又查找树——AvL树的原理,并对其使用C 语言进行了实现。 关键词:数据结构;平衡二叉查找树;AvL树 中图分类号:TP3ll 文献标识码:A 文章编号:1009—3O44(2O13)07—1532—04 Research and Implementation of AVL Tree XIEChen (Zhongshan University,Guangzhou 510275,China) Abstract:One ofthe most well known is the advantages ofcomputer can store large amounts ofdata,and now with the develop— ment of the times,the storage capaciyt is more like Japan into thousands of general extended,hard disk,U disk has large capacity can be seen everywhere.However,tO search for in the huge data in the needs of the content is not a easy thing,therefore,in or— der tO reduce the data storage overhead in the search,all kinds of adaptation tO different access search emerge as the times require ata strducture background.Tree,is one of the most basic data structure in computer science,provides fast storage and access per— formance.This paper explores the two binary search tree with equilibrium conditions一一principle ofAVL tree,and the use ofC language tO realize. Key words:data stuctrure;balanced binary search tree;AVL tree 对于大量的输入数据,普通的线性数据结构访问时间太慢,例如,对于一个有N个数据的线性数据结构,假设对每个数据的访 问几率大致相同,每个数据每次访问有I/N的机会被访问,由于是线性数据,因此每个数据的访问花销可以经过一定的排列,最通常 的是访问第一个数据花销1个单位时间,第二个2个单位时间,第三个3各单位时间……第N个N各单位时间,于是访问一次的平均 花销为(Ⅳ+N )/2N=(I+N)/2,用计算机专业的符号来说,其访问运行时间可以用0(N)来表示,即访问一次线性数据结构的花销 在N这个数量级上。使用树这一数据结构可将访问花销将至logN这个数量级上,也即O(1ogN),这里logN是以二为底的N的对数。 可以对比一下,若N=1267650600228229401496703205376,则logN=100。数字越大,则O(N)与O(1ogN)相差越大。 一般来说,计算机学科中使用的最基本的树为二叉查找树,下图是一颗二叉树的简单示意图: 图1二叉树示意图 二叉查找树则是在二叉树的基础上得来。假设在一颗二叉树中,每个节点都有一个关键词值,并且关键词值都是互异且可以 比较,若对于此二又树中的每个节点,其左子树中所有节点的关键词值小于其本身关键词值,其右子树中所有关键词值大于其本身 关键词值,则此二叉树为二叉查找树。 收稿日期:2013一叭一10 作者简介:解晨(1992一),男,安徽合肥人,中山大学信息安全专业,研究方向为人工智能、算法设计。 1532㈣软件设计开发 本栏目责任编辑:谢媛媛 第9卷第O7期(2013年03月) Computer Knowledge and Technology电脑知识与技术 AVL树,则是最先发明的带有平衡条件的二叉查找树。 下面,就让我们来分析一下AVL树的思想和原理。 1 AVL树思想和原理 正如上所述,AVL树是一种带有平衡条件的二叉查找树。那么,这个平衡条件是什么呢? 对于二叉查找树这样的数据结构来说,由于其节点有着按顺序排列的性质,若有数据往此数据结构中插入,则可能会引起树的 高度过高,使得访问数据的花销可能会比应有的要多。 例如,对于只有一个节点x的二叉查找树,若此后往树中插人的元素其关键词值皆小于x的关键词值,那么这棵树的左子树就 会越来越庞大,最终访问一个比x小得多的数据可能会花费相当多的开销,而如果在插入数据到一定程度时选择X的左子树中适当 的节点作为根节点,则情况会好得多。 如上所述的即是平衡条件,即使得树的深度不致过于深,让左子树和右子树的高度相差不宜过大。同时,从应用的角度来说, 这个平衡条件必须容易实现,并且应该允许能够易如反掌地对数据结构进行如插入数据、删除数据这样的常见操作。 1.1 AVL树的思想与原理 对于一颗AVL树来说,其平衡条件是要求其每个节点的左子树和右子树的高度最多差一。例如,在图2中,左边的树为AVL 树,右边的则不是: 图2二叉树 据资料显示,一个AVL树的高度平均来说只有1.44log(N+2)一1.328,并且其实际上的高度只比logN多一点,这样的访问花销 是比较高效的。 那么,AVL树是如何实现这个平衡条件的呢?很幸运,这个解决方法并不难。事实上,我们是可以通过足够简单的对树的修改 来做到。 1.2 AVL树的旋转操作 在对一颗AVL树进行插入数据或者删除数据的操作时,我们通过一种称之为“旋转”的操作来保持树的左右子树之差。由于对 像二叉查找树这样本身已经包含排列性质的数据结构的修改,一般来说只有插入数据和删除数据是常用的,所以在这作者只使用 插入数据来分析AVL树的旋转操作,删除数据可以依理推知。 同时,由于插入节点后,只有那些从插人点到根节点路径上的节点的平衡性会改变,所以在对树进行操作以更新平衡时,能找 到这样一个节点,它破坏了平衡性,但是可以对它进行操作使得树重新变得平衡。 现在假设这个破换平衡的节点为W。可知,根据AVL树的定义可知,此时w的左子树和右子树的高度差为二,并且这种造成不 平衡的插人操作会有如下四种情况: 1)对W的左儿子的左子树进行一次插入; 2)对W的右儿子的右子树进行一次插入; 3)对w的左儿子的右子树进行一次插入; 4)对w的右儿子的左子树进行一次插入。 可以看出,1)和2)是一个镜像关系,3)和4)也是一个镜像关系,因此,从理论的角度来说实际上只有两种情况。 对于1)和2)的情形,可以使用“单旋转”来恢复平衡。 单旋转的操作示意图如下: 图3单旋转操作示意图 本栏目责任编辑:谢媛媛 w 软件设计开发 1533 Computer Knowledge and Technology电脑知识与技_术 第9卷第07期(2013年03月) 可以看到,在这个示意图中,节点k2扮演着w的角色,其左子树与右子树的高度差为2,并且再插入包含新数据的新节点之前, k2满足AvL树的平衡条件。于是为了恢复平衡,对kl和k2及其左右子树进行操作。在示意图中,是以k1取代k2作为根节点,将Y 变成了k2的左子树,并将此时的k2作为k1的右儿子。 对于其镜像情形的操作也是一样,在此就不赘述。 而对于3)和4)的情形,则必须使用双旋转操作来保持树的平衡。例如,可以根据如下示意图来说明: 图4双旋转操作示意图 在这个情形中,对于以k1为根节点的树来说,其高度比树D多二,问题发生在k1的右子树,更准确的说,是发生在B或C,具体 哪个不要紧,【大1为都有可能,所以此处将B和C画得一样高。 对于这种情形,可以像示意图那样改变根节点,并且将k l、k2、k3的左右子树进行交换而使树重新得到平衡。 对于其镜像情况也可以使用相同的技巧使树的平衡得到保持,在此就不赘述。 可以看出,对于这两种情况,一次旋转足以解决问题,因此,其效率能够在接受的范围之内,并且易于实现。 下面,作者使用C语言对AV1树这一数据结构进行了实现。 2 AVL树的C语言实现 作者使用C语言对AVL树的节点、获取节点所在高度函数、数据节点的插入函数、左右单旋转函数、左右双旋转函数以及以中 序遍历在屏幕上显示节点信息函数等进行了实现。 2.1 AVL树节点实现 由前文分析可知,要实现的AVL树节点包含四个元素,即节点的关键词值,指向左儿子的指针以及指向右儿子的指针,此外,还 需有一个记录节点高度的元素用以判断平衡状态。可以使用一个结构来表示节点,其源代码如下: truer Avltree { int element; Avltree left; Avltree right; int high; }; 2.2 AVI.树获取节点高度函数实现 获取节点的高度比较容易,只需返回节点中保存的高度信息即可,唯一要注意的是若是一颗空树,则返回一1这个高度。源代码 如下: int HlGH(Avhree t)f if(t=:NULL)f return-i; } else return t—+high; l 2.3 AVL树插入元素函数实现 向AVL树中插入元素即使用一般的向二叉查找树中插入元素的操作即可,唯一要注意的是需修改节点高度信息,若平衡被破 坏则使用两种旋转对树进行修改。其源代码如下: ratio Avltree insert(int Avltree t){ if(t==NULL)I t=(Avltree )malloc(sizeof(struct Avltree)); t-*element x: t—high=0; t—left=t_÷right=NUI—L; 1534 软件设计开发 * 本栏目责任编辑:谢媛媛 Computer Knowledge and『ecnn0Jp 电脑知识与技术 第9卷第07期(2013年O3月) } else{ if(x>t-- ̄element)I t—+right:insert(x,t— right); if(H1GH(t一 ̄right)一HIGH(t- ̄Ie0) 2)f if(x>t__+righr e1ement) t=singalrotatewithright(t); else t=doublerotatewithright(t); }J else if(x<t--- ̄element){ t—lef【=insert(x,t lefl1; if(HIGH(t-- ̄lef1)一HIGH(t—r ht)==2){ if(x<t—}lefl—}e1ement)f t=singalrotatewithleft(t); } else t=doubler0tatewith1eftm; }}1 ifHIGH(t---+lef1)>=HIGH(t- ̄right)){ t— gh=HIGH(t--qeft)+l; } else{ t— igh=HIGH(t-- ̄right)+1: }return t; } 2.4左右单旋转函数实现 左右单旋转函数的过程可以按上文所分析的来实现,左右单旋转只是互为镜像。 右单旋转的源代码如下: Avltree水singalr0tatewiihright(AV1tree水t) { Avltree d=t— right; t.-+ri曲t=d一1eff; d-- ̄left=t: if(HIGH(t-+letf)>:HIGH(t--- ̄right)){ 卜+h h=HIGH(t-+left)+1; 1 else( t—high=HIGi{(t--- ̄right)+1; 1if(HiGH(d-+left)>=Hl(瑚(d—ri gl11)){ d—_’high=HIGH(d--- ̄lef1)+l; }else( d—+h唔h=HIGH(d--- ̄right)+1; 1return d; l 左单旋转的源代码如下: Avltree*singalrotatewithlefl vhree t1 fAvhree d=t_+left; t— lefI=d—}rjght; d_+r ht=t; i(fHIGH(t--qef1)>=HIGH(t--- ̄right)){ t—high=HIGH(t-- ̄le1f)+l; 本栏目责任编辑:谢媛媛 # ∞ 软件设计开发…1535 Compu ̄r Knowledge and Technology电脑知识与技术 }else{ t—,high=HIGHff—+rjght)+1; 第9卷第O7期(2013年03,EJ) }if(HIGH(d--'left)>=H1GH(d—ri t)){ d— high=HIGH(d--Jeff1+1: }else{ d—— high=HlGH(d-- ̄right)+1; }return d; J 2.5左右双旋转函数实现。 从上文中的分析可知,双旋转可以看成两次使用单旋转,因此,双旋转函数可以调用两次相对应的单旋转函数来实现。 右双旋转函数源代码如下: Avltree doublerotatewithright(Avhree t1 { t— right=singalrotatewithleft(t--*right); return singalrotatewithright(t); } 左双旋转函数源代码如下: Avhree doublerotatewithleft(Avltree t1 f卜÷left=singalrotatewithright(t- ̄left); retum singalrotatewithleft(t); l 2.6中序遍历函数实现 中序遍历是一种常用的遍历树这一数据结构的方法。此顺序先访问节点中的信息,再递归访问节点左子树中节点的信息,最 后递归访问右子树节点中的信息。 其源代码如下: void printtree(Avhree t1 {if(t!=NULL){ cout<<t--- ̄element<<””: }i t—left『-NULL){ printtree(t-*left); }if(t—right!=NULL){ printtree(t- ̄right); }J 以上,便是作者使用c语言实现的有关AVL树的所有源代码,其他操作如删除元素等可以依原理推知。 3总结 本文分析了AVL树的思想与原理,并根据其特点,结合C语言的特性,对AVL树和一系列的操作进行了实现。 AVL树是最早出现的数据结构之一,大大提高了访问数据的效率,也为以后数据结构的发展起着开拓性的作用。虽然如今计 算机的性能越来越匪夷所思,计算速度简直无法想象,访问速度早已大有提升,但毫无疑问,使用良好的数据结构依然对提高访问 速度有着举足轻重的作用。 参考文献: [1]Robert Sedgewick.算法:c语言实现【M】.北京:机械工业出版,2009. [2]Ellis Horowitz,Sartaj Sahni,Susan Anderson—Freed.数据结构(c语言版)【M】.北京:机械工业出版社,2006 [33] Mark Allen Weiss.数据结构与算法分析【M】.北京:人民邮电出版社,2005. [4]Sesh Venugopa1.数据结构:从应用到实 ̄(Java版)[M].北京:机械工业出版社,2008. 【5】Adam Drozdek.数据结构与算法:Java语言版[M].2版.北京:机械工业出版社,2006. 1536…软件设计开发 % 本栏目责任编辑:谢媛媛 

因篇幅问题不能全部显示,请点此查看更多更全内容