1、红黑树的属性

1. 树中的每个节点要么是红色，要么是黑色；
2. 根节点是黑色；
3. 每个叶子节点（null）是黑色；
4. 如果某节点是红色的，它的两个子节点都是黑色；
5. 对于每个节点到后面任一叶子节点（null）的所有路径，都有相同数量的黑色节点。

``````public enum Color {
Black("黑色"), Red("红色");
private String color;
private Color(String color) {
this.color = color;
}
@Override
public String toString() {
return color;
}
}
``````

``````public class Node {
public int key;
public Color color;
public Node left;
public Node right;
public Node parent;
public Node() {
}
public Node(Color color) {
this.color = color;
}
public Node(int key) {
this.key = key;
this.color = Color.Red;
}
public int height() {
return Math.max(left != RedBlackTree.NULL ? left.height() : 0, right != RedBlackTree.NULL ? right.height() : 0) + 1;
}
public Node minimum() {
Node pointer = this;
while (pointer.left != RedBlackTree.NULL)
pointer = pointer.left;
return pointer;
}
@Override
public String toString() {
String position = "null";
if (this.parent != RedBlackTree.NULL)
position = this.parent.left == this ? "left" : "right";
return "[key: " + key + ", color: " + color + ", parent: " + parent.key + ", position: " + position + "]";
}
}
``````

``````public class RedBlackTree {
// 表示哨兵变量
public final static Node NULL = new Node(Color.Black);
public Node root;
public RedBlackTree() {
this.root = NULL;
}
}
``````

2、旋转

`````` public void leftRotate(Node node) {
Node rightNode = node.right;
node.right = rightNode.left;
if (rightNode.left != RedBlackTree.NULL)
rightNode.left.parent = node;
rightNode.parent = node.parent;
if (node.parent == RedBlackTree.NULL)
this.root = rightNode;
else if (node.parent.left == node)
node.parent.left = rightNode;
else
node.parent.right = rightNode;
rightNode.left = node;
node.parent = rightNode;
}
public void rightRotate(Node node) {
Node leftNode = node.left;
node.left = leftNode.right;
if (leftNode.right != RedBlackTree.NULL)
leftNode.right.parent = node;
leftNode.parent = node.parent;
if (node.parent == RedBlackTree.NULL) {
this.root = leftNode;
} else if (node.parent.left == node) {
node.parent.left = leftNode;
} else {
node.parent.right = leftNode;
}
leftNode.right = node;
node.parent = leftNode;
}
``````

3、插入

`````` public void insert(Node node) {
Node parentPointer = RedBlackTree.NULL;
Node pointer = this.root;
while (this.root != RedBlackTree.NULL) {
parentPointer = pointer;
pointer = node.key < pointer.key ? pointer.left : pointer.right;
}
node.parent = parentPointer;
if(parentPointer == RedBlackTree.NULL) {
this.root = node;
}else if(node.key < parentPointer.key) {
parentPointer.left = node;
}else {
parentPointer.right = node;
}
node.left = RedBlackTree.NULL;
node.right = RedBlackTree.NULL;
node.color = Color.Red;
// 维护红黑树属性的方法
this.insertFixUp(node);
}
``````

1. 当树中没有节点时，此时插入的节点称为根节点，而此节点的颜色为红色。
2. 当新插入的节点成为一个红色节点的子节点时，此时存在一个红色结点有红色子节点的情况。

`````` public void insertFixUp(Node node) {
// 当node不是根结点，且node的父节点颜色为红色
while (node.parent.color == Color.Red) {
// 先判断node的父节点是左子节点，还是右子节点，这不同的情况，解决方案也会不同
if (node.parent == node.parent.parent.left) {
Node uncleNode = node.parent.parent.right;
if (uncleNode.color == Color.Red) { // 如果叔叔节点是红色，则父父一定是黑色
// 通过把父父节点变成红色，父节点和兄弟节点变成黑色，然后在判断父父节点的颜色是否合适
uncleNode.color = Color.Black;
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
node = node.parent.parent;
} else if (node == node.parent.right) {
node = node.parent;
this.leftRotate(node);
} else {
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
this.rightRotate(node.parent.parent);
}
} else {
Node uncleNode = node.parent.parent.left;
if (uncleNode.color == Color.Red) {
uncleNode.color = Color.Black;
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
node = node.parent.parent;
} else if (node == node.parent.left) {
node = node.parent;
this.rightRotate(node);
} else {
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
this.leftRotate(node.parent.parent);
}
}
}
// 如果之前树中没有节点，那么新加入的点就成了新结点，而新插入的结点都是红色的，所以需要修改。
this.root.color = Color.Black;
}
``````

