JAVA实现自定向下的红黑树
主要是记录自己的内容,具体原理可能不够详细,代码可以参考。
红黑树
红黑树是AVL树的一种流行的变种。
红黑树的操作再最坏的情况下花费O(logN)的时间
参考:参考:《数据结构与算法分析:JAVA语言描述》P362
红黑树的插入、删除操作都较为复杂,本代码已实现插入操作,但书上的删除操作虽然看起来简单,但实在难以实现,网上的删除操作资料过于复杂(需大量分类讨论)。如有大佬有较为简洁的实现方式,不吝赐教。
红黑树 的特点
红黑树是具有以下着色性质的二叉查找树:
- 每个节点可以为红色和黑色
- 根节点为黑色
- 如果一个节点为红色,那么其子节点必须是黑色
- 从一个节点到一个null引用的每条路径必须包含相同数量的黑色节点
使用以上着色法则的红黑树的高度最多为2log(N+1),这就能保证其操作的时间花费为O(logN)
代码实现
package chapter12;
import chapter04.MyCustomException;
public class RedBlackTree<T extends Comparable<? super T>> {
private final Node<T> header; // 不是真正的根节点,但其右子树指向真正的根
private final Node<T> nullNode; // 表示空节点,相当于null
private static final int RED = 0;
private static final int BLACK = 1;
private Node<T> current; // 当前节点
private Node<T> parent; // 父节点
private Node<T> grand; // 祖父
private Node<T> great; // 曾祖父
private static class Node<T> {
T element;
Node<T> left;
Node<T> right;
int color;
Node(T element) {
this(element, null, null);
}
Node(T element, Node<T> left, Node<T> right) {
this.element = element;
this.left = left;
this.right = right;
this.color = BLACK;
}
}
// *********************************************************************************************************
public RedBlackTree() {
nullNode = new Node<>(null);
nullNode.left = nullNode.right = nullNode;
header = new Node<>(null);
header.left = header.right = nullNode;
}
public void makeEmpty() {
header.right = nullNode;
}
public boolean isEmpty() {
return header.right == nullNode;
}
public void insert(T element) {
current = parent = grand = header;
nullNode.element = element;
while (compare(element, current) != 0) {
great = grand;
grand = parent;
parent = current;
current = compare(element, current) < 0 ? current.left : current.right;
// 如果两个遇到两个儿子都为红色的情况,则进行颜色翻转
if (current.left.color == RED && current.right.color == RED) {
handleReorient(element);
}
}
// 该元素element已存在,则不进行操作
if (current != nullNode) {
return;
}
// 该元素element不存在,则将该元素放入对应位置中(叶子节点中)
current = new Node<>(element, nullNode, nullNode);
if (compare(element, parent) < 0) {
parent.left = current;
} else {
parent.right = current;
}
handleReorient(element); // 进行涂色
}
public boolean contains(T element) {
nullNode.element = element;
current = header.right;
while (true) {
if( element.compareTo( current.element ) < 0 )
current = current.left;
else if( element.compareTo( current.element ) > 0 )
current = current.right;
else return current != nullNode;
}
}
public T findMin() {
if (isEmpty()) {
throw new MyCustomException();
}
return findMin(header.right).element;
}
public T findMax() {
if (isEmpty()) {
throw new MyCustomException();
}
return findMax(header.right).element;
}
public void printTree() {
if (isEmpty()) {
throw new MyCustomException();
} else {
printTree(header.right);
}
}
// *********************************************************************************************************
// 比较element与节点node的元素大小
private int compare(T element, Node<T> node) {
if (node == header) {
return 1;
}
return element.compareTo(node.element);
}
// 进行涂色操作
private void handleReorient(T element) {
current.color = RED;
current.left.color = BLACK;
current.right.color = BLACK;
// 如果父节点也为红色,则需要进行旋转
if (parent.color == RED) {
grand.color = RED;
// 如果为之字形,则需要进行两次单旋转
if ((compare(element, grand) < 0) != (compare(element, parent) < 0)) {
parent = rotate(element, grand); // 一次单选择
}
// 如果为一字型,则只需进行一次单旋转
current = rotate(element, great); // 一次单选择
current.color = BLACK;
}
// 根节点的颜色应始终为黑色
header.right.color = BLACK;
}
// 进行单旋转
private Node<T> rotate(T element, Node<T> parent) {
if (compare(element, parent) < 0) {
if (compare(element, parent.left) < 0) {
return parent.left = rotateWithLeftChild(parent.left); // LL
} else {
return parent.left = rotateWithRightChild(parent.left); // LR
}
} else {
if (compare(element, parent.right) < 0) {
return parent.right = rotateWithLeftChild(parent.right); // RL
} else {
return parent.right = rotateWithRightChild(parent.right); // RR
}
}
}
// 左一字型的单旋转
private Node<T> rotateWithLeftChild(Node<T> t) {
Node<T> tmp = t.left;
t.left = tmp.right;
tmp.right = t;
return tmp;
}
// 右一字型的单旋转
private Node<T> rotateWithRightChild(Node<T> t) {
Node<T> tmp = t.right;
t.right = tmp.left;
tmp.left = t;
return tmp;
}
private Node<T> findMin(Node<T> node) {
if (node.left == nullNode) {
return node;
} else {
return findMin(node.left);
}
}
private Node<T> findMax(Node<T> node) {
if (node.right == nullNode) {
return node;
} else {
return findMin(node.right);
}
}
private void printTree(Node<T> node) {
if (node != nullNode) {
printTree(node.left);
System.out.println(node.element);
printTree(node.right);
}
}
// *********************************************************************************************************
public static void main(String[] args) {
RedBlackTree<String> redBlackTree = new RedBlackTree<>();
redBlackTree.insert("GG");
redBlackTree.insert("TT");
redBlackTree.insert("OO");
redBlackTree.insert("BB");
redBlackTree.insert("NN");
redBlackTree.insert("LL");
redBlackTree.insert("GG");
redBlackTree.insert("UU");
redBlackTree.printTree();
}
}