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;
}
本文介绍红黑树的基本概念,如何通过简单的改造从二叉平衡树基础上构建红黑树,并保留2-3-4树的特性。文章详细解释了红黑树的操作如分裂、插入与平衡调整,以及其关键性质。
980

被折叠的 条评论
为什么被折叠?