4、删除

`````` public void transplant(Node n1, Node n2) {
if(n1.parent == RedBlackTree.NULL){
this.root = n2;
}else if(n1.parent.left == n1) {
n1.parent.left = n2;
}else {
n1.parent.right = n2;
}
n2.parent = n1.parent;
}
``````

`````` public void delete(Node node) {
Node pointer1 = node;
// 用于记录被删除的颜色，如果是红色，可以不用管，但如果是黑色，可能会破坏红黑树的属性
Color pointerOriginColor = pointer1.color;
// 用于记录问题的出现点
Node pointer2;
if (node.left == RedBlackTree.NULL) {
pointer2 = node.right;
this.transplant(node, node.right);
} else if (node.right == RedBlackTree.NULL) {
pointer2 = node.left;
this.transplant(node, node.left);
} else {
// 如要删除的字节有两个子节点，则找到其直接后继（右子树最小值），直接后继节点没有非空左子节点。
pointer1 = node.right.minimum();
// 记录直接后继的颜色和其右子节点
pointerOriginColor = pointer1.color;
pointer2 = pointer1.right;
// 如果其直接后继是node的右子节点，不用进行处理
if (pointer1.parent == node) {
pointer2.parent = pointer1;
} else {
// 否则，先把直接后继从树中提取出来，用来替换node
this.transplant(pointer1, pointer1.right);
pointer1.right = node.right;
pointer1.right.parent = pointer1;
}
// 用node的直接后继替换node，继承node的颜色
this.transplant(node, pointer1);
pointer1.left = node.left;
pointer1.left.parent = pointer1;
pointer1.color = node.color;
}
if (pointerOriginColor == Color.Black) {
this.deleteFixUp(pointer2);
}
}
``````

1. 当node是红色时，直接变成黑色即可。
2. 当node是黑色时，需要调整红黑树结构。，
`````` private void deleteFixUp(Node node) {
// 如果node不是根节点，且是黑色
while (node != this.root && node.color == Color.Black) {
// 如果node是其父节点的左子节点
if (node == node.parent.left) {
// 记录node的兄弟节点
Node pointer1 = node.parent.right;
// 如果他兄弟节点是红色
if (pointer1.color == Color.Red) {
pointer1.color = Color.Black;
node.parent.color = Color.Red;
leftRotate(node.parent);
pointer1 = node.parent.right;
}
if (pointer1.left.color == Color.Black && pointer1.right.color == Color.Black) {
pointer1.color = Color.Red;
node = node.parent;
} else if (pointer1.right.color == Color.Black) {
pointer1.left.color = Color.Black;
pointer1.color = Color.Red;
rightRotate(pointer1);
pointer1 = node.parent.right;
} else {
pointer1.color = node.parent.color;
node.parent.color = Color.Black;
pointer1.right.color = Color.Black;
leftRotate(node.parent);
node = this.root;
}
} else {
// 记录node的兄弟节点
Node pointer1 = node.parent.left;
// 如果他兄弟节点是红色
if (pointer1.color == Color.Red) {
pointer1.color = Color.Black;
node.parent.color = Color.Red;
rightRotate(node.parent);
pointer1 = node.parent.left;
}
if (pointer1.right.color == Color.Black && pointer1.left.color == Color.Black) {
pointer1.color = Color.Red;
node = node.parent;
} else if (pointer1.left.color == Color.Black) {
pointer1.right.color = Color.Black;
pointer1.color = Color.Red;
leftRotate(pointer1);
pointer1 = node.parent.left;
} else {
pointer1.color = node.parent.color;
node.parent.color = Color.Black;
pointer1.left.color = Color.Black;
rightRotate(node.parent);
node = this.root;
}
}
}
node.color = Color.Black;
}
``````

