《C算法》笔记13:30行内写出红黑树

30行当然是不够的,插入程序也没有考虑数据项相等时不需要处理的特殊情况。但是插入只用了32行,包括括号、注释在内,可见红黑树的优美。
简单的说,做一个小改造就可以在二叉平衡树的基础上构造出一棵红黑树,同时保留2-3-4树的性质。将每个节点加入一个颜色属性,代表和父节点的连通性。红色代表该节点和父节点连在一起,相当于2-3-4树中的3节点一部分或者4节点的一部分,黑色代表该节点和父节点分离,相当于2节点或者4节点中间的那个。

操作

2-3-4树的所有操作都可以在红黑树中用相应的方法来实现。
1、分裂:底下的两个红色节点置黑。上部的黑色节点置红。(相当于将上部节点和它的父节点结合,因为是二叉平衡树,所以在结合前和结合后都保持了左小右大的性质)
2、插入:按照二叉平衡树左小右大的性质插入。
3、平衡:为了平衡,4节点的实现采用了一个黑父节点带两个红子节点的方式。如果不是(也就是红节点的某个子节点也是红节点时)怎么办?旋转。

性质

红黑树有几条性质,可以从2-3-4树中找到对应的证明:

1)每个结点要么是红的,要么是黑的。

定义。

2)根结点是黑的。

根节点没有一个能连接的父节点。

3)每个叶结点,即空结点(NIL)是黑的。

空节点也不可能是3节点或者4节点的一部分。

4)如果一个结点是红的,那么它的俩个儿子都是黑的。

实现3。

5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

2-3-4树从根到所有叶子节点的路径长度相等。

实现

新建节点

RBLink new_node(Item item, RBLink l, RBLink r, bool red, int n)
{
    RBLink node = (RBLink)malloc(sizeof(RBSTNode));
    node->item = item, node->l = l, node->r = r, node->red = red, node->n = n;
    return node;
}

左右旋

RBLink rotR(RBLink h)
{
    RBLink x = HL; HL = x->r; x->r = h;
    return x;
}

RBLink rotL(RBLink h)
{
    RBLink x = HR; HR = x->l; x->l = h; 
    return x;
}

插入
这里z是一个终止的空节点。实际上,只有在插第一个元素的时候会跳转到h==z语句。

RBLink _insert(RBLink h, Item item, int sw)
{
    if(h == z)
        return new_node(item, z, z, 1, 1);
    if(HL->red && HR->red)      // 4 -> 2
    {
        h->red = 1, HL->red = HR->red = 0;
    }
    Key iKey = KEY(item), hKey = KEY(h->item);
    if(iKey < hKey)
    {
        HL = _insert(HL, item, 0);
        if(sw && h->red && HL->red)     // different heading
            h = rotR(h);
        if(HL->red && HLL->red)     // normal 4
        {
            h = rotR(h);
            h->red = 0, HL->red = HR->red = 1;
        }
    }
    else
    {
        HR = _insert(HR, item, 1);
        if(!sw && h->red && HR->red)
            h = rotL(h);
        if(HR->red && HRR->red)
        {
            h = rotL(h);
            h->red = 0, HR->red = HL->red = 1;
        }
    }
    return h;
}

你可能感兴趣的:(算法)