AVL树的定义
AVL实现
通用头文件 fatal.h
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
声明头文件 avltree.h
typedef int ElementType;
#ifndef _AvlTree_H
#define _AvlTree_H
struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;
AvlTree MakeEmpty(AvlTree T);
Position Find(ElementType X, AvlTree T);
Position FindMin(AvlTree T);
Position FindMax(AvlTree T);
AvlTree Insert(ElementType X, AvlTree T);
AvlTree Delete(ElementType X, AvlTree T);
ElementType Retrieve(Position P);
#endif
实现文件 avltree.c
#include "avltree.h"
#include <stdlib.h>
#include "fatal.h"
struct AvlNode
{
ElementType Element; // 数据项
AvlTree Left; // 左子树
AvlTree Right; // 右子树
int Height; // 树的高度(树根节点的深度 == 树所有节点中的最大深度)
};
AvlTree
MakeEmpty(AvlTree T)
{
if (T != NULL)
{
MakeEmpty(T->Left);
MakeEmpty(T->Right);
free(T);
}
return NULL;
}
Position
Find(ElementType X, AvlTree T)
{
if (T == NULL)
return NULL;
if (X < T->Element)
return Find(X, T->Left);
else if (X > T->Element)
return Find(X, T->Right);
else
return T;
}
Position
FindMin(AvlTree T)
{
if (T == NULL)
return NULL;
else if (T->Left == NULL)
return T;
else
return FindMin(T->Left);
}
Position
FindMax(AvlTree T)
{
if (T != NULL)
while (T->Right != NULL)
T = T->Right;
return T;
}
static int
Height(Position P)
{
if (P == NULL)
// 的空节点 高度定义为 -1 例如空树的高度 叶子节点子节点NULL的高度
return -1;
else
return P->Height;
}
static int
Max(int Lhs, int Rhs)
{
return Lhs > Rhs ? Lhs : Rhs;
}
// 插入节点导致之前是平衡的AVL树失去平衡性 我们把失去平衡的那个节点称为要旋转的目标节点 也就是调用以下4个旋转函数的入参节点
// 4种场景第一种 在K2节点的左节点K1的左子树中插入新节点导致原本平衡的K2失去了平衡 需要对K2做一次从左往右的单旋:
// 把K1变为根节点 K1的右子树变K2的左子树 K2变K1的右节点 同时更新可能发生改变的 K2 K1节点的高度属性 自此 该局部子树的高度与之前完全一致 树整体恢复平衡
static Position
SingleRotateWithLeft(Position K2)
{
Position K1;
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), K2->Height) + 1;
return K1;
}
// 4种场景第二种 在K1节点的右节点K2的右子树中插入新节点导致原本平衡的K1失去了平衡 需要对K1做一次从右往左的单旋:
// 把K2变为根节点 K2的左子树变K1的右子树 K1变K2的左节点 同时更新可能发生改变的 K2 K1节点的高度属性 自此 该局部子树的高度与之前完全一致 树整体恢复平衡
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(K1->Height, Height(K2->Right)) + 1;
return K2;
}
// 4种场景第三种 在K3节点的左节点K1的右子节点K2的子树中插入新节点导致原本平衡的K3失去了平衡 需要先对K2做一次从右往左的单旋,再对K3做一次从左往右的单旋:
// K2作为新的局部子树根节点 自此 该局部子树的高度与之前完全一致 树整体恢复平衡
static Position
DoubleRotateWithLeft(Position K3)
{
K3->Left = SingleRotateWithRight(K3->Left);
return SingleRotateWithLeft(K3);
}
// 4种场景第四种 在K1节点的右节点K3的左子节点K2的子树中插入新节点导致原本平衡的K1失去了平衡 需要先对K3做一次从左往右的单旋,再对K1做一次从右往左的单旋:
// K2作为新的局部子树根节点 自此 该局部子树的高度与之前完全一致 树整体恢复平衡
static Position
DoubleRotateWithRight(Position K1)
{
K1->Right = SingleRotateWithLeft(K1->Right);
return SingleRotateWithRight(K1);
}
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);
else
T = DoubleRotateWithLeft(T);
}
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);
else
T = DoubleRotateWithRight(T);
}
T->Height = Max(Height(T->Left), Height(T->Right)) + 1;
return T;
}
AvlTree Delete(ElementType X, AvlTree T)
{
Position temp;
if (T == NULL)
{
printf("Error! No such node! \n");
return NULL;
}
if (X < T->Element)
{
T->Left = Delete(X, T->Left);
// 删除子节点完成之后更新父节点的高度
T->Height = Height(T->Left) > Height(T->Right) ? Height(T->Left) + 1 : Height(T->Right) + 1;
// 检测是否失去平衡
if (Height(T->Right) - Height(T->Left) == 2)
{
if (Height(T->Right->Left) > Height(T->Right->Right))
T = DoubleRotateWithRight(T);
else
T = SingleRotateWithRight(T);
}
}
else if (X > T->Element)
{
T->Right = Delete(X, T->Right);
// 删除子节点完成之后更新父节点的高度
T->Height = Height(T->Left) > Height(T->Right) ? Height(T->Left) + 1 : Height(T->Right) + 1;
// 检测是否失去平衡
if (Height(T->Left) - Height(T->Right) == 2)
{
if (Height(T->Left->Left) < Height(T->Left->Right))
T = DoubleRotateWithLeft(T);
else
T = SingleRotateWithLeft(T);
}
}
else
{
if (T->Left && T->Right)
{
temp = FindMin(T->Right);
T->Element = temp->Element;
T->Right = Delete(T->Element, T->Right);
}
else
{
temp = T;
if (T->Left == NULL)
T = T->Right;
else if (T->Right == NULL)
T = T->Left;
free(temp);
}
}
return T;
}
ElementType
Retrieve(Position P)
{
return P->Element;
}
测试代码 testavl.c
#include "avltree.h"
#include <stdio.h>
main()
{
AvlTree T;
Position P;
int i;
int j = 0;
T = MakeEmpty(NULL);
for (i = 0; i < 50; i++, j = (j + 7) % 50)
T = Insert(j, T);
for (i = 0; i < 50; i++)
if ((P = Find(i, T)) == NULL || Retrieve(P) != i)
printf("Error at %d\n", i);
for( i = 0; i < 50; i += 2 )
T = Delete( i, T );
for( i = 1; i < 50; i += 2 )
if( ( P = Find( i, T ) ) == NULL || Retrieve( P ) != i )
printf( "Error at %d\n", i );
for( i = 0; i < 50; i += 2 )
if( ( P = Find( i, T ) ) != NULL )
printf( "Error at %d\n", i );
printf("Min is %d, Max is %d\n", Retrieve(FindMin(T)),
Retrieve(FindMax(T)));
return 0;
}
测试输出
Min is 1, Max is 49
参考资料: 《数据结构与算法分析: C语言描述》