红黑树原理详解
- 格式:doc
- 大小:357.50 KB
- 文档页数:9
c++ 红黑树 map原理
C++中的红黑树是一种自平衡的二叉查找树,它常用于实现关联
容器中的map数据结构。
红黑树通过对节点进行着色和旋转操作来
保持树的平衡,从而确保在最坏情况下的查找、插入和删除操作的
时间复杂度为O(log n)。
红黑树的基本原理包括以下几点:
1. 节点着色,每个节点都被标记为红色或黑色,这些颜色标记
用于确保树的平衡。
2. 根节点和叶子节点,根节点是黑色的,叶子节点(NIL节点)是黑色的。
3. 红色节点规则,红色节点的子节点必须是黑色的,即不能出
现两个相连的红色节点。
4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色
节点。
这保证了树的黑色平衡。
在C++中,STL中的map数据结构通常使用红黑树来实现。
map 是一种关联容器,它提供了一种将键和值关联起来的方式。
当我们向map中插入新的键值对时,红黑树会自动进行调整以保持平衡。
查找、插入和删除操作都能在O(log n)的时间复杂度内完成,这使得map非常高效。
总之,红黑树是一种高效的自平衡二叉查找树,它通过节点着色和旋转操作来维持平衡。
在C++中,map数据结构通常使用红黑树来实现,从而提供了高效的插入、删除和查找操作。
这些原理和实现细节都是为了确保数据结构的高效性和稳定性。
数据结构中的平衡二叉树AVL树和红黑树的原理与实现在计算机科学中,数据结构是指一种组织和存储数据的方式,同时也是一种操作数据的方法。
其中,平衡二叉树是一种常用的数据结构,在平衡二叉树中,每个节点的左子树和右子树的高度最多相差1。
然而,平衡二叉树在插入和删除节点时可能会出现树结构不平衡的问题,这就引出了AVL树和红黑树的概念。
一、AVL树的原理与实现AVL树是由G. M. Adelson-Velsky和E. M. Landis于1962年提出的一种自平衡二叉查找树。
它通过在每个节点中添加一个平衡因子来维持树的平衡性。
平衡因子可以是-1、0或1,对应于左子树比右子树高、左右子树高度相等以及右子树比左子树高的情况。
在插入或删除节点时,AVL树会通过旋转操作来调整树的结构,以保持平衡因子的平衡。
旋转操作有四种情况:左旋、右旋、先左旋后右旋和先右旋后左旋。
通过这些旋转操作,AVL树能够保持树的平衡性,从而提高查找、插入和删除操作的效率。
AVL树的实现需要考虑节点的旋转、平衡因子的更新以及树的遍历等问题。
在节点的插入和删除操作中,需要对节点进行平衡处理,并更新相应的平衡因子。
在树的遍历中,可以使用中序遍历、前序遍历或后序遍历等方式来访问树的节点。
二、红黑树的原理与实现红黑树是由Rudolf Bayer在1972年提出的一种平衡二叉查找树。
它通过在每个节点中添加一个额外的属性表示节点的颜色(红色或黑色)来保持树的平衡性。
红黑树具有以下性质:1. 每个节点要么是红色,要么是黑色。
2. 根节点是黑色。
3. 每个叶子节点(NIL节点)是黑色。
4. 如果一个节点是红色,则它的两个子节点都是黑色。
5. 对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点。
通过这些性质,红黑树可以保持树的黑色平衡,在插入和删除节点时通过颜色变换和旋转操作来维持树的平衡性。
与AVL树相比,红黑树的调整操作较为简单,适用于动态插入和删除节点的情况。
红黑树系列,六篇文章于今日已经完成:1、教你透彻了解红黑树2、红黑树算法的实现与剖析3、红黑树的c源码实现与剖析4、一步一图一代码,R-B Tree5、红黑树插入和删除结点的全程演示6、红黑树的c++完整实现源码------------------------------一、红黑树的介绍先来看下算法导论对R-B Tree的介绍:红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red 或Black。
通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
前面说了,红黑树,是一种二叉查找树,既然是二叉查找树,那么它必满足二叉查找树的一般性质。
下面,在具体介绍红黑树之前,咱们先来了解下二叉查找树的一般性质:1.在一棵二叉查找树上,执行查找、插入、删除等操作,的时间复杂度为O(lgn)。
因为,一棵由n个结点,随机构造的二叉查找树的高度为lgn,所以顺理成章,一般操作的执行时间为O(lgn)。
//至于n个结点的二叉树高度为lgn的证明,可参考算法导论第12章二叉查找树第12.4节。
2.但若是一棵具有n个结点的线性链,则此些操作最坏情况运行时间为O(n)。
而红黑树,能保证在最坏情况下,基本的动态几何操作的时间均为O(lgn)。
ok,我们知道,红黑树上每个结点内含五个域,color,key,left,right,p。
如果相应的指针域没有,则设为NIL。
一般的,红黑树,满足以下性质,即只有满足以下全部性质的树,我们才称之为红黑树:1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。
(注:上述第3、5点性质中所说的NULL结点,包括wikipedia.算法导论上所认为的叶子结点即为树尾端的NIL指针,或者说NULL结点。
TreeMap底层实现和原理-红⿊树
TreeMap实现了SotredMap接⼝,它是有序的集合。
⽽且是⼀个红⿊树结构,每个key-value都作为⼀个红⿊树的节点。
如果在调⽤TreeMap的构造函数时没有指定⽐较器,则根据key执⾏⾃然排序,如果指定了⽐较器则按照⽐较器来进⾏排序。
红⿊树是⼀个更⾼效的检索⼆叉树,有如下特点:
1. 每个节点只能是红⾊或者⿊⾊
2. 根节点永远是⿊⾊的
3. 所有的叶⼦的⼦节点都是空节点,并且都是⿊⾊的
4. 每个红⾊节点的两个⼦节点都是⿊⾊的(不会有两个连续的红⾊节点)
5. 从任⼀个节点到其⼦树中每个叶⼦节点的路径都包含相同数量的⿊⾊节点(叶⼦节点到根节点的⿊⾊节点数量每条路径都相同)
关于红⿊树的节点插⼊操作,⾸先是改变新节点,新节点的⽗节点,祖⽗节点,和新节点的颜⾊,能在当前分⽀通过节点的旋转改变的,则通过此种操作,来满⾜红⿊书的特点。
如果当前相关节点的旋转解决不了红⿊树的冲突,则通过将红⾊的节点移动到根节点解决,最后在将根节点设置为⿊⾊
对于红⿊⼆叉树⽽⾔它主要包括三⼤基本操作:左旋、右旋、着⾊。
红黑树的例子
红黑树是一种自平衡二叉搜索树,它具有以下特性:
1. 节点为红色或者黑色;
2. 根节点为黑色;
3. 叶子节点为黑色(叶子节点指的是NULL节点);
4. 如果一个节点为红色,那么它的子节点必须是黑色;
5. 从任何一个节点到它的每个叶子节点的所有路径都包含相同数目的
黑色节点。
下面是一棵红黑树的例子:
```
11B
/ \
7R 15B
/ \ / \
5B 9B 13R 20R
/ \
8R 10R
```
解释如下:
- 根节点是11,颜色为黑色。
- 左子树的根节点是7,颜色为红色。
它的左子树节点是5,颜色为黑色,右子树节点是9,颜色为黑色。
9的左子树为节点8,颜色为红色,右子树节点是10,颜色为红色。
- 右子树的根节点是15,颜色为黑色。
它的左子树节点是13,颜色为
红色,右子树节点是20,颜色为红色。
红黑树的特性可以保证在进行插入、删除等操作时,树的深度始
终不会超过2倍,所以其操作效率非常高。
c++中map的实现原理
C++中的map是通过红黑树(Red-Black Tree)实现的。
红黑树是一种自平衡二叉搜索树,它具有以下特性:
1. 每个节点都有一个颜色,要么是红色,要么是黑色。
2. 根节点是黑色的。
3. 叶节点(即空节点)是黑色的。
4. 如果一个节点是红色的,那么它的两个子节点都是黑色的。
5. 对于任意一个节点,从该节点到其子孙节点的所有路径上的黑色节点数量是相同的。
红黑树的特性保证了它的平衡性,使得查找、插入和删除操作的时间复杂度都是O(log n)。
在C++中,map是使用红黑树实现的。
红黑树通过节点的key 值来进行排序和查找。
每个节点包含一个key和一个value,通过key来进行查找和插入操作。
当进行插入操作时,先按照红黑树的插入规则将节点插入到正确的位置上,然后通过旋转和重新染色等操作来保持树的平衡性。
当进行查找操作时,按照红黑树的查找规则进行查找。
查找操作的时间复杂度为O(log n)。
总结来说,C++中的map通过红黑树实现,利用红黑树的平衡性和查找特性实现了高效的插入和查找操作。
红黑树算法原理与实现红黑树是一种自平衡二叉查找树,它能够保证查找、插入和删除操作最坏情况下的时间复杂度都为O(log n),是一种十分高效的数据结构。
本文将对红黑树算法的原理和实现进行介绍,帮助读者深入了解红黑树的运作流程和应用场景。
一、红黑树的定义和性质红黑树和其他的自平衡二叉查找树(如AVL树)一样,能够自动调整树的结构以保证平衡,并且能够保持树中每个节点的黑高相等。
下面是红黑树的具体定义:(1)每个节点要么是红色,要么是黑色。
(2)根节点是黑色。
(3)每个叶子节点(NIL节点,空节点)都是黑色的。
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)任意一个节点到每个叶子节点所经过的黑色节点数都相同。
这些性质确保了红黑树的平衡,在插入和删除节点时能够自动平衡而不需要人工干预,从而保证了树的性能。
二、红黑树的基本操作红黑树的插入和删除操作是它最为关键和难点的部分,下面我们将针对这两个操作进行介绍。
(1)插入操作插入节点时,首先按照二叉查找树的方式将新节点插入到树中。
接下来需要进行的操作是将节点的颜色进行调整,保证该节点符合红黑树的五大性质。
如果插入的节点不满足性质(4),需要执行进行一系列颜色调整和旋转操作,使得节点重新满足红黑树性质。
一般情况下,情况分为两种:(a)情况1:插入的节点为根节点此时只需要将节点的颜色设置为黑色即可。
(b)情况2:插入的节点的父节点为红色此时需要进行一系列的旋转和颜色调整操作。
可以分为以下三种情况:①插入节点的叔叔节点是红色的,此时需要进行颜色调整和旋转。
②插入节点的叔叔节点是黑色的,并且插入节点为父节点的右子节点,此时需要进行左旋操作。
③插入节点的叔叔节点是黑色的,并且插入节点为父节点的左子节点,此时需要进行颜色调整、右旋操作。
(2)删除操作删除节点时,首先按照二叉查找树的方式删除节点。
接着需要对树进行自平衡操作,使之重新满足红黑树性质。
与插入操作相比,删除操作需要考虑更多的情况。
java红黑树的原理Java红黑树(Red-BlackTree)是一种自平衡二叉查找树,其中任何节点的左子树都小于它的父节点,右子树都大于它的父节点。
它可以被用来存储有序的键值对,并具有高效的查找、插入和删除操作性能。
它被广泛用于编程语言编程,例如Java。
Java红黑树的概念由Leo J. Guibas和Robert Sedgewick在1978年的一篇论文中提出。
它是一种基于二叉查找树的红黑树结构,它具有自平衡特性,表现出比二叉查找树更高的性能。
在维护红黑树树结构方面,实现者需要满足两个基本要求:(1)红黑树中的所有节点必须是黑色或红色。
(2)根节点必须是黑色。
(3)每个叶节点(最后的空节点)都是黑色的。
(4)如果一个节点是红色的,那么它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑色节点。
红黑树的这些特性可以使它成为一种高效的数据结构。
它们能够确保树总是处于“平衡”状态,这意味着所有叶节点到根节点的距离都相同,搜索时间复杂度也能得到最优化。
Java红黑树的实现有多种方式,其中最常见的是经典的红黑树,它使用指针来存储节点之间的关系,并且为每个节点设置颜色位来指示其是红节点还是黑节点。
另一种实现方式是使用链表存储红黑树,也就是使用孩子兄弟法或CS树。
在这种实现方式中,每个节点都有两个指针,一个指向其左孩子,另一个指向其右孩子,同时增加一个指向其兄弟节点的指针。
这种实现方式会更加空间高效,因为它只需要使用一个孩子节点来存储其兄弟节点。
除了经典红黑树和链表红黑树外,还有另一种称为AA树的红黑树实现。
AA树是一种平衡的多叉查找树,它维护着若干红黑树的平衡,以此提高查找性能。
在AA树中,每个节点都有一个表示节点的红黑树状态的标志位,用于检测其是否满足红黑树的约束条件。
Java红黑树的优点在于它的查找、插入和删除操作性能优于二叉查找树,它能更快速地处理数据。
它还能更有效地存储键值对,因为它们节点中附带了更多的数据,尤其是颜色位。
红⿊树(R-BTree)R-B Tree简介R-B Tree,全称是Red-Black Tree,⼜称为“红⿊树”,它⼀种特殊的⼆叉查找树。
红⿊树的每个节点上都有存储位表⽰节点的颜⾊,可以是红(Red)或⿊(Black)。
红⿊树的特性:(1)每个节点或者是⿊⾊,或者是红⾊。
(2)根节点是⿊⾊。
(3)每个叶⼦节点(NIL)是⿊⾊。
[注意:这⾥叶⼦节点,是指为空(NIL或NULL)的叶⼦节点!](4)如果⼀个节点是红⾊的,则它的⼦节点必须是⿊⾊的。
(5)从⼀个节点到该节点的⼦孙节点的所有路径上包含相同数⽬的⿊节点。
注意:(01) 特性(3)中的叶⼦节点,是只为空(NIL或null)的节点。
(02) 特性(5),确保没有⼀条路径会⽐其他路径长出俩倍。
因⽽,红⿊树是相对是接近平衡的⼆叉树。
红⿊树⽰意图如下:红⿊树的应⽤红⿊树的应⽤⽐较⼴泛,主要是⽤它来存储有序的数据,它的时间复杂度是O(lgn),效率⾮常之⾼。
例如,Java集合中的和,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红⿊树去实现的。
红⿊树的时间复杂度和相关证明红⿊树的时间复杂度为: O(lgn)下⾯通过“数学归纳法”对红⿊树的时间复杂度进⾏证明。
定理:⼀棵含有n个节点的红⿊树的⾼度⾄多为2log(n+1).证明:"⼀棵含有n个节点的红⿊树的⾼度⾄多为2log(n+1)" 的逆否命题是 "⾼度为h的红⿊树,它的包含的内节点个数⾄少为 2h/2-1个"。
我们只需要证明逆否命题,即可证明原命题为真;即只需证明"⾼度为h的红⿊树,它的包含的内节点个数⾄少为 2h/2-1个"。
从某个节点x出发(不包括该节点)到达⼀个叶节点的任意⼀条路径上,⿊⾊节点的个数称为该节点的⿊⾼度(x's black height),记为bh(x)。
关于bh(x)有两点需要说明:第1点:根据红⿊树的"特性(5) ,即从⼀个节点到该节点的⼦孙节点的所有路径上包含相同数⽬的⿊节点"可知,从节点x出发到达的所有的叶节点具有相同数⽬的⿊节点。
java treeset原理Java中的TreeSet是一个基于红黑树实现的有序集合,具有自动排序和去重功能。
它是Set接口的实现类之一,继承自AbstractSet 类,实现了NavigableSet接口。
本文将深入介绍Java TreeSet的原理,包括红黑树、TreeSet的实现、遍历方式和常用操作等内容。
1. 红黑树红黑树是一种自平衡二叉查找树,它的每个节点都有一个颜色属性,可以是红色或黑色。
这种树具有以下特性:1. 每个节点要么是黑色,要么是红色。
2. 根节点是黑色。
3. 每个叶子节点(NIL节点,空节点)是黑色。
4. 如果一个节点是红色,那么它的子节点必须是黑色。
5. 从任意一个节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。
这些特性确保了红黑树的平衡性和搜索效率。
插入、删除节点时,需要对树进行旋转和改变颜色等操作,以维持平衡。
2. TreeSet的实现Java TreeSet是基于红黑树实现的有序集合,它的元素按照自然顺序或者指定的比较器顺序进行排序。
TreeSet中的元素必须是可比较的,即实现了Comparable接口或者传入了Comparator比较器。
TreeSet的底层数据结构是红黑树,它的节点类是TreeMap中的Entry类,包含三个属性:key、value和color。
TreeSet的实现主要涉及以下几个方法:1. add(E e):向TreeSet中添加元素e。
首先通过比较器或者自然顺序找到要插入的位置,然后将元素包装成Entry对象,插入红黑树中,最后进行平衡操作。
2. remove(Object o):从TreeSet中删除元素o。
首先通过比较器或者自然顺序找到要删除的节点,然后进行删除操作,最后进行平衡操作。
3. clear():清空TreeSet中的所有元素。
4. iterator():返回一个迭代器,按照自然顺序或者指定的比较器顺序遍历元素。
5. size():返回TreeSet中元素的个数。
红⿊树(平衡操作详解)摘⾃ https:///qq_26323323/article/details/796432161.红⿊树红⿊树本⾝也是⼀种⼆叉树,只不过是⼀种⽐较特殊的⼆叉树⼆叉树如果插⼊的数值是有序时,⼆叉树就是⾮平衡的,基本跟链表类似了(时间复杂度O(N))针对这种情况,就产⽣了红⿊树,这种树在插⼊的过程中,会通过⼀系列的⽅式来保持树的平衡,使其时间复杂度⼀直维持在O(logN) 2.红⿊树规则* 每⼀个节点不是⿊⾊就是红⾊* 根节点总是⿊⾊的* 如果节点是红⾊的,则它的⼦节点必须是⿊⾊的(反之则不⼀定)* 从根到叶节点的每条路径,包含的⿊⾊节点数⽬必须相同3.红⿊树修正违规操作简介红⿊树之所以能够保持平衡,是因为严格遵守了上述规则在插⼊的过程中,如果某节点违反了以上规则,则需要进⾏修正,修正的⽅式包括:改变颜⾊、旋转1)术语为了平衡⼀棵树,需要对某些节点进⾏重新排列,将⼀些节点上升,将⼀些节点下降,以此来帮助树平衡。
切记:在树平衡操作的过程中不能破坏⼆叉树的特点(⼀个节点的左⼦节点的关键字值⼩于这个节点,右⼦节点的关键字值⼤于或等于这个⽗节点)旋转之前先了解⼀些基本概念:* 外侧⼦孙12在18的左侧,18在25的左侧,它们的相对⽗节点位置相同,则称新插⼊的节点12为外侧⼦孙节点38在35的右侧,35在25的右侧,它们的相对⽗节点位置相同,则称新插⼊的节点38为外侧⼦孙节点* 内侧⼦孙22在18的右侧,18在25的左侧,它们的相对⽗节点位置不同,则称新插⼊的节点22为内侧⼦孙节点30在35的左侧,35在25的右侧,它们的相对⽗节点位置不同,则称新插⼊的节点30为内侧⼦孙节点可以看到,在插⼊新节点之前的树都是平衡的,但是插⼊新节点之后就会违反规则3,故需要对这些树进⾏修正(看到⼦节点和⽗节点都是红⾊的,就要想到使⽤旋转来保持树的平衡)* 右旋转当以35为顶端元素进⾏右旋转时,需要注意:该顶端元素必须有⼀个左⼦元素右旋结果如下:35下移,30上移到35的位置,20位置不变,依旧是30的左⼦元素* 左旋转当以30为顶端元素进⾏左旋转时,需要注意:该顶端元素必须有⼀个右⼦节点左旋结果如下:30下移到左侧,35上移到30的位置,45位置不变,依旧是35的右⼦节点2)颜⾊变换场景:当在插⼊的过程中遇到⼀个⿊⾊节点下有两个红⾊节点,则需要进⾏颜⾊变换⽰例:当前场景下,是符合红⿊树规则的,如果此时再插⼊⼀个节点,按照规则3,则新节点只能是⿊⾊的,但是这样就会违反规则4,所以对现有节点进⾏变⾊* 把25、75两个⼦节点变⾊为⿊⾊* 再新插⼊节点为红⾊即可操作完成之后的树为3)外侧⼦孙的旋转平衡术针对上述这种情况,找到新插⼊节点12的祖⽗节点25,然后以25为顶端,进⾏右旋转上述这种情况,找到新插⼊节点38的祖⽗节点25,以25为顶端,进⾏左旋转4)内侧⼦孙的旋转平衡术上述这种情况,找到新插⼊节点22的⽗节点18,然后以18位顶端,进⾏左旋转,旋转后结果如下然后以22的⽗节点25进⾏右旋转,旋转结果如下再修改22和18、25节点的颜⾊,即保持树的正确总结:外侧⼦孙和内侧⼦孙的平衡都是需要进⾏旋转,不同的是外侧⼦孙只需要进⾏⼀次旋转即可,⽽内侧⼦孙则需要进⾏两次旋转,第⼀次旋转后变成外侧⼦孙的模式,再根据外侧⼦孙的⽅式来进⾏平衡即可3.插⼊新节点红⿊树插⼊新节点的过程中,会遇到违背红⿊树规则的情况,为了保持树的平衡,则需要使⽤以上的⼏种⽅式来保持树平衡下⾯介绍下以下⼏种插⼊新节点过程中遇到的问题及其解决⽅案:1)在下⾏过程中发现⿊⾊节点下有两个红⾊⼦节点为什么这种情况是会违背红⿊树规则呢?因为根据规则3,红⾊节点下的⼦节点必须为⿊⾊节点,那么插⼊⿊⾊⼦节点后就会违背规则4,所以碰到这种情况,需要对这三个节点进⾏颜⾊变换当再插⼊12节点时,就会与18节点产⽣颜⾊冲突,所以需要对18 25 30三个节点进⾏颜⾊变换,变换成如下,再插⼊12节点即可2)插⼊节点后发⽣颜⾊冲突接着上个树来继续添加节点6发现6节点和12节点都是红⾊,违背规则3,则根据上述外侧⼦孙节点处理⽅案对6的祖⽗节点18进⾏右转此时12和25节点都是红⾊,同样违背规则3,对12的祖⽗节点50节点进⾏右转再对上述节点颜⾊错误的进⾏颜⾊变换,25、12、6节点都变成⿊⾊,即变成⼀颗复合规则的红⿊树3)插⼊过程中发⽣颜⾊冲突以上节点属于平衡状态,此时如果再插⼊节点3,则需要对12、6、18节点进⾏颜⾊变换操作此时12和25节点⼜发⽣了颜⾊冲突,则需要找到12节点的祖⽗节点50,然后以50节点进⾏右旋转再改变25和12的颜⾊为⿊⾊,以符合规则2和4此时已经平衡,再插⼊节点3即可,结果如下总结:针对于红红冲突,需要找到合适的祖⽗节点,然后进⾏旋转,再进⾏节点颜⾊变换,则就可以保持树的平衡⾄于代码实现,可以参考TreeMap参考:Java数据结构和算法(第⼆版)。
红黑树(摘自)满足下面几个条件的二叉搜索树,称为红黑树:1. 任何一个节点都被着色――红色或是黑色。
2. 根节点是黑色的。
3. 所有的NIL节点都看成黑色(NIL节点是就是一个假想的或是无实在意义的节点,所有应该指向NULL的指针,都看成指向了NIL节点。
包括叶节点的子节点指针或是根节点的父指针)。
4. 如果一个节点是红色的,那么它的子节点一定是黑色的。
5. 对于任何一个节点而言,从该节点到它的子孙节点中的NIL节点路径中,所包含的黑节点个数相同。
黑高度的定义:从任何一个节点,向下到底部的路径中,包含的黑节点的个数,称为这个节点的黑高度。
从红黑树的第5条性质可以看出,黑高度是唯一的、确定的。
只要同时满足红黑树的这些条件,就一定会有“红黑树可以保证任何两条从根部到树叶的路径节点个数相差不超过2倍”这个平衡的性质。
我们可以假设,如果存在两条路径L和S,L比S长两倍以上(S路径上有n个节点,L上有大于2n个节点)。
可知,S的黑高度最大只可能是n,那么根据第5条性质,L的黑高度也大也只可能是n,也就是,L路径上一定有超过n个红色节点(因为节点不是黑的就必定是红的)。
所以,肯定会有两个以上的红色节点是相邻的。
这就与第4个条件矛盾了。
所以,红黑树可以保证任何两条从根部到树叶的路径节点个数相差不超过2倍。
红黑树的高度h<2lg(n+1)(这个在《算法导论》节中有证明)。
也就是说,红黑树的操作的时间复杂度是O(lgn)的。
二叉搜索树的操作时间复杂度,取决于树高h,因此,我们当然就希望h尽量地小以提高操作的效率。
从直观上就可以发现,二叉搜索树各子树的规模越平均,它的高度就会越小。
所以在应用中,一般都会将二叉搜索树实现成一种平衡树,以保证最差时间复杂度为O(lgn)。
红黑树就是其中的一种,应用得很广泛(SGI STL的set和map就是基于红黑树来实现,Linux内核中也用到这个数据结构)红黑树是二叉搜索树的一种。
红⿊树详解前⾔红⿊树的起源,⾃然是⼆叉查找树了,这种树结构从根节点开始,左⼦节点⼩于它,右⼦节点⼤于它。
每个节点都符合这个特性,所以易于查找,是⼀种很好的数据结构。
但是它有⼀个问题,就是容易偏向某⼀侧,这样就像⼀个链表结构了,失去了树结构的优点,查找时间会变坏。
所以我们都希望树结构都是矮矮胖胖的,像这样:⽽不是像这样:在这种需求下,平衡树(AVL)的概念就应运⽽⽣了。
红⿊树就是⼀种平衡树,它可以保证⼆叉树基本符合矮矮胖胖的结构,但是理解红⿊树之前,必须先了解另⼀种树,叫2-3树,红⿊树背后的逻辑就是它。
好吧来看2-3树吧。
2-3树是⼆叉查找树的变种,树中的2和3代表两种节点,以下表⽰为2-节点和3-节点。
2-节点即普通节点:包含⼀个元素,两条⼦链接。
3-节点则是扩充版,包含2个元素和三条链接:两个元素A、B,左边的链接指向⼩于A的节点,中间的链接指向介于A、B值之间的节点,右边的链接指向⼤于B的节点 2-节点: 3-节点:在这两种节点的配合下,2-3树可以保证在插⼊值过程中,任意叶⼦节点到根节点的距离都是相同的。
完全实现了矮胖矮胖的⽬标。
怎么配合的呢,下⾯来看2-3树的构造过程。
所谓构造,就是从零开始⼀个节点⼀个节点的插⼊。
在⼆叉查找树中,插⼊过程从根节点开始⽐较,⼩于节点值往右继续与左⼦节点⽐,⼤于则继续与右⼦节点⽐,直到某节点左或右⼦节点为空,把值插⼊进去。
这样⽆法避免偏向问题。
在2-3树中,插⼊的过程是这样的。
如果将值插⼊⼀个2-节点,则将2-节点扩充为⼀个3-节点。
如果将值插⼊⼀个3-节点,分为以下⼏种情况。
(1).3-节点没有⽗节点,即整棵树就只有它⼀个三节点。
此时,将3-节点扩充为⼀个4-节点,即包含三个元素的节点,然后将其分解,变成⼀棵⼆叉树。
此时⼆叉树依然保持平衡。
(2).3-节点有⼀个2-节点的⽗节点,此时的操作是,3-节点扩充为4-节点,然后分解4-节点,然后将分解后的新树的⽗节点融⼊到2-节点的⽗节点中去。
数据结构中的红黑树原理及应用场景红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,它是通过对普通的二叉搜索树的节点进行染色来实现自平衡的。
红黑树的性质保证了其操作的时间复杂度能够被控制在O(log n)。
下面将介绍红黑树的原理、性质以及应用场景。
一、红黑树的原理红黑树是由Rudolf Bayer于1972年提出的,其原理基于二叉搜索树(Binary Search Tree,BST)进行改进。
在BST中,所有节点的键值小于左子树的节点,大于右子树的节点。
红黑树在此基础上引入了五个性质,以达到自平衡的目的:1.每个节点要么是红色,要么是黑色。
2.根节点是黑色。
3.每个叶子节点(NIL)都是黑色。
4.如果一个节点是红色的,那么它的两个子节点都是黑色的。
5.对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数量的黑色节点。
通过这些规则,红黑树的高度最多是2倍的log(n+1),其中n是红黑树的节点数量。
这使得红黑树的搜索、插入和删除操作的时间复杂度都能控制在O(log n)。
二、红黑树的性质1.根节点是黑色的。
2.所有的叶子节点(NIL节点)都是黑色的。
3.如果一个节点是红色的,那么它的两个子节点都是黑色的。
4.从任一节点到其每个叶子节点的所有简单路径都包含相同数目的黑色节点。
5.每个节点的左右子树都是红黑树。
红黑树的这些性质使得红黑树在很多应用场景中表现出色,并成为一种非常重要的数据结构。
三、红黑树的应用场景1. C++的STL库中的map和set就是使用红黑树作为底层的数据结构。
这是因为红黑树具有快速查找和插入的特性,同时能够保持数据有序。
2.数据库中的索引结构。
在数据库中,红黑树被广泛用作索引结构,以便快速查找数据。
例如,MySQL数据库中的InnoDB存储引擎,就使用了红黑树来管理主键索引和辅助索引。
3. C++标准模板库(STL)中的set和multiset容器,用于有序集合的存储和查找。
一种高效的二叉查找树——红黑树1. 红黑树的定义查找是计算机信息管理的最常见操作。
普通的二叉查找树的查找效率与树的深度有关。
当它的左右子树深度相差较大时,查找效率就与单链表差不多。
为提高查找效率,必须设法使二叉查找树的左、右子树的深度保持平衡。
红黑查找树就是一种平衡的二叉查找树。
定义一棵二叉查找树如果满足下列性质,则称为红黑树:(1) 每个结点或是红色的,或是黑色的(增加一位表示颜色的存储位);(2) 每个空结点NIL是黑色的;(3) 如果一个结点是红色的,则它的儿子应是黑色的;(4) 从任何一给定结点到其子孙叶结点每条简单路径上都具有相同个数的黑结点。
图1给出了一棵红黑树的例子,其中黑结点用方框表示,红结点用椭圆表示。
2、例:3、推论:若一棵二叉查找树是红黑树,则它的任一子树也必为红黑树。
4、红黑树的生成可以从空树开始,通过逐步插入结点来生成一棵红黑树。
向一棵红黑树T中插入一个新结点x的过程如下:先按普通二叉查找树那样,在T中插入结点x,并将x着为红色。
为保证红黑树的的性质要求得以继续保持,一般需随时进行调整。
具体可分为以下几种情况:(1) 若x的父结点是黑色的,则插入过程结束。
(2) 若x的父结点是红色的,而x的叔叔结点y是黑色的,则需按图2或图3方式进行调整,其中子树a , 6 , 丫, 8每一棵都有一个黑根。
(3) 若x的结点是红色的,而x的叔叔结点y也是红色的,则需按图4或图5方式进行调整。
对插入结点x在其祖父结点的右子树中的情况,不难给出调整规则。
将x的祖父结点作为新的x,继续按情况(1)、(2)、(3) 处理。
由于需要判定插入结点的父结点及叔叔结点的红与黑,为便于操作,红黑树的结点就具有如下结构:Ichild parent data tag rchild其中Ichild、parent、rchild分别是指向左儿子、父结点和右儿子的指针,tag是红黑标志位,data是数据域2 红黑树的查找效率为方便起见,我们把红黑树的叶结点(NIL )称为外部结点,带有关键字的结点称为内部结点。
红黑树(Red-Black Tree)是二叉搜索树(Binary Search Tree)的一种改进。
我们知道二叉搜索树在最坏的情况下可能会变成一个链表(当所有节点按从小到大的顺序依次插入后)。
而红黑树在每一次插入或删除节点之后都会花O(log N)的时间来对树的结构作修改,以保持树的平衡。
也就是说,红黑树的查找方法与二叉搜索树完全一样;插入和删除节点的的方法前半部分节与二叉搜索树完全一样,而后半部分添加了一些修改树的结构的操作。
红黑树的每个节点上的属性除了有一个key、3个指针:parent、lchild、rchild 以外,还多了一个属性:color。
它只能是两种颜色:红或黑。
而红黑树除了具有二叉搜索树的所有性质之外,还具有以下4点性质:1. 根节点是黑色的。
2. 空节点是黑色的(红黑树中,根节点的parent以及所有叶节点lchild、rchild 都不指向NULL,而是指向一个定义好的空节点)。
3. 红色节点的父、左子、右子节点都是黑色。
4. 在任何一棵子树中,每一条从根节点向下走到空节点的路径上包含的黑色节点数量都相同。
如下图就是一棵红黑树:有了这几条规则,就可以保证整棵树的平衡,也就等于保证了搜索的时间为O (log N)。
但是在插入、删除节点后,就有可能破坏了红黑树的性质。
所以我们要做一些操作来把整棵树修补好。
下面我就来介绍一下。
首先有一个预备知识,那就是节点的Left-Rotate和Right-Rotate操作。
所谓Left-Rotate(x)就是把节点x向左下方向移动一格,然后让x原来的右子节点代替它的位置。
而Right-Rotate当然就是把Left-Rotate左、右互反一下。
如下图:注意,Left-Rotate(x)后,x的右子树变成了原来y的左子树,Right-Rotate反之。
思考一下,这样一次变换后,仍然满足二叉搜索树的性质。
在红黑树的插入、删除中,要用到很多Left-Rotate和Right-Rotate操作。
平衡二叉树AVL树与红黑树平衡二叉树(AVL树)与红黑树概述:平衡二叉树与红黑树是常见的自平衡二叉搜索树,用于解决传统二叉搜索树在频繁插入、删除等操作下出现的性能问题。
本文将介绍平衡二叉树(AVL树)与红黑树的原理、特点以及应用场景。
一、平衡二叉树(AVL树):1.1 原理:平衡二叉树,又称AVL树,是一种特殊的二叉搜索树。
它通过在每个节点上记录一个平衡因子来保持树的平衡。
平衡因子为左子树的高度减去右子树的高度,平衡因子的绝对值不超过1。
当平衡二叉树失去平衡时,通过旋转操作来恢复平衡。
1.2 特点:1) 每个节点的平衡因子只能为-1、0、1;2) 左右子树的高度差不超过1;3) 插入、删除操作可能导致平衡因子失衡,需要进行旋转操作;4) 查询、插入、删除时间复杂度为O(logn)。
1.3 应用场景:平衡二叉树适用于插入、删除频繁的情况下的搜索、排序操作。
由于其严格的平衡性,适合用于对数据集的高效维护和查找。
二、红黑树:2.1 原理:红黑树是另一种自平衡的二叉搜索树结构。
每个节点都有一个颜色属性,红色或黑色,用来确保树的平衡。
红黑树通过一些额外的性质来保持平衡,包括:1) 节点是红色或黑色;2) 根节点是黑色;3) 所有叶子节点(NULL节点)是黑色;4) 不能有相邻的两个红色节点;5) 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
2.2 特点:1) 相对于平衡二叉树,红黑树的平衡性更宽松,插入、删除操作后的调整更灵活;2) 查询、插入、删除时间复杂度为O(logn);3) 可用于范围查询和有序输出。
2.3 应用场景:红黑树广泛应用于各种编程语言的标准库中,如C++的STL中的map、set等数据结构。
其平衡性和高效性使其在高性能的存储系统中得到广泛应用。
三、平衡二叉树(AVL树)与红黑树的比较:在性能方面,平衡二叉树(AVL树)和红黑树的查询、插入、删除操作的时间复杂度都为O(logn)。
红黑树原理详解(上)前言:之所以要写这篇文章,第一个目的是为了各位朋友在查看我写的源代码之前有一个可以理解理论的文章因为红黑树还是有点难的,如果不想搞懂理论,而直接看代码,那绝对是云里雾里,不知所云。
第二个目的是我觉得网上虽然后不少我文章也在讲,但是我就是理解不上有点困难,在我参考了很多文章之后,认真阅读才慢慢摸透了其中的原理,所以我想用自己的方式来表达,希望有助于各位的朋友理解。
你可以在这里获得配套源代码红黑树由来:他是在1972年由Rudolf Bayer发明的,他称之为“对称二叉B树”,它现代的名字是Leo J. Guibas和 Robert Sedgewick 于1978年写的一篇论文中获得的。
它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
红黑树性质:1. 每个结点或红或黑。
2. 根结点为黑色。
3. 每个叶结点(实际上就是NULL指针)都是黑色的。
4. 如果一个结点是红色的,那么它的周边3个节点都是黑色的。
5. 对于每个结点,从该结点到其所有子孙叶结点的路径中所包含的黑色结点个数都一样。
讨论的前提:1,我们只讨论往树的左边和从树的左边删除的情况,与之对称的情况一样。
2,假设我们要删除一个元素的方法都是采取删除后继节点,而非前驱节点。
3,NL或全黑表示黑空节点,也可以不用画出。
4,“=>”这个符号我们用来表示“变成”的意思。
一.插入当红黑树中没有节点的时候,新节点直接涂黑就可以了。
当树中已有节点,我们就将新节点涂红,并且底下挂两个黑空节点。
1.1 新节点的父亲为黑色这种情况最简单,只接插入将新节点可以了,不会出现红色警戒。
1.2 新节点的父亲为红色这种情况出现红色警戒,并且通过红色的父亲,我们可以推出一定有一个黑色的父,并且父亲不可能为树根(树根必须为黑)。
这种情况需要修复。
1.2.1 新节点的叔叔是红色。
(红叔)图1.2.1-1图1.2.1-2注解:在这种情况下,我们可以通过这样的方式来修复红黑树的性质。
因为遇到红色警戒所以我们首先可以想到的就是将父亲变成黑色,但这样祖父的左子树的黑高就增加了,为了达到祖父的平衡,我们红叔变成黑色,这样祖父就平衡了。
但是整个祖父这颗树的高度增高了,所以再此将祖父的颜色变成红色来保持祖父这颗树的高度不变。
因为祖父变成了红色,因此往上遍历。
方法:父=>黑;叔=>黑;祖=>红;往上遍历;1.2.2 新节点的叔叔是黑色(黑叔)图1.2.2-1图1.2.2-2注解:首先可以说明的是,这种情况下我们都可以通过改变颜色和旋转的方式到达平衡,并且不再出现红色警戒,因为无需往上遍历。
图1.2.2-1:首先我们将红父变成黑色,祖父变成红色,然后对祖父进行右旋转。
这样我们可以看到,整颗树的黑高不变,并且这颗树的左右子树也达到平衡。
新的树根为黑色。
因此无需往上遍历。
方法:图1.2.2-1 父=>黑;祖=>红;祖父右旋转;图1.2.2-2 新=>黑;祖=>红;父左旋转;祖右旋转;插入我们就算做完了,与之对称的右边插入的情况完全一样,请自己下来分析;一.删除删除是比较经典但也是最困难的一件事了,所以我们必须一步一步地理解。
为了中途思想不混乱,请始终记住一点,下面我们删除的节点都已经表示的是实际要删除的后继节点了。
因此可以得出一下结论。
首先,可以肯定的是我们要删除的节点要么是红色,要么是黑色。
其次,既然我们要删除的结点是后继节点,那么要删除的节点的左子树一定为空。
所以当删除的节点为黑色时只剩下两种情况。
最后,如果删除的节点为红色,那么它必为叶子节点。
(自己好好想象为什么)。
请在看下面的内容前先牢记上面的结论,这样更加方便让你理解下面的知识。
a:当删除的节点为黑色时删黑a 删黑bb:当删除的节点为红色时上面的几附图都是很简单的。
因为你可以将空节点去掉不看。
所就形成了要删除的节点要么有一个右孩子,要么为叶子节点。
下面我们就开始真正的删除操作了。
2.1 删除红色节点注解:这种情况是最简单的,因为根据上面的结论我们可以推出子节点一定为空,也就是说删除的红色节点为叶子节点。
只需将这个旧节点的右孩子付给父亲的左孩子就可以了,高度不变。
方法:略2.2 删除黑色节点遇到黑色节点情况就将变得复杂起来,因此我们一定要慢慢来,仔细分析。
2.2.1当删除的节点有一个红色子孩子注解:这种情况其实就是上面我们分析的三种情况之一,如图"删黑b"。
这种情况是非常简单的,只需将旧节点的右孩子取代旧节点,并将子孩子的颜色变为黑色,树平衡;方法:子取代旧;子=>黑;2.2.2当删除的节点无左右孩子这种情况其实就是上面我们分析的三种情况之一,如图"删黑a"。
我们推出子节点一定为空,请务必记住这点,不然在后面你将很容易被混淆,父亲的颜色我们标记为绿色,是表示,父亲的颜色可为红或黑。
黄色的子节点其实就是一个黑空节点,这样方便后面分析。
a:红兄注解:当我们删除的节点拥有一个红色的兄弟时,这种情况还相对比较简单,因为兄弟为黑色,我们可以推出父亲一定为黑色。
因为父节点的左树高度减一,所以我们可以通过左旋转父节点,来将节点1旋转到左边来恢复左边的高度。
然后将父变成红,兄变成黑。
这样整颗树的高度不变,父节点也平衡记住子节点为空所以可以删除看,这样便于理解。
其实我们也可以推出1,2为空,但这里没有必要。
方法:父=>红;兄=>黑;左旋转父节点;红黑树原理详解(下)b :黑兄遇到黑兄就又麻烦了,我们又必须引入要删除的节点的侄子了。
所以我们这里再次细分为b1: 黑兄双黑侄 b2: 黑兄左黑侄右红侄 b3: 黑兄右黑侄左红侄。
可能你会问b4呢,双红侄的情况呢?其实双红侄的情况同属于b2,b3的情况,所以可以默认用 b2,b3其中一种情况来处理就可以了。
现在我们开始了b1黑兄双黑侄注解:我们首先可以肯定的是父节点的左子树高度减一了,所以我们必须想方设法来弥补这个缺陷。
如果我们把父节点的右子树高度也减一(兄变成红色)那么父节点这颗树就可以保持平衡了,但整颗树的高度减一,所以我们可以判断,如果父亲是红色,那么我们可以通过把父亲变成黑色来弥补这一缺陷。
但如果父亲是黑色呢,既然遇到到黑色了我们就只好往上遍历了。
方法:兄=>红;子=黑;红父=>黑;往上遍历(黑父);补充:其实子节点就是空节点,没有必要变。
就算遍历上去,父节点也为黑b2 黑兄左黑侄右红侄注解:绿色表示,颜色不影响修复的方式。
依然我们可以肯定父节点的左子树高度减一,所以我们可以通过将父节点旋转下来并且变为黑色来弥补,但由于兄弟被旋转上去了,又导致右子树高度减一,但我们这有一个红侄,所以可以通过红侄变成黑色来弥补。
父亲所在位置的颜色不变;(子为空)方法:兄=>父色;父=>黑;侄=>黑;(子=>黑);左旋转父节点;b3 黑兄左红侄右黑侄注解:绿色表示,颜色不影响修复的方式。
依然我们可以肯定父节点的左子树高度减一,同样我们通过父节点左旋转到左子树来弥补这一缺陷。
但如果直接旋转的话,我们可以推出左右子树将不平衡(黑父),或者两个红色节点相遇(红父);这样将会更加的复杂,甚至不可行。
因此,我们考虑首先将兄弟所在子树右旋转,然后再左旋转父子树。
这样我们就可以得到旋转后的树。
然后通过修改颜色来使其达到平衡,且高度不变。
方法:侄=>父色;父=>黑;右旋转兄;左旋转父;总结:如果我们通过上面的情况画出所有的分支图,我们可以得出如下结论插入操作:解决的是红-红问题删除操作:解决的是黑-黑问题即你可以从分支图中看出,需要往上遍历的情况为红红(插入);或者为黑黑黑(删除)的情况,,如果你认真分析并总结所有的情况后,并坚持下来,红黑树也就没有想象中的那么恐怖了,并且很美妙;程序样列:点击这里下载源码声明:此文档为《C语言常用数据结构源代码全注解-红黑树源码》所写,此文档遵循GNU FDL协议,你可以修改重发,但因保留原始版权信息;此文档版本V1.0为初次发布,所以难面有错误的地方,如果你发现任何错误或缺点,非常感谢你发信息联系我。
此文档仅供学习使用。
参考文献:《百度百科红黑树》地址:/view/133754.htm《C#与数据结构-树论—红黑树》地址:/2008-12/1229486123100653_7.html《資料結構與演算法(上)》作者:呂學一《資料結構與演算法(上)》红黑树大部分图片来源版权信息:本文来源:『20065562's Blog』有水的地方就有余文章转载自20065562's Blog请点击这里查看原文地址:/20065562/blog/item/8777467e5292f30229388a0f.html。