13、二叉搜索树-AVL树

来源:互联网 发布:一句话经典 知乎 编辑:程序博客网 时间:2024/06/03 19:36

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)从儿子节点往短的那边折
图中最底层的节点也可以是红圈的位置,它影响平衡调整
这里写图片描述
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;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 红米4x外屏坏了怎么办 honor手机开不了机怎么办 honor黑屏开不了机怎么办 红米2开机停在mi怎么办 红米手机无法开机怎么办 小米手机帐号密码忘了怎么办 小米手机忘记小米账号密码怎么办 小米4账号密码忘了怎么办 小米2a触屏失灵怎么办 红米note5拍照不清晰怎么办 红米手机太卡怎么办 红米3x忘记密码怎么办 红米手机太卡了怎么办 红米手机太卡怎么办? 红米3老是死机怎么办 红米3s经常死机怎么办 红米4a进水了怎么办 魅族耳机声音小怎么办 魅蓝note6声音小怎么办 魅蓝3s锁定怎么办 红米1密码忘了怎么办 小米手环升级失败怎么办 红米4忘记密码怎么办 红米1代忘记密码怎么办 红米3s忘记密码怎么办 小米3卡槽卡住了怎么办 红米4手机信号不好怎么办 红米note3信号差怎么办 红米note3没信号怎么办 红米3运行慢怎么办 红米手机运行慢怎么办 红米手机忘记解锁图案怎么办 小米手机解锁图案忘了怎么办 红米2内屏坏了怎么办 红米密码忘记了怎么办 红米pro玩王者卡怎么办 红米note4不支持计步怎么办 红米pro玩游戏卡怎么办 红米手机费电快怎么办 荣耀5c忘记密码怎么办 小米之家不退货怎么办