5、所有代码

``````public enum Color {
Black("黑色"), Red("红色");
private String color;
private Color(String color) {
this.color = color;
}
@Override
public String toString() {
return color;
}
}
``````
``````public class Node {
public int key;
public Color color;
public Node left;
public Node right;
public Node parent;
public Node() {
}
public Node(Color color) {
this.color = color;
}
public Node(int key) {
this.key = key;
this.color = Color.Red;
}
/**
* 求在树中节点的高度
*
* @return
*/
public int height() {
return Math.max(left != RedBlackTree.NULL ? left.height() : 0, right != RedBlackTree.NULL ? right.height() : 0) + 1;
}
/**
* 在以该节点为根节点的树中，求最小节点
*
* @return
*/
public Node minimum() {
Node pointer = this;
while (pointer.left != RedBlackTree.NULL)
pointer = pointer.left;
return pointer;
}
@Override
public String toString() {
String position = "null";
if (this.parent != RedBlackTree.NULL)
position = this.parent.left == this ? "left" : "right";
return "[key: " + key + ", color: " + color + ", parent: " + parent.key + ", position: " + position + "]";
}
}
``````
``````import java.util.LinkedList;
import java.util.Queue;
public class RedBlackTree {
public final static Node NULL = new Node(Color.Black);
public Node root;
public RedBlackTree() {
this.root = NULL;
}
/**
* 左旋转
*
* @param node
*/
public void leftRotate(Node node) {
Node rightNode = node.right;
node.right = rightNode.left;
if (rightNode.left != RedBlackTree.NULL)
rightNode.left.parent = node;
rightNode.parent = node.parent;
if (node.parent == RedBlackTree.NULL)
this.root = rightNode;
else if (node.parent.left == node)
node.parent.left = rightNode;
else
node.parent.right = rightNode;
rightNode.left = node;
node.parent = rightNode;
}
/**
* 右旋转
*
* @param node
*/
public void rightRotate(Node node) {
Node leftNode = node.left;
node.left = leftNode.right;
if (leftNode.right != RedBlackTree.NULL)
leftNode.right.parent = node;
leftNode.parent = node.parent;
if (node.parent == RedBlackTree.NULL) {
this.root = leftNode;
} else if (node.parent.left == node) {
node.parent.left = leftNode;
} else {
node.parent.right = leftNode;
}
leftNode.right = node;
node.parent = leftNode;
}
public void insert(Node node) {
Node parentPointer = RedBlackTree.NULL;
Node pointer = this.root;
while (pointer != RedBlackTree.NULL) {
parentPointer = pointer;
pointer = node.key < pointer.key ? pointer.left : pointer.right;
}
node.parent = parentPointer;
if (parentPointer == RedBlackTree.NULL) {
this.root = node;
} else if (node.key < parentPointer.key) {
parentPointer.left = node;
} else {
parentPointer.right = node;
}
node.left = RedBlackTree.NULL;
node.right = RedBlackTree.NULL;
node.color = Color.Red;
this.insertFixUp(node);
}
private void insertFixUp(Node node) {
// 当node不是根结点，且node的父节点颜色为红色
while (node.parent.color == Color.Red) {
// 先判断node的父节点是左子节点，还是右子节点，这不同的情况，解决方案也会不同
if (node.parent == node.parent.parent.left) {
Node uncleNode = node.parent.parent.right;
if (uncleNode.color == Color.Red) { // 如果叔叔节点是红色，则父父一定是黑色
// 通过把父父节点变成红色，父节点和兄弟节点变成黑色，然后在判断父父节点的颜色是否合适
uncleNode.color = Color.Black;
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
node = node.parent.parent;
} else if (node == node.parent.right) { // node是其父节点的右子节点，且叔叔节点是黑色
// 对node的父节点进行左旋转
node = node.parent;
this.leftRotate(node);
} else { // node如果叔叔节点是黑色，node是其父节点的左子节点，父父节点是黑色
// 把父节点变成黑色，父父节点变成红色，对父父节点进行右旋转
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
this.rightRotate(node.parent.parent);
}
} else {
Node uncleNode = node.parent.parent.left;
if (uncleNode.color == Color.Red) {
uncleNode.color = Color.Black;
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
node = node.parent.parent;
} else if (node == node.parent.left) {
node = node.parent;
this.rightRotate(node);
} else {
node.parent.color = Color.Black;
node.parent.parent.color = Color.Red;
this.leftRotate(node.parent.parent);
}
}
}
// 如果之前树中没有节点，那么新加入的点就成了新结点，而新插入的结点都是红色的，所以需要修改。
this.root.color = Color.Black;
}
/**
* n2替代n1
*
* @param n1
* @param n2
*/
private void transplant(Node n1, Node n2) {
if (n1.parent == RedBlackTree.NULL) { // 如果n1是根节点
this.root = n2;
} else if (n1.parent.left == n1) { // 如果n1是其父节点的左子节点
n1.parent.left = n2;
} else { // 如果n1是其父节点的右子节点
n1.parent.right = n2;
}
n2.parent = n1.parent;
}
/**
* 删除节点node
*
* @param node
*/
public void delete(Node node) {
Node pointer1 = node;
// 用于记录被删除的颜色，如果是红色，可以不用管，但如果是黑色，可能会破坏红黑树的属性
Color pointerOriginColor = pointer1.color;
// 用于记录问题的出现点
Node pointer2;
if (node.left == RedBlackTree.NULL) {
pointer2 = node.right;
this.transplant(node, node.right);
} else if (node.right == RedBlackTree.NULL) {
pointer2 = node.left;
this.transplant(node, node.left);
} else {
// 如要删除的字节有两个子节点，则找到其直接后继（右子树最小值），直接后继节点没有非空左子节点。
pointer1 = node.right.minimum();
// 记录直接后继的颜色和其右子节点
pointerOriginColor = pointer1.color;
pointer2 = pointer1.right;
// 如果其直接后继是node的右子节点，不用进行处理
if (pointer1.parent == node) {
pointer2.parent = pointer1;
} else {
// 否则，先把直接后继从树中提取出来，用来替换node
this.transplant(pointer1, pointer1.right);
pointer1.right = node.right;
pointer1.right.parent = pointer1;
}
// 用node的直接后继替换node，继承node的颜色
this.transplant(node, pointer1);
pointer1.left = node.left;
pointer1.left.parent = pointer1;
pointer1.color = node.color;
}
if (pointerOriginColor == Color.Black) {
this.deleteFixUp(pointer2);
}
}
/**
* The procedure RB-DELETE-FIXUP restores properties 1, 2, and 4
*
* @param node
*/
private void deleteFixUp(Node node) {
// 如果node不是根节点，且是黑色
while (node != this.root && node.color == Color.Black) {
// 如果node是其父节点的左子节点
if (node == node.parent.left) {
// 记录node的兄弟节点
Node pointer1 = node.parent.right;
// 如果node兄弟节点是红色
if (pointer1.color == Color.Red) {
pointer1.color = Color.Black;
node.parent.color = Color.Red;
leftRotate(node.parent);
pointer1 = node.parent.right;
}
if (pointer1.left.color == Color.Black && pointer1.right.color == Color.Black) {
pointer1.color = Color.Red;
node = node.parent;
} else if (pointer1.right.color == Color.Black) {
pointer1.left.color = Color.Black;
pointer1.color = Color.Red;
rightRotate(pointer1);
pointer1 = node.parent.right;
} else {
pointer1.color = node.parent.color;
node.parent.color = Color.Black;
pointer1.right.color = Color.Black;
leftRotate(node.parent);
node = this.root;
}
} else {
// 记录node的兄弟节点
Node pointer1 = node.parent.left;
// 如果他兄弟节点是红色
if (pointer1.color == Color.Red) {
pointer1.color = Color.Black;
node.parent.color = Color.Red;
rightRotate(node.parent);
pointer1 = node.parent.left;
}
if (pointer1.right.color == Color.Black && pointer1.left.color == Color.Black) {
pointer1.color = Color.Red;
node = node.parent;
} else if (pointer1.left.color == Color.Black) {
pointer1.right.color = Color.Black;
pointer1.color = Color.Red;
leftRotate(pointer1);
pointer1 = node.parent.left;
} else {
pointer1.color = node.parent.color;
node.parent.color = Color.Black;
pointer1.left.color = Color.Black;
rightRotate(node.parent);
node = this.root;
}
}
}
node.color = Color.Black;
}
private void innerWalk(Node node) {
if (node != NULL) {
innerWalk(node.left);
System.out.println(node);
innerWalk(node.right);
}
}
/**
* 中序遍历
*/
public void innerWalk() {
this.innerWalk(this.root);
}
/**
* 层次遍历
*/
public void print() {
while (!queue.isEmpty()) {
Node temp = queue.poll();
System.out.println(temp);
if (temp.left != NULL)
if (temp.right != NULL)
}
}
// 查找
public Node search(int key) {
Node pointer = this.root;
while (pointer != NULL && pointer.key != key) {
pointer = pointer.key < key ? pointer.right : pointer.left;
}
return pointer;
}
}
``````

