AVL树的插入、删除、查找操作

AVL树是一种带有平衡条件的二叉查找树,所有节点都是基于平衡的。所谓平衡,即某个节点的左右子树的高度差最多相差1。空树的高度定义为-1。

下面我们通过如下两棵树(图片来自《数据结构与算法分析–C语言描述》)进一步了解怎样的树才是AVL树。
《AVL树的插入、删除、查找操作》
上图只有左边的树才是AVL树,那么下面我们来分析一下左边的树
(某个节点的高 = MAX(子树的高, 右子树的高 )+ 1)
节点3的高为0
节点4的高为1
节点1的高为0
节点7的高为0
节点2的高为2
节点8的高为1
节点5的高为3

你可以看到任一节点的左右子树的差都没有超过2,那么我们再看看右边的树

节点2的高为2
节点8的高为0
所以对于节点7来说,左右子树的高度差相差为2 > 1,失去平衡。

下面我们接着来说AVL的插入、删除、查找操作。
插入和删除操作都有可能导致AVL树的不平衡(为什么呢?原来的树是平衡的,即某个节点的左右子树的高度差小于2,假设左子树的高为1,右子树的高为0,如果这个时候,在这个节点的左子树插入一个节点,那么该节点的左右子树的高度差就为2了,删除操作也是一样的)。

对于出现不平衡的时候,需要通过旋转来解决。下面我们直接来看看插入操作。

插入操作

插入节点==》有可能失去平衡==》通过旋转操作来使树达到平衡

我们把需要重新平衡的节点叫做A,那么出现不平衡的情况,会有下面四种
1. 对A节点的左儿子的左子树进行插入
2. 对A节点的左儿子的右子树进行插入
3. 对A节点的右儿子的左子树进行插入
4. 对A节点的右儿子的右子树进行插入

下图对应上面四种情况
《AVL树的插入、删除、查找操作》

针对情况一和情况四,我们采取的是单旋转(旋转一次)的操作
针对情况二和情况三,我们采取的是双旋转(旋转两次)的操作

单旋转,其法则是,如果哪边偏高,就往另一边旋转,
如情况一,旋转后的效果如下图
《AVL树的插入、删除、查找操作》
情况四旋转后的效果如下图
《AVL树的插入、删除、查找操作》

下图(来自《数据结构与算法分析–C语言描述》)对应情况一,从图中可以看出,K2的左右节点的高度差为2,不平衡,左边偏高,所以要往右边旋转。
《AVL树的插入、删除、查找操作》

我们直接来看看该单旋转算法的实现

Position * avl_tree_single_rotate_with_left(AVL_TREE * k2)
{
    Position * k1;

    k1 = k2->lChild;
    k2->lChild = k1->rChild;
    k1->rChild = k2;

    k2->height = avl_tree_max(avl_tree_height(k2->lChild), avl_tree_height(k2->rChild)) + 1;
    k1->height = avl_tree_max(avl_tree_height(k1->lChild), avl_tree_height(k1->rChild)) + 1;

    return k1;
}

双旋转,先旋转失去平衡节点K3的第一个儿子节点K1,然后再旋转K3。如情况二,旋转后的最终效果如下图
《AVL树的插入、删除、查找操作》
情况三,旋转后的最终效果如下图
《AVL树的插入、删除、查找操作》

下图(来自《数据结构与算法分析–C语言描述》)对应情况二,从图上可以看出,K3节点的左右子树高度差为2,不平衡,需要先旋转K1和K2,然后再旋转K2和K3。
《AVL树的插入、删除、查找操作》

我们来看看该双旋转算法的实现

Position * avl_tree_double_rotate_with_left(AVL_TREE * k3)
{
    /* Rotate between k1 and k2 */
    k3->lChild = avl_tree_single_rotate_with_right(k3->lChild);

    /* Rotate between k2 and k3 */
 return avl_tree_single_rotate_with_left(k3);
}

删除操作

