概念:
红黑树是一棵二叉搜索树,每个节点是红色或黑色。通过对每条从根节点到叶子结点路径上的节点的颜色限制,确保没有一条路径长度会超过其他路径长度的两倍,因而是接近平衡的。
所以AVL树比红黑树更集中。
红黑树的特点:
- 每个节点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的孩子节点是黑色的
- 对于每个节点从该结点到其所有后代叶节点的路径上,均包含相同的黑色节点
- 每个叶节点(是指叶节点指向的空节点)是黑色的。
小问题:红黑树概念中说确保 没有一条路径会比其他路径长一倍,也就是说最长的路径长度绝不可能超过最短路径的2倍,why?
首先根节点是黑的,黑节点的子结点可以是黑的也可以是红的,而红节点的子节点必须是黑的。并且根节点到叶节点的每条路径上的黑节点数量要求相等;所以最短路径上如果全为黑节点,有n个,那么最长路径上面一定有n个黑节点,另加上n个红节点。在增加节点就不符合红黑树的性质了。
红黑树代码实现:
如果想看红黑树插入时更新的五种情况,可以直接通过目录移到“五种情况”的位置。
如果不明白红黑树的旋转,请看博客:https://mp.csdn.net/console/editor/html/106836542
插入:
当我们新插入节点之后,我们面临一个选择,新插入的节点是红色还是黑色呢?
如果插入的节点是红色的,而其父节点也是红色的,那么就违反了红节点的子结点是黑色的性质
如果插入的节点是黑色的,那么肯定违反了每个路径上的黑节点数量相同的性质。
相比之下,我们还是选择插入的节点是红节点,因为比较好调节。
那么插入一个红节点必定会面临两种选择
父节点是黑色的,符合红黑树性质;
父节点是红色的,不符合红黑树性质,我们需要进行调节;
图片解析:
我们 设 插入的节点为cur 其父节点为p 祖父节点为 g 父节点的兄弟节点为u
当我们插入节点后是否调节需要p节点判断,然而怎么调节我们有需要u节点判断
情况1:u节点不存在(因为u节点不存在,则一定是新插入节点造成的这种情况)
情况2:u存在且为红色
不论出于什么样的位置,这种情况我们只需要进行变色处理;
如果g节点的父节点不存在,即g节点肯定为父节点,再将g节点变为黑节点即可完成更新
如果g节点的父节点是黑色的,我们也完成了更新
如果g节点的父节点是红色的,我们还需要向上进行更新
情况3:u节点存在且为黑色
我们可以对上面的情况进行总结:
五种情况:
情况一: u存在且为红色:
不论什么情况,我们同样处理
g节点变为红色,p、u节点变为黑色
如果g节点的父节点不存在,即g节点肯定为父节点,再将g节点变为黑节点即可完成更新
如果g节点的父节点是黑色的,我们也完成了更新
如果g节点的父节点是红色的,我们还需要向上进行更新
情况二:u不存在或者为黑色 并且 p为g的左节点,cur为p的左节点
以g节点进行右旋,p节点变黑,g节点变红,更新完毕
情况三:u不存在或者为黑色 并且 p为g的右节点,cur为p的右节点
以g节点进行左旋,p节点变黑,g节点变红,更新完毕
情况四:u不存在或者为黑色 并且 p为g的左节点,cur为p的右节点
以p节点进行左旋,变为情况二
情况五:u不存在或者为黑色 并且 p为g的右节点,cur为p的左节点
以p节点进行右旋,变为情况三
代码实现:
bool insert(const pair<K, V>& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_color = Black;
return true;
}
else
{
Node* parent = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
if (cur->_data.first < data.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_data.first>data.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//插入新节点,将新节点默认给成红色
cur = new Node(data);
if (parent->_data.first< data.first)
{
parent->_right = cur;
}
else if (parent->_data.first>data.first)
{
parent->_left = cur;
}
cur->_color = Red;
cur->_parent = parent;
//判断当前树是否符合红黑树性质,不符合则进行调整
while (parent != nullptr&&parent->_color == Red)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
//叔叔存在且为红色,那么我们只需要变色
//父节点和叔叔节点变为黑色
//祖父节点变为红色
if (uncle != nullptr&&uncle->_color == Red)
{
parent->_color = uncle->_color = Black;
grandfather->_color = Red;
//向上更新
cur = grandfather;
parent = cur->_parent;
}
else
{
//叔叔不存在或者为黑色
//如果cur是父节点的左节点,右单旋+父节点变黑、祖父节点变红
//如果cur是父节点的右节点,需要进行双旋操作
if (cur == parent->_right)
{
RotateL(parent);
swap(parent, cur);
}
RotateR(grandfather);
parent->_color = Black;
grandfather->_color = Red;
break;
}
}
else //if (parent == grandfather->_right)
{
Node* uncle = grandfather->_left;
//叔叔存在且为红色,那么我们只需要变色
//父节点和叔叔节点变为黑色
//祖父节点变为红色
if (uncle != nullptr&&uncle->_color == Red)
{
parent->_color = uncle->_color = Black;
grandfather->_color = Red;
//向上更新
cur = grandfather;
parent = cur->_parent;
}
else
{
//叔叔不存在或者为黑色
if (cur == parent->_left)
{
RotateR(parent);
swap(cur, parent);
}
RotateL(grandfather);
parent->_color = Black;
grandfather->_color = Red;
break;
}
}
}
_root->_color = Black;
return true;
}
}
谢谢你们的观看!
创作不易,不要白嫖哦! 小伙伴,动动手点个赞,(*^▽^*)!
注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!