码迷,mamicode.com
首页 > 其他好文 > 详细

红黑树

时间:2014-05-14 15:29:28      阅读:287      评论:0      收藏:0      [点我收藏+]

标签:style   blog   class   code   c   ext   

红黑树是一个二叉搜索树,具有如下规则:
  1. 每个节点不是红色就是黑色。
  2. 根节点必须为黑色。
  3. 如果节点为红,其子节点必须为黑,父子节点不得同时为红。
  4. 任一节点至NULL(NULL为黑色)的任何路径,所含黑节点数必须相同。
根据规则4,新增节点必须为红。
根据规则3,新增节点的父节点必须为黑。
因为新增节点必须是红,那么只有在父节点不为黑的时候才需要调整,父节点为黑则无需调整。

着色法则的一个推论(证明过程未了解)是,红黑树的高度最多是2log(N+1)。因此,查找保证是一种对数的操作。

红黑树的平衡性比AVL树要弱,但红黑树通常能够导致良好的平衡状态。经验告诉我们,红黑树的搜索平均效率和AVL树几乎相等(STL源码剖析P210)。

红黑树的调整大体分三种情况,单旋转和双旋转非常类似于AVL树的旋转方法:
1、叔父节点为黑色,新节点在外侧插入。调整方法是:父节点和祖父节点单旋转并改变颜色,如下图。
bubuko.com,布布扣

2、叔父节点为黑色,新节点在内侧插入。调整方法是:先用新节点和父节点执行一次单旋转,如下图。
bubuko.com,布布扣
右图和第一种情况一样了,执行一次单旋转再变色即可。

3、叔父节点为红色,即祖父节点为黑,父节点和叔父节点为红。调整方法是:改变祖父、父、叔父颜色。 
bubuko.com,布布扣
如果节点G的父节点为红,那么使用前两种方法进行调整即可。

从上面的插入操作可以看出,不管是内侧插入还是外侧插入,只要叔父节点颜色为黑,那么执行相应的单旋转或双旋转即可。但如果叔父节点为红,则需要改变三个节点的颜色。上图中,G的父节点又有可能为红,那么就要根据G的叔父节点的颜色持续向上改变,这是自底向上的插入方法,STL中的红黑树就用了这种做法(源码剖析P225)。另外一种做法是自顶向下,在沿着路径搜寻插入点的同时,只要发现某个黑节点的两个儿子全为红,则改变颜色,从而避免了持续向上的改变,《数据结构与算法分析》中的例程就用了这种方法(P356)。

下面是代码:
#include <stdio.h>

typedef int ElementType;
typedef struct RedBlackNode *Position;
typedef Position RedBlackTree;
typedef enum ColorType {Red, Black} ColorType;

struct RedBlackNode {
    ElementType Element;
    RedBlackTree Left;
    RedBlackTree Right;
    ColorType Color;
};

Position NullNode = NULL;

// 初始化两个特殊节点:根标记和NULL节点
RedBlackTree Initialize(void)
{
    RedBlackTree T;

    if (NullNode == NULL)
    {
        NullNode = malloc(sizeof (struct RedBlackNode));
        if (NullNode == NULL)
            return -1;
        NullNode->Left = NullNode->Right = NullNode;
        NullNode->Element = 65535;
        NullNode->Color = Black;    // NULL节点为黑色
    }

    T = malloc(sizeof (struct RedBlackNode));
    if (T == NULL)
        return -1;
    T->Left = T->Right = NullNode;
    T->Element = -65535;
    T->Color = Black;

    return T;
}


Position SingleRotate_Left(Position T)
{
    Position NewRoot;

    NewRoot = T->Left;
    T->Left = NewRoot->Right;
    NewRoot->Right = T;

    return NewRoot;
}

Position SingleRotate_Right(Position T)
{
    Position NewRoot;

    NewRoot = T->Right;
    T->Right = NewRoot->Left;
    NewRoot->Left = T;

    return NewRoot;
}

static Position Rotate(Position Parent, ElementType Item)
{
    if (Item < Parent->Element)
    {
        if (Item < Parent->Left->Element)
            return Parent->Left = SingleRotate_Left(Parent->Left);     // 左-左
        else
            return Parent->Left = SingleRotate_Right(Parent->Left);    // 左-右
    }
    else
    {
        if (Item > Parent->Right->Element)
            return Parent->Right = SingleRotate_Right(Parent->Right);   // 右-右
        else
            return Parent->Right = SingleRotate_Left(Parent->Right);    // 右-左
    }
}

static Position x, p, gp, ggp;

static void HandleReorient(RedBlackTree T, ElementType Item)
{
    x->Color = Red;
    x->Left->Color = Black;
    x->Right->Color = Black;

    if (p->Color == Red)
    {
        gp->Color = Red;
        if ((Item < gp->Element) != (Item < p->Element))
            p = Rotate(gp, Item);   // 之字形,双旋转
        x = Rotate(ggp, Item);
        x->Color = Black;
    }

    T->Right->Color = Black;
}

// 每进行一次插入都要从上至下的遍历
RedBlackTree Insert(RedBlackTree T, ElementType Item)
{
    gp = p = x = T;
    NullNode->Element = Item;

    while (x->Element != Item)
    {
        ggp = gp;
        gp = p;
        p = x;
        if (Item < x->Element)
            x = x->Left;
        else
            x = x->Right;
        if (x->Left->Color == Red && x->Right->Color == Red)
            HandleReorient(T, Item);
    }
    if (x != NullNode)
        return T;

    x = malloc(sizeof (struct RedBlackNode));
    if (x == NULL)
        return -1;
    x->Element = Item;
    x->Left = x->Right = NullNode;
    if (Item < p->Element)
        p->Left = x;
    else
        p->Right = x;

    HandleReorient(T, Item);
    return T;
}

static void MidPrint(RedBlackTree T)
{
    if (T != NullNode)
    {
        MidPrint(T->Left);
        printf("%d ", T->Right->Element);
        MidPrint(T->Right);
    }
}

int main()
{
    RedBlackTree tree;

    tree = Initialize();
    tree = Insert(tree, 10);
    tree = Insert(tree, 85);
    tree = Insert(tree, 15);
    tree = Insert(tree, 70);
    tree = Insert(tree, 20);
    tree = Insert(tree, 60);
    tree = Insert(tree, 30);
    tree = Insert(tree, 50);
    tree = Insert(tree, 65);
    tree = Insert(tree, 80);
    tree = Insert(tree, 90);
    tree = Insert(tree, 40);
    tree = Insert(tree, 5);
    tree = Insert(tree, 55);
    MidPrint(tree);
    return 0;
}


参考:
《STL源码剖析》 P208.
《数据结构与算法分析》 P351.

红黑树,布布扣,bubuko.com

红黑树

标签:style   blog   class   code   c   ext   

原文地址:http://blog.csdn.net/nestler/article/details/25738139

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!