Red-Black Tree 红黑树

如果viewer对Red-Black Tree先前没有任何了解,可以看看先搞定AVL树,因为AVL树比红黑树要简单的多

涉及同样的rotate技巧,搞懂了AVL树再和红黑大战三百回合绝对轻松的多。

(我见过讲AVL最好的教程就是 Mark Allen Weiss 写的《数据结构与算法分析
C语言描述》里面讲AVL树的部分)

AVL树的C语言实现:

http://blog.csdn.net/cinmyheart/article/details/20527037

Here we go ~ 笔记贴~

----------------------------------------------------------------------------------------------------------------------------------------

Red-Black
Tree

这颗神树肿么来的,为嘛就这么神捏?如下:碉堡的性能

如下即为一个红黑树的例子:

红黑树之所以有之前提到的那么好的性能(搜索,删除,插入各种 lg N),是因为它本身设计时具有很好的性质:

树中的每个节点至少包含五个域:

color, key,left,right,和p(parent)

据此,我们可以对节点进行抽象(Python实现):

1. Every node is either red or black.

2. The root is black.

3. Every leaf ( NIL ) is black.

4. If a node is red, then both its children are black.

5. For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.

前三点都很容易掌握,一开始接触Red Black Tree需要特别注意第4和第5条性质。

We call the number of black nodes on any simple path from, but not including, a node x down to a leaf the black-height of the node, denotedbh(x).By property
5, the notion of black-height is well defined, since all descending simple paths from the node have the same number of black nodes. We define the black-height of a red-black tree to be
the black-height of its root.

一颗有n个内节点的红黑树的高度至多为2lg(n+1)。关于这个性质的证明CLRS上有详细的证明,非常值得一看。

左旋,右旋操作:

做个“神奇”的操作不要想多了,首先别怕。。。

本质上就是节点的交换位置,而且很有规律。

对于右旋,就是像下图中x,y节点的布局一样,当节点x位于y的左下放时,可以通过提升x的高度,降低y的高度,调整,α β γ 三个子树和x,y节点的关系,进而保持二叉树的特性,最后实现x节点的提升。

而左旋就是右旋的逆过程而已。

这里之所以称为左旋右旋,这里的旋是因为“看起来”好像按照上面位置节点(对于左旋,上面位置节点就是y)

的竖直中轴旋转180°,好像就可以从左边的状态变成右边的状态,但是还要调整一下节点关系。这就是“旋”称呼的来源,rotation。

具体用代码实现时,只要死磕节点关系,按照下面的状态转换图进行调整即可。

对于节点的插入:

三种情况:

Case 1:  ?’s uncle y is red

策略很简单就是把z.parent的黑节点“沉降”下来。

Case 2:  ?’s uncle y is black and  ? is a right child

Case 3:  ?’s uncle y is black and  ? is a left child

策略也比较简单,就是先在case 2里对A节点左旋,然后进入了case 3 对C节点右旋,并调整节点颜色。

"""
Code writer : EOF
Code date   : 2015.01.29
Code file   : rbt.py
e-mail      : [email protected]

Code description :

    Here is a implementation of red-black-tree in Python.
If you find something wrong with my code, please touch me
by e-mail. Thank you!

"""

class node() :
    def __init__(self, num, color) :
        self.right  = None
        self.left   = None
        self.parent = None
        self.color  = color
        self.key    = num

