您的位置:首页 > 理论基础 > 数据结构算法

数据结构:自平衡二叉查找树(AVL树)

2017-10-22 13:43 423 查看
(1)二叉查找树的定义

在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。

二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。每一棵子树的根叫做根r的儿子,而r是每一棵子树的根的父亲。

具有N个节点的每一棵二叉树都将需要N+1个NULL指针。对于树中的每个结点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。

二叉查找树的平均深度为O(log N)。
(2)AVL树与非自平衡二叉查找树

相比较于非自平衡二叉查找树,AVL树是带有平衡条件的二叉查找树。这个平衡条件必须需要保持。对于一棵AVL树,每个结点的左子树和右子树的高度最多差1。在这里,我们将空树的高度定义为-1。所以一个问题在于,插入一个结点可能破坏AVL树的特性,所以我们可以通过对树的修正来完成,我们称其为旋转。

(3)AVL树的旋转

由于任意结点最多有两个儿子,因此高度不平衡时,a点的两个子树的高度差为2。容易看出,这种不平衡容易可能出现在下面4种情形。

1、对a的左儿子的左子树进行一次插入。

2、对a的左儿子的右子树进行一次插入。

3、对a的右儿子的左子树进行一次插入。

4、对a的右儿子的右子树进行一次插入。

第一种情况是插入发生在外边的情况(即左-左的情况或者右-右的情况),该情况可通过对树的一次单旋转而完成调整。第二种则是发生在内部的情形。(即左-右情况或右-左情况),该情况可通过一次双旋转完成。

(4)AVL树的操作例程。

1、声明

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

#ifndef _AVLTREE_H
#define _AVLTREE_H
#define DATA_TYPE int

struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *Tree;

Tree Delete_tree(Tree T);							//删除树
Tree New_tree(DATA_TYPE X);							//新建一棵树
Position Find(Tree T, DATA_TYPE X);					//查找
Position Find_Min(Tree T);							//查找树的最小值
Position Find_Max(Tree T);							//查找树的最大值
Position Insert(Tree T, DATA_TYPE X);				//插入结点
Position Delete(Tree T, DATA_TYPE X);				//
Position Print_tree(Tree T);						//先序遍历二叉树
static int Height(Position P);						//计算当前结点的高度
static Position Single_Rotate_left(Position K2);	//左左单旋转
static Position Single_Rotate_right(Position K2);	//右右单旋转
static Position Double_Rotate_left(Position K3);	//左右双旋转
static Position Double_Rotate_right(Position K3);	//右左双旋转
static int Max(int a, int b);
static Position Fix(Position K2);
struct AvlNode
{
DATA_TYPE num;
Tree left;
Tree right;
int height;
};

#endif


2、结点的高度与判定最大值函数

Tree Delete_tree(Tree T)
{
if (T != NULL)
{
Delete_tree(T->left);
Delete_tree(T->right);
free(T);
}
return NULL;
}

static int Height(Position P)
{
if (P == NULL)	//如果树为空则高度为-1
return -1;
else
return P->height;
}


3、新建查找树与删除查找树

Tree New_tree(DATA_TYPE X)
{
Position first;
first = malloc(sizeof(struct AvlNode));
if (first == NULL)
return NULL;
first->num = X;
first->right = NULL;
first->left = NULL;
return first;
}

Tree Delete_tree(Tree T)
{
if (T != NULL)
{
Delete_tree(T->left);
Delete_tree(T->right);
free(T);
}
return NULL;
}


4、查找目标节点、查找最小结点和查找最大结点

Position Find(Tree T, DATA_TYPE X)
{
while (T != NULL)
{
if (X < T->num)
T = T->left;
else if (X > T->num)
T = T->left;
else return T;
}
return NULL;
}

Position Find_Min(Tree T)
{
if (T != NULL)
{
for (; T->left != NULL; T = T->left);
return T;
}
return T;
}

Position Find_Max(Tree T)
{
if (T != NULL)
{
for (; T->left != NULL; T = T->right);
return T;
}
return NULL;
}


5、插入结点

Position Insert(Tree T, DATA_TYPE X)
{
if (T == NULL)	//成功找出插入位置
{
T = malloc(sizeof(struct AvlNode));
if (T == NULL)
return NULL;
else
{
T->num = X;
T->height = 0;
T->left = T->right = NULL;
}
}
else if (X < T->num)			//如果待插入结点小于该节点,则移向左子树
{
T->left = Insert(T->left, X);
if (Height(T->left) - Height(T->right) == 2)//判定左子树高度与右子树高度差为2
if (X < T->left->num)		//判定情况属于L-L还是L-R
T = Single_Rotate_left(T);
else
T = Double_Rotate_left(T);
}
else if (X > T->num)			//如果待插入结点大于该节点,则移向右子树
{
T->right = Insert(T->right, X);
if (Height(T->right) - Height(T->left) == 2)//判定右子树高度与左子树高度差为2
if (X > T->right->num)		//判定情况属于R-R还是R-L
T = Single_Rotate_right(T);
else
T = Double_Rotate_right(T);
}
T->height = Max(Height(T->left), Height(T->right)) + 1;	//更新结点高度
return T;
}


6、删除结点

Position Delete(Tree T, DATA_TYPE X)
{
Position TmpCell;

if (T == NULL)
{
printf("Element not found!!\n");
return NULL;
}
else if (T->num > X)						//往左边查找元素X
T->num = Delete(X, T->left);
else if (T->num < X)						//往右边查找元素X
T->num = Delete(X, T->right);
else if (T->left && T->right)				//元素找到了并且左右子树都不为空
{
TmpCell = FindMin(T->right);		    //将要删除的节点用右子树中的最小节点代替
T->num = TmpCell->num;
T->right = Delete(T->num, T->right);
}
else                                      //元素找到了并且左右子树有一个为空
{
TmpCell = T;
if (T->left == NULL)
T = T->right;
else if (T->right == NULL)
T = T->left;

free(TmpCell);
}

if (T != NULL)
{
T->height = Max(Height(T->left), Height(T->right)) + 1;		//删除完节点之后要更新高度
//判断是否在节点T处失去平衡
if ((Height(T->left) - Height(T->right) >= 2) || (Height(T->right) - Height(T->left) >= 2))
{
T = Fix(T);
T->height = Max(Height(T->left), Height(T->right)) + 1;
}
}
return T;
}


static Position Fix(Position K2)
{
if (Height(K2->left) > Height(K2->right))
{
//K2左儿子的左儿子的高度大于K2的左儿子的右儿子的高度, 执行左单旋转, 否则执行左-右双旋转
if (Height(K2->left->left) > Height(K2->left->right))
K2 = Single_Rotate_Left(K2);
else if (Height(K2->left->left) < Height(K2->left->right))
K2 = Double_Rotate_Left(K2);
}
else if (Height(K2->left) < Height(K2->right))
{
//K2右儿子的右儿子的高度大于K2的右儿子的左儿子的高度, 执行右单旋转, 否则执行右-左双旋转
if (Height(K2->right->right) > Height(K2->right->left))
K2 = Single_Rotate_Right(K2);
else if (Height(K2->right->right) < Height(K2->right->left))
K2 = Double_Rotate_Right(K2);
}

return K2;
}


7、先序打印树中的结点

Position Print_tree(Tree T)
{
if (T == NULL)
{
printf("The Tree is empty.\n");
return NULL;
}
else if (T->left != NULL && T->right != NULL)
{
printf("%d ", T->num);
T->left = Print_tree(T->left);
T->right = Print_tree(T->right);
}
else if (T->left != NULL && T->right == NULL)
{
printf("%d ", T->num);
T->left = Print_tree(T->left);
}
else if (T->left == NULL && T->right != NULL)
{
printf("%d ", T->num);
T->right = Print_tree(T->right);
}
else if (T->left == NULL && T->right == NULL)
printf("%d ", T->num);
return T;
}


8、树的旋转

左左单旋转

static Position Single_Rotate_left(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->right) + 1;
return K1;
}




右右单旋转

static Position Single_Rotate_right(Position K2)
{
Position K1;
K1 = K2->right;
K2->right = K1->left;
K1->left = K2;

K2->height = Max(Height(K2->right), Height(K2->left)) + 1;
K1->height = Max(Height(K1->right), K2->height) + 1;
return K1;
}




左右双旋转

static Position Double_Rotate_left(Position K3)
{
K3->left = Single_Rotate_right(K3->left);
return Single_Rotate_left(K3);
}




右左双旋转

static Position Double_Rotate_right(Position K3)
{
K3->right = Single_Rotate_left(K3->right);
return Single_Rotate_right(K3);
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: