算法精解----13、二叉搜索树-AVL树

1、树的组织方式:左节点小于根节点,右节点大于根节点。平衡二叉树最坏情况log2 (n)。顺序排列只有单支最坏情况为n。可以采取随机插入等方式解决此问题,其中最好的方法就是 二叉搜索树实现AVL树。

2、AVL树:每个节点额外保存一个平衡因子,值为右子树高度减去左子树高度。插入节点时,AVL树需要自我调整保持所有平衡因子值为-1(左倾斜)、0、+1(右倾斜)。根节点的平衡因子代表整个树的平衡性。

3、实际上红黑树的统计性比AVL树更好。

4、几种其他树:
(1)K叉树:每个节点有多条分支

(2)红黑树:节点有颜色属性,红、黑

(3)Trie树:用来查找变长字符串组合

(4)B、B+、B*树:数据库系统使用来提高访问辅助存储设备上的数据。一般通过优化手段使节点大小和辅助存储设备的块大小保持一致。

5、AVL树旋转:旋转分为LL旋转、LR旋转、RR旋转、RL旋转。任何平衡因子变为+-2时,重新向下平衡。
总结为两步:
(1)把长分支转换到最左侧,或最右侧
(2)从儿子节点往短的那边折
图中最底层的节点也可以是红圈的位置,它影响平衡调整
《算法精解----13、二叉搜索树-AVL树》
6、AVL树函数实现
(1)数据结构

//AVL树节点,BIT_TREE_NODE树节点的*data指向这个节点
typedef struct AvlNode_{
    void *data;//节点存储的具体内容
    int hidden;//0代表该节点不在树中
    int factor;//平衡因子,表示该节点子树左右的倾斜程度
}AvlNode;

(2)LL旋转和LR旋转

//调整tree树,node为返回变换后的root点,一般每插一个节点都会调整一次,不会出现超过+-2的情况
//LL旋转:节点*node的左叶的左叶重,*node -2,只有root节点和其左叶节点要变
//root节点的左叶变为,左叶的右叶;左叶变为root,其右叶为原root

//LR:节点*node的左叶的右叶重,*node -2,root节点、左子叶、左左子叶的右子叶(孙子叶)要变
static void rotate_left(BisTree *tree, BiTreeNode **node)
{
    BiTreeNode *left, *grandchild;
    left = bittree_left(*node);
    //LL旋转
    if(((AvlNode *)bittree_left(left))->factor == AVL_LFT_HEAVY) { bittree_left(*node) = bittree_right(left); bittree_right(left) = *node; ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED;
        ((AvlNode *)bittree_data(left))->factor = AVL_BALANCED;
        *node = left;
    }

    //LR旋转
    else
    {
        grandchild = bittree_right(left);

        //左叶的右子树为,孙子的左子树
        bittree_right(left) = bittree_left(grandchild);
        //孙子的左子树为,原左叶
        bittree_left(grandchild) = left;
        //root节点的左叶为,孙子的右叶
        bittree_left(*node) =bittree_right(grandchild);
        //孙子右为,原root
        bittree_right(grandchild) = *node;

        //调整权重,孙子肯定平衡,孙子之前的左偏、右偏决定,父和左节点的平衡性
        switch(((AvlNode *)bittree_left(grandchild))->factor) { case AVL_LFT_HEAVY: ((AvlNode *)bittree_data(*node))->factor = AVL_REG_HEAVY;
                ((AvlNode *)bittree_data(left))->factor = AVL_BALANCED;
                break;
            case AVL_REG_HEAVY:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(left))->factor = AVL_LFT_HEAVY;
                break;
            case AVL_BALANCED:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(left))->factor = AVL_BALANCED;
                break;  

        }
        ((AvlNode *)bittree_data(grandchild))->factor = AVL_BALANCED;
        *node = grandchild;
    }
}

(3)RR、RL旋转

static void rotate_right(BiTreeNode **node)
{
    BiTreeNode *right, *grandchild;
    right = bittree_right(*node);
    if(((AvlNode *)bittree_right(right))->factor == AVL_REG_HEAVY) { bittree_right(*node) = bittree_left(right); bittree_left(right) = *node; ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED;
        ((AvlNode *)bittree_data(right))->factor = AVL_BALANCED;
        *node = right;
    }
    else
    {
        grandchild = bittree_left(right);
        bittree_left(right) = bittree_right(grandchild);
        bittree_right(grandchild) = right;
        bittree_right(*node) =bittree_left(grandchild);
        bittree_left(grandchild) = *node;

        switch(((AvlNode *)bittree_left(grandchild))->factor) { case AVL_LFT_HEAVY: ((AvlNode *)bittree_data(*node))->factor = AVL_REG_HEAVY;
                ((AvlNode *)bittree_data(right))->factor = AVL_BALANCED;
                break;
            case AVL_REG_HEAVY:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(right))->factor = AVL_LFT_HEAVY;
                break;
            case AVL_BALANCED:
                ((AvlNode *)bittree_data(*node))->factor =  AVL_BALANCED;
                ((AvlNode *)bittree_data(right))->factor = AVL_BALANCED;
                break;  

        }
        ((AvlNode *)bittree_data(grandchild))->factor = AVL_BALANCED;
        *node = grandchild;
    }
}

(4)删掉树结构:包括删掉node的左子树,原树节点*data指向的AVL节点,AVL节点*data指向的数据,若node=NULL,则删除整个树

