新节点内侧插入情况:先对父节点左单选(如果这里不进行左旋转,则经过下一步的右旋转后,新节点即成为祖父节点的左孩子,如果祖父节点为红色,则会引入额外的调整和麻烦),改变新节点和祖父节点颜色,再对祖父节点右单旋;
叔父节点颜色为红色
该情况下比较简单,因为叔父和父节点都是红色,而且祖父节点为黑色,则将祖父节点颜色变为红色,父节点和叔父节点颜色为黑色,即可消除相邻的两个红色节点而且不改变相应的黑高度,此时如果曾祖父节点颜色为黑色,则调整结束,如果曾祖父节点颜色为红色,则可将祖父节点视为新节点,递归新插入情况,迭代向上处理。
总体来说插入情况相对比较简单,主要涉及上述几种操作,以下是c语言相关红黑树插入实现代码:
/*
* key:新插入节点键值,root:红黑树根节点
* 红黑树节点插入
* 1、插入新节点
* 2、旋转红黑树并做颜色调整
*/
rb_node_t *rb_tree_insert(int key, rb_node_t* root)
{
rb_node_t *last_node;
rb_node_t *curnode;
/* 创建节点 */
rb_node_t *node = (rb_node_t *)malloc(sizeof(rb_node_t));
node->key = key;
curnode = root; //temp node,just for save something
/* 树为空 */
if (NULL == root)
{
node->color = black;
node->left_child = NULL;
node->right_child = NULL;
node->parent = NULL;
return node;
}
/* 向下搜索,直到找到相应的位置可以插入 */
while (curnode)
{
last_node = curnode;
node->key > curnode->key ? (curnode = curnode->right_child) : (curnode = curnode->left_child);
}
/* 判断插入搜索到的节点的左孩子还是右孩子 */
if (node->key > last_node->key)
last_node->right_child = node;
else
last_node->left_child = node;
node->parent = last_node; //回马枪设置父节点
node->left_child = NULL;
node->right_child = NULL;
node->color = red;
/* 重新使红黑树调整为平衡状态 */
root = rb_tree_rebalance(node, root);
return root;
}
删除操作:
红黑树节点删除操作后的调整相比插入操作更加复杂,但是同样可以分情况讨论之。
首先红黑树删除同样采取跟二叉搜索树同样的删除方式,即如果需要删除节点A,则将A左子树中最大的节点(即最右边节点)和右子树中最小的节点(最左边的节点)删除,然后用删除节点替换A节点。
如下图:
需要删除8节点时,先搜索到7或9节点,将对应节点删除掉,同时将7或9的节点替换8的节点,详细参考请查阅二叉搜索树的删除。