6、演示

``````public class Test01 {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 };
RedBlackTree redBlackTree = new RedBlackTree();
for (int i = 0; i < arr.length; i++) {
redBlackTree.insert(new Node(arr[i]));
}
System.out.println("树的高度： " + redBlackTree.root.height());
System.out.println("左子树的高度： " + redBlackTree.root.left.height());
System.out.println("右子树的高度： " + redBlackTree.root.right.height());
System.out.println("层次遍历");
redBlackTree.print();
// 要删除节点
Node node = redBlackTree.search(4);
redBlackTree.delete(node);
System.out.println("树的高度： " + redBlackTree.root.height());
System.out.println("左子树的高度： " + redBlackTree.root.left.height());
System.out.println("右子树的高度： " + redBlackTree.root.right.height());
System.out.println("层次遍历");
redBlackTree.print();
}
}
``````

``````树的高度： 4

[key: 4, color: 黑色, parent: 0, position: null]
[key: 2, color: 红色, parent: 4, position: left]
[key: 6, color: 红色, parent: 4, position: right]
[key: 1, color: 黑色, parent: 2, position: left]
[key: 3, color: 黑色, parent: 2, position: right]
[key: 5, color: 黑色, parent: 6, position: left]
[key: 7, color: 黑色, parent: 6, position: right]
[key: 8, color: 红色, parent: 7, position: right]

