数据结构与算法基础-学习-21-查找之平衡二叉树(AVL树)

目录

一、个人理解

二、最小失衡子树

三、平衡调整的四种类型

1、LL型

2、RR型

3、LR型 

4、RL型

四、如何平衡调整

1、LL型调整

2、LR型调整

五、宏定义

六、结构体类型定义

1、AVL树结点类型

2、AVL树类型

3、AVL树结点搜索路径类型

4、其他类型

七、函数定义

1、初始化AVL树

2、新建一个AVL树结点

3、比较数据大小

4、数学中的LOG

5、初始化AVL树搜索路径

6、插入AVL树搜索路径

7、销毁AVL树搜索路径

8、RL型转换

9、LR型转换

10、RL型转换

11、LL型转换

12、RR型转换

13、AVL树转换

14、求AVL树的深度

15、计算结点平衡因子

16、插入数据到AVL树

17、销毁AVL树结点

 18、销毁AVL树

八、Linux环境测试LL型



一、个人理解

平衡二叉树(Balance Binary Tree)别名AVL树,是由三位科学家姓名首字母组成的。

它是二叉排序树(Binary Sort Tree简称BST)的一个衍生,具有BST所有的性质,除此之外还具有如下特性:

1、左子树和右子树的高度之差的绝对值小于等于1。

2、左子树和右子树也都是平衡二叉树。

为了方便区分这颗树是不是AVL树,加了一个参数平衡因子。

平衡因子 = 左子树高度 - 右子树高度

平衡因子为1,-1,0时,表示以这个节点为根的AVL树是平衡的。

二叉排序树(Binary Sort Tree简称BST)的介绍可以参考之前写的文章《数据结构与算法基础-学习-15-二叉树之前序、后序、中序遍历的递归和非递归方法实现以及BST的初始化、插入、获取结点数

二、最小失衡子树

d2441dff98b040feb807c4d5cc07497e.png

 当插入新节点时,可能会出现多个失衡节点,这时我们需要找到最小失衡子树,如上图,再进行调整,变回AVL树。

三、平衡调整的四种类型

a:失衡节点。

b:a的孩子节点,c的双亲结点。

c:插入新节点的子树。

1、LL型

299201529e3d4287a9665232542a66be.png

2、RR型

 17c6ef533e6743a0b4213ca713bb02cc.png

3、LR型 

4a777bd27471421e80f34984891ab301.png

4、RL型

d3639ba3faa14f4c94eb880c9be61f0f.png

四、如何平衡调整

本文讲解其中两种LL,LR如何进行调整。

1、LL型调整

b530a45396ed46b88a374459f5a2b85e.png

 插入18,发现24结点出现失衡且为最小失衡子树,判断为LL型。

之后我们找到中间值结点,这里为20,我们把24挂到20的右侧上,这时需要注意20是否有右子树,如果有的话,需要挂到24的左子树上,最后断开24和40的链接,将20与40链接,如下图,重新计算平衡因子,已调整回平衡二叉树。

ed0a336e59cc4316952ad03187e363b2.png

2、LR型调整

4771a149a3294c4d9cef470af20ef7f2.png

插入23,发现24结点出现失衡且为最小失衡子树,判断为LR型。

之后我们找到中间值结点,这里为23,断开24与40的链接,23和40进行链接,23如果有左孩子需要放到20的右指针上。如果23右右孩子的话,需要放到24的左指针上。23的左指针链接20,右指针链接24,如下图,重新计算平衡因子,已调整回平衡二叉树。

3961923aa4fa4211b9f7061861a2f8a7.png

五、宏定义

#define CMP_LARGE           0
#define CMP_LITTLE          1
#define CMP_EQUAL           2
#define BALANCE_FACTOR_INIT 0
#define AVL_BALANCE_FLAG    1
#define AVL_NO_BALANCE_FLAG 2
#define AVL_LEFT_DIRECTION  'l'
#define AVL_RIGHT_DIRECTION 'r'

六、结构体类型定义

1、AVL树结点类型

typedef struct AvlTreeNode
{
    AvlTreeNodeDataType Data;
    BalanceFactorType   BalanceFactor;
    struct AvlTreeNode* LeftNodePtr;
    struct AvlTreeNode* RightNodePtr;
}AvlTreeNode;
名称解释
Data存放数据。
BalanceFactor存放平衡因子。
LeftNodePtr存放左子树指针。
RightNodePtr存放右子树指针。

2、AVL树类型

typedef struct AvlTree
{
    AvlTreeNode*        RootNodePtr;
    AvlTreeNodeDataType TreeNodeNum;
}AvlTree;
名称解释
RootNodePtr存放AVL树根结点指针。
TreeNodeNum存放AVL树总结点数。

3、AVL树结点搜索路径类型

typedef struct AvlNodeSelectPathType
{
    AvlTreeNode**       NodePtrArray;
    AvlDirectionFlag*   DirectionArray;
    AvlTreeNodeDataType ArrayLen;
    AvlTreeNodeDataType ArrayMaxLen;
}AvlNodeSelectPathType;
名称解释
NodePtrArray存放AVL树插入数据时访问的结点指针。
DirectionArray存放AVL树插入数据时访问的方向标识(是左子树还是右子树)。
ArrayLen存放上述两个数组的实际使用长度。
ArrayMaxLen存放上述两个数组的最大使用长度。

其实也就是用了串的思想。

4、其他类型

typedef long long int       AvlTreeNodeDataType;
typedef int                 NumCmpType;
typedef AvlTreeNodeDataType BalanceFactorType;
typedef short               BalanceFactorStatus;
typedef char                AvlDirectionFlag; //对应AVL_LEFT_DIRECTION、AVL_RIGHT_DIRECTION

七、函数定义

1、初始化AVL树

Status InitAvlTree(AvlTree** AT)
{
    JudgeAllNullPointer(AT);
    *AT = (AvlTree*)MyMalloc(sizeof(AvlTree));
    (*AT)->RootNodePtr = NULL;
    (*AT)->TreeNodeNum = 0;
    Log("Init Avl Tree OK\n",Debug);
    return SuccessFlag;
}

2、新建一个AVL树结点

AvlTreeNode* NewAvlTreeNode(AvlTreeNodeDataType InputData)
{
    AvlTreeNode* NewNodePtr   = (AvlTreeNode*)MyMalloc(sizeof(AvlTreeNode));
    NewNodePtr->Data          = InputData;
    NewNodePtr->BalanceFactor = BALANCE_FACTOR_INIT;
    NewNodePtr->LeftNodePtr   = NULL;
    NewNodePtr->RightNodePtr  = NULL;
    //Log("New Avl Tree Node OK\n",Debug);
    return NewNodePtr;
}

3、比较数据大小

NumCmpType CmpAvlTreeNodeData(AvlTreeNodeDataType Data1, AvlTreeNodeDataType Data2)
{
    if(Data1 > Data2)
    {
        return CMP_LARGE;
    }
    else if(Data1 < Data2)
    {
        return CMP_LITTLE;
    }
    else
    {
        return CMP_EQUAL;
    }
}

4、数学中的LOG

//实现数学中的log,Num1为底数,Num2为对数。
//实现比较粗糙。以后改进。
AvlTreeNodeDataType MathLog(AvlTreeNodeDataType Num1, AvlTreeNodeDataType Num2)
{
    AvlTreeNodeDataType Cnt    = 1;
    AvlTreeNodeDataType TmpVal = Num1;
    while(TmpVal < Num2)
    {
        TmpVal = TmpVal * Num1;
        Cnt++;
    }
    return Cnt;
}

5、初始化AVL树搜索路径

Status InitAvlNodeSelectPath(AvlTree* AT, AvlNodeSelectPathType** SelectPath)
{
    JudgeAllNullPointer(AT);
    JudgeAllNullPointer(SelectPath);

    *SelectPath                   = (AvlNodeSelectPathType*)MyMalloc(sizeof(AvlNodeSelectPathType));
    (*SelectPath)->ArrayMaxLen    = MathLog(2,AT->TreeNodeNum) + 2;//平衡二叉树的最大高度,log2(n)+1,多加一个一节点,再加一。
    (*SelectPath)->NodePtrArray   = (AvlTreeNode**)MyMalloc(sizeof(AvlTreeNode*) * (*SelectPath)->ArrayMaxLen);
    (*SelectPath)->DirectionArray = (AvlDirectionFlag*)MyMalloc(sizeof(AvlDirectionFlag) * (*SelectPath)->ArrayMaxLen);
    (*SelectPath)->ArrayLen       = 0;

    Log("Init Avl Node Select Path OK\n",Debug);
    return SuccessFlag;    
}

