本文是红黑树系列文章的第三篇,前两篇分别介绍了2-3树和红黑树常用操作的理论,本文主要介绍红黑树的实现。
/**
* 红黑树类
* @author Administrator
*
*/
public class RedBlackTree<T extends Comparable> {
//定义红黑树的颜色
private static final boolean RED = true;
private static final boolean BLACK = false;
/**
* 节点类
* @author Administrator
*
*/
static class Node{
Object data;
Node parent,left,right;
//节点的默认颜色是黑色
boolean color = BLACK;
public Node(Object data, Node parent, Node left, Node right) {
this.data = data;
this.parent = parent;
this.left = left;
this.right = right;
}
@Override
public String toString() {
return "Node [data=" + data + ", parent=" + parent + ", left=" + left + ", right=" + right + ", color="
+ color + "]";
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj.getClass() == Node.class){
Node target = (Node) obj;
return data.equals(target.data) &&
parent ==(target.parent) &&
left == (target.left) &&
right == (target.right) &&
color == (target.color);
}
return false;
}
}
//根节点
private Node root;
public RedBlackTree() {
root = null;
}
public RedBlackTree(T data) {
this.root = new Node(data, null, null, null);
}
/**
* 添加节点
* @param ele
*/
public void add(T ele){
//如果根节点为空
if(root == null){
root = new Node(ele, null, null, null);
}
else{
Node current = root;
Node parent = null;
int cmp ;
//搜索合适的叶子节点,以该节点为父节点添加合适的子节点
do
{
parent = current;
cmp = ele.compareTo(current.data);
//如果新节点大于当前节点
if(cmp > 0){
//以右子节点为当前节点
current = current.right;
}
//如果新节点小于当前节点
if(cmp < 0){
current = current.left;
}
else{
current.data = ele;
}
}while(current != null);
//创建新节点
Node newNode = new Node(ele, parent, null, null);
if(cmp > 0){
//新节点作为父节点的右孩子
parent.right = newNode;
}
else{
//新节点作为父节点的右孩子
parent.left = newNode;
}
//维护修复红黑树
fixAfterInsertion(newNode);
}
}
/**
* 插入新节点后维护修复红黑树
* @param newNode 新插入的节点
*/
private void fixAfterInsertion(Node x) {
x.color = RED;
//知道x的父节点不是根节点且x的父节点是红色
while(x != null && x != root && x.parent.color == RED){
//x的父节点是其父节点的左子节点
if(parentOf(x) == leftOf(parentOf(parentOf(x)))){
//获取父节点的兄弟节点
Node y = rightOf(parentOf(parentOf(x)));
//如果x的父节点的兄弟节点是红色
if(colorOf(y) == RED){
//将x的父节点设为黑色
setColor(parentOf(x),BLACK);
//将x的父节点的兄弟节点设为黑色
setColor(y, BLACK);
//将x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
}
//如果x的父节点的兄弟节点是黑色的
else{
//如果x是父节点的右子节点
if(x == rightOf(parentOf(x))){
//将x的父节点设为x
x = parentOf(x);
rotateLeft(x);
}
//把x的额父节点设为黑色
setColor(parentOf(x), BLACK);
//把x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
}
//x的父节点是其父节点的右子节点
else{
//获取父节点的兄弟节点
Node y = leftOf(parentOf(parentOf(x)));
//如果x的父节点的兄弟节点为红色
if(colorOf(y) == RED){
//将x的父节点设为黑色
setColor(parentOf(x),BLACK);
//将x的父节点的兄弟节点设为黑色
setColor(y, BLACK);
//将x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
}
//如果x的父节点的兄弟节点是黑色的
else{
//如果x是父节点的左子节点
if(x == leftOf(parentOf(x))){
//将x的父节点设为x
x = parentOf(x);
rotateRight(x);
}
//把x的额父节点设为黑色
setColor(parentOf(x), BLACK);
//把x的父节点的父节点设为红色
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}
/**
* 右旋
* @param parentOf
*/
private void rotateRight(Node p) {
if(p != null){
//求得左右左右子节点
Node l = p.left;
Node q = l.right;
//将l的右子节点链接到p的左子节点
p.left = q;
//让l的you子节点的parent指向p节点
if(q != null){
q.parent = p;
}
l.parent = p.parent;
//如果p已经是根节点
if(p.parent == null){
root = l;
}
//如果p是其父节点的you子节点
else if(p.parent.left == p){
//将r设为x的父节点的you子节点
p.parent.right = l;
}else{
//将l设为p的父节点的zuo子节点
p.parent.left = l;
}
l.right = p;
p.parent = l;
}
}
/**
* 左旋
* @param x
*/
private void rotateLeft(Node x) {
if(x != null){
//求得左右左右子节点
Node r = x.right;
Node q = r.left;
//将r的左子节点链接到x的右子节点
x.right = q;
//让r的左子节点的parent指向x节点
if(q != null){
q.parent = x;
}
r.parent = x.parent;
//如果x已经是根节点
if(x.parent == null){
root = r;
}
//如果x是其父节点的左子节点
else if(x.parent.left == x){
//将r设为x的父节点的左子节点
x.parent.left = r;
}else{
//将r设为x的父节点的右子节点
x.parent.right = r;
}
r.left = x;
x.parent = r;
}
}
/**
* 为指定节点设置颜色
* @param p 指定节点
* @param c 颜色
*/
private void setColor(Node p, boolean c) {
if(p != null){
p.color = c;
}
}
/**
* 获取指定节点的颜色
* @param y 指定节点
* @return 返回指定节点的颜色
*/
private boolean colorOf(Node y) {
return (y == null ? BLACK : y.color);
}
/**
* 获取指定节点的右子节点
* @param p 指定节点
* @return 返回自定节点的右子节点
*/
private Node rightOf(Node p) {
return (p == null) ? null : p.right;
}
/**
* 获取指定节点的左子节点
* @param p 指定节点
* @return 返回自定节点的左子节点
*/
private Node leftOf(Node p) {
return (p == null) ? null : p.left;
}
/**
* 获取指定节点的父节点
* @param x 指定节点
* @return 返回自定节点的父节点
*/
private Node parentOf(Node x) {
return (x == null ? null : x.parent);
}
/**
* 删除节点
* @param ele 要删除的节点的值
*/
public void remove(T ele){
//获取要删除的节点
Node target = getNode(ele);
//如果被删除的节点的左右子树都不为空
if(target.left != null && target.right != null){
//找到target中序便利的前一个节点,用s表示
Node s = target.left;
//搜索左子树中的最大节点
while(s.right != null){
s = s.right;
}
//用s代替p节点
target.data = s.data;
target = s;
}
//开始修复替换节点,如果该节点不为null
Node replacement = (target.left != null ? target.left : target.right);
if(replacement != null){
//让replacement的parent指向target的parent
replacement.parent = target.parent;
//如果target的parent为null,则target为根节点
if(target.parent == null){
root = replacement;
}
//如果target是其父节点的左子孩子
else if(target == target.parent.left){
//让target的父节点的左子孩子指向replacement
target.parent.left = replacement;
}
//如果target是其父节点的右子孩子
else{
//让target的父节点的右子孩子指向replacement
target.parent.right = replacement;
}
//彻底删除target节点
target.parent = target.left = target.right = null;
//修复红黑树
if(target.color == BLACK){
fixAfterDeletion(replacement);
}
}
//target本身为根节点
else if(target.parent == null){
root = null;
}
else{
//target没有子节点,把它当成虚的替换节点
//修复红黑树
if(target.color == BLACK){
fixAfterDeletion(target);
}
if(target.parent != null){
//如果target是其父节点的左子节点
if(target == target.parent.left){
target.parent.left = null;
}
//如果target是其父节点的右子节点
if(target == target.parent.right){
target.parent.right = null;
}
//将target的parent置为null
target.parent = null;
}
}
}
/**
* 杀出节点后修复红黑树
* @param replacement
*/
private void fixAfterDeletion(Node x) {
//直到x不是根节点且x的颜色是黑色
while(x != root && colorOf(x) == BLACK){
//如果x是其父节点的左子节点
if(x == leftOf(parentOf(x))){
//获取x节点的兄弟节点
Node sid = rightOf(parentOf(x));
//如果sid节点是红色的
if(sid.color == RED){
//将sid设为黑色
setColor(sid, BLACK);
//将x的父节点设为红色
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
//再次将sid设为x的父节点的右子节点
sid = rightOf(parentOf(x));
}
//如果sid的两个子节点均为黑色
if(colorOf(leftOf(sid)) == BLACK && colorOf(rightOf(sid)) == BLACK){
//将sid设为红色
setColor(sid, BLACK);
//让x等于它的父节点
x = parentOf(x);
}
else{
//如果sid只有右子节点是黑色的
if(colorOf(rightOf(sid)) == BLACK){
//将sid的左子节点设为黑色
setColor(leftOf(sid), BLACK);
//将sid设为红色
setColor(sid, RED);
rotateRight(sid);
sid = rightOf(parentOf(sid));
}
//设置sid的颜色与x的父节点的颜色相同
setColor(sid, colorOf(parentOf(x)));
//将x的父节点设为黑色
setColor(parentOf(x), BLACK);
//将sid的右子节点设为黑色
setColor(rightOf(sid), BLACK);
rotateLeft(parentOf(x));
x = root;
}
}else{
//如果x是其父节点的右子节点
//获取x的兄弟节点
Node sid = leftOf(parentOf(x));
//如果sid的颜色是红色的
if(colorOf(sid) == RED){
//将sid点的颜色设为黑色
setColor(sid, BLACK);
//将sid的父节点设为红色
setColor(parentOf(sid),RED);
rotateRight(parentOf(x));
sid = leftOf(parentOf(x));
}
//如果sid的两个节点都是黑色
if(colorOf(leftOf(sid)) == BLACK && colorOf(rightOf(sid)) == BLACK){
//将sid设为红色
setColor(sid, BLACK);
//让x等于它的父节点
x = parentOf(x);
}else{
//如果sid只有左子节点是黑色的
if(colorOf(leftOf(sid)) == BLACK){
//将sid的右子节点设为黑色
setColor(rightOf(sid), BLACK);
//将sid设为红色
setColor(sid, RED);
rotateLeft(sid);
sid = leftOf(parentOf(sid));
}
//设置sid的颜色与x的父节点的颜色相同
setColor(sid, colorOf(parentOf(x)));
//将x的父节点设为黑色
setColor(parentOf(x), BLACK);
//将sid的右子节点设为黑色
setColor(leftOf(sid), BLACK);
rotateLeft(parentOf(x));
x = root;
}
}
}
setColor(x, BLACK);
}
/**
* 根据节点的值获取节点
* @param ele 节点的值
* @return
*/
public Node getNode(T ele) {
// 从根节点开始搜索
Node p = root;
while(p != null){
int cmp = ele.compareTo(p.data);
if(cmp > 0){
p = p.right;
}else if(cmp < 0){
p = p.left;
}else{
return p;
}
}
return null;
}
}
参考文献
- 《算法》
- 《java突破程序员基本功的16课》