static void destroy_left(BisTree *tree, BiTreeNode *node)
{
    BiTreeNode **position;
    if(tree->size == 0)
        return;

    //如果node等于NULL则从头节点开始删掉 
    if(node == NULL)
        position = &tree->root;
    else
        position = &node->left;
    if(*position != NULL)
    {
        //如果tree已经没有子叶,则destroy_left,destroy_right直接返回,继续执行下面的删除该节点
         destroy_left(tree, *position);
         destroy_right(tree, *position);

         if(tree->destroy != NULL)
         {
            tree->destroy(((AvlNode *)bittree_data(position)->data)->data);
        } 
        free((*position)->data);
        free(*position);
        *position = NULL;
        tree->size--;
    }
    return;
}

static void destroy_right(BisTree *tree, BiTreeNode *node)
{
    BiTreeNode **position;
    if(tree->size == 0)
        return;

    //如果node等于NULL则从头节点开始删掉 
    if(node == NULL)
        position = &tree->root;
    else
        position = &node->right;
    if(*position != NULL)
    {
         destroy_left(tree, *position);
         destroy_right(tree, *position);

         if(tree->destroy != NULL)
         {
            tree->destroy(((AvlNode *)bittree_data(position)->data)->data);
        } 
        free((*position)->data);
        free(*position);
        *position = NULL;
        tree->size--;
    }
    return;
}

(5)向节点插入子节点,要考虑左插还是右插,是否需要旋转

//*node==NULL表示插入第一个节点
static int insert(BisTree *tree, BiTreeNode **node, const void *data, int *balanced)
{ AvlNode *avl_data; int cmpval, retval;//cmpval是节点数据比较的结果,retval是返回的错误类型 if(*node == NULL) { if((avl_data = (AvlNode *)malloc(sizeof(AvlNode))) == NULL) return -1; avl_data->factor = AVL_BALANCED; avl_data->hidden = 0; avl_data->data = (void *)data; return bittree_ins_left(tree, *node, avl_data); }
    else
    { //比较数据大小决定往右边插还是往左边插 cmpval = tree->compare(data, ((AvlNode *)bittree_data(*node))->data); //判断大小,递归到最底层插入 if(cmpval < 0) { if(bittree_left(*node) == NULL) { if((avl_data = (AvlNode *)malloc(sizeof(AvlNode))) == NULL) return -1; avl_data->factor = AVL_BALANCED; avl_data->hidden = 0; avl_data->data = (void *)data; if(bittree_ins_left(tree, *node, avl_data) != 0) return -1; //在最底层插入后让*balance=0,才可进行旋转,只需要旋转最下面一颗不平衡的树 *balance = 0; }
            else
            { if((retval = insert(tree, &bittree_left(*node), data, balance)) != 0) return retval; }
            if(!(*balanced)) { //从插入节点的父节点开始,判断平衡,再到爷爷节点,只有这两层(除新插入的,最底的两层)需要判断 switch (((AvlNode *)bittree_data(*node))->factor) { case AVL_LFT_HEAVY: rotate_left(node); *balanced = 1; break; //本来平衡左插后左偏 case AVL_BALANCED: ((AvlNode *)bittree_data(*node))->factor = AVL_LFT_HEAVY; break; case AVL_REG_HEAVY: ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED; *balanced = 1; break; } } } else if(cmpval > 0) { //到最底层才能插入 if(bittree_right(*node) == NULL) { if((avl_data = (AvlNode *)malloc(sizeof(AvlNode))) == NULL)
                        return -1;
                avl_data->factor = AVL_BALANCED;
                avl_data->hidden = 0;
                avl_data->data = (void *)data;

                if(bittree_ins_right(tree, *node, avl_data) != 0)
                    return -1;

                //*balance表示是否到达最底层,没到最底层的父树*balance都为1
                *balance = 0;
            }
            else
            { if((retval = insert(tree, &bittree_right(*node), data, balance)) != 0) return retval; }
            if(!(*balanced)) { //现在是要往左边插入 switch (((AvlNode *)bittree_data(*node))->factor) { 本来就左偏,再左插就要旋转,递归旋转 case AVL_REG_HEAVY: rotate_right(node); *balanced = 1; break; //本来平衡右插后右偏 case AVL_BALANCED: ((AvlNode *)bittree_data(*node))->factor = AVL_REG_HEAVY; break; case AVL_LFT_HEAVY: ((AvlNode *)bittree_data(*node))->factor = AVL_BALANCED; *balanced = 1; break; } } } //cmpval==0,即和*node节点数据相等 else { //为了防止原数节点指向的数据和新加的相同,但是空间数据不同 if(!((AvlNode *)bittree_data(*node))->hidden) return 1; else { if(tree->destroy != NULL) { tree->destroy(((AvlNode *)bittree_data(*node))->data); } ((AvlNode *)bittree_data(*node))->data = (void *)data;
                ((AvlNode *)bittree_data(*node))->hidden = 0; *balanced = 1; } } } return 0; }

(6)标记节点是否已经在树中

//node是开始比较的节点
static int hide(BisTree *tree, BiTreeNode *node, const void *data)
{
    int cmpval, retval;

    //已经找到底 
    if(node == NULL)
    {
        return -1;
    }

    cmpval = tree->compare(data, ((AvlNode *)bittree_data(*node))->data); if(cmpval < 0) { retval = hide(tree, bittree_left(node), data); } else if(cmpval > 0) { retval = hide(tree, bittree_right(node), data); } else { ((AvlNode *)bittree_data(*node))->hidden = 1;
        retval = 0;
    } 
    return retval;

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