6、插入AVL树搜索路径

Status InsertAvlNodeSelectPath(AvlNodeSelectPathType* SelectPath, AvlTreeNode* AvlTreeNodePtr, AvlDirectionFlag DirectionFlag)
{
    JudgeAllNullPointer(SelectPath);
    JudgeAllNullPointer(AvlTreeNodePtr);

    if(SelectPath->ArrayLen == SelectPath->ArrayMaxLen)
    {
        Log("Insert Avl Node Select Path Fail, reason : array is full.\n",Warning);
        return FailFlag;
    }

    SelectPath->NodePtrArray[SelectPath->ArrayLen]   = AvlTreeNodePtr;
    SelectPath->DirectionArray[SelectPath->ArrayLen] = DirectionFlag;
    SelectPath->ArrayLen++;

    Log("Insert Avl Node Select Path OK\n",Debug);
    return SuccessFlag; 
}

7、销毁AVL树搜索路径

Status DestoryAvlNodeSelectPath(AvlNodeSelectPathType** SelectPath)
{
    JudgeAllNullPointer(SelectPath);
    JudgeAllNullPointer(*SelectPath);

    free((*SelectPath)->NodePtrArray);
    free((*SelectPath)->DirectionArray);
    (*SelectPath)->ArrayMaxLen    = 0;
    (*SelectPath)->NodePtrArray   = NULL;
    (*SelectPath)->DirectionArray = NULL;
    (*SelectPath)->ArrayLen       = 0;
    free(*SelectPath);
    *SelectPath                   = NULL;

    Log("Destory Avl Node Select Path OK\n",Debug);
    return SuccessFlag;
}

8、RL型转换

Status RevoleRL(AvlNodeSelectPathType* SelectPath, AvlTreeNodeDataType StartIndex, AvlTreeNodeDataType EndIndex, AvlTreeNode** NewNodePtr)
{
    *NewNodePtr = SelectPath->NodePtrArray[EndIndex];
    SelectPath->NodePtrArray[StartIndex]->RightNodePtr    = (*NewNodePtr)->LeftNodePtr;
    SelectPath->NodePtrArray[StartIndex + 1]->LeftNodePtr = (*NewNodePtr)->RightNodePtr;
    (*NewNodePtr)->LeftNodePtr                            = SelectPath->NodePtrArray[StartIndex];
    (*NewNodePtr)->RightNodePtr                           = SelectPath->NodePtrArray[StartIndex + 1];
    
    Log("Revole RL OK\n",Debug);
    return SuccessFlag;
}

9、LR型转换

Status RevoleLR(AvlNodeSelectPathType* SelectPath, AvlTreeNodeDataType StartIndex, AvlTreeNodeDataType EndIndex, AvlTreeNode** NewNodePtr)
{
    *NewNodePtr = SelectPath->NodePtrArray[EndIndex];
    SelectPath->NodePtrArray[StartIndex]->LeftNodePtr      = (*NewNodePtr)->RightNodePtr;
    SelectPath->NodePtrArray[StartIndex + 1]->RightNodePtr = (*NewNodePtr)->LeftNodePtr;
    (*NewNodePtr)->LeftNodePtr                             = SelectPath->NodePtrArray[StartIndex + 1]; 
    (*NewNodePtr)->RightNodePtr                            = SelectPath->NodePtrArray[StartIndex];

    Log("Revole LR OK\n",Debug);
    return SuccessFlag;
}

10、RL型转换

