《演算法導論》紅黑樹詳解(二):Java實現Demo
阿新 • • 發佈:2019-01-28
使用Java簡單地實現紅黑樹,程式碼如下:
/**
* 紅黑樹實現demo
*/
public class RedBlackTree<Key extends Comparable<Key>> {
private static final boolean RED = false;
private static final boolean BLACK = true;
/**
* 葉結點
*/
private final Node nil = new Node();
/**
* 根結點初始化為nil
*/
private Node root = nil;
/**
* 結點類
*/
private class Node {
private Key key;
private Node left;
private Node right;
private Node parent;
private boolean color = BLACK;
public Node() {
}
public Node(Key key) {
this .key = key;
}
@Override
public String toString() {
String nodeColor = color ? "BLACK" : "RED";
return " " + key + "-" + nodeColor + " ";
}
}
/**
* 左旋
* @param x
*/
private void leftRotate(Node x){
Node y = x.right;
x.right = y.left;
if (y.left != nil) {
y.left.parent = x;
}
y.parent = x.parent;
if (x.parent == nil) {
root = y;
} else if (x == x.parent.left) {
x.parent.left = y;
} else {
x.parent.right = y;
}
y.left = x;
x.parent = y;
}
/**
* 右旋
* @param x
*/
private void rightRotate(Node x) {
Node y = x.left;
x.left = y.right;
if (y.right != nil) {
y.right.parent = x;
}
y.parent = x.parent;
if (x.parent == nil) {
root = y;
} else if (x == x.parent.left) {
x.parent.left = y;
} else {
x.parent.right = y;
}
y.right = x;
x.parent = y;
}
/**
* 插入
* @param key
*/
public void insert(Key key) {
if (key == null) {
return;
}
Node y = nil;
Node x = root;
while (x != nil) {
y = x;
if (key.compareTo(x.key) < 0) {
x = x.left;
} else if (key.compareTo(x.key) > 0) {
x = x.right;
} else { //重複結點不插入
return;
}
}
Node z = new Node(key);
z.parent = y;
if (y == nil) {
root = z;
} else if (z.key.compareTo(y.key) < 0) {
y.left = z;
} else {
y.right = z;
}
z.left = nil;
z.right = nil;
z.color = RED;
insertFixup(z);
}
/**
* 插入修復
* @param z
*/
private void insertFixup(Node z) {
while (z.parent.color == RED) {
if (z.parent == z.parent.parent.left) {
Node y = z.parent.parent.right;
if (y.color == RED) {
z.parent.color = BLACK;
y.color = BLACK;
z.parent.parent.color = RED;
z = z.parent.parent;
} else {
if (z == z.parent.right) {
z = z.parent;
leftRotate(z);
}
z.parent.color = BLACK;
z.parent.parent.color = RED;
rightRotate(z.parent.parent);
}
} else {
Node y = z.parent.parent.left;
if (y.color == RED) {
z.parent.color = BLACK;
y.color = BLACK;
z.parent.parent.color = RED;
z = z.parent.parent;
} else {
if (z == z.parent.left) {
z = z.parent;
rightRotate(z);
}
z.parent.color = BLACK;
z.parent.parent.color = RED;
leftRotate(z.parent.parent);
}
}
}
root.color = BLACK;
}
/**
* 用v子樹替換u子樹
* @param u
* @param v
*/
private void transplant(Node u, Node v) {
if (u.parent == nil) {
root = v;
} else if (u == u.parent.left) {
u.parent.left = v;
} else {
u.parent.right = v;
}
v.parent = u.parent;
}
/**
* 查詢以x為根的最小結點
* @param x
* @return
*/
private Node minimum(Node x) {
while (x.left != nil) {
x = x.left;
}
return x;
}
/**
* 查詢結點的key值為key的結點
* @param key
* @return
*/
private Node search(Key key) {
Node x = root;
while (x != nil && key.compareTo(x.key) != 0) {
if (key.compareTo(x.key) < 0) {
x = x.left;
} else {
x = x.right;
}
}
return x;
}
/**
* 刪除結點的key值為key的結點
* @param key
*/
public void delete(Key key) {
if (key == null) {
return;
}
Node z = search(key);
if (z == nil) {
return;
}
Node y = z;
Node x;
boolean yOriginalColor = y.color;
if (z.left == nil) {
x = z.right;
transplant(z, z.right);
} else if (z.right == nil) {
x = z.left;
transplant(z, z.left);
} else {
y = minimum(z.right);
yOriginalColor = y.color;
x = y.right;
if (y.parent == z) {
x.parent = y;
} else {
transplant(y, y.right);
y.right = z.right;
y.right.parent = y;
}
transplant(z, y);
y.left = z.left;
y.left.parent = y;
y.color = z.color;
}
if (yOriginalColor == BLACK) {
deleteFixup(x);
}
}
/**
* 刪除修復
* @param x
*/
private void deleteFixup(Node x) {
while (x != root && x.color == BLACK) {
if (x == x.parent.left) {
Node w = x.parent.right;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
leftRotate(x.parent);
w = x.parent.right;
}
if (w.left.color == BLACK && w.right.color == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (w.right.color == BLACK) {
w.left.color = BLACK;
w.color = RED;
rightRotate(w);
w = x.parent.right;
}
w.color = x.parent.color;
x.parent.color = BLACK;
w.right.color = BLACK;
leftRotate(x.parent);
x = root;
}
} else {
Node w = x.parent.left;
if (w.color == RED) {
w.color = BLACK;
x.parent.color = RED;
leftRotate(x.parent);
w = x.parent.left;
}
if (w.left.color == BLACK && w.right.color == BLACK) {
w.color = RED;
x = x.parent;
} else {
if (w.left.color == BLACK) {
w.right.color = BLACK;
w.color = RED;
leftRotate(w);
w = x.parent.left;
}
w.color = x.parent.color;
x.parent.color = BLACK;
w.left.color = BLACK;
rightRotate(x.parent);
x = root;
}
}
}
x.color = BLACK;
}
/**
* 先序遍歷
*/
public void preOrder() {
preOrder(root);
}
/**
* 對以x為根的子樹進行先序遍歷
* @param x
*/
private void preOrder(Node x) {
if (x != nil) {
System.out.print(x);
preOrder(x.left);
preOrder(x.right);
}
}
/**
* 中序遍歷
*/
public void inOrder() {
inOrder(root);
}
/**
* 對以x為根的子樹進行中序遍歷
* @param x
*/
private void inOrder(Node x) {
if (x != nil) {
inOrder(x.left);
System.out.print(x);
inOrder(x.right);
}
}
/**
* 後序遍歷
*/
public void postOrder() {
postOrder(root);
}
/**
* 對以x為根的子樹進行後序遍歷
* @param x
*/
private void postOrder(Node x) {
if (x != nil) {
postOrder(x.left);
postOrder(x.right);
System.out.print(x);
}
}
public static void main(String[] args) {
RedBlackTree<Integer> redBlackTree = new RedBlackTree<>();
//構造一顆紅黑樹 可參考上一篇中完整的插入修復圖例
redBlackTree.insert(11);
redBlackTree.insert(2);
redBlackTree.insert(14);
redBlackTree.insert(15);
redBlackTree.insert(1);
redBlackTree.insert(7);
redBlackTree.insert(5);
redBlackTree.insert(8);
System.out.println("原紅黑樹:");
System.out.print("先序遍歷:");
redBlackTree.preOrder();
System.out.print("\n中序遍歷:");
redBlackTree.inOrder();
System.out.print("\n後序遍歷:");
redBlackTree.postOrder();
System.out.println();
//插入元素4
redBlackTree.insert(4);
System.out.println("插入元素4後:");
System.out.print("先序遍歷:");
redBlackTree.preOrder();
System.out.print("\n中序遍歷:");
redBlackTree.inOrder();
System.out.print("\n後序遍歷:");
redBlackTree.postOrder();
System.out.println();
//刪除元素5
redBlackTree.delete(5);
System.out.println("刪除元素5後:");
System.out.print("先序遍歷:");
redBlackTree.preOrder();
System.out.print("\n中序遍歷:");
redBlackTree.inOrder();
System.out.print("\n後序遍歷:");
redBlackTree.postOrder();
System.out.println();
}
}
執行結果:
原紅黑樹:
先序遍歷: 11-BLACK 2-RED 1-BLACK 7-BLACK 5-RED 8-RED 14-BLACK 15-RED
中序遍歷: 1-BLACK 2-RED 5-RED 7-BLACK 8-RED 11-BLACK 14-BLACK 15-RED
後序遍歷: 1-BLACK 5-RED 8-RED 7-BLACK 2-RED 15-RED 14-BLACK 11-BLACK
插入元素4後:
先序遍歷: 7-BLACK 2-RED 1-BLACK 5-BLACK 4-RED 11-RED 8-BLACK 14-BLACK 15-RED
中序遍歷: 1-BLACK 2-RED 4-RED 5-BLACK 7-BLACK 8-BLACK 11-RED 14-BLACK 15-RED
後序遍歷: 1-BLACK 4-RED 5-BLACK 2-RED 8-BLACK 15-RED 14-BLACK 11-RED 7-BLACK
刪除元素5後:
先序遍歷: 7-BLACK 2-RED 1-BLACK 4-BLACK 11-RED 8-BLACK 14-BLACK 15-RED
中序遍歷: 1-BLACK 2-RED 4-BLACK 7-BLACK 8-BLACK 11-RED 14-BLACK 15-RED
後序遍歷: 1-BLACK 4-BLACK 2-RED 8-BLACK 15-RED 14-BLACK 11-RED 7-BLACK