平衡二叉查找树——AVL树

  二叉查找树在最坏情况下高度可能为N-1,即插入元素时后插入的元素总比以前插入的元素大或者小。为了解决这种不平衡的情况,引入了平衡条件来限制树中节点的深度不能过深,其中最老的一种平衡树称为AVL树。这种树限制树中每个节点的左右子树的高度相差不能超过一。(另一种更严格的树限制节点的左右子树高度必须相等,但这样的树要求树中的节点数目为2的k次幂减1,是一种理想平衡树,但是要求太严格,无法实际使用。)

AVL树平衡条件分析

  AVL树是一棵特殊的二叉查找树,对AVL树的操作中,除了插入操作与普通二叉查找树不同外,其他对AVL树的操作与对普通二叉查找树的操作相同。AVL树的插入操作与普通二叉查找树的不同之处在于它在插入新元素(这个操作就是普通的二叉查找树插入操作)后需要判断新树是否满足AVL树的平衡条件,如果不满足平衡条件需要对新树进行调整使其满足平衡条件。进行调整的起点就在第一个(即最深的节点)破坏平衡条件的节点处。可以证明,只要调整完以此节点为根的子树使其满足平衡树的平衡条件,就可以保证整棵树满足平衡树的平衡条件。

  当插入新元素后,可能造成新树不满足平衡条件的情况可以分为四种。设a为插入新元素后不满足平衡条件的第一个节点(即不满足左右子树高度差不大于1的最深节点),在此基础上描述这四种情况:

(1)   对a的左子树的左子树进行一次插入

(2)   对a的左子树的右子树进行一次插入

(3)   对a的右子树的左子树进行一次插入

(4)   对a的右子树的右子树进行一次插入

  其中情况(1)和(4)在逻辑上是同一种情况,(2)和(3)是同一种情况。但是在编程上需要进行不同的处理(思路相同)。其中对(1)和(4)使用单旋转,对(2)和(3)使用双旋转(即两次单旋转)处理。旋转的主要思路就是通过降低a的深度,使其作为原来以a为根的树中的某个节点(具体情况选择的新根节点不同)的子节点,从而降低原来以a为根的子树中较高的那棵子树的深度,提高原来较低的子树的深度,从而使其满足平衡树的平衡条件。

AVL树基本例程

  AVL树节点的基本结构与普通的二叉查找树节点结构没有太大区别,唯一的区别是多了一个高度信息:

struct AvlNode

{

ElementType Element;

AVLTree Left;

AVLTree Right;

int Height;

} ;

  另外相应的,AVL树有一个计算获取节点高度的例程,如下:

static int Height(Position P)

{

if(P==NULL)

return -1;

else

return P->Height;

}

单旋转

  单旋转处理情形(1)和(4)的情况,单旋转的主要思路就是将第一个不平衡节点的左子树(或者右子树,取决于左或者右单旋。情形(1)是左单旋,情形(4)是右单旋)的根节点作为不平衡树的新根节点,原来的根节点作为新根节点的右子树(或者左子树)的根节点。同时新根节点的原来的右子树(或者左子树)作为原来不平衡树根节点的左子树(或者右子树)。最后,需要考虑将不平衡树的新根节点返回给上一层作为上一层节点的某一棵子树的根,这部分工作是由插入例程的递归机制处理的。例程如下:

//K2是一个不平衡树,同时是第一个不平衡节点

static Position SingleRotateWithLeft(Position K2)

{

Postion K1;

K1=K2->Left;

K1->Right=K2;

K2->Left=K1->Right;

K2->Height=Max(Height(K2->Left),Height(K2->Right))+1;

K1->Height=Max(Height(K1->Left),K2->Height)+1;

Return K1;

}

双旋转

  双旋转处理(2)和(3)的情况,此时使用一次单旋转无法降低高度较高的子树的深度,原因是较高的那棵子树会作为被降低了深度的原不平衡树的根的子树,此时与未旋转前的树深度相同。解决方案是使用两次单旋转,首先对不平衡节点的左(右)子树进行一次右(左)单旋转,使高子树(不平衡节点的左(右)子树的右(左)子树)的根向上提,降低高子树的深度。然后再对不平衡节点应用一次左(右)单旋转,将经历一次单旋转后成为不平衡节点的子树的根的节点继续向上提升,这样两次旋转后,就可以使不平衡树重新成为平衡树。例程如下:

//K3是第一个不平衡节点

static Postion DoubleRotateWithLeft(Position K3)

{

K3->Left=SingelRotateWithRight(K3->Left);

Return SingleRotateWithLeft(K3);

}

插入操作

  AVL树保持平衡是在插入时保证的,每当插入一个新节点时,都会判断树是否保持平衡状态,如果不平衡则对第一个不平衡节点进行旋转处理,插入例程根据插入新节点的情况来选择具体进行的旋转的方式。简单来说,AVL树的插入操作是在普通二叉查找树插入操作基础上进行了两个操作,分别是判断是否满足平衡条件的操作以及在不满足平衡条件的情况下进行旋转的操作。例程如下:

AVLTree Insert(ElementType X,AVLTree T)

