红黑树:
一颗二叉搜索树,每个节点上增加了一个存储位来表示节点的颜色,通过对任意一条叶子节点到根节点的路径上的颜色进行约束,保证最长路径不超过最短路径的两倍,因此红黑树是近似平衡。
红黑树因为是近似平衡,在构建红黑树的时候触发的旋转自然要比AVL树少(AVL树触发旋转是左子树和右子树高度之差的绝对值大于1),构建树的效率降低;
红黑树的时间复杂度是O(n*logN),AVL树的时间复杂度是O(logN),单从表达式来看AVL树的效率要高于红黑树,但是计算机在处理数据的时候单位是以亿计的,所以两个效率差别不大。
满足下述特性的二叉搜索树是红黑树:
每个节点不是红色就是黑色;
根节点必须是黑色的;
不能有连续的红节点,如果一个节点是红的,那么该节点的两个子节点是黑色的;
对每个节点来说,从该节点到其后所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
-
思考:为啥红黑树最长路径不超过最短路径的二倍?
答:一颗红黑树的最长路径是红黑节点相间的路径;最短路径是只有黑节点的路径,红黑树又满足每个节点到其后叶子节点的路径上包含的黑节点数相同。
红黑树的插入:
红黑树插入节点的时候需要考虑新节点的颜色是红色的还是黑色的,假设新节点缺省颜色是黑色的,那么只要插入进去,该路径上的黑色节点数比其他路径上的节点数多一个,这时就要对其他路径进行调整;如果插入的节点是红色节点,如果该节点父亲节点是黑色,直接插入,如果该节点父亲节点是红色,就只在该条路径上进行调整。
注:cur:新插入节点;parent:父亲节点;pparent:祖父节点;uncle:叔叔节点。
分析的所有情况都只是一棵完整树中子树的情况。
情况一:cur节点为红色,parent节点为红色,pparent节点为黑色,uncle节点存在且为红色
(将parent节点,uncle节点改为黑色,pparent节点改为红色,接下来将pparent作为cur,向上进行调整)
if (uncle&&uncle->_col == RED)
{
pparent->_col = RED;
parent->_col = uncle->_col = BLACK;
cur = pparent;
parent = cur->_parent;
}
情况二是由情况一向上进行调整所遇到的情况,当cur节点是新插入的时候,parent节点是红色的,pparent节点和uncle节点是黑色的,明显uncle那条路径上黑色节点数多,所以cur以前是黑色的,经过第一种情况的调整之后变成了红色。
情况二:cur节点为红色,parent节点为红色,pparent节点为黑色,uncle节点为黑色或不存在
1.parent节点为pparent节点的左孩子,cur节点为parent节点的左孩子,进行右单旋,相反进行左单旋
2.parent节点为pparent节点的左孩子,cur为parent节点的右孩子,parent节点进行左单旋,相反,parent节点做右单旋
if (uncle == NULL || uncle->_col == BLACK)
{
//parent在pparent的左,cur在parent的左
if (pparent->_left == parent)
{
if (parent->_left == cur)
{
Rotate_R(pparent);
parent->_col = BLACK;
/*pparent->_col = RED;*/
}
else if (parent->_right == cur)
{
Rotate_LR(pparent);
cur->_col = BLACK;
/*pparent->_col = RED;*/
}
}
else if (pparent->_right == parent)
{
if (parent->_left == cur)
{
Rotate_RL(pparent);
cur->_col = BLACK;
//pparent->_col = RED;
}
else if (parent->_right == cur)
{
Rotate_L(pparent);
parent->_col = BLACK;
//pparent->_col = RED;
}
}
pparent->_col = RED;
}
_root->_col = BLACK;
}
return false;
}