Status RevoleRL(AvlNodeSelectPathType* SelectPath, AvlTreeNodeDataType StartIndex, AvlTreeNodeDataType EndIndex, AvlTreeNode** NewNodePtr)
{
    *NewNodePtr = SelectPath->NodePtrArray[EndIndex];
    SelectPath->NodePtrArray[StartIndex]->RightNodePtr    = (*NewNodePtr)->LeftNodePtr;
    SelectPath->NodePtrArray[StartIndex + 1]->LeftNodePtr = (*NewNodePtr)->RightNodePtr;
    (*NewNodePtr)->LeftNodePtr                            = SelectPath->NodePtrArray[StartIndex];
    (*NewNodePtr)->RightNodePtr                           = SelectPath->NodePtrArray[StartIndex + 1];
    
    Log("Revole RL OK\n",Debug);
    return SuccessFlag;
}

11、LL型转换

Status RevoleLL(AvlNodeSelectPathType* SelectPath, AvlTreeNodeDataType StartIndex, AvlTreeNodeDataType EndIndex, AvlTreeNode** NewNodePtr)
{
    *NewNodePtr = SelectPath->NodePtrArray[StartIndex + 1];
    SelectPath->NodePtrArray[StartIndex]->LeftNodePtr    = (*NewNodePtr)->RightNodePtr;
    (*NewNodePtr)->RightNodePtr                          = SelectPath->NodePtrArray[StartIndex];

    Log("Revole LL OK\n",Debug);
    return SuccessFlag;
}

12、RR型转换

Status RevoleRR(AvlNodeSelectPathType* SelectPath, AvlTreeNodeDataType StartIndex, AvlTreeNodeDataType EndIndex, AvlTreeNode** NewNodePtr)
{
    *NewNodePtr = SelectPath->NodePtrArray[StartIndex + 1];
    SelectPath->NodePtrArray[StartIndex]->RightNodePtr    = (*NewNodePtr)->LeftNodePtr;
    (*NewNodePtr)->LeftNodePtr                            = SelectPath->NodePtrArray[StartIndex]; 

    Log("Revole RR OK\n",Debug);
    return SuccessFlag;
}

13、AVL树转换

Status RevoleAvlTree(AvlNodeSelectPathType* SelectPath, AvlTreeNodeDataType StartIndex, AvlTreeNodeDataType EndIndex, AvlTreeNode** NewNodePtr)
{
    JudgeAllNullPointer(SelectPath);
    JudgeAllNullPointer(NewNodePtr);

    if(SelectPath->DirectionArray[StartIndex] == AVL_LEFT_DIRECTION)
    {
        if(SelectPath->DirectionArray[StartIndex + 1] == AVL_LEFT_DIRECTION)//LL
        {
            RevoleLL(SelectPath, StartIndex, EndIndex, NewNodePtr);
        }
        else//LR
        {
            RevoleLR(SelectPath, StartIndex, EndIndex, NewNodePtr);
        }
    }
    else
    {
        if(SelectPath->DirectionArray[StartIndex + 1] == AVL_LEFT_DIRECTION)//RL
        {
            RevoleRL(SelectPath, StartIndex, EndIndex, NewNodePtr);
        }
        else//RR
        {
            RevoleRR(SelectPath, StartIndex, EndIndex, NewNodePtr);
        }
    }
    return SuccessFlag;
}

就是把RR,RL,LL,LR进行封装了一层。

14、求AVL树的深度

AvlTreeNodeDataType GetAvlTreeDepth(AvlTreeNode* NodePtr)
{
    if(NodePtr == NULL)
    {
        return 0;
    }
    else
    {
        AvlTreeNodeDataType l = GetAvlTreeDepth(NodePtr->LeftNodePtr);
        AvlTreeNodeDataType r = GetAvlTreeDepth(NodePtr->RightNodePtr);
        if(l >= r)
        {
            return l + 1;
        }
        else
        {
            return r + 1;
        }
    }
}

详细的实现和思路可以参考之前写的文章《数据结构与算法基础-学习-16-二叉树之层次遍历、创建树、复制树、销毁树,获取树的深度、结点数、叶子结点数

15、计算结点平衡因子

