目录
这个性质可以总结为
红黑树的最短最长路径
红黑树的路径范围
code
结构
搞颜色
类
插入
插入逻辑
新插入节点
思考:2. 检测新节点插入后,红黑树的性质是否造到破坏?
解决方法
变色
旋转+变色
第三种情况,如果根节点上面还有节点
1.每个节点不是红色就是黑色
2.根节点是黑色的
3.不能有两个连续的红色节点 ,即可以出现 红黑 黑黑 不能出现红红
4.每条路径上的黑色机节点数量不一样
至于性质5:每个叶子结点都是黑色的,这里的叶子节点并不是真的叶子节点,而是NIL节点,即空节点。如图(a):
正确答案是有7条。路径路径的判断规则是:从根节点到NULL。
如果我们把NIL节点标记出来就好找路径了:
再比如,图(a-3)是否是红黑树:
大致一看好像是,但是把NIL节点标出来之后:
路径(b)只有两个黑色节点,不满足红黑树的性质,不是红黑树。
那么红黑树的最短路径是什么样子的,应该是全黑的最短:
那最长的路径呢,应该是一黑一红间隔排列的最长:
根据图(a-1)我们可以看出,最长的路径是最短的路径的2倍。
ps
一个红黑树不一定有最长路径,也不一定有最短路径。
而知道了最短路径,最长路径,剩下的路径都在最短路径,最长路径范围内,可以写为
[n,2*n]
template
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* parent;
pair;
Color _col;
//初始话列表
RBTreeNode(const pairkv)
:_left(nullptr)
,_right(nullptr)
, _parent(nullptr)
, pair
,_col(RED)
{}
};
enum Color
{
RED,
BALACK
};
template
class RBTree
{
typedef RBTreenode Node;
public:
private:
Node* _root = nullptr;
};
如果节点为空,就给黑色。如果节点不为空,就插入值。
这个值如果比根节点小,就往左边插入,否则就往右边插入。
bool Insert(const pair& kv)
{
if (_root == nullptr)
{
_root = new(kv);
_root->_col = BALACK;
return true;
}
//初始化父亲节点和根节点
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
//key值大,往右走
if (cur->kv.first < kv.first)
{
cur = cur->right;
}
//key值小,往左走
else if (cur->kv.first > kv.first)
{
cur = -cur->left;
}
//否则key值和当前节点相等,不插入
else
{
return false;
}
}
//找到了返回true1
return true;
}
如图(b-1),现在要插入一个节点,那么是插入一个黑色节点还是红色节点呢?
如果插入黑色节点,那么该路径就会多一个黑色节点,根据红黑树特性,其他路径都要补一棵黑色节点,
如果插入红色节点,则只会影响父节点
(即
1.如果父节点也会红节点。两个红节点不能紧挨,需调整
2.如果父亲节点是黑色,则不需调整,直接插入。)。
我们看一下怎么调整,如图(b-2),新插入了一个红色节点7:
能变色先变色,变色完之后还不行再旋转
如图(b-3),先把父节点8变黑:
这个时候该路径就多了一个黑色节点,再变图(b-4)把6节点变红:
这个时候该路径又少了个黑色节点,再变图(b-5) 把5节点变黑:
第二种情况,例如图(b-6):如果还是把父节点变为黑色,把6节点变为红色,那么其他路径就会多一个黑色节点。
而该路径又没有其他节点可以再变黑色来平衡这种状态,所以靠变色解决不了这个问题。
这个时候就要旋转了。
先右旋为图(c-1):
如图(d-0),新插入了一个节点cur:
cur为红色节点,那就需要调整。
把p节点变为黑色节点,那么为了u节点也要变为黑色节点,那么此时就要把g节点变为红色节点。也就是图(d-1)
为什么要把g节点变为红色节点呢?
假设g节点不变为红色也就是图(d-3):
由图(d-1)变为图(d-3)我们发现每条路径凭空多了1个黑色节点。
g节点上面还有节点,那么多了个黑色节点,就会影响上面的路径,所以需要把g节点变红来平衡一下。
这个时候万一g节点的父节点是红色节点,如图(d-4):
两个红色节点不能连续,还要调整,如果g节点的父亲节点为黑色,如图(d-5),那就不需要再调整: