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

来源:互联网 发布:软件测试工程师题库 编辑:程序博客网 时间:2024/06/06 18:00

(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 intstruct 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)//如果树为空则高度为-1return -1;elsereturn 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)//判定左子树高度与右子树高度差为2if (X < T->left->num)//判定情况属于L-L还是L-RT = Single_Rotate_left(T);elseT = Double_Rotate_left(T);}else if (X > T->num)//如果待插入结点大于该节点,则移向右子树{T->right = Insert(T->right, X);if (Height(T->right) - Height(T->left) == 2)//判定右子树高度与左子树高度差为2if (X > T->right->num)//判定情况属于R-R还是R-LT = Single_Rotate_right(T);elseT = 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)//往左边查找元素XT->num = Delete(X, T->left);else if (T->num < X)//往右边查找元素XT->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);}





原创粉丝点击