💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!
文章目录
前言
今天我们终于来到了我们以前经常提到的一个比较难的数据结构–红黑树,这个数比较抽象,但是我们上一篇学过了AVL数,我觉得在复杂度上红黑树还是相比较而言简单一些,他的分类情况比AVL树少,但是前面的内容要理解好才行,所以前面我会尽量把具体图画的详细一点,然后再带大家来看抽象图。前面的性质我也会给大家铺垫好,大家一定瑶一步步的看下去,跳着是看不懂的,话不多说,我们开始进入红黑树进行讲解
一、红黑树是什么?
1.1概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。
为什么要有红黑树?
我们上面的概念第一句话就说这是一个二叉搜索树,通过AVL树的讲解,他是优化二叉搜索树的最差情况的,使得复杂度接近满二叉树,效率已经非常高的了,为什么还要有红黑树呢??他其实也是来改善二叉搜索树的最差情况的,相比较而言AVL是一个绝对平衡的树,而红黑树是一个近似平衡的树,这样就导致红黑树的高度会比AVL树的高度深,AVL中不合理的条件在红黑树中合理,导致红黑树的旋转次数少。AVL树的搜索性能可以说是最好的了,但是他的插入或者删除需要进行大量的旋转带来的消耗是很多的,所以有了红黑树,他虽然高度比AVL深一点,但是旋转次数少很多,对于大量数据红黑树的整体性能可能比AVL好。因为搜索的时候多出的高度也就是几十次的查找而已,对于cpu来说忽略不计,所以说红黑树减少的旋转带来的消耗,来增加的高度,而增加的高度对性能的影响忽略不计。这也就是我们学习红黑树的原因(对于10亿数据,顶多多了十几层,但是旋转次数可能少了好几万次,等这篇博客结束,我会带大家来对比AVL和红黑树的高度以及旋转次数的对比)
1.2红黑树的性质
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的 (父亲也不是红色的,任何路径上没有连续的红节点)
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
通过上面五点规则为什么就可以保证最长路径不超过最短路径的两倍呢??
大家看到上面的树不是绝对平衡的,但是他符合红黑树的要求,对于AVL树就要进行旋转了,所以说红黑树减少了旋转的消耗。
提示,我们破坏规则3不会影响其他路径上的规则,破坏规则四会影响所有路径,所以修改颜色的时候不方便,这个一会再详细说下,大家先看看能不能理解我说的
二、红黑树的原理讲解
2.1红黑树节点的定义
enum color
{
RED,
BLACK
};
template<class T>
struct RBTNode
{
T _val;
RBTNode<T>* _left;
RBTNode<T>* _right;
RBTNode<T>* _parent;
color _col;
RBTNode(const T&val=T())
:_val(val)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(RED)
{
}
};
因为对节点有颜色的属性,所以定义一个枚举。因为要涉及到旋转,所以还是需要三叉链的结构。
2.2红黑树的插入
红黑树本质还是二叉搜索树,按照前面的插入方式先找到插入位置。
template<class T>
class RBTree
{
typedef RBTNode<T> Node;
public:
RBTree() {
}
bool insert(const T& val = T())
{
if (_root == nullptr)
{
_root = new Node(val);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = _root;
while (cur)