[key: 5, color: 黑色, parent: 0, position: null]
[key: 2, color: 红色, parent: 5, position: left]
[key: 7, color: 红色, parent: 5, position: right]
[key: 1, color: 黑色, parent: 2, position: left]
[key: 3, color: 黑色, parent: 2, position: right]
[key: 6, color: 黑色, parent: 7, position: left]
[key: 8, color: 黑色, parent: 7, position: right]
``````

《算法导论》（第3版） 英文版

用Java实现红黑树的更多相关文章

1. Java实现红黑树

转自:http://www.cnblogs.com/skywang12345/p/3624343.html 红黑树的介绍 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉 ...

2. 基于Java实现红黑树的基本操作

首先,在阅读文章之前,我希望读者对二叉树有一定的了解,因为红黑树的本质就是一颗二叉树.所以本篇博客中不在将二叉树的增删查的基本操作了,需要了解的同学可以到我之前写的一篇关于二叉树基本操作的博客:htt ...

3. Java 集合 | 红黑树 | 前置知识

一.前言 0tnv1e.png 为啥要学红黑树吖? 因为笔者最近在赶项目的时候,不忘抽出时间来复习 Java 基础知识,现在准备看集合的源码啦啦.听闻,HashMap 在 jdk 1.8 的时候,底层 ...