删除操作可以参考二叉查找树的删除操作,其实就是分以下三种情况
1. 如果删除的value比tree->value大,那么继续往右边搜索
2. 如果删除的value比tree->value小,那么继续往左边搜索
3. 如果找到删除的value,那么又要分以下两种情况处理
1. 如果该节点有左右孩子的,那么用右子树的最小节点替代这个被删除的节点,然后再递归删除右子树的最小节点
2. 如果该节点只有一个左或者右孩子或者是没有孩子节点的,直接删除,返回相应的tree指针

删除操作,也是有可能造成树的不平衡。比如,删除下面这棵树的节点4,就会引起节点3的不平衡(左孩子的高为2,右孩子的高为0)
《AVL树的插入、删除、查找操作》

有一个很重要的一点,删除之前,树是平衡的,所以删除之后,不管删除节点有几个孩子,其左右子节点的高度差最多是2,不会超过2(删除节点的父节点或者是父父节点,再往上也是一样的),否则原来的树就是不平衡的,删除之后,无非有可能出现下面这四种情况
《AVL树的插入、删除、查找操作》
《AVL树的插入、删除、查找操作》
《AVL树的插入、删除、查找操作》
《AVL树的插入、删除、查找操作》

当删除之后,先要更新tree的高度,然后再判断tree是否失去平衡,如果失去平衡,再按照下面的算法调整

        /* Update the height of tree */
        tree->height = avl_tree_max(avl_tree_height(tree->lChild), avl_tree_height(tree->rChild)) + 1;

        if(avl_tree_height(tree->lChild) - avl_tree_height(tree->rChild) == 2)
        {
            if(tree->lChild->rChild)
                tree = avl_tree_double_rotate_with_left(tree);
            else
                tree = avl_tree_single_rotate_with_left(tree);
        }
        else if(avl_tree_height(tree->rChild)- avl_tree_height(tree->lChild) == 2)
        {
            if(tree->rChild->lChild)
                tree = avl_tree_double_rotate_with_right(tree);
            else
                tree = avl_tree_single_rotate_with_right(tree);
        }

查找操作

这个最简单,主要有三种情况:
1. 当查找value比tree->value小的时候,继续往左边查找
2. 当查找value比tree->value大的时候,继续往右边查找
3. 当查找value == tree->value时,返回

