高效实现红黑树的插入--c实现

高效实现红黑树的插入

引言:
红黑树是一种特殊的二叉排序树,像java,c++的关联数组,如map都是用红黑树实现。
为什么红黑树应用比原生的二叉排序树(BST)和高度平衡二叉树(AVL)要更为广泛?
答:BST的深度不可控性,比如数据有序插入。不同形态的二叉排序树有不同的性能。
线性
图中a蜕化为线性链表,查找复杂度O(n),b图查找复杂度lg(n)。
而AVL插入、查找的时间复杂度都是lg(n),和红黑树相同。但是AVL是高度平衡的,插入删除更加容易引起不平衡,维护开销大。
所以红黑树是BST和AVL的这种选择,拥有插入,删除,查找的lg(n)时间复杂度。我个人理解,红黑树的查找性能肯定略逊于AVL,但这会在插入和删除开销上得到弥补,所有红黑树的统计性能最高。

红黑树的五个性质

  1. 每个结点要么是红的,要么是黑的。
  2. 根结点是黑的。
  3. 每个叶结点,即空结点(NIL)是黑的。
  4. 如果一个结点是红的,那么它的俩个儿子都是黑的。
  5. 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

红黑树是主要通过性质五来约束树的高度,提高树的平衡性。因为从该结点到其子孙结点的所有路径上包含相同数目的黑结点,所以新插入的结点需要是红结点来保证黑节点数目相等。又通过性质四来维护树的平衡性。

红黑树的插入
红黑树示例
这里写图片描述

插入动画演示

动画演示红黑树的插入过程-点击观看

插入情况及解决方案:

  1. 空树
    方案:检测是否是根节点,如果是,将颜色改为黑

  2. 父亲节点p是黑色
    方案:不会破坏红黑树的性质,不需要改变

  3. 父节点P红色,祖父节点G黑色,叔节点U红色
    方案:祖父结点必然是黑色,不是已经不满足红黑树的性质了。
    将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点(递归平衡,进入新的情况)

  4. 父节点P红色,祖父节点G黑色,叔节点U黑色,N左叶子
    方案:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋
    (递归平衡,进入新的情况)

  5. 父节点P红色,祖父节点G黑色,叔节点U黑色,N右叶子
    方案:以新当前节点的父节点左旋,当前节点的父节点做为新的当前节点(递归平衡,进入新的情况)

建议参考优秀博客,对入插入情况非常详细点这里查看
配合上面的红黑树的插入视频,把几种情况弄懂非常容易。

附上c的源码,希望对您有些帮助,核心代码不过20行。

/*2016-8-30 hiluo-scu*/
#include <stdio.h>
#include <stdlib.h>
typedef struct node* link;
link null=NULL;
struct node {
    int item;
    link l;
    link r;
    int red;
};

link NODE(int item,link l,link r,int red)
{
    link t = (link)malloc(sizeof(struct node));
    t->item = item;
    t->l = l;
    t->r = r;
    t->red = red;
    return t;
}

//初始化简历哨兵结点(叶节点或NULL结点)
link RB_init()
{
    null = NODE(0,NULL,NULL,0);
    null->l = null;null->r=null;
    return null;
}

//线序遍历
void pprintf(link t)
{
    if(t!=null)
    {
        printf("%d%c \n",t->item,t->red?'+':' ');
        pprintf(t->l);
        pprintf(t->r);
    }
}
//中序遍历
void IN_pprintf(link t)
{
    if(t!=null)
    {
        IN_pprintf(t->l);
        printf("%d%c \n",t->item,t->red?'+':' ');
        IN_pprintf(t->r);
    }
}

link rotR(link t)
{
    link x = t->l;t->l = x->r; x->r = t;
    return x;
}

link rotL(link t)
{
    link x = t->r;t->r = x->l; x->l = t;
    return x;
}

//核心代码 高效地实现红黑树插入
link insert_node(link t,int item,int sw)
{
    if(t==null) return NODE(item,null,null,1);
    if( (t->l->red==1) && (t->r->red==1) )
    {
        t->red = 1;
        t->l->red = 0;
        t->r->red = 0;
    }
    if(item < t->item)
    {
        t->l = insert_node(t->l,item,0);
        if(t->red && t->l->red &&sw) t=rotR(t);
        if(t->l->red && t->l->l->red)
        {
            t=rotR(t);t->red = 0;t->r->red = 1;
        }
    }else{
        t->r = insert_node(t->r,item,1);
        if(t->red && t->r->red && !sw) t=rotL(t);
        if(t->r->red && t->r->r->red)
        {
            t=rotL(t);
            t->red = 0;
            t->l->red = 1;
        }
    }
    return t;
}

link RB_insert(link root,int item)
{
    root = insert_node(root,item,0);
    root->red = 0;
    return root;
}
/*2016-8-30 hiluo-scu*/
int main()
{
    int N = 14;
    int a[]={10,85,15,70,20,60,30,50,65,80,90,40,5,55};
    //srand(time(NULL));
    link root = RB_init();
    for(int i=0;i<N;i++)
    {
        root = RB_insert(root,a[i]);
    }
    printf("\t---线序遍历tree------(+表示红色结点)\n");
    pprintf(root);
    printf("\t---中序遍历tree------(+表示红色结点)\n");
    IN_pprintf(root);
    return 0;
}

参考博客:
http://blog.csdn.net/v_JULY_v/article/details/6105630
http://blog.csdn.net/eric491179912/article/details/6179908
感谢!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值