红黑树是一种几近平衡的二叉搜索树, 但不是AVL树.
1 红黑树的一些特殊性质
1. 每个节点皆为红色或者黑色。
2. 根节点是黑色。
3. 每个叶子节点(NIL)是黑色(注意, 每个叶子节点必须都为空节点, 也就是指针为nullptr, 无key值)。
4. 每个红色结点的两个子结点一定都是黑色。
5. 任意一结点到以其为根节点的树的每个叶子结点的路径都包含数量相同的黑结点。
2 红黑树的插入和删除操作
2.1 插入操作
当我们要插入一个key值的节点时, 需要走以下步骤
1. 按照二叉搜索树的插入操作规则插入节点(此时节点并无颜色, 但是我们要通过后续操作让此时的树变为红黑树).
2. 把新插入的节点(如果不是根节点的话)置为红色
原因如下:
根据性质5, 如果将新插入的节点A置为黑色, 那么A需要有两个黑色的子节点(空的), 那么其父节点到A的两个叶子节点的路径上就会有两个黑色节点(包括A和A的子节点), 多出A到其他叶节点的1个.
3. 如果当前节点的父节点是红色, 进行"调整"(具体调整方法如下).
调整:
由于此时插入节点为红色且其父节点也为红色, 那么此时树不满足红黑树的性质4, 那么就不是一棵红黑树, 那么需要让其满足性质4. 如图:
3.1 叔叔节点也是红色
将父节点和叔叔节点均置为黑色, 若祖父节点不是根节点, 将祖父节点置为红色, 将当前节点置为祖父节点, 对当前节点继续进行"调整"
如例题所示, 当我们要插入key值为35的节点:
- 发现需要插在50的左子节点, 然后置为红色:
- 发现35的父亲50和叔叔节点75都为红色, 那么把二者都置为黑色, 并把祖父节点60置为红色:
- 当前节点为60, 红色, 其父节点40和叔叔节点120皆为红色, 那么将二者置为黑色, 祖父节点为根节点, 不变色:
3.2 叔叔节点为黑色, 且当前节点是右孩子
当前节点是红色, 父节点也是红色, 但是其叔叔节点是黑色, 且当前节点是父节点的右孩子, 那么就将父节点左旋.
3.3 叔叔节点为黑色, 且当前节点是左孩子
当前节点是红色, 父节点也是红色, 但是其叔叔节点是黑色, 且当前节点是父节点的左孩子, 那么就将父节点置为黑色, 将祖父节点置为红色, 并将祖父节点右旋.
2.2 删除操作
删除操作, 跟二叉搜索树的操作一样, 先把节点删除, 然后:
1. 如果节点是叶节点, 那么直接删除
2. 如果被删除的节点只有一个子节点, 那么子节点直接代替删除节点位置
3. 如果被删除节点有左右子节点, 那么找出中序遍历的后继节点, 把要删除的节点的值更新为其后继节点的值, 然后删除后继节点(注意, 其后继节点必然是其右子树的中序遍历的第一个节点, 也就是肯定不会有左子节点, 但凡有左子节点, 左子节点一定排在它本身前面, 所以被删除的节点最多有一个子节点, 可以按照1, 2情况对其进行分析).
4. 如果删除的节点位置是黑色节点, 那么就需要进行"调整"
调整:
调整还是根据删除后的当前情况进行.
删除节点后, 当前树可能会不符合红黑树的2,4,5性质, 也就是根节点为黑色, 红色节点的子节点为黑色, 节点到该节点的子孙节点的所有路径上包含相同数目的黑节点. 此时我们需要观察删除的那个节点位置代替者的情况, 如果其原本为红色, 直接将该位置置为黑色, 结束调整. 如果其原本为黑色且是该位置为根节点, 也是不需要做什么, 结束掉.
那么剩下的情况就是, 被删除的节点为黑色, 且代替他位置的节点也为黑色, 且该位置不是根节点, 那么有以下四种情况(假设当前节点为删除位置的节点):
https://www.jianshu.com/p/e136ec79235c
1. 兄弟节点为红色
2. 兄弟节点为黑色, 且兄弟节点的子节点也都为黑色
3. 兄弟节点为黑色, 且兄弟节点左子为红色, 右子为黑色
4. 兄弟节点为黑色, 且兄弟节点右子为红色.