Status ComputeAvlNodeBalanceFactor(AvlTreeNode* NodePtr)
{
    JudgeAllNullPointer(NodePtr);
    NodePtr->BalanceFactor = GetAvlTreeDepth(NodePtr->LeftNodePtr) - GetAvlTreeDepth(NodePtr->RightNodePtr);
    Log("Compute Avl Node Balance Factor OK\n",Debug);
    return SuccessFlag;
}

给出需要重新计算平衡因子的Avl树的节点,即可把此节点的平衡因子重新计算一次。
 

16、插入数据到AVL树

//假设Avl树中没有相同元素,根节点大于左子树,小于右子树。
Status AddAvlTreeNode(AvlTree* AT, AvlTreeNodeDataType InputData)
{
    JudgeAllNullPointer(AT);
    if(AT->RootNodePtr == NULL)
    {
        AT->RootNodePtr = NewAvlTreeNode(InputData);
        AT->TreeNodeNum++;
        Log("Add Avl Tree Root Node OK\n",Debug);
        return SuccessFlag;
    }

    AvlTreeNode* TmpPtr               = AT->RootNodePtr;
    AvlNodeSelectPathType* SelectPath = NULL;
    InitAvlNodeSelectPath(AT, &SelectPath);

    while(TmpPtr)
    {
        if(CmpAvlTreeNodeData(TmpPtr->Data, InputData) == CMP_LARGE)
        {
            InsertAvlNodeSelectPath(SelectPath, TmpPtr, AVL_LEFT_DIRECTION);
            if(TmpPtr->LeftNodePtr == NULL)
            {
                TmpPtr->LeftNodePtr = NewAvlTreeNode(InputData);
                AT->TreeNodeNum++;
                InsertAvlNodeSelectPath(SelectPath, TmpPtr->LeftNodePtr, AVL_LEFT_DIRECTION);
                break;
            }
            TmpPtr = TmpPtr->LeftNodePtr;
        }
        else if(CmpAvlTreeNodeData(TmpPtr->Data, InputData) == CMP_LITTLE)
        {
            InsertAvlNodeSelectPath(SelectPath, TmpPtr, AVL_RIGHT_DIRECTION);
            if(TmpPtr->RightNodePtr == NULL)
            {
                TmpPtr->RightNodePtr = NewAvlTreeNode(InputData);
                AT->TreeNodeNum++;
                InsertAvlNodeSelectPath(SelectPath, TmpPtr->RightNodePtr, AVL_RIGHT_DIRECTION);
                break;
            }
            TmpPtr = TmpPtr->RightNodePtr;
        }
        else
        {
            Log("AddAvlTreeNode function not supported : same element.\n",Debug);
            Log("Add Avl Tree Node Fail\n",Debug);
            return FailFlag;
        }
    }
    PrintfAvlNodeSelectPath(SelectPath);

    //Avl树搜索路径收集完成。
    //倒叙遍历搜索路径,也就是从叶子节点遍历到根节点。
    //如果叶子节点的父节点的平衡因子从1或-1变为0,搜索路径上的其他节点平衡因子不变。
    if(SelectPath->DirectionArray[SelectPath->ArrayLen - 2] == AVL_LEFT_DIRECTION)
    {
        (SelectPath->NodePtrArray[SelectPath->ArrayLen - 2]->BalanceFactor)++;
    }
    else
    {
        (SelectPath->NodePtrArray[SelectPath->ArrayLen - 2]->BalanceFactor)--;
    }

    if(SelectPath->NodePtrArray[SelectPath->ArrayLen - 2]->BalanceFactor == 0)//平衡二叉树的平衡因子不会发生变化的情况
    {
        DestoryAvlNodeSelectPath(&SelectPath);
        Log("Add Avl Tree Node OK, Balance Factor No Change.\n",Debug);
        return SuccessFlag;
    }

    //平衡二叉树的平衡因子会发生变化的情况,需要按照情况讨论。
    //从倒数第二个节点开始计算平衡因子。
    AvlTreeNodeDataType i;
    for(i = SelectPath->ArrayLen - 3; i >= 0; i--)
    {
        if(SelectPath->DirectionArray[i] == AVL_LEFT_DIRECTION)
        {
            (SelectPath->NodePtrArray[i]->BalanceFactor)++;
        }
        else
        {
            (SelectPath->NodePtrArray[i]->BalanceFactor)--;
        }

        if(JudgeBalanceFactorStatus(SelectPath->NodePtrArray[i]->BalanceFactor) == AVL_NO_BALANCE_FLAG)
        {
            Log("Find Avl Tree Node No Balance.\n",Debug);
            break;
        }
    }

    if(i != -1)//表示搜索路径没有遍历完,某节点出现了不平衡因子
    {
        //进行LL,LR,RR,RL
        AvlTreeNode* NewNodePtr = NULL;
        RevoleAvlTree(SelectPath, i, i + 2, &NewNodePtr);

        if(i != 0)//除根节点以外的节点出现节点有不平衡因子,在LL,LR,RR,RL之后,需要把转换之后的子树连回Avl树。
        {
            if(SelectPath->DirectionArray[i - 1] == AVL_LEFT_DIRECTION)
            {
                SelectPath->NodePtrArray[i - 1]->LeftNodePtr = NewNodePtr;
            }
            else
            {
                SelectPath->NodePtrArray[i - 1]->RightNodePtr = NewNodePtr;
            }
        }
        else//根节点出现不平衡因子,在LL,LR,RR,RL之后,需要把转换之后的Avl树根节点放回RootNodePtr。
        {
            AT->RootNodePtr = NewNodePtr;
        }
        //重算平衡因子,只算最小平衡树根节点开始的三个节点的平衡因子即可。 
        AvlTreeNodeDataType j;
        for(j = i; j <= i + 2; j++)
        {
            ComputeAvlNodeBalanceFactor(SelectPath->NodePtrArray[j]);
        }
    }
    
    DestoryAvlNodeSelectPath(&SelectPath);
    Log("Add Avl Tree Node OK.\n",Debug);
    return SuccessFlag; 
}

