avl是一种平衡二叉树,其难点在于插入和删除,这两个操作可能会导致avl树不再满足平衡条件(左右子树的高度相差小于2),所以需要旋转来重新回到平衡状态。
本文实现的插入与《数据结构与算法分析–C语言描述 第二版》的方法类似,但稍有不同,本文没有用到单旋转和双旋转的概念,而是是用《算法导论》中“左旋”、“右旋”的概念。
实际上左旋和右旋就是单旋转,而双旋转就是左旋和右旋的结合。
我在写代码是就用手画一下这个图。
下面是代码,可以在vs中直接运行。
//avl二叉平衡树
#include <stdafx.h> //Microsoft Visual Studio
#include <stdlib.h>//malloc free
#include <assert.h>
typedef struct avl_t{
int key;
int height;
avl_t * left;
avl_t * right;
}avl_t;
//函数声明
void avl_deposite(avl_t * T);
avl_t* avl_insert(avl_t* &T, int k);
avl_t* avl_delete(avl_t* &T, int k);
avl_t* avl_find( avl_t * T, int k);
avl_t* avl_findMin( avl_t* T);
avl_t* avl_findMax( avl_t* T);
int avl_height(avl_t* T);
static int avl_Max(int, int);
static avl_t* avl_left_rotate(avl_t*T);
static avl_t* avl_right_rotate(avl_t*T);
void avl_inPrint(const avl_t* T);//中序遍历
void avl_prePrint(const avl_t * T);//前序遍历
void avl_print(const avl_t* T);
void avl_test();
/*
*@brief avl_insert 向树中插入一个元素,如果树不存在,则新创建一个
*@param[in] T avl树
*@param[in] k 要插入的元素
*@return T 做插入操作是一定要使用T= avl_insert(T,k),用以更新T的指向!
*注意更新高度 保持平衡
*重要说明 为什么使用 avl_t* &T, 而不是avl_t* T,后者创建了局部变量来接受传过来的 T(不妨用oldT表示),在avl_insert过程中局部变量T始终代表根,
*而oldT指向的节点却有可能不再是根了,所以必须用T= avl_insert(T,k)来调用插入,而不能只使用avl_insert(T,k);这会造成使用者的困惑。
*但是如果使用avl_t* &T,那么局部变量时刻都代表着传过来的oldT,所以可以不用明着返回T.
*/
avl_t* avl_insert(avl_t* &T, int k){
if(T==NULL){
T = (avl_t*)malloc(sizeof(avl_t));
//void assert( int expression );
//assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
assert(T!=NULL);
T->key = k;
T->height=0;
T->left = T->right = NULL;
}else if(k < T->key)
{
T->left = avl_insert(T->left,k);
if(avl_height(T->left)-avl_height(T->right) == 2){
if(k>T->left->key)
T->left = avl_left_rotate(T->left);
T = avl_right_rotate(T);
}
}
else if(k > T->key){
T->right = avl_insert(T->right,k);
if(avl_height(T->right) - avl_height(T->left) == 2){
if(k<T->right->key)
T->right = avl_right_rotate(T->right);
T = avl_left_rotate(T);
}
}
//只有一个return,在return前更新高度
T->height = avl_Max(avl_height(T->left),avl_height(T->right))+1;
return T;
}
/*
*@brief avl_delete 从树中删除一个元素
*@param[in] T avl树
*@param[in] k 要删除的元素
*@return T
*注意更新高度 保持平衡
*/
avl_t* avl_delete(avl_t* &T, int k){
if(T == NULL) return T;
if(k<T->key){
T->left = avl_delete(T->left,k);
}
else if(k>T->key){
T->right = avl_delete(T->right,k);
}else{
if(T->left != NULL && T->right!= NULL){//both child
avl_t * y = NULL;
//哪边比较高就删除那边,但是并不能从根源解决平衡问题。
if(T->left->height < T->right->height){
y = avl_findMin(T->right);
T->key = y->key;
T->right = avl_delete(T->right,y->key);
}else{
y = avl_findMax(T->left);
T->key = y->key;
T->left = avl_delete(T->left,y->key);
}
}else if(T->right != NULL){//only right child
avl_t* rchild = T->right;
free(T);
T = rchild;
}else{ //only left child or no child
avl_t *lchild = T->left;
free(T);
T = lchild;
}
}
//通过旋转调整左右高度
if(avl_height(T->left) - avl_height(T->right)==2){
if(avl_height(T->left->right) - avl_height(T->left->left) == 1){
T->left = avl_left_rotate(T->left);
}
T = avl_right_rotate(T);
}else if(avl_height(T->right) - avl_height(T->left) == 2){
if(avl_height(T->right->left) - avl_height(T->right->right) == 1){
T->right = avl_right_rotate(T->right);
}
T = avl_left_rotate(T);
}else{
//already balance
};
T->height = avl_Max(avl_height(T->left),avl_height(T->right))+1;
return T;
}
/*
*@brief avl_height 返回树高
*@param[in] 树
*return 返回树高
*/
int avl_height(avl_t* T){
if(T==NULL)
return -1;
else
return T->height;
}
int avl_Max(int x, int y){
return x>y?x:y;
}
/*
*@brief avl_left_rotate
*@param[in] 树根
*@return 返回旋转之后的树根
*/
avl_t * avl_left_rotate(avl_t*T){
avl_t * y = T->right;
T->right = y->left;
y->left = T;
T->height = avl_Max(avl_height(T->left), avl_height(T->right))+1;
y->height = avl_Max(avl_height(y->left), avl_height(y->right))+1;
return y;
}
/*
*@brief avl_right_rotate
*@param[in] 树根
*@return 返回旋转之后的树根
*/
avl_t* avl_right_rotate(avl_t*T){
avl_t * y = T->left;
T->left = y->right;
y->right = T;
T->height = avl_Max(avl_height(T->left), avl_height(T->right))+1;
y->height = avl_Max(avl_height(y->left), avl_height(y->right))+1;
return y;
}
avl_t* avl_find( avl_t * T, int k){
avl_t* p = T;
while( NULL != p && p->key != k){
if( k < p->key)
p = p->left;
else
p = p->right;
}
return p;
}
avl_t* avl_findMin( avl_t* T){
assert(T!= NULL);
avl_t* p = T->left;
while(p->left != NULL){
p = p->left;
}
return p;
}
avl_t* avl_findMax( avl_t* T){
assert(T!= NULL);
avl_t* p = T->right;
while(p->right != NULL){
p = p->right;
}
return p;
}
void avl_deposite(avl_t* T){
if(NULL == T)
return ;
else{
avl_deposite(T->left);
avl_deposite(T->right);
free(T);
T = NULL;
}
}
void avl_prePrint(const avl_t * T){
if(NULL ==T)return ;
printf("%3d",T->key);
avl_prePrint(T->left);
avl_prePrint(T->right);
}
void avl_inPrint(const avl_t* T){
if(NULL == T) return ;
avl_inPrint(T->left);
printf("%3d",T->key);
avl_inPrint(T->right);
}
void avl_print(const avl_t* T){
assert(T!=NULL);
printf("\n前序遍历 :");
avl_prePrint(T);
printf("\n中序遍历 :");
avl_inPrint(T);
printf("\n");
}
/*
*@brief avl 测试程序
*/
void avl_test(){
avl_t * T = NULL;
int d;
/************************************************************************/
/* 1 测试插入
/*
/*输入 5 2 8 1 4 7 3 6 end
/*输出 前序遍历 : 5 2 1 4 3 7 6 8
/* 中序遍历 : 1 2 3 4 5 6 7 8
/************************************************************************/
while(scanf("%d",&d)){
avl_insert(T,d);
}
avl_print(T);
/************************************************************************/
/* 2 测试最大 最小
/************************************************************************/
avl_t * max = avl_findMax(T);
avl_t * min = avl_findMin(T);
printf("\nmax:%d \n",max->key); //max:8
printf("\nmin:%d \n",min->key);//min:1
/************************************************************************/
/* 3 测试删除
/*输出 前序遍历 : 4 2 1 3 7 6 8
/* 中序遍历 : 1 2 3 4 6 7 8
/************************************************************************/
avl_delete(T,5);
avl_print(T);
avl_deposite(T);
}
int _tmain(int argc, _TCHAR* argv[])
{
avl_test();
printf("\nhelo\n");
return 0;
}