• 平衡二叉树


    AVL树说明:

        该树是一种高度平衡的二叉搜索树,该树中的每一个结点左右子树的高度至多相差1。

        AVL树本身也是一个二叉搜索树。

        AVL基本结构定义如下: 

      #define LH +1  // 左高 
      #define EH  0  // 等高 
      #define RH -1  // 右高 
    
      struct BTNode
      {
          int data;
          int bf;
          struct BTNode *lchild;
          struct BTNode *rchild;
      };
    

    斐波那契数列:

        1、1、2、3、5、8、13、21、34、……

        其递推式定义为:F(1) = 1, F(2) = 1, F(n) = F(n-1) + F(n-2) (n>=3)

        即斐波那契数列的第1、第2项都为1,然后后面的每一项都是前两项之和。

    平衡二叉树最少结点计算:

        完全二叉树是平衡二叉树最“完全”的状态。

        那满足平衡二叉树的最不完全的状态,即结点最少的状态是怎样的?

        树高度记为h,树中结点总数记为C,结点内的值代表平衡因子,则:

        

        高度为h的平衡二叉树的最少结点总数为Ch = Ch-1 + Ch-2 + 1

        和斐波那契数列对比:

         Fh 1 1 2 3  5 8  13 21 34
         Ch 1 2 4 7 12 20 33

         所以Ch = F(n+2) - 1

         如何画出上面的图:每次增加一个最左结点导致高度加1,然后需要补充一些结点,在原来树中度为0的结点下增加一个左孩子,度为1的

         结点下增加一个右孩子即可。

    AVL树旋转详解

        若某节点A出现失衡,即左子树或右子树长高了,导致左右子树的高度差2,会有以下四种情况:

    •  该点左子树比右子树高度高2,因为原来是平衡的,所以新结点一定是左孩子的孩子结点

           1. 在左孩子的左子树上插入结点

              

               由于是左子树增高,所以左孩子B结点一定存在,其余抽象,BL,BR,AR的高度均是H,否则无法导致插入后A点失衡。

               插入新结点后,BL这棵树高度加1。

               需要进行右旋,对比上图可得如下代码:   

             void R_Rotate(BTNode *&A)
             {
                 BTNode *B= A->lchild;
                 A->lchild = B->rchild;
                 B->rchild = A;
                 A = B;
             }
    

               插入到左子树的左孩子整体的平衡调整代码如下:

             A->bf = EH;
             B->bf = EH;
             R_Rotate(A);
    

                

           2. 在左孩子的右子树上插入结点

              

                      结点插入在BR上这棵树上,BR树高度变为H+1,将BR树变成b图所示形式,必存在一个C结点,其左右子树高度差1,

               b图画的是CL比CR高,当然也可能是CR比CL高,调整平衡因子的时候需要做判断。

               插入到左孩子的右子树导致的失衡,应该先左旋再右旋,代码如下:  

             BTNode *B = A->lchild;
             BTNode *C = B->rchild;
    
             switch (C->bf)
             {
                 case LH:  // CL高度H, CR高度H-1
                     A->bf = RH;
                     B->bf = EH;
                     break;
                 case EH:  // CL高度H, CR高度H
                     A->bf = EH;
                     B->bf = EH;
                     break;
                 case RH:  // CL高度H-1, CR高度H
                     A->bf = EH;
                     B->bf = LH;
                     break;
             }
    
             C->bf = EH;
             L_Rotate(B);
             R_Rotate(A);  // 右旋代码见下
    • 该点右子树比左子树高度高2,因为原来是平衡的,所以新结点一定是右孩子的孩子结点

           1. 在右孩子的右子树上插入结点

              

               需要进行左旋,对比上图可得如下代码:   

             void L_Rotate(BTNode *&A)
             {
                 BTNode *B = A->rchild;
                 A->rchild = B->lchild;
                 B->lchild = A;
                 A = B;
             }
    

             插入到右子树的右孩子整体的平衡调整代码如下:

             A->bf = EH;
             B->bf = EH;
             L_Rotate(A);
    

          

                2. 在右孩子的左子树上插入结点

              

              插入到右孩子的右子树导致的失衡,应该先右旋再左旋,代码如下:    

            BTNode *B = A->rchild;
            BTNode *C = B->lchild;
    
            switch (C->bf)
            {
                case LH:  // CL高度H, CR高度H-1
                    A->bf = EH;
                    B->bf = RH;
                    break;
                case EH:  // CL高度H, CR高度H
                    A->bf = EH;
                    B->bf = EH;
                    break;
                case RH:  // CL高度H-1, CR高度H
                    A->bf = LH;
                    B->bf = EH;
                    break;
            }
    
            C->bf = EH;
            R_Rotate(B);
            L_Rotate(A);
    

    算法实现:

    层层递归到栈底,插入一个结点后,返回到栈上一层,taller置为true,然后判断是否该旋转该结点并修改平衡因子,判断是否增高,再返回栈上一层。。。。

    void LeftBalance(BTNode *&A)
    {
        BTNode *C = A->lchild;
        switch (C->bf)
        {
            case LH:
                A->bf = EH;
                B->bf = EH;
                R_Rotate(A);
                break;
            case RH:
                BTNode *B = C->rchild;
                switch (B->bf)
                {
                    case LH:
                        A->bf = RH;
                        C->bf = EH;
                        break;
                    case EH:
                        A->bf = EH;
                        C->bf = EH;
                        break;
                    case RH:
                        A->bf = EH;
                        C->bf = LH;
                        break;
                }
                B->bf = EH;
                L_Rotate(C);
                R_Rotate(A);
                break;
        } 
    }
    
    void RightBalance(BTNode *&A)
    {
        BTNode *B = A->rchild;
        switch (B->bf)
        {
            case RH:
                A->bf = EH;
                B->bf = EH;
                L_Rotate(A);
                break;
            case LH:
                BTNode *C = B->lchild;
                switch (C->bf)
                {
                    case LH:
                        A->bf = EH;
                        B->bf = RH;
                        break;
                    case EH:
                        A->bf = EH;
                        B->bf = EH;
                        break;
                    case RH:
                        A->bf = LH;
                        B->bf = EH;
                        break;
                }
                C->bf = EH;
                R_Rotate(B);
                L_Rotate(A);
                break;
        }
    }
    
    int InsertAVL(BTNode *&t, int e, int &taller)
    {
        if (t == NULL)
        {
            t = (BTNode*)malloc(sizeof(BTNode));
            t->data = e;
            t->lchild = NULL;
            t->rchild = NULL;
            t->bf = EH;
            taller = true;
        }
        else
        {
            if (t->data == e)
            {
                taller = false;
                return false;
            }
            else if(t->data > e)
            {
                if (InsertAVL(t->lchild, e, taller) == false)
                    return false;
                
                // e插入到左子树,且左子树长高 
                if (taller)
                {
                    // 判断结点原来的平衡因子
                    switch(t->bf)
                    {
                        case LH:
                            LeftBalance(t);
                            taller = false;
                            break;
                        case EH:
                            t->bf = LH;
                            taller = true;
                            break;
                        case RH:
                            t->bf = EH;
                            taller = false;
                            break; 
                    } 
                } 
            }
            else
            {
                if (InsertAVL(t->rchild, e, taller) == false)
                    return false;
                
                // e插入到右子树,且右子树长高 
                if(taller)
                {
                    // 判断结点原来的平衡因子
                    switch(t->bf)
                    {
                        case LH:
                            t->bf = EH;
                            taller = false;
                            break;
                        case EH:
                            t->bf = RH;
                            taller = true;
                            break;
                        case RH:
                            RightBalance(t);
                            taller = false;
                            break; 
                    } 
                }
            }
        }
        return true;
    }
    
  • 相关阅读:
    c# -- 实现浏览功能(备忘)
    自己动手写中文分词解析器完整教程,并对出现的问题进行探讨和解决(附完整c#代码和相关dll文件、txt文件下载)
    爬虫技术 -- 进阶学习(九)使用HtmlAgilityPack获取页面链接(附c#代码及插件下载)
    爬虫技术 -- 进阶学习(八)模拟简单浏览器(附c#代码)
    爬虫技术 -- 进阶学习(七)简单爬虫抓取示例(附c#代码)
    c# -- 介绍File.AppendAllText 方法
    c# -- 解决FromsAuthentication上下文不存在
    c# -- Form1_Load()不被执行的三个解决方法
    爬虫技术 -- 基础学习(六)解析相对地址
    爬虫技术 -- 基础学习(五)解决页面编码识别(附c#代码)
  • 原文地址:https://www.cnblogs.com/yanghh/p/12683017.html
Copyright © 2020-2023  润新知