红黑树是平衡二叉树的一种,不像严格的平衡二叉树(AVL树),当左右子树深度差大于1时就会进行平衡操作,严格控制树的深度。红黑树只有当左右子树深度差大于2时会进行平衡操作。其次,由于AVL树严格追求平衡的特性,在插入删除时,在不同情况下,进行复衡旋转的次数要比红黑树多。
插入导致失衡时,AVL树和红黑树最多通过两次旋转复衡,都为O(1)。
删除导致失衡时,AVL树复衡是O(logn),红黑树最多需要三次就能复衡,只需要O(1)。
由此来看,在插入时,二者的效率差不多,但是在进行删除操作时,红黑树的效率就比AVL树高。同样的由于AVL树更加严格追求平衡,在查询效率上略高于红黑树。
总的来说,红黑树是一种折中的选择,它比AVL树更易于维护,除了在查询效率上略低于AVL树,插入删除效率比AVL树高,维护红黑特性的代价也比追求严格意义的平衡小。
红黑树的特性
1.节点颜色非红即黑
2.红节点必有两个黑子节点,一条路径上不可能连续出现两个红节点
3.根节点必为黑
4.每个叶子节点nil都为黑(nil为null节点)
5.从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点
实现红黑树的插入和删除都是围绕着特性展开
插入操作
插入的新节点必为红节点!
分以下情况
A.根节点为null,直接作为根节点插入并染黑。
B.父节点为黑节点,直接插入。
C.父节点为红节点。
C1.叔叔节点存在且为红节点。
将祖父节点染红,父节点和叔叔节点染黑。完成以上操作后,判断祖父节点的父节点是否为红,因为祖父节点此时已经为红节点,祖父节点的父节点再为红的话就会违反红黑树特性,所以进行两次旋转。
(当祖父节点为根节点时的特殊情况,此时不用将祖父节点染红)
C2. 叔叔节点不存在或为黑节点。
根据左右条件进行相应的左右旋转
最后还要判断左右子树深度差是否大于2进行复衡旋转操作。
删除操作
第一种情况 被删除节点为叶子节点
为红节点时直接删除
为黑节点时需判断兄弟节点是否为黑节点还是红节点,还需要判断兄弟节点是否是叶子节点或者存在叶子节点的情况
第二种情况 被删除节点只有一个子节点
第三种情况 被删除节点有两个子节点
为了方便理解不同情况下的操作,没有完全参照JDK源码实现
public class RBTree {
TreeNode root;
public void add(int val){
if (root == null){
root = new TreeNode(val,2);
}else root.add(new TreeNode(val,1));
}
public void delete(int val){
root.deleteNode(root.find(val));
}
public void mid(){
root.mid();
System.out.println();
}
}
public class TreeNode {
int val;
int color;//1红 2黑
TreeNode left;
TreeNode right;
public TreeNode(int val,int color){
this.val = val;
this.color = color;
}
/**
* 添加节点
* 插入节点分为以下情况
* 1 根节点为空时 方法:直接插入根节点,将根节点染黑
* 2 插入节点的父节点为黑节点时 方法:直接插入作为子节点,不会破坏红黑树的特性
* 3 插入节点的父节点为红节点时 分以下情况
* 3.1 叔叔节点存在且为红节点 方法:将祖父节点染红,父节点和叔叔节点染黑 后续找到祖父节点的父节点,判断父节点是否为红,然后进行旋转操作 特殊情况 当祖父节点为根节点时,不需要染红根节点
* 3.2
* A 叔叔节点不存在或者叔叔节点为黑节点,并且父节点为祖父节点的左子节点
* 3.2.A.1 插入节点为父节点的左子节点时 方法:祖父节点染红,父节点染黑,父节点变为新的祖父节点, 将父节点的左子节点指向插入节点,右子节点指向旧的祖父节点
* 3.2.A.2 插入节点为父节点的右子节点时 方法:祖父节点染红,父节点染黑,插入节点变为新的祖父节点,将插入节点的左子节点指向父节点,右子节点指向旧的祖父节点
* B 叔叔节点不存在或者叔叔节点为黑节点,并且父节点为祖父节点的右子节点
* 3.2.B.1 插入节点为父节点的左子节点时 方法:祖父节点染红,父节点染黑,父节点变为新的祖父节点, 将父节点的左子节点指向插入节点,右子节点指向旧的祖父节点
* 3.2.A.2 插入节点为父节点的右子节点时 方法:祖父节点染红,父节点染黑,插入节点变为 新的祖父节点,将插入节点的左子节点指向父节点,右子节点指向旧的祖父节点
*
* * 注意!
* 新插入的节点必为红节点
* 当左右子树高度差大于2时,会进行左右旋转达到平衡
*/
public void add(TreeNode node){
TreeNode parent = findParent(node);
//父节点为黑
if(parent.color == 2){
if(node.val < parent.val) parent.left = node;
else parent.right = node;
}
//父节点为红
else{
TreeNode grandPa = findParent(parent);
TreeNode uncle;
if(grandPa.left == parent) uncle = grandPa.right;
else uncle = grandPa.left;
//祖父节点为根节点的情况且叔叔节点存在且叔叔节点为红
if( grandPa == this && uncle != null && uncle.color == 1){
parent.color = 2;
uncle.color = 2;
if(node.val < parent.val) parent.left = node;
else parent.right = node;
}
//祖父节点不为根节点且叔叔节点存在且叔叔节点为红
else if(uncle != null && uncle.color == 1){
grandPa.color = 1;
parent.color = 2;
uncle.color = 2;
if(node.val < parent.val) parent.left = node;
else parent.right = node;
//祖父节点的父节点为红,此时 祖父节点已经调整为红节点,违背了红黑树特性,进行选择操作进行调整
TreeNode newRoot = findParent(grandPa);
if(newRoot.left == grandPa){
if(newRoot.color == 1){
newRoot.rightRota();
leftRota();
}
}else {
if(newRoot.color == 1){
newRoot.leftRota();
rightRota();
}
}
}
//叔叔节点不存在或叔叔节点为黑 且父节点为祖父节点的左子节点
else if((uncle == null || uncle.color == 2) && grandPa.left == parent){
TreeNode temp = new TreeNode(grandPa.val,1);
//插入节点是父节点的左子节点
if(node.val < parent.val){
temp.right = grandPa.right;
grandPa.val = parent.val;
grandPa.color = 2;
grandPa.left = node;
grandPa.right = temp;
}
//插入节点是父节点的右子节点
else {
temp.right = grandPa.right;
grandPa.val = node.val;
grandPa.right = temp;
}
}
//叔叔节点不存在或为黑 且父节点为祖父节点的右子节点
else if((uncle == null || uncle.color == 2) && grandPa.right == parent){
TreeNode temp = new TreeNode(grandPa.val,1);
if(node.val < parent.val){
//插入节点是父节点的左子节点
grandPa.color = 2;
grandPa.val = node.val;
grandPa.left = temp;
}
//插入节点是父节点的右子节点
else{
grandPa.color = 2;
grandPa.val = parent.val;
grandPa.left = temp;
grandPa.right = node;
}
}
}
//右子树高度比左子树高度大2,进行右旋
if(rightHigh() - leftHigh() > 2){
if(right.leftHigh() > right.rightHigh()){
rightRota();
leftRota();
}else{
leftRota();
}
}
//左子树高度比右子树高度大2,进行左旋
if(leftHigh() - rightHigh() > 2){
if(left.rightHigh() > left.leftHigh()){
rightRota();
leftRota();
}else{
rightRota();
}
}
}
public void deleteNode(TreeNode delNode){
TreeNode parent = findParent(delNode);
TreeNode bro;
if(parent.left == delNode) bro = parent.right;
else bro = parent.left;
//被删除节点为叶子节点
if(delNode.left == null && delNode.right == null ){
//被删除节点为红节点时
if(delNode.color == 1) {
if (parent.left == delNode) parent.left = null;
else parent.right = null;
}
//被删除节点为黑节点时
else{
//兄弟节点为黑节点时
if(bro.color == 2){
//兄弟节点也为叶子节点
if(bro.left == null && bro.right == null ) {
if (parent.left == delNode) parent.left = null;
else parent.right = null;
//父节点为红节点
if (parent.color == 1) {
parent.color = 2;
bro.color = 1;
}
//父节点为黑节点
else {
bro.color = 1;
}
}
//左侄子节点不为空
else if(bro.left != null && bro.right == null){
TreeNode temp = new TreeNode(parent.val,2);
if(parent.left == delNode){
parent.left = temp;
parent.val = bro.left.val;
bro.left = null;
}else{
parent.right = temp;
parent.left = bro.left;
parent.val = bro.val;
bro.left.color = 2;
}
}
//右侄子节点不为空
else if(bro.right != null && bro.left == null){
TreeNode temp = new TreeNode(parent.val,2);
if(parent.left == delNode){
parent.left = temp;
parent.right = bro.right;
bro.right.color = 2;
parent.val = bro.val;
}else{
parent.right = temp;
bro.right = null;
parent.val = bro.right.val;
}
}
//左右侄子节点都不为空
else if(bro.left !=null && bro.right != null){
if(parent.right == delNode){
parent.right = null;
parent.rightRota();
}else{
parent.left = null;
parent.leftRota();
}
parent.left.color = 2;
parent.right.color = 2;
}
}
//兄弟节点为红
else{
if(parent.left == delNode){
parent.left = null;
parent.leftRota();
if(parent.left.right.left !=null && parent.left.right.right != null){
parent.left.leftRota();
}else if(parent.left.right.left !=null && parent.left.right.right == null){
TreeNode temp = new TreeNode(parent.left.val,1);
parent.left.val = parent.left.right.right.val;
parent.left.color = 2;
deleteNode(parent.left.right.left);
parent.left.left = temp;
parent.left.right.color = 1;
}else{
parent.left.leftRota();
}
}else{
parent.right = null;
parent.rightRota();
if(parent.right.right.left !=null && parent.right.right.right != null){
parent.right.rightRota();
}else if(parent.right.left.left ==null && parent.right.left.right != null){
TreeNode temp = new TreeNode(parent.right.val,1);
parent.right.val = parent.right.left.right.val;
parent.right.color = 2;
deleteNode(parent.right.left.right);
parent.right.right = temp;
parent.right.left.color = 1;
}else{
parent.right.rightRota();;
}
}
}
}
}
//被删除节点是非叶子节点
else{
//被删除节点为红节点时 (父节点为红节点,必然有两个黑子节点,不会出现只有一个子节点的问题)
if(delNode.color == 1){
int val = findMaxNodeValue(delNode.left);
delNode.val = val;
if(delNode.rightHigh() - delNode.leftHigh() > 1){
delNode.leftRota();
}else if(delNode.left == null && delNode.right != null){
delNode.right.color = 1;
}
}
//被删除节点为黑节点时
else{
if(delNode.left != null && delNode.right == null){
if(parent.left == delNode){
parent.left = delNode.left;
delNode.left.color = 2;
}else{
parent.right = delNode.left;
delNode.left.color = 2;
}
}else if(delNode.right != null && delNode.left == null){
if(parent.left == delNode){
parent.left = delNode.right;
delNode.right.color = 2;
}else{
parent.right = delNode.right;
delNode.right.color = 2;
}
}else{
int val = findMaxNodeValue(delNode.left);
delNode.val = val;
}
}
}
}
//寻找节点
public TreeNode find(int val){
if(this.val == val) return this;
TreeNode node = null;
if(val < this.val) node = this.left.find(val);
if(val > this.val) node =this.right.find(val);
return node;
}
//寻找父节点
public TreeNode findParent(TreeNode node){
if((this.left != null && this.left.val == node.val) || (this.right != null && this.right.val == node.val))return this;
else if((this.left == null && node.val < this.val) || (this.right == null && node.val > this.val)) return this;
TreeNode parent = null;
if(this.left != null && node.val < this.val) parent = left.findParent(node);
if(this.right != null && node.val > this.val) parent = right.findParent(node);
return parent;
}
//寻找最小节点值
public int findMinNodeValue(TreeNode node){
while(node.left != null){
node = node.left;
}
deleteNode(node);
return node.val;
}
//寻找最大节点值
public int findMaxNodeValue(TreeNode node){
while (node.right != null){
node = node.right;
}
deleteNode(node);
return node.val;
}
//右旋
public void rightRota(){
TreeNode temp = new TreeNode(val,1);
temp.right = this.right;
temp.left = this.left.right;
this.val = this.left.val;
this.left = this.left.left;
this.right = temp;
}
//左旋
public void leftRota(){
TreeNode temp = new TreeNode(val,1);
temp.left = this.left;
temp.right = this.right.left;
this.val = this.right.val;
this.right = this.right.right;
this.left = temp;
}
//当前节点为根节点进行求树的高度
public int treeHigh(){
return Math.max(left == null ? 0 : left.treeHigh(),right == null ? 0 : right.treeHigh())+1;
}
public int leftHigh(){
if(left == null) return 0;
return left.treeHigh();
}
public int rightHigh(){
if(right == null) return 0;
return right.treeHigh();
}
//中序遍历
public void mid(){
if(this.left != null) this.left.mid();
System.out.print(this+" ");
if(this.right != null) this.right.mid();
}
public String toString(){
return "TreeNode["+val+","+(color == 1 ? "红" : "黑")+"]";
}
}