树 -- AVL树

前言



  通过之前对二叉查找树的讨论,我们知道在给定节点数目的情况下,二叉树的高度越低,查找所用时间也就越短.

  在讨论红黑树的时候,我们说过红黑树并非完全"平衡"的二叉树,只是近似"平衡".那么这个平衡到底指的是什么呢?有没有完全"平衡"的二叉树?

平衡二叉树



  什么样的二叉树能被形容为平衡二叉树呢?

    1)空树

    2)根的左右子树的高度之差的绝对值不超过1,并且左右子树也都是一棵平衡二叉树。

  这样的树就被我们认作时平衡二叉树.

  显然,当一颗二叉搜索树能够保证上面的性质时,树整体的高度就能得到良好的控制.

   

二叉树失衡



  既然我们已经知道了平衡二叉树的定义,并且了解到了它的诸多好处.那么如何将一颗二叉搜索树构建成平衡二叉搜索树呢? (我们首先约定,叶子节点的高度为1.NULL节点的高度为0.)

  首先让我们分析一下插入和删除操作中,二叉搜索树"失衡"后的状态.如下图所示:

  

  我们在2的左边插入了新的节点3后,使得对于1来讲,其左子树高度为2,右子树高度为1.进入了失衡的状态.

  概括的讲,如果将平衡二叉树上某个节点的较高子树(比另一颗子树的高度大1)再增加1的高度,或者将某个节点的较低子树(比另一颗子树的高度小1)再减小1的高度,就会产生二叉树的失衡.

  下面列举一下失衡的状态.

   --泛型>因为是1左侧的左侧的节点造成的失衡,所以称为LL失衡.

   --泛型>与LL失衡对称的RR失衡.

  --泛型>因为是1左侧的右侧的节点造成的失衡,所以成为LR失衡.

  --泛型>与LR失衡对称的RL失衡.

  

失衡二叉树的恢复操作



  在红黑树中,我们对于失衡的调整是根据节点的颜色,进行旋转和赋值操作来保证一种"近似的平衡".

  那么对于一颗要保证"平衡的"的二叉树,该如何调整呢?我们分情况讨论一下.

1)LL失衡与LR失衡

  对于某处的LL失衡,需要进行右旋操作,化解此处的失衡.然后向上查看是否还存在其他类型的失衡.

  

  对于RR失衡的修正类似于LL失衡的处理,旋转的方向改变成了左旋.

  

 1 template<class T>
 2 TNode<T>* AvlTree<T>::__leftleftRotate(TNode<T> *dest){
 3     assert(dest!=nil || dest->left!=nil);
 4
 5     TNode<T> *l = dest->left;
 6     dest->left = l->right;
 7     l->right = dest;
 8
 9     dest->height = __maxHeight(dest->left,dest->right)+1;
10     l->height = __maxHeight(l->left,l->right)+1;
11
12     if(root == dest)
13         root = l;
14     return l;
15 }
16 template<class T>
17 TNode<T>* AvlTree<T>::__rightrightRotate(TNode<T> *dest){
18     assert(dest!=0 || dest->right!=0);
19
20     TNode<T> *r = dest->right;
21     dest->right = r->left;//Between dest and new left
22     r->left = dest;
23
24     dest->height = __maxHeight(dest->left,dest->right)+1;
25     r->height = __maxHeight(r->left,r->right)+1;
26
27     if(root == dest)
28         root = r;
29     return r;
30 }

2) 对于LR失衡和RL失衡  

  对于LR失衡,我们需要先对2节点进行左旋操作,然后对1节点进行右旋操作.这样可以将1节点下的不平衡消除.之后需要向上查看是否有其他不平衡节点.

  对于RL失衡的处理,与LR类似.

  

 1 template<class T>
 2 TNode<T>* AvlTree<T>::__leftrightRotate(TNode<T> *dest){
 3     __rightrightRotate(dest->left);
 4     return __leftleftRotate(dest);
 5 }
 6 template<class T>
 7 TNode<T>* AvlTree<T>::__rightleftRotate(TNode<T> *dest){
 8     __leftleftRotate(dest->right);
 9     return __rightrightRotate(dest);
10 }

