八大数据结构——红黑树(七)
树是数据结构中非常重要的一项,有关树的数据结构有许多种,本文重点研究的是红黑树。
关于红黑树,是二叉树范畴里的高级数据结构,内容十分的多,网上各种文章参差不齐,经过我的血泪史,读者可以通过以下文章,完整的了解红黑树,并且最后附上Java实现代码。
二叉搜索树
红黑树是建立在二叉搜索树基础上的,如果您还不了解,请看 八大数据结构——二叉搜索树(七)。
2-4树
在学习红黑树之前,您需要搞懂:红黑树中最重要的,红与黑两种颜色代表什么?为什么要用标上红与黑这两种颜色?
通过了解2-4树(您不一定要完全掌握2-4树),来理解红黑树。请看 通过2-3-4树理解红黑树 。
红黑树的定义和插入
通过该篇文章,您可以初步了解红黑树的定义和插入操作。请看 彻底理解红黑树(二)之 插入 。
红黑树的删除
红黑树的删除是其重点与难点,涉及的情况非常多,如果您一时无法明白,可以结合下面的实现代码理解。请看 彻底理解红黑树(三)之 删除 。
红黑树演示网站
有一个网站,非常不错,可以动态演示很多常用的数据结构,您可以通过该网站直观地了解红黑树的插入和删除操作。请看 红黑树演示网站 。
如果您还想了解其他的数据结构动画,可以点击它们的目录 演示网站目录 。
红黑树与AVL树
学习过AVL树的都知道,AVL树的平衡程度更高于红黑树,为什么许多的实际数据结构应用,还是使用了红黑树呢?
- 著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块
- epoll在内核中的实现,用红黑树管理事件块
- nginx中,用红黑树管理timer等
- Java的TreeMap实现
请看 红黑树与AVL树,各自的优缺点总结 。
面试中关于红黑树
代码实现
洋洋洒洒地学完那么多,来看看Java代码实现吧。您可以对照前面的文章来看代码,就会好理解很多,代码中给出了一些重要注释,也方便您的理解。
//红黑树
public class RedBlackTree<T extends Comparable> {
private RBNode<T> root;
private int size;
public RedBlackTree() {
root = null;
size = 0;
}
public RedBlackTree(T val) {
root = new RBNode<>();
root.color = Color.black;
root.val = val;
size = 1;
}
public boolean empty() {
return size == 0;
}
public int size() {
return size;
}
// 插入节点
public boolean insert(T val) {
// 如果val为null直接返回
if (val == null) {
return false;
}
// 如果root为null,那新建一个节点,并让保存为root
if (root == null) {
root = new RBNode<>();
root.val = val;
root.color = Color.black;
size++;
return true;
}
// root不为null,那就通过循环找到正确的插入位置
RBNode<T> node = root;
while (true) {
// 如果val与已有值相等,则不允许插入
if (node.val.compareTo(val) == 0) {
return false;
}
// val值小于当前节点,则插入到左子树
if (node.val.compareTo(val) > 0) {
// 如果左子节点为空,则插入到此处
if (node.leftNode == null) {
RBNode<T> leftNode = new RBNode<>();
leftNode.val = val;
leftNode.color = Color.red;
node.leftNode = leftNode;
adjustInsert(leftNode);
size++;
return true;
} else {
// 不为空继续往下找
node = node.leftNode;
}
// val值大于当前节点,则插入到右子数
} else {
// 如果右子节点为空,则插入到此处
if (node.rightNode == null) {
RBNode<T> rightNode = new RBNode<>();
rightNode.val = val;
rightNode.color = Color.red;
node.rightNode = rightNode;
adjustInsert(rightNode);
size++;
return true;
} else {
// 不为空继续往下找
node = node.rightNode;
}
}
}
}
// 删除节点
public boolean remove(T val) {
RBNode<T> node = find(val);
if (node == null) {
return false;
}
// 要删除的节点有三种情况,度为2,度为1和度为0的。
// 平衡的情况也分三种:1.1删除的节点度为0,且为红色,无需调整。
// 1.2删除的节点度为0,且为黑色,需调整。
// 2
// .删除的节点度为1,将子节点涂为黑色即可。(只有一个子节点时,删除节点比为是黑色,其子节点为红色)
// 3
// .删除的节点度为2,实际上删除节点知识替换了值,真正被删除的是其左子树中最大节点,而这个最大节点度为0,或1,所以又转向上面的情况。
if (node.leftNode != null && node.rightNode != null) {
// 度为2的节点,删除步骤为
// 1.找到要删除节点的左子数中最大节点。
// 2.替换待删除节点的值为这个最大节点值
// 3.将这个最大节点删除
RBNode<T> maxNode = node.leftNode;
while (maxNode.rightNode != null) {
maxNode = maxNode.rightNode;
}
remove(maxNode.val);
node.val = maxNode.val;
} else {
// 度为1和度为2的节点一起处理,分两种情况。
// 1.要删除的节点为根节点。
// 2.要删除的节点为非根节点。
RBNode<T> parent = parent(node);
RBNode<T> brother = brother(node);
RBNode<T> child =
node.leftNode == null ? node.rightNode : node.leftNode;
// 根节点无父节点,直接将根节点指向子节点即可。
if (parent == null) {
root = child;
} else {
// 非根节点,找到它是父节点的左子节点,还是右子节点,然后通过修改父节点指针即可。
adjustParent(node, child);
}
if (child == null) {
// 删除节点度为0,且为黑色,需要调整。
if (node.color.compareTo(Color.black) == 0) {
adjustDelete(parent, brother);
}
} else {
// 删除节点度为1,只需将子节点涂黑。
child.color = Color.black;
}
}
size--;
return true;
}
// 插入后调整红黑树。
private void adjustInsert(RBNode<T> node) {
// 处理情景4.1的情况,如果祖先节点是根节点,将根节点又设置回黑色。
if (node == root) {
node.color = Color.black;
return;
}
RBNode<T> parent = parent(node);
if (parent.color.compareTo(Color.black) == 0) {
// 情景3:父节点为黑色
return;
} else {
// 父节点如果为红色,那么必然存在祖先节点,因为根节点是黑色,而且两个红色节点不能相连。
// 情景4:插入结点的父结点为红结点
RBNode<T> grandparent = parent(parent);
RBNode<T> uncle = uncle(node);
if (uncle != null && uncle.color.compareTo(Color.red) == 0) {
// 情景4.1:叔叔结点存在并且为红结点
parent.color = Color.black;
uncle.color = Color.black;
grandparent.color = Color.red;
adjustInsert(grandparent);
} else {
if (grandparent.leftNode == parent) {
// 情景4
// .2:叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的左子结点
if (parent.leftNode == node) {
// 情景4.2.1:插入结点是其父结点的左子结点
RTurn(grandparent);
grandparent.color = Color.red;
parent.color = Color.black;
} else {
// 情景4.2.2:插入结点是其父结点的右子结点
LTurn(parent);
RTurn(grandparent);
node.color = Color.black;
grandparent.color = Color.red;
}
} else {
// 情景4
// .3:叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的右子结点
if (parent.leftNode == node) {
// 情景4.3.1:插入结点是其父结点的左子结点
RTurn(parent);
LTurn(grandparent);
node.color = Color.black;
grandparent.color = Color.red;
} else {
// 情景4.3.2:插入结点是其父结点的右子结点
LTurn(grandparent);
grandparent.color = Color.red;
parent.color = Color.black;
}
}
}
}
}
// 删除后调整红黑树,brother无需进行null判断,因为当删除节点是度为0的黑色时,其左子树黑色点已经达到2(null算黑色),
// 而兄弟节点如果为null,那么右子树黑色节点只有1,这是不可能的,在删除前,树一定是平衡的。
// 而兄弟节点的子节点,只要是red,必然不为null,而只有是red的情况,我们才调用到,所以也不会出现空指针。
// 像下面的兄弟节点的子节点为黑时,是不会有对这个黑色子节点的操作的,有些旋转后是它另外一个红色子节点上位了,
// 而原来的兄弟节点下去当子节点了,依然不会涉及黑色子节点的操作。
private void adjustDelete(RBNode<T> parent, RBNode<T> brother) {
// 1.n为根节点,无需平衡操作
if (parent == null) {
return;
}
if (brother.color.compareTo(Color.black) == 0) {
// 2.兄弟节点为黑色
if (!(brother.leftNode != null &&
brother.leftNode.color.compareTo(Color.red) == 0) &&
!(brother.rightNode != null &&
brother.rightNode.color.compareTo(Color.red) ==
0)) {
// 2.1兄弟子节点全黑
if (parent.color.compareTo(Color.red) == 0) {
// 2.1.1父红
exchangeColor(parent, brother);
} else {
// 2.1.2父黑
brother.color = Color.red;
adjustDelete(parent(parent), brother(parent));
}
} else {
// 2.2.1兄在左
if (parent.leftNode == brother) {
// 兄左子红
if (brother.leftNode != null &&
brother.leftNode.color.compareTo(Color.red) == 0) {
RTurn(parent);
exchangeColor(parent, brother);
brother.leftNode.color = Color.black;
} else {
// 兄左子黑
RBNode<T> rightNode = brother.rightNode;
LTurn(brother);
exchangeColor(brother, rightNode);
adjustDelete(parent, rightNode);
}
} else {
// 2.2.2兄在右
if (brother.rightNode != null &&
brother.rightNode.color.compareTo(Color.red) == 0) {
// 兄右子红
LTurn(parent);
exchangeColor(parent, brother);
brother.rightNode.color = Color.black;
} else {
// 兄右子黑
RBNode<T> leftNode = brother.leftNode;
RTurn(brother);
exchangeColor(brother, leftNode);
adjustDelete(parent, leftNode);
}
}
}
} else {
// 3.兄弟节点为红色
if (parent.leftNode == brother) {
// 兄在左
RBNode<T> rightNode = brother.rightNode;
RTurn(parent);
exchangeColor(parent, brother);
adjustDelete(parent, rightNode);
} else {
// 兄在右
RBNode<T> leftNode = brother.leftNode;
LTurn(parent);
exchangeColor(parent, brother);
adjustDelete(parent, leftNode);
}
}
}
// 修改父节点的左右子节点指针。
private void adjustParent(RBNode<T> node, RBNode<T> child) {
RBNode<T> parent = parent(node);
if (parent.leftNode != null && parent.leftNode == node) {
parent.leftNode = child;
} else {
parent.rightNode = child;
}
}
// 交换颜色
private void exchangeColor(RBNode<T> node1, RBNode<T> node2) {
Color color = node1.color;
node1.color = node2.color;
node2.color = color;
}
// 查找节点
private RBNode<T> find(T val) {
if (root == null || val == null) {
return null;
}
RBNode<T> node = root;
while (node != null) {
if (node.val.compareTo(val) == 0) {
return node;
} else if (node.val.compareTo(val) > 0) {
node = node.leftNode;
} else {
node = node.rightNode;
}
}
return null;
}
// 左旋
private void LTurn(RBNode<T> node) {
RBNode<T> parent = parent(node);
RBNode<T> rightNode = node.rightNode;
if (parent == null) {
root = rightNode;
} else {
adjustParent(node, rightNode);
}
node.rightNode = rightNode.leftNode;
rightNode.leftNode = node;
}
// 右旋
private void RTurn(RBNode<T> node) {
RBNode<T> parent = parent(node);
RBNode<T> leftNode = node.leftNode;
if (parent == null) {
root = leftNode;
} else {
adjustParent(node, leftNode);
}
node.leftNode = leftNode.rightNode;
leftNode.rightNode = node;
}
// 查找父节点。
private RBNode<T> parent(RBNode<T> current) {
if (root == null || current == null) {
return null;
}
RBNode<T> node = root;
while (node != null) {
if (node.leftNode == current || node.rightNode == current) {
return node;
} else if (node.val.compareTo(current.val) > 0) {
node = node.leftNode;
} else {
node = node.rightNode;
}
}
return null;
}
// 查找叔叔节点
private RBNode<T> uncle(RBNode<T> node) {
RBNode<T> parent = parent(node);
return brother(parent);
}
// 查找兄弟节点
private RBNode<T> brother(RBNode<T> node) {
RBNode<T> parent = parent(node);
if(parent==null){
return null;
}
if (parent.leftNode != null && parent.leftNode == node) {
return parent.rightNode;
} else {
return parent.leftNode;
}
}
private void LDR(RBNode<T> node) {
if (node == null) {
return;
}
LDR(node.leftNode);
System.out.println(node.val+","+node.color);
LDR(node.rightNode);
}
public void LDR() {
LDR(root);
}
}
//红黑树节点。
class RBNode<T extends Comparable> {
Color color;
T val;
RBNode<T> leftNode;
RBNode<T> rightNode;
}
//枚举类,定义红黑两种颜色。
enum Color {
red, black
}