平衡二叉树是在二叉搜索树的基础上增加了限制:
①:树的深度为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;
}