对比AVL树
AVL树在引入平衡因子后,已经可以确保时间复杂度在O(log(n))内了,但是每次插入和删除都可能会引起树的不平衡,从而引发AVL树旋转。
红黑树在AVL树的基础上相对又一点不一样的理念,不要求高度为1的平衡,转而追求红色和黑色之间的平衡。
基础性质
✅满足基本的二叉树性质
- ✅ 节点是红色或黑色 【性质一】
- ✅ 根是黑色 【性质二】
- ✅ 所有叶子都是黑色(叶子是NIL节点)
- ✅ 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点) 【性质三】
- ✅ 这就可以理解所有叶子都是NIL节点(都是黑色)
- ✅ 两个孩子节点都是黑色,自然不可能出现2个连续的红色节点
- ✅ 红色节点的孩子节点必然是黑色,父亲节点必然是黑色
- ✅ 从任一节点(父亲节点)到其每个叶子的所有简单路径)都包含相同数目的黑色节点。【性质四】
- 为了保持性质四,新插入的节点都是红色节点
插入节点
新插入的节点均为红色节点,因为红色不会影响路径上黑色节点的数量,保持性质四。如果父节点为黑色,就直接结束了;如果父节点为红色,则需要另外处理了。
情形4.1.1 <br />情形4.1.2 
删除节点
节点删除存在三种情况
- 待删除节点是叶子节点,即不存在子节点
- 删除节点是红色节点,直接删除即可
- 删除节点是黑色节点,需要进行平衡操作
- 删除操作可能会导致红色节点只有一个黑色子节点了,可能路径上的黑色节点个数不一致了
- 只有一个子节点,说明待删除节点一定是黑色节点,红色节点必须满足有2个黑色子节点,删除黑节点,将子节点的红色节点涂黑。
- 存在两个子节点,找到左子树的最大值|右子树的最小值,替换即可,由于替换产生,这时情况转换为删除叶子或者删除一个子节点的情况
基于下图基本上可以实现红黑树的删除操作。
红黑树平衡一定要满足的性质
- 红色节点必须有两个黑色子节点,红色为叶子也是有NIL节点,不过可以忽略。
- 从任一节点到每个叶子节点的黑色节点个数保持一致
代码实现
插入节点顺序 20 ,10 , 30 , 1, 2, 3, 4, 5, 6, 7 实现效果如下

由于代码较长 (没有做啥优化,大概在600行左右),这里放部分代码,完整代码 这里RedBlackTree.java
- 插入节点后进行着色
删除黑色叶子节点的过程
/*** 插入节点后进行着色*/private void coloringNode(Node node) {if (node == null) {return;}//1、节点N的parent节点(root)Node parent = node.parent;if (parent == null) {node.black = true;return;}//2、父黑 无需其他操作if (parent.black) {return;}//3、叔叔节点 父亲红叔叔红的情况Node uncle = getUncle(parent);//if (!node.black && !uncleIsBlack(uncle)) {parent.black = true;uncle.black = true;if (parent.parent != null) {parent.parent.black = false;coloringNode(parent.parent);}return;}Node p = parent;do {if (parent.black) {//4、父亲红 叔叔黑//4.1、父亲和N在同一边//4.1.1、父亲和N都在左边final Node gp = parent;if (gp.leftChild == p && p.leftChild == node) {rr(gp, parent == root);} else if (gp.rightChild == p && p.rightChild == node) {//4.1.2、父亲和N都在右边ll(gp, parent == root);} else if (gp.leftChild == p && p.rightChild == node) {//4.2.1、父亲左,N在右lr(gp.leftChild, parent == root);} else if (gp.rightChild == p && p.leftChild == node) {//4.2.2、父亲右,N在左rl(gp.rightChild, parent == root);} else {throw new IllegalStateException("不应该跑到这里");}break;}parent = parent.parent;} while (parent != null);}//==================================================================================================//删除节点/*** 待删除节点为黑色叶子节点** @param node 节点N,N为3*/private void deleteBlackLeaf(Node node) {//查询当前节点为parent的左节点还是右节点//parent节点为2final Node parent = node.parent;//node3是parent2的右子boolean isRight = node != parent.leftChild;//1、获取兄弟节点//获取兄弟节点,如果当前节点是左子,那么兄弟节点就是右子,反之亦然//sibling为1Node sibling = isRight ? parent.leftChild : parent.rightChild;//2、兄弟节点为黑色if (sibling.black) {//2.1、兄子节点全黑if (childAllBlack(sibling)) {//2.1.1、父亲为红色if (!parent.black) {changeNodeDir(node);//交换P和S的颜色,这里因为上边的判断所以可以直接判定parent.black = true;sibling.black = false;} else {//2.1.2、父亲为黑色//兄弟节点S涂红changeNodeDir(node);sibling.black = false;//将P作为新的N,进行递归处理deleteBlackLeaf(parent);}} else {//2.2、兄子节点不全黑//isRight(true)当前节点在右,兄在左if (isRight) {//2.2.1 兄在左,兄左子红final Node sl = sibling.leftChild;boolean red = sl != null && !sl.black;if (red) {//以当前节点的parent节点右旋,右旋完成后交互P和S的颜色,SL涂黑 平衡结束rrNotColor(parent, parent == root);final boolean parentColor = parent.black;parent.black = sibling.black;sibling.black = parentColor;sibling.leftChild.black = true;//为了兼容处理删除含2个子节点的数据,这里是调整删除nil节点if (node.nil) {changeNodeDir(node);}} else {//2.2.2 兄弟节点在左,兄弟节点左子树黑final Node SR = sibling.rightChild;final Node SL = sibling.leftChild;//以兄弟节点S左旋llNotColor(sibling, false);//交换S和SR的颜色final boolean srColor = SR.black;SR.black = sibling.black;sibling.black = srColor;deleteBlackLeaf(node);}} else {//2.2.2、兄在右(既成事实)final Node sr = sibling.rightChild;boolean red = sr != null && !sr.black;if (red) {//以P左旋,交换P和S的颜色,SR涂黑,平衡结束llNotColor(parent, parent == root);final boolean parentColor = parent.black;parent.black = sibling.black;sibling.black = parentColor;sibling.rightChild.black = true;if (node.nil) {changeNodeDir(node);}} else {final Node SL = sibling.leftChild;//以S右旋rrNotColor(sibling, false);//交换S和SL颜色final boolean slColor = sibling.black;sibling.black = SL.black;SL.black = slColor;deleteBlackLeaf(node);}}}} else {//3、兄弟节点为红色//3.1、兄弟节点在左//isRight(true)当前节点在右,兄在左if (isRight) {llNotColor(parent, parent == root);} else {//3.2、兄弟节点在右rrNotColor(parent, parent == root);}final boolean parentColor = parent.black;parent.black = sibling.black;sibling.black = parentColor;deleteBlackLeaf(parent);}}
参考链接
图片来源于下链接,讲解和配图都很不错的。