4. java数据结构——红黑树（R-B Tree）

红黑树相比平衡二叉树(AVL)是一种弱平衡树,且具有以下特性: 1.每个节点非红即黑; 2.根节点是黑的; 3.每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的; 4.如图所示,如果一个 ...

5. Java数据结构——红黑树

红黑树介绍红黑树(Red-Black Tree),它一种特殊的二叉查找树.执行查找.插入.删除等操作的时间复杂度为O(logn). 红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点 ...

6. 红黑树(五)之 Java的实现

概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

7. 红黑树 Java实现

概要 前面分别介绍红黑树的理论知识.红黑树的C语言和C++的实现.本章介绍红黑树的Java实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章.还是那句老话,红黑树的C/C+ ...

8. 从2-3-4树到红黑树(下) Java与C的实现

欢迎探讨,如有错误敬请指正 如需转载,请注明出处   http://www.cnblogs.com/nullzx/ 相关博客: 从2-3-4树到红黑树(上) 从2-3-4树到红黑树(中) 1. 实现技 ...

9. java中treemap和treeset实现（红黑树）

java中treemap和treeset实现(红黑树)   TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 Tre ...

10. Java 7之集合类型 - 二叉排序树、平衡树、红黑树---转

http://blog.csdn.net/mazhimazh/article/details/19961017 为了理解 TreeMap 的底层实现,必须先介绍排序二叉树和平衡二叉树,然后继续介绍红黑 ...

随机推荐

1. Educational Codeforces Round 15 Road to Post Office

Road to Post Office 题意: 一个人要从0走到d,可以坐车走k米,之后车就会坏,你可以修或不修,修要花t时间,坐车单位距离花费a时间,走路单位距离花费b时间,问到d的最短时间. 题解 ...

2. IE6下div遮盖select的最优解决方案

a.本节精选html5/css频道里一款IE6下div遮盖select的最优解决方案 原理:利用iframe来遮挡select,再用div来遮挡iframe,就这么简单. 1)首先,建一个div层和i ...

3. 关闭myeclipse中jsp的校验功能

window--->preference--->Myeclipse--->Validation,取消下图红框中的选中状态.

4. MO_GLOBAL - EBS R12 中 Multi Org 设计的深入研究 (3)

这是多组织访问的第三篇文章,翻译自Anil Passi的MO_GLOBAL-Dive into R12 Multi Org Design 我希望你已经读了文章 EBS R12 中的 Multi Org ...

5. JDK及JRE目录结构

JDK文件结构及目录: c:\jdk1.7.0: JDK安装根目录,包括版权.许可证和READEME文件,还包含ser.zip记录Java平台档案. c:\jdk1.7.0\bin 包含在Java开发 ...

6. 20165309 Linux安装及学习

Linux安装及学习 安装虚拟机 结合娄老师的博客<基于VirtualBox虚拟机安装Ubuntu图文教程>和对一些小问题的百度,我也算是很顺利地完成了安装. 然后,按照步骤安装了虚拟机增 ...

7. Java如何使用线程异常？

在Java编程中,如何使用线程异常? 此示例显示如何在处理线程时处理异常. package com.yiibai; class MyThread extends Thread { public voi ...

8. python3 os.walk()使用

os.walk() 方法用于通过在目录树种游走输出在目录中的文件名,向上或者向下. 在Unix,Windows中有效. os.walk(top[, topdown=True[, onerror=Non ...

9. Python 错误和异常小结

1.Python异常类 Python是面向对象语言,所以程序抛出的异常也是类.常见的Python异常有以下几个,大家只要大致扫一眼,有个映像,等到编程的时候,相信大家肯定会不只一次跟他们照面(除非你不 ...

10. 微信公众号 报token验证失败

最近两天一直碰到token验证失败的问题,如下图所示 然后上网疯狂的搜索答案,碰到的人还真不少,原因大概有这几个: 1)服务器URL未实名认证 2)token重名(基本不可能) 3)服务器部署的项目 ...