class Red_Black_Tree() :
    def __init__(self, array) :
        self.nil  = node(0, 'black')
        self.root = self.nil

        for i in range(0,len(array)) :
            self.rb_insert(array[i])

    def rb_search(node, num) :
        if node.key > num :
            return rb_search(node.left, num);
        elif node.key < num :
            return rb_search(node.right, num);
        else :
            return node

    def tree_mininum(self, x) :
        while x.left != self.nil :
            x = x.left
        return x

    def tree_successor(self, x) :
        if x.right != self.nil :
            return self.tree_mininum(x.right)

        y = x.parent
        while y != self.nil and x == y.right :
            x = y
            y = y.parent
        return y    

    def left_rotate(self, x) :
        y = x.right
        x.right = y.left

        if y.left is not self.nil :
            y.left.parent = x

        if x.parent is self.nil :
           self.root = y
        elif x is x.parent.left :
             x.parent.left = y
        else :
             x.parent.right = y

        y.parent = x.parent
        y.left = x
        x.parent = y

    def right_rotate(self, x) :
        y = x.left

        if y.right is not self.nil :
            y.right.parent = x

        if x.parent is self.nil :
            self.root = y
        elif x is x.parent.left :
             x.parent.left = y
        else :
             x.parent.right = y

        y.parent = x.parent
        y.right = x
        x.parent = y

    def rb_insert(self, num) :
        z = node(num, 'red')
        z.right  = self.nil
        z.left   = self.nil
        z.parent = self.nil

        y = self.nil
        x = self.root

        while x != self.nil :
            y = x
            if z.key < x.key :
                x = x.left
            else :
                x = x.right

        z.parent = y

        if y is self.nil :
            self.root = z
        elif z.key < y.key :
            y.left = z
        else :
            y.right = z

        z.left  = self.nil
        z.right = self.nil
        z.color = 'red'
        self.rb_insert_fixup(z)

    def rb_insert_fixup(self, z) :
        while z.parent.color is 'red' :
            if z.parent is z.parent.parent.left :
               y = z.parent.parent.right # @y is the uncle of @z
               if y.color is 'red' :     # $case 1
                   z.parent.color        = 'black'
                   y.color               = 'black'
                   z.parent.parent.color = 'red'
                   z = z.parent.parent
               else : # here is the color of uncle-node @y is 'black'
                   if z is z.parent.right : # $case 2
                       z = z.parent
                       self.left_rotate(z)
                   z.parent.color = 'black' # $case 3
                   z.parent.parent.color = 'red'
                   self.right_rotate(z.parent.parent)
            else : # In this situation, p[z] == right[p[p[z]]]
                 y = z.parent.parent.left
                 if y.color is 'red' :
                     z.parent.color  = 'black'
                     y.color         = 'black'
                     z.parent.parent.color = 'red'
                     z = z.parent.parent
                 else :
                     if z is z.parent.left :
                         z = z.parent
                         self.right_rotate(z)
                     z.parent.color = 'black'
                     z.parent.parent.color = 'red'
                     self.left_rotate(z.parent.parent)

        self.root.color = 'black'

    def __str__(self):

        def recurse(node) :
            if node is None:
                return [], 0, 0
            else :
                left_lines, left_pos, left_width = recurse(node.left)
                right_lines, right_pos, right_width = recurse(node.right)

            label = str(node.key) + ' ' + str(node.color)
            middle = max(right_pos + left_width - left_pos +1, len(label), 2)
            pos    = left_pos + middle//2
            width  = left_pos + middle + right_width - right_pos

            while len(left_lines) < len(right_lines) :
                left_lines.append(' ' * left_width)
            while len(right_lines) < len(left_lines) :
                right_lines.append(' ' * right_width)

            line = [    ' ' * left_pos + label +
                        ' ' * (right_width-right_pos + 1),
                        ' ' * left_pos + '/' +
                        ' ' * (middle-2) + '\\' +
                        ' ' * (right_width - right_pos)
                                ] +                         [
                        left_line +
                        ' ' * (width - left_width - right_width) +
                        right_line
                        for left_line, right_line
                        in zip(left_lines, right_lines)
                        ]

            if node is self.root :
                return line
            else :
                return line, pos, width

        if self.root is None :
            return '<Empty tree>'

        output = recurse(self.root)
        for i in range(1, len(output)-2) :
            output[0] += '\n' + output[i]

        return output[0]+'\n'

#-----------  for testing ------------------------------

array = [1,2,4,5,7,8,11,14,15]

my_little_tree = Red_Black_Tree(array)

print my_little_tree

测试结果:

树形结构还待改进~ 不过不影响测试。能看清楚,凑合

-----------------------------------------------------------------------------------------------------------

删除节点嘛~ 要重点扯一扯所以先上代码,然后后续再分析。。。

女神啊~

时间: 2024-10-09 22:36:03

Red-Black Tree 红黑树的相关文章

STL RB Tree(红黑树)分析

当我2014年上半年看内核代码的时候,进程调度用的就是RB  Tree,而现在分析STL源码的时候发现Set和Map也使用了这个数据结构,说明了RBTree的使用时如此的广泛,所以我花了两天时间看了这,分三部分来说明,首先我要说明下红黑树的基本概念,然后说明下STL中的RB Tree的迭代器,最后说下STL中RB Tree容器的实现. 一.红黑树的基本概念 红黑树是平衡二叉搜索树的一种(平衡二叉搜索树中又有AVL Tree),满足二叉搜索树的条件外,还应买足下面的4个条件 1) 每个节点不是红色