{

if(T==NULL)

{

T=malloc(sizeof(struct AvlNode));

If(T==NULL)

FataError(“Out OF space!!!”);

Else

{

T->Element=X;

T->Height=0;

T->Left=T->Right=NULL;

}

}

else if(x<T->element)

{

T->Left=Insert(X,T->Left);

//保持平衡的操作

If(Height(T->left)-Height(T->Right)==2)

{

if(X<T->Left->Element)

T=SingleRotateWithLeft(T);

Else

T=DoubleRotateWihtRight(T);

}

}

else if(X>E->element)

{     //与插入左子树时相反的操作… }

T->Heihgt=Max(Height(T->Left),Height(T->Rigth))+1;

Return T;

}

时间: 2024-10-14 04:48:01

平衡二叉查找树——AVL树的相关文章

[重温数据结构]一种自平衡二叉查找树avl树的实现方法

最近重温<数据结构>,发现其中的东西我上学的时候几乎都没写过... 惭愧啊.于是打算一一写点.算是对我逝去青春的纪念... avl树的代码网上有很多, 这个在平衡二叉树里面算是比较简单的. 需要注意的就是树的平衡因子和其子树的平衡因子符号相反的旋转情况.这个在函数avl_rotate_right等中有处理. 目前只做了插入,删除等哪天想做了再做吧. avl.h 1 #define INSERT_ERROR -1 2 #define INSERT_OK 1 3 4 #define LEFT_LE

二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较

http://www.iteye.com/topic/614070 此少侠总结的特棒,直接收藏了. 我们这个专题介绍的动态查找树主要有: 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree).这四种树都具备下面几个优势: (1) 都是动态结构.在删除,插入操作的时候,都不需要彻底重建原始的索引树.最多就是执行一定量的旋转,变色操作来有限的改变树的形态.而这些操作所付出的代价都远远小于重建一棵树.这一优势在<查找结构专题(1):静态查找结构概论 >中讲到

13、自平衡二叉查找树AVL

1 package ren.laughing.datastructure.baseImpl; 2 3 /** 4 * 自平衡二叉查找树AVL 继承二叉查找树 5 * 6 * @author Laughing_Lz 7 * @time 2016年4月20日 8 */ 9 public class AVLTree extends BSTree { 10 /** 11 * 统一平衡方法 旋转操作 12 * 13 * @param z 14 * z是失衡的结点 15 * @return 返回平衡后子树的

【查找结构3】平衡二叉查找树 [AVL]

在上一个专题中,我们在谈论二叉查找树的效率的时候.不同结构的二叉查找树,查找效率有很大的不同(单支树结构的查找效率退化成了顺序查找).如何解决这个问题呢?关键在于如何最大限度的减小树的深度.正是基于这个想法,平衡二叉树出现了. 平衡二叉树的定义 (AVL—— 发明者为Adel'son-Vel'skii 和 Landis) 平衡二叉查找树,又称 AVL树. 它除了具备二叉查找树的基本特征之外,还具有一个非常重要的特点:它 的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值(平衡因子

数据结构14.自平衡二叉查找树_AVL树

引言 在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增加和删除可能需要通过一次或多次树旋转来重新平衡这个树. AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis,他们在1962年的论文<An algorithm for the organization of information>中发表了它. 一. AVL树定义 平衡

平衡二叉查找树AVL

1.AVL简介 这篇文章我们要介绍的是能够在key插入时一直保持平衡的二叉查找树(AVL树,AVL是发明者的名字缩写) 利用AVL实现ADT MAP,基本上与BST的实现相同.不同之处在于二叉树的生成与维护过程. 2.AVL中的概念 AVL树的实现中,需要对每个节点跟踪"平衡因子balance factor"参数. 平衡因子是根据节点的左右子树的高度来定义的.确切的来说,是左右子树的高度差.balanceFactor = height(leftSubTree) - height(rig

二叉树-二叉查找树-AVL树

一.二叉树 定义:每个节点都不能有多于两个的儿子的树. 二叉树节点声明: 1 struct treeNode 2 { 3 elementType element; 4 treeNode * left; 5 treeNode * right; 6 } 应用: 中缀表达式——>后缀表达式(栈的应用)——>表达式树(栈的应用2) 栈的应用2:读取后缀表达式,操作数入栈,遇操作符后,指向栈里前两位元素t1和t2的指针出栈(t1先弹出,作为该操作符的右儿子),并将指向该操作符的指针入栈. 二.二叉查找树

java数据结构与算法之平衡二叉树(AVL树)的设计与实现

[版权申明]未经博主同意,不允许转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53892797 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) java数据结构与算法之栈(Stack)设

AVL树的旋转实现

AVL树:带有平衡条件的二叉查找树,即一棵AVL树是其每个节点的左子树和右子树的高度最多相差1的二叉查找树.一般通过Single Rotate和Double Rotate来保持AVL树的平衡.AVL树的实现如下: 1) Single Rotate 2)Double Rotate 1) Single Rotate ( SingleRotateWithRight同理) static Position SingleRotateWithLeft(Position K2) { Position K1; K