平衡二叉树(AVL树)

平衡二叉树是在二叉搜索树的基础上增加了限制:

①:树的深度为logN。

②:每个节点的左子树和右子树的高度最多差一的二叉搜索树。


基本操作:调整!!!

引入平衡因子:左右子树的高度差。

当平衡因子绝对值大于等于2的时候,就需要调整。

单旋转比较简单,直接把被破坏节点下一个节点提上去,然后再根据二叉搜索树的特点进行换儿子即可。如下图:


实现:

#include<stdio.h>
#include<stdlib.h>

#define ElementType int

typedef struct BiNode
{
    ElementType Data;
    int Height;
    struct BiNode* Left;
    struct BiNode* Right;
} BiNode, *BinTree,*Position;

int Height(Position P)
{
    if(!p)return 0;
    else return P->Height;
}//为什么非要用这个函数?直接用结构体中的不行吗?---NULL!!!

Position Single_Rotate_With_Left(Position K2)//把k2的左儿子k1提上去,k2当k1的右儿子。
{
	Position K1 = K2->Left;
	K2->Left = K1->Right;//换儿子
	K1->Right = K2;//提上去
	K2->Height = max(Height(K2->Left), Height(K2->Right)) + 1;
	K1->Height = max(Height(K1->Left), Height(K1->Right)) + 1;
	return K1;
}
Position Single_Rotate_With_Right(Position K2)
{
	Position K1 = K2->Right;
	K2->Right = K1->Left;
	K1->Left = K2;
	K2->Height = max(Height(K2->Left), Height(K2->Right)) + 1;
	K1->Height = max(Height(K1->Left), Height(K1->Right)) + 1;
	return K1;
}


双旋转是“麻烦节点”在左儿子的右边,或者右儿子的左边。如下图:这时候是把麻烦节点提上去,然后再进行儿子的交换即可。

实现:可以通过两次单旋转进行完成,避免了换儿子的过程。

Position Double_Rotate_With_Left(Position K3)
{
	K3->Left = Single_Rotate_With_Right(K3->Left);
	return Single_Rotate_With_Left(K3);
}


Position Double_Rotate_With_Right(Position K3)
{
	K3->Right = Single_Rotate_With_Left(K3->Right);
	return Single_Rotate_With_Right(K3);
}

Position Double_Rotate_With_Left(Position K3)
{
    Position K2=K3->Left->Right,K1=K3->Left;
       K3->Left=K2->Right;//换儿子
       K2->Right=K3;//提
       K1->Right=K2->Left;//换儿子
       K2->Left=K1;//提
}



AVL树的插入,在二叉搜索树插入的基础上,增添调整就可以!

注意这里有递归回溯。(拓展GCD有没有)。

至于删除,我的思路是假设是删除左边了,这时候要看根节点右边的树高是否比左边树高大于等于2,然后进而根据右子树对应的左树高和右树高,右大于左,那就要对根节点进行RR旋转,否则RL旋转。(网上都是引入的平衡因子,也就是高度差,我这种想法的正确与否,考完期末再写个例子进行检验~!插入的历程是正确的(直接在黑书上拿来的。))。

BinTree Insert( ElementType X, BinTree BST )
if( !BST )
{
    BST = (Bintree)malloc(sizeof(struct TreeNode));
    BST->Data = X;
    BST->Left = BST->Right = NULL;
    BST->Height=1;
}
else if( X < BST->Data )
{
    BST->Left = Insert( X, BST->Left);
    if(Height(BST->Left)-Height(BST->Right)==2)//自底向上回溯
        if(X<BST->Left->Data)
            BST=Single_Rotate_With_Left(BST);
        else BST=Position Double_Rotate_With_Left(BST);

}
else if( X > BST->Data )
{
    BST->Right = Insert( X, BST->Right);
    if(Height(BST->Right)-Height(BST->Left)==2)
        if(X>BST->Right->Data)   BST=Single_Rotate_With_Right(BST);
        else BST=Double_Rotate_With_Right(BST);
}

/* else X已经存在,什么都不做 */
BST->Height=max(Height(BST->left),Height(BST->Right))+1;//更新树高
return BST;
}








BinTree Delete( ElementType X, BinTree BST )
{
    Position Tmp;
    if( !BST ) printf("要删除的元素未找到");
    else if( X < BST->Data )
    {
        BST->Left = Delete( X, BST->Left); /* 左子树递归删除 */
        if(Height(BST->Right)-Height(BST->Left)==2)
            if(Height(BST->Right->Right)>=Height(BST->Right->Left))
                Single_Rotate_With_Right(BST);
            else Double_Rotate_With_Right(BST);
    }
    else if( X > BST->Data )
    {
        BST->Right = Delete( X, BST->Right);
        if(Height(BST->Left)-Height(BST->Right)==2)
            if(Height(BST->Left->Left)>=Height(BST->Left->Right))
                Single_Rotate_With_Left(BST);
            else Double_Rotate_With_Left(BST);
    }/* 右子树递归删除 */
    else /*找到要删除的结点 */
        if( BST->Left && BST->Right )
        {
            /*被删除结点有左右两个子结点 */
            Tmp = FindMin( BST->Right ); /*在右子树中找最小的元素填充删除结点*/
            BST->Data = Tmp->Data;
            BST->Right = Delete( BST->Data, BST->Right); /*在删除结点的右子树中删除最小元素*/
            if(Height(BST->Right)-Height(BST->Left)==2)
                if(Height(BST->Right->Right)>=Height(BST->Right->Left))
                    Single_Rotate_With_Right(BST);
                else Double_Rotate_With_Right(BST);
        }
        else
        {
            /*被删除结点有一个或无子结点*/
            Tmp = BST;
            if( !BST->Left ) /* 有右孩子或无子结点*/
                BST = BST->Right;
            else if( !BST->Right ) /*有左孩子或无子结点*/
                BST = BST->Left;
            free( Tmp );
        }
    BST->Height=max(Height(BST->left),Height(BST->Right))+1;//更新树高
    return BST;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值