算法导论 第13章 红黑树

二叉查找树的基本操作包括搜索.插入.删除.取最大和最小值等都能够在O(h)时间复杂度内实现,因此能在期望时间O(lgn)下实现,但是二叉查找树的平衡性在这些操作中并没有得到维护,因此其高度可能会变得很高,当其高度较高时,而二叉查找树的性能就未必比链表好了,所以二叉查找树的集合操作是期望时间O(lgn),最坏情况下为O(n). 红黑树也是一种二叉查找树,它拥有二叉查找树的性质,同时红黑树还有其它一些特殊性质,这使得红黑树的动态集合基本操作在最坏情况下也为O(lgn),红黑树通过给节点增加颜色和其它

数据结构--树--红黑树

R-B Tree简介 R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树.红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black). 红黑树的特性:(1)每个节点或者是黑色,或者是红色.(2)根节点是黑色.(3)每个叶子节点(NIL)是黑色. [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!](4)如果一个节点是红色的,则它的子节点必须是黑色的.(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点.

浅谈算法和数据结构: 九 平衡查找树之红黑树

原文:浅谈算法和数据结构: 九 平衡查找树之红黑树 前面一篇文章介绍了2-3查找树,可以看到,2-3查找树能保证在插入元素之后能保持树的平衡状态,最坏情况下即所有的子节点都是2-node,树的高度为lgN,从而保证了最坏情况下的时间复杂度.但是2-3树实现起来比较复杂,本文介绍一种简单实现2-3树的数据结构,即红黑树(Red-Black Tree) 定义 红黑树的主要是像是对2-3查找树进行编码,尤其是对2-3查找树中的3-nodes节点添加额外的信息.红黑树中将节点之间的链接分为两种不同类型,

【转】浅谈算法和数据结构: 九 平衡查找树之红黑树

http://www.cnblogs.com/yangecnu/p/3627386.html 前面一篇文章介绍了2-3查找树,可以看到,2-3查找树能保证在插入元素之后能保持树的平衡状态,最坏情况下即所有的子节点都是2-node,树的高度为lgN,从而保证了最坏情况下的时间复杂度.但是2-3树实现起来比较复杂,本文介绍一种简单实现2-3树的数据结构,即红黑树(Red-Black Tree) 定义 红黑树的主要是像是对2-3查找树进行编码,尤其是对2-3查找树中的3-nodes节点添加额外的信息.

第十四章 红黑树——C++代码实现

红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值.除了具备该特性之外,红黑树还包括许多额外的信息. 红黑树的每个节点上都有存储位表示节点的颜色,颜色是红(Red)或黑(Black).红黑树的特性:(1) 每个节点或者是黑色,或者是红色.(2) 根节点是黑色.(3) 每个叶子节点是黑色. [注意:这里叶子节点,是指为空的叶子

Java实现红黑树

转自:http://www.cnblogs.com/skywang12345/p/3624343.html 红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树.红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值.除了具备该特性之外,红黑树还包括许多额外的信息. 红黑树的每个节点上都有存储位表示节点的颜色,颜色是红(Red)或黑(Black).红黑树的特性:(1) 每个节点或者

算法05 之红-黑树

从第4节的分析中可以看出,二叉搜索树是个很好的数据结构,可以快速地找到一个给定关键字的数据项,并且可以快速地插入和删除数据项.但是二叉搜索树有个很麻烦的问题,如果树中插入的是随机数据,则执行效果很好,但如果插入的是有序或者逆序的数据,那么二叉搜索树的执行速度就变得很慢.因为当插入数值有序时,二叉树就是非平衡的了,排在一条线上,其实就变成了一个链表--它的快速查找.插入和删除指定数据项的能力就丧失了. 为了能以较快的时间O(logN)来搜索一棵树,需要保证树总是平衡的(或者至少大部分是平衡的),这

算法导论 之 红黑树 - 插入[C语言]

作者:邹祁峰 邮箱:[email protected] 博客:http://blog.csdn.net/qifengzou 日期:2013.12.24 21:00 转载请注明来自"祁峰"的CSDN博客 1 引言 在之前的博文中,本人对平衡二叉树的处理做了较详尽的分析,有兴趣的朋友可以参阅博文<算法导论 之 平衡二叉树 - 创建 插入 搜索 销毁>和<算法导论 之 平衡二叉树 - 删除>.平衡二叉树AVL是严格的平衡树,在增删结点时,其旋转操作的次数较多:而红黑树