(1)、插入的数据比根节点小,插入到左子树中,不然插入到右子树中,且把走过的结点指针压入搜索路径SelectPath中,此实现暂时只支持不相同值的插入。

(2)、插入完后,通过SelectPath检查插入结点的双亲结点,看其平衡因子是不是变化为0,如果是,说明双亲结点是平衡结点且左右孩子指针都有数据结点。不用需要进行平衡转换,结束。

(3)、如果不是0,倒序遍历SelectPath,计算平衡因子,如果出现没有不平衡结点,结束。

(4)、如果出现不平衡结点,进行平衡转换RevoleAvlTree,转换之后判断是不是根结点,不是重新链回原AVL树,如果是更新RootNodePtr结点。

(5)、重新计算不平衡结点开始的三个结点的平衡因子,就可以了,因为三个节点之后的结点在步骤3已经计算出来了,转换不会影响平衡因子的变化。

(6)、三个结点之前的结点不用重新计算,因为平衡了,所以不影响(这一步我测试了几组数据,都正确)。

17、销毁AVL树结点

Status DestoryAvlTreeNode(AvlTreeNode** RootPTR)
{
    if(*RootPTR == NULL)
    {
        return SuccessFlag;
    }
    else
    {
        DestoryAvlTreeNode(&((*RootPTR)->LeftNodePtr));
        DestoryAvlTreeNode(&((*RootPTR)->RightNodePtr));
        free(*RootPTR);
        *RootPTR = NULL;
        Log("Destroy Avl Tree Node OK\n",Debug);
    }
    return SuccessFlag;
}

 18、销毁AVL树

Status DestoryAvlTree(AvlTree** AvlTree)
{
    DestoryAvlTreeNode(&((*AvlTree)->RootNodePtr));
    (*AvlTree)->RootNodePtr = NULL;
    (*AvlTree)->TreeNodeNum = 0;
    free(*AvlTree);
    *AvlTree                = NULL;
    Log("Destroy Avl Tree OK\n",Debug);
    return SuccessFlag;
}

八、Linux环境测试LL型

747ad538c34b4534bc6faa98b7f306e3.png

