原文链接:https://www.cnblogs.com/ZhaoxiCheung/p/6012783.html
平衡二叉树,又称AVL(Adelson-Velskii和Landis)树,是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持,而且它必须保证树的深度是 O(log N)。
一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树( 空树的高度定义为 -1 )。查找、插入和删除在平均和最坏情况下都是 O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
1、LL型(单次右旋转)
k2的左子树比右子树高2,所以不平衡,我们需要把k1提到k2的位置,然后k2下降到k1的右子树,最后还有把k1的右子树放到k2的左子树即可。
//LL型旋转(单次右旋)
static Position SingleRotateWithLeft( Position K2 )
{
Position K1;
K1 = K2->Left; //找到 K2 左子树
K2->Left = K1->Right; //将 K1 右子树移到 K2 的左子树
K1->Right = K2; //建立 K1 和 K2 的关系
K2->Height = Max( Height( K2->Left ), Height( K2->Right ) ) + 1;
K1->Height = Max( Height( K1->Left ), K2->Height ) + 1;
return K1; /* New root */
}
2、RR型(单次右旋转)
与LL型对称,原理类似
static Position SingleRotateWithRight( Position K1 )
{
Position K2;
K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1;
K1->Height = Max( Height( K1->Left ), Height( K1->Right ) ) + 1;
K2->Height = Max( Height( K2->Right ), K1->Height ) + 1;
return K2; /* New root */
}
3、LR型双旋转(单次左旋后右旋)
先以K3的左子树为根节点执行一次左左旋转,然后以k3的根节点,执行一次右右旋转即可。
static Position DoubleRotateWithLeft( Position K3 )
{
/* Rotate between K1 and K2 */
K3->Left = SingleRotateWithRight( K3->Left );
/* Rotate between K3 and K2 */
return SingleRotateWithLeft( K3 );
}
4、RL型双旋转(单次右旋后单次左旋)
与LR型双旋转对称,原理类似
static Position DoubleRotateWithRight( Position K1 )
{
/* Rotate between K3 and K2 */
K1->Right = SingleRotateWithLeft( K1->Right );
/* Rotate between K1 and K2 */
return SingleRotateWithRight( K1 );
}
5、结点插入
AVL树进行插入操作时,会破坏二叉树的平衡性,所以每当插入一个数据时,都要从插入点往上,一步一步检测出是否出现平衡因子大于1的,如果有,则要做相应的旋转。
AvlTree Insert( ElementType X, AvlTree T )
{
if( T == NULL )
{
/* Create and return a one-node tree */
T = malloc( sizeof( struct AvlNode ) );
if( T == NULL )
FatalError( "Out of space!!!" );
else
{
T->Element = X;
T->Height = 0;
T->Left = T->Right = NULL;
}
}
else if( X < T->Element ) //插入值比当前结点值小,往左子树插入
{
T->Left = Insert( X, T->Left ); //递归插入
if( Height( T->Left ) - Height( T->Right ) == 2 ) //判断子树是否平衡
if( X < T->Left->Element ) //比当前结点左子树的值小,即为左左情形。
T = SingleRotateWithLeft( T ); //LL旋转(右单旋转)
else //否则为左右情形
T = DoubleRotateWithLeft( T ); //LR旋转
}
else if( X > T->Element ) //插入值比当前结点值大,往右子树插入
{
T->Right = Insert( X, T->Right ); //递归插入
if( Height( T->Right ) - Height( T->Left ) == 2 ) //判断子树是否平衡
if( X > T->Right->Element ) //比当前结点右子树大,即为右右情形
T = SingleRotateWithRight( T ); //RR旋转(左单旋转)
else //否则为右左情形
T = DoubleRotateWithRight( T ); //RL旋转
}
/* Else X is in the tree already; we'll do nothing */
T->Height = Max( Height( T->Left ), Height( T->Right ) ) + 1;
return T;
}
6、结点删除
结点删除包括四种情况:
- 左右子树都非空
- 左子树为空,右子树非空
- 右子树为空,左子树非空
- 左右子树都为空
AvlTree Delete(ElementType X,AvlTree T)
{
if (T == NULL) //空树直接返回
return NULL;
if (x < T->Element) //删除值小于当前节点,说明删除节点在当前节点左侧
{
T->Left = Delete(X,T->Left);
if (Height(T->Right) - Height(T->Left) == 2)
{
if (Height(T->Right->Left) > Height(T->Right->Right))
T = DoubleRotateRL(T);
else
T = SingleRotateRight(T);
}
}
else if (X > T->Element) //删除节点在当前节点右侧
{
T->Right = Delete(X,T->Right);
if (Height(T->Left) - Height(T->Right) == 2)
{
if (Height(T->Left->Right) > Height(T->Left->Left))
T = DoubleRotateLR(T);
else
T = SingleRotateLeft(T);
}
}
else //找到删除节点
{
if (T->Right) //右子树不为空的情况
{
AvlTree tmp = T->Right;
while (tmp->Left != NULL) tmp = tmp->Left; //找到要删除的结点的右子树的左子树最小值,以便替要删除的结点
T->Element = tmp->Element;
T->height = tmp->height;
T->Right = Delete(tmp->Element,T->Right); //递归删除
}
else
{
//右子树为空的情况,free节点,返回被删除节点的左节点
//这也是真正删除节点的地方
AvlTree tmp=T;
T = T->Left;
free(emp);
return T;
}
}
//每次删除之后,都要更新节点的高度
T->height = Max(Height(T->Left),Height(T->Right)) + 1;
return T;
}