插入



  能破坏一课平衡二叉树的操作为插入新节点,和删除已有节点.我们结合前面讲的平衡恢复方法来实现平衡二叉树的插入操作.  

  插入某个节点之后,可能会破坏插入所经过的路径上的节点的平衡度.所以需要回溯路径上节点当前的平衡性.这种场合十分适合递归的方法.

  

 1 template<class T>
 2 TNode<T>* AvlTree<T>::__insert(T val,TNode<T> *curr){
 3     if(curr==nil){
 4         TNode<T> *in = new TNode<T>(val,nil,nil,1);
 5         assert(in);
 6         if(nil == root)
 7             root = in;
 8         curr = in;
 9     }else if(curr->val > val){
10         curr->left = __insert(val,curr->left);
11         if(std::abs(height(curr->left)-height(curr->right))>1){
12             if(val < curr->left->val){
13                 curr = __leftleftRotate(curr);
14             }else{
15                 curr = __leftrightRotate(curr);
16             }
17         }
18     }else if(curr->val < val){
19         curr->right = __insert(val,curr->right);
20         if(std::abs(height(curr->left)-height(curr->right))>1){
21             if(val > curr->right->val){
22                 curr = __rightrightRotate(curr);
23             }else{
24                 curr = __rightleftRotate(curr);
25             }
26         }
27     }else{
28         std::cout<<"Duplicate val !\n"<<std::endl;
29         assert(0);
30     }
31     curr->height = __maxHeight(curr->left,curr->right) + 1;
32     return curr;
33 }

删除



  产出某个节点后带来的失衡就类似于在另一支上插入了一个节点而带来的失衡.

  依然需要回溯路径上的节点.

  

 1 template<class T>
 2 TNode<T>* AvlTree<T>::__erase(TNode<T> *dest,TNode<T> *currRoot){
 3     assert(dest);
 4
 5     if(currRoot->val > dest->val){
 6         currRoot->left = __erase(dest,currRoot->left);
 7
 8         if(std::abs(height(currRoot->left)-height(currRoot->right))>1){
 9             if(height(currRoot->right->right) > height(currRoot->right->left))
10                 currRoot = __rightrightRotate(currRoot);
11             else
12                 currRoot = __rightleftRotate(currRoot);
13         }
14     }else if(currRoot->val < dest->val){
15         currRoot->right = __erase(dest,currRoot->right);
16         if(std::abs(height(currRoot->left)-height(currRoot->right)>1)){
17             if(height(currRoot->left->left) > height(currRoot->left->right))
18                 currRoot = __leftleftRotate(currRoot);
19             else
20                 currRoot = __leftrightRotate(currRoot);
21         }
22     }else{//currRoot->val == dest->val
23         TNode<T> *replace;
24         if(currRoot->left!=nil && currRoot->right!=nil){
25             if(height(currRoot->left) > height(currRoot->right)){
26                 replace = predecessor(currRoot);
27                 currRoot->val = replace->val;
28                 currRoot->left = __erase(replace,currRoot->left);
29             }else{
30                 replace = successor(currRoot);
31                 currRoot->val = replace->val;
32                 currRoot->right = __erase(replace,currRoot->right);
33             }
34         }else{
35             replace = (currRoot->left!=nil)?currRoot->left:currRoot->right;
36             delete dest;
37             currRoot = replace;
38         }
39     }
40     currRoot->height = ((currRoot==nil)?0:__maxHeight(currRoot->left,currRoot->right)+1);
41     return currRoot;
42 }

参考



  http://www.cnblogs.com/skywang12345/p/3603935.html

时间: 2024-10-07 19:47:42

树 -- AVL树的相关文章

《数据结构与算法分析:C语言描述》复习——第四章“树”——AVL树

2014.06.15 16:22 简介: AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母.此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1.有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别.没有bad case是AVL树与普通的二叉搜索树的最大区别.为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况.为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双

04-树4. Root of AVL Tree-平衡查找树AVL树的实现

