红黑树是60年代中期计算机科学界找寻一种算法复杂度稳定,容易实现的数据存储算法的产物。在优先级队列、字典等实用领域都有广泛地应用,更是70年代提出的关系数据库模型--B树的鼻祖。在Linux kernel中,高精度定时器也工作在红黑树之上。为便于初学者掌握其基本算法,本文一步一步地演示了红黑树的创建过程。
首先回顾一下红黑树的基本性质:
1. 红黑树本质上是一个二叉查找树(BST),但是它从根到最远叶子的长度不会超过到最近叶子长度的两倍,因此是近似平衡的。
2. 红黑树的节点不是黑的就是红的,不会有第三种颜色。
3. 树根必须是黑色。
4. 叶子所指的空节点必须是黑色。
5. 如果某个节点是红色,那么它的两个儿子必须都是黑色。
6. 从任意节点出发的所有向下的路径上包含相同个数的黑节点。这个个数我们称为黑高度Bh。
有了上面的认识,我们要从无到有构造一颗红黑树的话,心里就有底了。这个构造的过程可以分两步:
第一步:执行BST的插入算法;
第二步:对节点着色;
第一步不会有什么问题,关键是第二步怎么对节点着色才不会违反红黑树的基本性质;
这是一个难点,我在写这篇文章的时候脑子也卡了一下,节点不多的时候好办,但是如果节点很多了,就必须找到一种普遍适用的算法来处理。通过这两天的观察,我发现这六条性质中最关键的其实是最后一条---从任意结点出发的任意路径黑高度相等!这才是红黑树算法保持近似平衡的精华所在!其它性质要么是这条性质的产物,要么就是为这条性质服务的。
现在我演示一下怎么从无到有生成一棵红黑树。
例如我们有一组数:{9,7,15,6,11,19},现在按照从左到右的顺序存放在一颗红黑树中。
第一个数是9,很自然地成为了树根,如图:
每个新节点都默认地被渲染成了红色,为什么要这么做呢?后面我们将会看到它的好处!现在先忽略不谈。
根节点9是红色,这违背了性质3,所以必须改成黑色,如图:
下一个数字是7,显然要被插入到9的左边,并且这时满足红黑树的所有性质,如图:
下一个数字是15,要插入到9的右边,并且也满足红黑树的所有性质,如图:
图-4
下一个数字是6,要插入到7的左边,这回似乎有麻烦了,性质5被违背了,如图:
图-5
可能有人会说,那很简单,既然违背了性质5,那我改一下6的颜色不就OK了?
图-6
现在,恭喜你---也走进了我曾经走过的误区:)你的无意之举改变了新增节点路径上面的黑高度,这棵树已经不是红黑树了!
写代码的人都知道,对树的遍历,最简单的方法就是递归,那么树的数学模型就是一个可穷举的递归式。递归式中每一步的正确性都建立在前一步正确的基础之上。现在我们回过头来想想为什么每次插入的新节点都被渲染成红色呢?你肯定猜到了,因为我们要保证红黑树的核心性质--黑高度不发生变化,虽然牺牲了性质5,但这是可以补救的,并且代价很小。再来看看图-5
既然我们不能通过改变新插入节点的颜色来维持红黑树的性质,那么就只好从原来的树结构入手了。
我们注意到新插入的节点的父亲是一个红节点,其叔叔也是一个红节点。那么假如我把它的父亲改成黑色,则恢复了性质5,可是从树根出发的黑高度还是不相等,干脆把它的叔叔也改成黑色吧!结果如下:
图-7
现在它满足红黑树所有的性质。好了,我们继续。
插入数字11和19的过程平淡无奇,不深入探讨,最终的树如图:
图-8
如果现在要插入数字10怎么办?它肯定会是11的左节点:
图-9
明显违背了性质5!难道依葫芦画瓢,把11和19都改成黑色?这样从树根出发的左边路径黑高度还是2,而右边两条路径的黑高度将变成了3,老办法失效了!
图-10
其实不然,改了新增节点的父亲和叔叔的颜色以后,右边路径黑高度全加一,但我们只要把它的爷爷改成红色不就又减去了多出来的黑高度吗?
图-11
如果你认真看到这里,我想你的潜意识一定告诉你---这里存在某种规律等着我们去发现。
让我们再仔细审视一下图-5
在生成树的过程中,我们已经两次遇到类似情况了,归纳一下,这个场景就是:新节点的父亲是红色,叔叔也是红色。
至于别的节点,我们大可不必关心,因为很显然,这个场景是原子的。
我们的处理办法是把7和15渲染成黑色,就像图-7那样,可是因为这是一个普遍适用的场景,所以要做一个扩展:假设在这个原子树的每个节点上还有别的分支。那么图-7就不能保证所有路径的黑高度相等了,即使把9改成红色也无济于事,因为9也许还有父节点,所以也许它的父节点又是红色,这就再次违反了性质5。我最喜欢的作家之一--柯南.道尔,曾说过:“历史就像车轮的辐条,每一根都终将再次转回来。”眼前的场景正是如此---我们设计的原子场景再次出现。
一个清晰的递归算法呈现在我们面前:
1. 新增节点渲染成红色;
2. 如果它的父亲是红色,则违反了性质5;
3. 如果它的叔叔也是红色,则通过同时修改其父亲和叔叔的颜色为黑色来恢复性质5;
4. 如果它的爷爷不是根节点,则有可能在另外的路径上再次违反性质5,于是我们把它的爷爷改成红色;
5. 可是如果他的太爷爷也是红色呢?很自然地,我们重新回到步骤2;
6. 不断循环,直到第二步满足就可以结束。
最后留给感兴趣的同学两个问题:
1. 如果新增节点的父亲是红色,但它的叔叔是黑色,该怎么办?(提示:使用旋转)
2. 有人说,下面这种场景,我设计的算法就失效了,真的吗?(粉色的6是新插入的节点)
相关推荐
理解并正确实现这些操作是构建高效红黑树的关键。《算法导论》这本书提供了详细的红黑树理论和实现指导,是学习红黑树的重要资源。通过阅读书中的代码和实践,可以深入理解红黑树的工作原理及其C语言实现细节。
同时,为了优化查找和插入操作,可以使用平衡二叉查找树(如AVL树或红黑树)作为辅助数据结构,存储悬挂路径。 在"SuffixTree"文件中,你应该能找到一个名为"UKK_vs2008cpp"的源文件,这个文件实现了上述的UKK算法...
- **红黑树**:在AVL树的基础上放宽了平衡条件,每个节点被赋予红或黑两种颜色,通过颜色规则和旋转操作保持大致平衡。 - **Splay树**:自适应平衡树,每次访问一个节点时将其移动到根位置,通过“伸展”操作来...
常见的平衡二叉树有AVL树和红黑树等。 1. **AVL树**:AVL树是最早提出的自平衡二叉查找树,由G. M. Adelson-Velsky和E. M. Landis于1962年提出。AVL树要求任何节点的两个子树的高度差不超过1,确保了搜索、插入和...
常见的平衡二叉树有AVL树和红黑树。 1. AVL树:AVL树是由G. M. Adelson-Velsky和E. M. Landis于1962年提出的,是最早的自平衡二叉查找树。它的每个节点的两个子树的高度差不超过1,从而保证了高度平衡。AVL树的插入...
常见的平衡二叉树有AVL树和红黑树。AVL树是最早被提出的自平衡二叉搜索树,它要求每个节点的两个子树高度差不超过1,通过旋转操作(左旋、右旋)保持平衡。红黑树则是一种更宽松的平衡策略,允许节点不平衡,但保证...
- **题目**:将下列字符序列EASYQUESTION依次插入到初始为空的红黑树(RB-tree)中,请画出最终得到的红黑树。 - **解析**:本题要求构建一棵红黑树,并遵循红黑树的五个基本性质。 4. **广义表的Head和Tail运算*...
为了避免这种情况,我们可以采用自平衡二叉排序树,如AVL树或红黑树,它们通过自动调整树的结构,确保树的高度保持在一个较小的常数范围内。 综上所述,二叉排序树是计算机科学中一个重要的数据结构,它在动态集合...
但需要注意的是,如果该节点在树中具有特定的排序或平衡条件(如AVL树或红黑树),修改可能会触发重新平衡。 6. **排班资料**: - 在实际应用中,树结构可以用于排班系统,比如员工排班。通过构建一颗员工树,每个...
为了解决这个问题,有自平衡二叉排序树,如AVL树和红黑树,通过特定的旋转操作保持平衡。 霍夫曼编码树(Huffman Coding Tree),又称为最优前缀编码,是数据压缩技术中的一种变长编码方法。霍夫曼编码通过构建一棵...
在数据结构和算法设计中,构建高效的数据结构如二叉堆、红黑树等;在操作系统的文件系统中,实现文件和目录的层次结构;在社交网络分析中,理解用户之间的关系网络等。 除了最小生成树,还有最大生成树的概念,特别...
为了保持良好的性能,可以采用平衡二叉排序树,如AVL树或红黑树,它们通过旋转等操作保证树的平衡。 5. **Win7环境下VS下多线程编程**: 在Windows环境下,Visual Studio提供了对多线程的支持。创建多线程可以使用...
常见的平衡二叉树有AVL树和红黑树等。 在这个课程设计中,我们可能需要实现以下内容: 1. **二叉链表存储结构**:在Java中,可以使用类来表示节点,每个节点包含键、值、左子节点和右子节点的引用。节点类将作为...
- **红黑树(Red-Black Tree)**:红黑树是一种自平衡二叉查找树,保证了插入、删除和查找操作的平均时间复杂度为O(log n),并保持近似平衡。 3. **其他问题解决方案**: 项目中可能还包括其他算法和数据结构的...
常见的树类型包括二叉树、平衡树(如AVL树和红黑树)、B树和B+树等。树的数据结构允许快速查找、插入和删除操作,其性能通常优于线性搜索。 例如,在编译器设计中,语法分析阶段会构建抽象语法树(AST),它反映了...
- **红黑树**:另一种自平衡二叉排序树,每个节点都有颜色属性(红色或黑色),并遵循特定规则以保证树的平衡,如每个叶子节点都是黑色,根节点是黑色,红色节点的子节点必须是黑色等。红黑树在插入和删除操作后,...
4. **平衡二叉树**:左右子树的高度差不超过1,如AVL树和红黑树。 5. **堆**:一种特殊类型的树,满足堆属性(最大堆中父节点的值大于或等于其子节点,最小堆反之)。 6. **B树**和**B+树**:用于数据库和文件系统,...
二叉树可以用于快速查找、排序和遍历数据,其查找效率相比线性搜索大大提高,尤其是平衡二叉树,如AVL树或红黑树,它们保证了最坏情况下的查找时间复杂度为O(log n)。 在处理IP地址时,我们通常将其转换为整数形式...
接下来,平衡二叉树是另一种重要的数据结构,如AVL树和红黑树。这类树保证了左右子树的高度差不超过1,从而确保查找、插入和删除操作的时间复杂度为O(log n)。在构建平衡二叉树时,我们需要维护平衡条件,例如在插入...
它不仅用于实现符号表,还在各种高级数据结构(如红黑树等)的基础构造中扮演着重要角色。 #### 二、基本概念与特性 二叉排序树是一种特殊的二叉树,它满足以下条件: 1. **左子树**:每个节点的左子树上所有节点的...