平衡二叉查找树
这种二叉查找树就退化成了链表,由于树的深度变得多了,查找的效率也会大幅下降
所以需要对这种二叉树进行自平衡,红黑树就是一种自平衡的二叉查找树
红黑树(Red Black Tree)
除了二叉查找树(BST)的特征外,还有以下特征:
- 每个节点要么是黑色,要么是红色
- 根节点是黑色
- 每个叶子节点都是黑色的空结点(NIL结点)(为了简单期间,一般会省略该节点)
- 如果一个节点是红色的,则它的子节点必须是黑色的(父子不能同为红)
- 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点(平衡的关键)
- 新插入节点默认为红色,插入后需要校验红黑树是否符合规则,不符合则需要进行平衡
一颗典型的红黑树:
在对红黑树进行添加或者删除操作时可能会破坏这些特点,所以红黑树采取了很多方式来维护这些特
点,从而维持平衡。主要包括:左旋转、右旋转和颜色反转
左旋(RotateLeft)
逆时针旋转红黑树的两个结点,使得父结点被自己的右孩子取代,而自己成为自己的左孩子
上图所示过程如下:
- 以X为基点逆时针旋转
- X的父节点被x原来的右孩子Y取代
- c保持不变
- Y节点原来的左孩子c变成X的右孩子
右旋(RotateRight)
顺时针旋转红黑树的两个结点,使得父结点被自己的左孩子取代,而自己成为自己的右孩子
上图所示过程如下:
- 以X为基点顺时针旋转
- X的父节点被x原来的左孩子Y取代
- b保持不变
- Y节点原来的右孩子c变成X的左孩子
颜色反转
就是当前节点与父节点、叔叔节点同为红色,这种情况违反了红黑树的规则,需要将红色向祖辈上传,
父节点和叔叔节点红色变为黑色,爷爷节点从黑色变为红色(爷爷节点必为黑色,因为此前是符合红黑
树规则的)。这样每条叶子结点到根节点的黑色节点数量并未发生变化,因此都其他树结构不产生影响
代码实现
package com.yyjzy.redblack;
/**
* 红黑树结点
*/
public class RBTreeNode {
private int key;
private boolean isBlack;
private RBTreeNode left;
private RBTreeNode right;
private RBTreeNode parent;
public RBTreeNode(int key) {
this.key = key;
isBlack=false;// 新增节点默认为红色
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public boolean isBlack() {
return isBlack;
}
public void setBlack(boolean black) {
isBlack = black;
}
public RBTreeNode getLeft() {
return left;
}
public void setLeft(RBTreeNode left) {
this.left = left;
}
public RBTreeNode getRight() {
return right;
}
public void setRight(RBTreeNode right) {
this.right = right;
}
public RBTreeNode getParent() {
return parent;
}
public void setParent(RBTreeNode parent) {
this.parent = parent;
}
@Override
public String toString() {
return "RBTreeNode{" +