对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是O(logN),而接近O(N),这样将大大减少对树的查找效率.一种解决办法就是要有一个称为平衡的附加的结构条件:任何节点的深度均不得过深.有一种最古老的平衡查找树,即AVL树. AVL树是带有平衡条件的二叉查找树.平衡条件是每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1).相比于普通的二叉树,AVL树的节点需要增加一个变量保存节点高度.AVL树的节点声明如下: typedef st

红黑树/B+树/AVL树

RB Tree 红黑树  :http://blog.csdn.net/very_2/article/details/5722682 AVL Tree    :http://blog.csdn.net/collonn/article/details/20128205 B[+/-] Tree  :http://hxraid.iteye.com/blog/611105 几种Tree 总结对比 :http://www.iteye.com/topic/614070 [nginx模块开发与架构解析]

AVL树,红黑树,B-B+树,Trie树原理和应用

前言:本文章来源于我在知乎上回答的一个问题 AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中? 看完后您可能会了解到这些数据结构大致的原理及为什么用在这些场景,文章并不涉及具体操作(如插入删除等等) 目录 AVL树 AVL树原理与应用 红黑树 红黑树原理与应用 B/B+树 B/B+树原理与应用 Trie树 Trie树原理与应用 AVL树 简介: AVL树是最早的自平衡二叉树,在早期应用还相对来说比较广,后期由于旋转次数过多而被红黑树等结构取代(二者都是用来搜索的),AVL树内

数据结构之——AVL树

AVL树 AVL树又称为高度平衡的二叉搜索树,它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度: AVL树的性质 左子树和右子树的高度之差的绝对值不超过1 树中的每个左子树和右子树都是AVL树 下面实现一棵AVL树,主要实现其插入部分: #pragma once template <class K, class V> struct AVLTreeNode { K _key; V _val; AVLTreeNode<K, V>* _left; AVLTreeNod

【数据结构】平衡二叉排序树BBST之AVL树

平衡二叉排序树 平衡二叉排序树(Balanced Binary Sort Tree),上一篇博客[数据结构]二叉排序树BST讲了BST,并且在最后我们说BST上的操作不会超过O(h),既然树高这么重要,那么BBST的研究就是为了使得树的深度在可接受的范围内渐近意义下达到O(lgn) n个节点组成的二叉树,其高度为lgn取下限时,这棵树是理想平衡的,满足这样条件的树只有完全二叉树和满二叉树,这样的要求未免太苛刻,并且实际中没有意义. 适度平衡:保证树高在渐近意义上不超过O(lgn)适度平衡的树也称

红黑树和AVL树的实现与比较-----算法导论

一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以下五个性质: 1) 每个结点或是红色或是黑色 2) 根结点是黑色 3) 每个叶结点是黑的 4)如果一个结点是红的,则它的两个儿子均是黑色 5) 每个结点到其子孙结点的所有路径上包含相同数目的黑色结点 本实验主要实现红黑树的初始化,插入和删除操作.当对红黑树进行插入和 删除操作时,可能会破坏红黑树的五

算法学习笔记 平衡二叉树 AVL树

AVL树是最先发明的自平衡二叉查找树, 其增删查时间复杂度都是 O(logn), 是一种相当高效的数据结构.当面对需要频繁查找又经常增删这种情景时,AVL树就非常的适用.[ 博客地址:http://blog.csdn.net/thisinnocence ] AVL树定义 AVL树诞生于 1962 年,由 G.M. Adelson-Velsky 和 E.M. Landis 发明.AVL树首先是一种二叉查找树.二叉查找树是这么定义的,为空或具有以下性质: 若它的左子树不空,则左子树上所有的点的值均小

AVL树

定义:AVL树是每个节点左子树和右子树的高度差最大为1的二叉查找树 不平衡节点:假设在懒惰删除(删除操作时,并不删除节点,只是对节点进行特定标记)的条件下,插入操作有可能破坏AVL树的平衡特性. 如果插入节点导致平衡性被破坏,那么平衡性遭到破坏的节点只可能出现在插入节点到根节点的路径上.因为插入操作只会改变 插入节点的父节点的高度,而这些父节点就再这条路径上. 调整:对于平衡性遭到破坏的节点,需要对其进行调整以恢复平衡性.调整的方法称为旋转,针对不同的插入情况,调整操作稍有不同. 下面先对插入情