红黑树
R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。
红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
注意:
(01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
(02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。
应用
红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。
例如,Java集合中的TreeSet和TreeMap,Linux虚拟内存的管理,都是通过红黑树去实现的
左旋和右旋
红黑树的基本操作是添加、删除和旋转。在对红黑树进行添加或删除后,会用到旋转方法。为什么呢?道理很简单,添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。
代码如下
package com.example.demo.RedBlankTree;
/**
* 红黑树
*
* 左旋和右旋实现
* @author hh
*/
public class RBTree {
RBNode root;
/**
* 对x进行左旋
* 从上往下看变化
* p p
* / /
* x 对x左旋 y
* / \ -------> /\
* lx y x ry
* /\ / \
* ly ry lx ly
*
* @param x
*/
private void leftRoute(RBNode x) {
RBNode y = x.right;
RBNode ly = y.left;
//将y的左节点指向x的右节点
x.right = ly;
//如果y的左节点ly不为空 把ly的父节点 指向x
if (ly != null) {
ly.parent = x;
}
//将原来x的父节点 指向为y的父节点(更新父节点)
y.parent = x.parent;
if (x.parent == null) {
this.root = y;
} else {
//如果x为左节点
if (x == x.parent.left) {
x.parent.left = y;
} else {
//如果x为右节点
x.parent.right = y;
}
}
//更新xy与下面子节点的关系
y.left = x;
x.parent = y;
}
/**
* 右旋
* 同上
*
* @param x
*/
private void rightRoute(RBNode x) {
RBNode y = x.left;
x.left = y.right;
if (y.right != null) {
y.right.parent = x;
}
if (y == null) {
this.root = y;
} else {
if (x == x.parent.left) {
//如果为左节点
x.parent.left = y;
} else {
//x为右节点
x.parent.right = y;
}
}
y.left = x;
x.parent = y;
}
/**
* 红黑树节点
*
* @param <T>
*/
final class RBNode<T extends Comparable<T>> {
/**
* 颜色
*/
boolean color;
/**
* 节点值
*/
T key;
/**
* 左节点
*/
RBNode<T> left;
/**
* 右节点
*/
RBNode<T> right;
/**
* 父节点
*/
RBNode<T> parent;
public T getKey() {
return key;
}
}
}