• 树 -- 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 }
    View Code

    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 }
    View Code

    插入


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

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

      

     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 !
    "<<std::endl;
    29         assert(0);
    30     }
    31     curr->height = __maxHeight(curr->left,curr->right) + 1;
    32     return curr;                                                                               
    33 }
    View Code

    删除


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

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

      

     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 }
    View Code

    参考


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

  • 相关阅读:
    MySQL-5.6.xx-winx64 免安装版配置方法
    winForm窗体最大化的设置
    foreach内部做的一点事
    sqlserver创建同义词
    sql server 数据库创建链接服务器
    文件比对工具——WinMerge
    Devos病毒解决办法(转)
    设计模式学习笔记-单例模式
    Aspose.Word for DotNet 定位到每页,画笔 移动到某页。
    Word 固定文字或签名在底部
  • 原文地址:https://www.cnblogs.com/carlsama/p/4162073.html
Copyright © 2020-2023  润新知