下面是上述操作的实现代码(下面代码有用到tree_visual_create.h,该头文件是将二叉树可视化,方便查看结果,具体可以参考二叉树的可视化

avl_tree.h

#ifndef __AVL_TREE_H__
#define __AVL_TREE_H__


typedef int ElementType;

typedef struct AVL_TREE_T
{
    ElementType value;
    struct AVL_TREE_T * lChild;
    struct AVL_TREE_T * rChild;
    int height;
}AVL_TREE;

typedef AVL_TREE Node;
typedef AVL_TREE Position;


extern void avl_tree_main(void);

#endif

avl_tree.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "avl_tree.h"
#include "tree_visual_create.h"



int avl_tree_max(int h1, int h2)
{
    if(h1 > h2)
        return h1;
    else 
        return h2;
}

int avl_tree_height(AVL_TREE * tree)
{
    if(NULL == tree)
        return -1;
    else 
        return tree->height;
}

Node * avl_tree_find(AVL_TREE * tree, ElementType value)
{
    Node * node = NULL;

    if(tree)
    {
        if(tree->value == value)
            node = tree;
        else if(tree->value > value)
            node = avl_tree_find(tree->lChild, value);
        else if(tree->value < value)
            node = avl_tree_find(tree->rChild, value);
    }

    return node;
}

Node * avl_tree_find_min(AVL_TREE * tree)
{
    AVL_TREE * node = NULL;

    if(tree)
    {
        if(tree->lChild)
            node = avl_tree_find_min(tree->lChild);
        else 
            node = tree;
    }

    return node;
}

Node * avl_tree_find_max(AVL_TREE * tree)
{
    AVL_TREE * node = NULL;

    if(tree)
    {
        if(tree->rChild)
            node = avl_tree_find_max(tree->rChild);
        else 
            node = tree;
    }

    return node;
}

Position * avl_tree_single_rotate_with_left(AVL_TREE * k2)
{
    Position * k1;

    k1 = k2->lChild;
    k2->lChild = k1->rChild;
    k1->rChild = k2;

    k2->height = avl_tree_max(avl_tree_height(k2->lChild), avl_tree_height(k2->rChild)) + 1;
    k1->height = avl_tree_max(avl_tree_height(k1->lChild), avl_tree_height(k1->rChild)) + 1;

    return k1;
}

Position * avl_tree_single_rotate_with_right(AVL_TREE * k1)
{
    Position * k2;

    k2 = k1->rChild;
    k1->rChild = k2->lChild;
    k2->lChild = k1;

    k1->height = avl_tree_max(avl_tree_height(k1->lChild), avl_tree_height(k1->rChild)) + 1;
    k2->height = avl_tree_max(avl_tree_height(k2->lChild), avl_tree_height(k2->rChild)) + 1;

    return k2;
}

Position * avl_tree_double_rotate_with_left(AVL_TREE * k3)
{
    /* Rotate between k1 and k2 */
    k3->lChild = avl_tree_single_rotate_with_right(k3->lChild);

    /* Rotate between k2 and k3 */
    return avl_tree_single_rotate_with_left(k3);
}

Position * avl_tree_double_rotate_with_right(AVL_TREE * k1)
{
    /* Rotate between k2 and k3 */
    k1->rChild = avl_tree_single_rotate_with_left(k1->rChild);

    /* Rotate between k1 and k2 */
    return avl_tree_single_rotate_with_right(k1);
}

AVL_TREE * avl_tree_insert(AVL_TREE * tree, ElementType value)
{
    if(NULL == tree)
    {
        tree = (AVL_TREE *)malloc(sizeof(AVL_TREE));
        if(NULL == tree)
            printf("AVL_TREE malloc failed\n");
        else 
        {
            tree->value = value;
            tree->height = 0;
            tree->lChild = tree->rChild = NULL;
        }
    }
    else if(tree->value > value)
    {
        tree->lChild = avl_tree_insert(tree->lChild, value);
        if(avl_tree_height(tree->lChild) - avl_tree_height(tree->rChild) == 2)
        {
            if(value < tree->lChild->value)
                tree = avl_tree_single_rotate_with_left(tree);
            else
                tree = avl_tree_double_rotate_with_left(tree);
        }
    }
    else if(tree->value < value)
    {
        tree->rChild = avl_tree_insert(tree->rChild, value);
        if(avl_tree_height(tree->rChild)- avl_tree_height(tree->lChild) == 2)
        {
            if(value > tree->rChild->value)
                tree = avl_tree_single_rotate_with_right(tree);
            else
                tree = avl_tree_double_rotate_with_right(tree);
        }
    }    

    tree->height = avl_tree_max(avl_tree_height(tree->lChild), avl_tree_height(tree->rChild)) + 1;

    return tree;
}

Node * avl_tree_delete(AVL_TREE * tree, ElementType value)
{
    AVL_TREE * temp = NULL;

    if(NULL == tree)
    {
        printf("Not found the element\n");
    }
    else if(value > tree->value)        /* Go Right */
    {
        tree->rChild = avl_tree_delete(tree->rChild, value);
    }
    else if(value < tree->value)       /* Go Left */
    {
        tree->lChild = avl_tree_delete(tree->lChild, value);
    }
    else if(tree->lChild && tree->rChild)       /* Two Children */
    {
        temp = avl_tree_find_min(tree->rChild);

        tree->value = temp->value;
        tree->rChild = avl_tree_delete(tree->rChild, tree->value);
    }
    else                /* one or zero Children */
    {
        temp = tree;
        if(NULL == tree->lChild)
        {
            tree = tree->rChild;
        }
        else if(NULL == tree->rChild)
        {
            tree = tree->lChild;
        }

        free(temp);
    }

    if(tree)        /* Ignore the free node */
    {        
        /* Update the height of tree */
        tree->height = avl_tree_max(avl_tree_height(tree->lChild), avl_tree_height(tree->rChild)) + 1;

        if(avl_tree_height(tree->lChild) - avl_tree_height(tree->rChild) == 2)
        {
            if(tree->lChild->rChild)
                tree = avl_tree_double_rotate_with_left(tree);
            else
                tree = avl_tree_single_rotate_with_left(tree);
        }
        else if(avl_tree_height(tree->rChild)- avl_tree_height(tree->lChild) == 2)
        {
            if(tree->rChild->lChild)
                tree = avl_tree_double_rotate_with_right(tree);
            else
                tree = avl_tree_single_rotate_with_right(tree);
        }
    }

    return tree;
}


void avl_tree_destroy(AVL_TREE * tree)
{
    if(tree)
    {
        if(tree->lChild)
            avl_tree_destroy(tree->lChild);
        if(tree->rChild)
            avl_tree_destroy(tree->rChild);

        free(tree);
    }
}

void avl_tree_main(void)
{
    AVL_TREE * tree = NULL;
    //int i=0;

    //for(i=1; i<=127; i++)
    // tree = avl_tree_insert(tree, i);
#if 0
    tree = avl_tree_insert(tree, 7);
    tree = avl_tree_insert(tree, 6);
    tree = avl_tree_insert(tree, 10);
    tree = avl_tree_insert(tree, 5);
    tree = avl_tree_insert(tree, 13);
    tree = avl_tree_insert(tree, 8);
    tree = avl_tree_insert(tree, 11);
#endif
#if 0
    tree = avl_tree_insert(tree, 5);
    tree = avl_tree_insert(tree, 3);
    tree = avl_tree_insert(tree, 6);
    tree = avl_tree_insert(tree, 4);
#endif  
#if 0
    tree = avl_tree_insert(tree, 5);
    tree = avl_tree_insert(tree, 2);
    tree = avl_tree_insert(tree, 8);
    tree = avl_tree_insert(tree, 1);
    tree = avl_tree_insert(tree, 4);
    tree = avl_tree_insert(tree, 7);
    tree = avl_tree_insert(tree, 3);
#endif    
#if 0
    tree = avl_tree_insert(tree, 7);
    tree = avl_tree_insert(tree, 6);
    tree = avl_tree_insert(tree, 8);
    tree = avl_tree_insert(tree, 5);
    tree = avl_tree_insert(tree, 9);
    tree = avl_tree_insert(tree, 10);
#endif    
#if 0
    tree = avl_tree_insert(tree, 8);
    tree = avl_tree_insert(tree, 3);
    tree = avl_tree_insert(tree, 10);
    tree = avl_tree_insert(tree, 2);
    tree = avl_tree_insert(tree, 5);
    tree = avl_tree_insert(tree, 9);
    tree = avl_tree_insert(tree, 11);
    tree = avl_tree_insert(tree, 1);
    tree = avl_tree_insert(tree, 4);
    tree = avl_tree_insert(tree, 6);
    tree = avl_tree_insert(tree, 12);
    tree = avl_tree_insert(tree, 7);
#endif
#if 1
    tree = avl_tree_insert(tree, 3);
    tree = avl_tree_insert(tree, 2);
    tree = avl_tree_insert(tree, 4);
    tree = avl_tree_insert(tree, 1);
#endif
    tree_visual_create(tree, "tree_insert.dot");

    Node * min = avl_tree_find_min(tree);
    printf("min value : %d\n", min->value);

    Node * max = avl_tree_find_max(tree);
    printf("max value : %d\n", max->value);

    Node * find = avl_tree_find(tree, 2);
    if(find)
        printf("find value : %d\n", find->value);
    else 
        printf("Cannot find the value\n");

    tree = avl_tree_delete(tree, 4);
    tree_visual_create(tree, "tree_delete.dot");

    avl_tree_destroy(tree);
}
    原文作者:AVL树
    原文地址: https://blog.csdn.net/Timsley/article/details/54601205
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