手写代码 AVL 二叉平衡树(插入 删除)

avl是一种平衡二叉树,其难点在于插入和删除,这两个操作可能会导致avl树不再满足平衡条件(左右子树的高度相差小于2),所以需要旋转来重新回到平衡状态。

本文实现的插入与《数据结构与算法分析–C语言描述 第二版》的方法类似,但稍有不同,本文没有用到单旋转和双旋转的概念,而是是用《算法导论》中“左旋”、“右旋”的概念。

实际上左旋和右旋就是单旋转,而双旋转就是左旋和右旋的结合。

下面用插图说明下在什么情况下左旋与右旋操作。
《手写代码 AVL 二叉平衡树(插入 删除)》

我在写代码是就用手画一下这个图。

下面是代码,可以在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;
}

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/weewqrer/article/details/51840729
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