C实现AVL树

130 阅读5分钟

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语言描述》