关于红黑树, 这篇讲的更详细易懂。
https://www.cnblogs.com/jakelin/p/14324966.html
一颗平衡的二叉搜索树的任意节点平均查找效率为树的高度h,即O(lgn)。
但是如果二叉搜索树的失去平衡(元素全在一侧),搜索效率就退化为O(n),因此二叉搜索树的平衡是搜索效率的关键所在。
为了维护树的平衡性,数据结构内出现了各种各样的树,比如AVL树通过维持任何节点的左右子树的高度差不大于1保持树的平衡,而红黑树使用颜色的概念维持树的平衡,使二叉搜索树的左右子树的高度差保持在固定的范围。
相比于其他二叉搜索树树,红黑树对二叉搜索树的平衡性维持有着自身的优势。
红黑树是一种自平衡二叉搜索树,它通过对节点进行着色(红色或黑色)并在树的操作过程中维护一系列性质,以确保树大致保持平衡。这种平衡确保了树的搜索、插入和删除操作的最坏情况时间复杂度为O(log n),其中n是树中元素的数量。
红黑树的定义
1.节点非红即黑。
2.根节点是黑色。
3.所有NULL结点称为叶子节点,且认为颜色为黑。
4.所有红节点的子节点都为黑色。
5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。
红黑树数据结构
template<class T>class rb_tree_node{
typedef rb_tree_node_color node_color;
typedef rb_tree_node<T> node_type;
public:
node_color color;//颜色
node_type* parent;//父节点
node_type* left;//左子节点
node_type* right;//右子节点
T value;//值
....
};
红黑树插入节点
特殊情况考虑完成之后,下面假设又开始添加节点,我们面对的第一个问题是新增加的节点是标记成红色还是黑色?显然无论是新插入的节点是黑色或者是红色,红黑树限制1,2,3一定是满足的,那么如果将新插入的节点标识成黑色的话,可能违反5,但是如果将新插入的节点标识成红色,肯能违反4,看似好像是两个是类似的。
情况 1. 如果插入的节点是根节点(初始的红黑树为空)
直接将该节点颜色改成黑色。
情况 2. 插入结点的Key已经存在
直接更换节点的值。
情况 3. 插入的节点的父节点是黑色
插入的节点不是红黑树的根节点,如果新插入的节点的父节点是黑色的话,红黑树不需要调整,直接插入。
情况 4. 插入节点的父节点是红色
根结点是黑色。如果插入的父结点为红结点,那么该父结点不可能为根结点,所以插入结点总是存在祖父结点。
情况4.1 插入节点的父节点是红色,叔叔节点是黑色
4.1.1 父节点和祖父节点在一条线上。
需要旋转(左旋/右旋)后变色
4.1.2 父节点和祖父节点不在一条线上。
首先调换位置,然后旋转(左旋/右旋)后变色。
情况4.2 父节点是红色,叔叔节点是红色
首先,交换祖父节点和叔叔节点的颜色。
如果通过这样做使得祖父节点成为了双重红色(祖父节点的父节点也是红色)
则需要对祖父节点进行进一步的操作,可能是旋转或者继续向上层进行重新着色和调整(进行递归的操作)。
红黑树删除节点
红黑树删除节点需要考虑节点的位置,删除节点后需要保持红黑树的平衡性。
二叉树删除结点找替代结点有3种情景:
情景1:若删除结点无子结点
直接删除。
情景2:若删除结点只有一个子结点
用子结点替换删除结点。
情景3:若删除结点有两个子结点
用后继节点(大于删除结点的最小节点)替换删除结点。
当然用前绩节点也可以,不过通常我们会用后继节点。
(把二叉树所有结点投射在X轴上,所有结点都是从左到右排好序的,所有目标结点的前后结点就是对应的前继和后继结点)
如果待删除节点有两个子节点,则不能将该节点直接删除,而是从其右子树中选取最小值节点(或左子树的最大值节点)作为删除节点。
三种情况 和二叉搜索树的节点删除完全相同。
一个重要的思路:删除结点被替代后,在不考虑结点的键值的情况下,对于树来说,可以认为删除的是替代结点。
基于此,上面所说的3种二叉树的删除情景可以相互转换并且最终都是转换为情景1。
情景2:删除结点用其唯一的子结点替换,子结点替换为删除结点后,可以认为删除的是子结点,若子结点又有两个子结点,那么相当于转换为情景3,一直转换,总是能转换为情景1。
情景3:删除结点用后继结点(后继结点肯定不存在左结点),如果后继结点有右子结点,那么相当于转换为情景2,否则转为为情景1。
渐近边界的证明
红黑树的查找效率与二叉搜索树的查找效率相同,即在最坏的情况下时间复杂度为O(log n),其中n是树中节点的数量。
这是因为红黑树保持了树的平衡性,即从根节点到最远的叶子节点的最长路径不会超过最短路径的两倍。这意味着树的高度大致保持在log n的数量级,因此查找效率很高。
为什么STL map和set使用红黑树而不是平衡二叉树?
红黑树提供的平衡程度与性能之间的折中。与平衡二叉树(特别是AVL树)相比,红黑树在维持平衡的严格性上做了妥协。
(1)红黑树是一种自平衡二叉搜索树,它通过对节点进行着色(红色或黑色)并在树的操作过程中维护一系列性质,以确保树大致保持平衡。这种平衡确保了树的搜索、插入和删除操作的最坏情况时间复杂度为O(log n),其中n是树中元素的数量。
(2)AVL树是高度平衡的二叉搜索树,对平衡的要求更严格,任何时候任何节点的两个子树的高度差最多为1。
这种高度的平衡确保了极佳的查找性能,但是在插入和删除操作时可能需要更频繁的旋转来维持这种严格的平衡,导致这些操作相对于红黑树来说更加耗时。它不像AVL树那样对平衡有严格的要求,因此在插入和删除操作时通常需要较少的旋转,这可以在实际应用中提供更好的性能。在频繁的插入和删除操作时,红黑树较少的旋转次数意味着整体的性能往往更优。
参考:
https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91
https://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html
https://www.cnblogs.com/fanzhidongyzby/p/3187912.html