[root@czg2 Select]# make
gcc -Wall -O3 ../Log/Log.c ../PublicFunction/PublicFunction.c Select.c HashTable.c AvlTree.c main.c -o TestSelect -I ../Log/ -I ../PublicFunction/ -I ./ -I ../PublicFunction/SqStack/

[root@czg2 Select]# ./TestSelect 
[2023-4]--[ Debug ]--Init Avl Tree OK
[2023-4]--[ Debug ]--Add Avl Tree Root Node OK
[2023-4]--[ Debug ]--Init Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Printf Avl Node Select Path
[(0x1738fe0,l),(0x1739320,l)]
ArrayLen : 2, ArrayMaxLen : 3
[2023-4]--[ Debug ]--Destory Avl Node Select Path OK
[2023-4]--[ Debug ]--Add Avl Tree Node OK.
[2023-4]--[ Debug ]--Init Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Printf Avl Node Select Path
[(0x1738fe0,r),(0x1739350,r)]
ArrayLen : 2, ArrayMaxLen : 3
[2023-4]--[ Debug ]--Destory Avl Node Select Path OK
[2023-4]--[ Debug ]--Add Avl Tree Node OK, Balance Factor No Change.
[2023-4]--[ Debug ]--Init Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Printf Avl Node Select Path
[(0x1738fe0,l),(0x1739320,l),(0x17393b0,l)]
ArrayLen : 3, ArrayMaxLen : 4
[2023-4]--[ Debug ]--Destory Avl Node Select Path OK
[2023-4]--[ Debug ]--Add Avl Tree Node OK.
[2023-4]--[ Debug ]--Init Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Printf Avl Node Select Path
[(0x1738fe0,r),(0x1739350,r),(0x17393e0,r)]
ArrayLen : 3, ArrayMaxLen : 4
[2023-4]--[ Debug ]--Destory Avl Node Select Path OK
[2023-4]--[ Debug ]--Add Avl Tree Node OK.
[2023-4]--[ Debug ]--Init Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Insert Avl Node Select Path OK
[2023-4]--[ Debug ]--Printf Avl Node Select Path
[(0x1738fe0,l),(0x1739320,l),(0x17393b0,l),(0x1739410,l)]
ArrayLen : 4, ArrayMaxLen : 5
[2023-4]--[ Debug ]--Find Avl Tree Node No Balance.
[2023-4]--[ Debug ]--Revole LL OK
[2023-4]--[ Debug ]--Compute Avl Node Balance Factor OK
[2023-4]--[ Debug ]--Compute Avl Node Balance Factor OK
[2023-4]--[ Debug ]--Compute Avl Node Balance Factor OK
[2023-4]--[ Debug ]--Destory Avl Node Select Path OK
[2023-4]--[ Debug ]--Add Avl Tree Node OK.
Ptr : 0x1739410, Data : 18    , BalanceFactor : 0 , LeftNodePtr : (nil)     , RightNodePtr : (nil)
Ptr : 0x17393b0, Data : 20    , BalanceFactor : 0 , LeftNodePtr : 0x1739410 , RightNodePtr : 0x1739320
Ptr : 0x1739320, Data : 24    , BalanceFactor : 0 , LeftNodePtr : (nil)     , RightNodePtr : (nil)
Ptr : 0x1738fe0, Data : 40    , BalanceFactor : 0 , LeftNodePtr : 0x17393b0 , RightNodePtr : 0x1739350
Ptr : 0x1739350, Data : 53    , BalanceFactor : -1, LeftNodePtr : (nil)     , RightNodePtr : 0x17393e0
Ptr : 0x17393e0, Data : 70    , BalanceFactor : 0 , LeftNodePtr : (nil)     , RightNodePtr : (nil)
[2023-4]--[ Debug ]--Destroy Avl Tree Node OK
[2023-4]--[ Debug ]--Destroy Avl Tree Node OK
[2023-4]--[ Debug ]--Destroy Avl Tree Node OK
[2023-4]--[ Debug ]--Destroy Avl Tree Node OK
[2023-4]--[ Debug ]--Destroy Avl Tree Node OK
[2023-4]--[ Debug ]--Destroy Avl Tree Node OK
[2023-4]--[ Debug ]--Destroy Avl Tree OK

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值