一:红黑树的应用场景
红黑树(Red-Black Tree,以下简称RBTree)的实际应用非常广泛,比如Linux内核中的完全公平调度器、高精度计时器、ext3文件系统等等,各种语言的函数库如Java的TreeMap和TreeSet,C++ STL的map、multimap、multiset等。
RBTree也是函数式语言中最常用的持久数据结构之一,在计算几何中也有重要作用。值得一提的是,Java 8中HashMap的实现也因为用RBTree取代链表,性能有所提升。
二:RBTree的定义
RBTree的定义如下:
- 任何一个节点都有颜色,黑色或者红色。
- 根节点是黑色的。
- 父子节点之间不能出现两个连续的红节点。
- 任何一个节点向下遍历到其子孙的叶子节点,所经过的黑节点个数必须相等。
- 空节点被认为是黑色的。
数据结构表示如下:
class Node<T>{
public T value;
public Node<T> parent;
public boolean isRed;
public Node<T> left;
public Node<T> right;
}
RBTree在理论上还是一棵BST树,但是它在对BST的插入和删除操作时会维持树的平衡,即保证树的高度在[logN,logN+1](理论上,极端的情况下可以出现RBTree的高度达到2*logN,但实际上很难遇到)。这样RBTree的查找时间复杂度始终保持在O(logN)从而接近于理想的BST。RBTree的删除和插入操作的时间复杂度也是O(logN)。RBTree的查找操作就是BST的查找操作。
三:代码实现
RBTreeNode实体类:
package com.rbTree;
/**
* @author lizhangyu
* @date 2021/5/5 17:21
*/
public class RBTreeNode<T extends Comparable<T>> {
/**
* node value
*/
private T value;
/**
* eft child pointer
*/
private RBTreeNode<T> left;
/**
* right child pointer
*/
private RBTreeNode<T> right;
/**
* parent pointer
*/
private RBTreeNode<T> parent;
/**
* color is red or not red
*/
private boolean red;
public RBTreeNode() {
}
public RBTreeNode(T value) {
this.value = value;
}
public RBTreeNode(T value, boolean isRed) {
this.value = value;
this.red = isRed;
}
public T getValue() {
return value;
}
void setValue(T value) {
this.value = value;
}
RBTreeNode<T> getLeft() {
return left;
}
void setLeft(RBTreeNode<T> left) {
this.left = left;
}
RBTreeNode<T> getRight() {
return right;
}
void setRight(RBTreeNode<T> right) {
this.right = right;
}
RBTreeNode<T> getParent() {
return parent;
}
void setParent(RBTreeNode<T> parent) {
this.parent = parent;
}
boolean isRed() {
return red;
}
boolean isBlack() {
return !red;
}
/**
* is leaf node
**/
boolean isLeaf() {
return left == null && right == null;
}
void setRed(boolean red) {
this.red = red;
}
void makeRed() {
red = true;
}
void makeBlack() {
red = false;
}
@Override
public String toString() {
return value.toString();
}
}
RBTree实体类:
package com.rbTree;
/**
* @author lizhangyu
* @date 2021/5/5 17:24
*/
public class RBTree<T extends Comparable<T>> {
private final RBTreeNode<T> root;
/**
* node number
*/
private java.util.concurrent.atomic.AtomicLong size =
new java.util.concurrent.atomic.AtomicLong(0);
/**
* in overwrite mode,all node's value can not has same value
* in non-overwrite mode,node can have same value, suggest don't use non-overwrite mode.
*/
private volatile boolean overrideMode = true;
public RBTree() {
this.root = new RBTreeNode<T>();
}
public RBTree(boolean overrideMode) {
this();
this.overrideMode = overrideMode;
}
public boolean isOverrideMode() {
return overrideMode;
}
public void setOverrideMode(boolean overrideMode) {
this.overrideMode = overrideMode;
}
/**
* number of tree number
*
* @return
*/
public long getSize() {
return size.get();
}
/**
* get the root node
*
* @return
*/
private RBTreeNode<T> getRoot() {
return root.getLeft();
}
/**
* add value to a new node,if this value exist in this tree,
* if value exist,it will return the exist value.otherwise return null
* if override mode is true,if value exist in the tree,
* it will override the old value in the tree
*
* @param value
* @return
*/
public T addNode(T value) {
RBTreeNode<T> t = new RBTreeNode<T>(value);
return addNode(t);
}
/**
* find the value by give value(include key,key used for search,
* other field is not used,@see compare method).if this value not exist return null
*
* @param value
* @return
*/
public T find(T value) {
RBTreeNode<T> dataRoot = getRoot();
while (dataRoot != null) {
int cmp = dataRoot.getValue().compareTo(value);
if (cmp < 0) {
dataRoot = dataRoot.getRight();
} else if (cmp > 0) {
dataRoot = dataRoot.getLeft();
} else {
return dataRoot.getValue();
}
}
return null;
}
/**
* remove the node by give value,if this value not exists in tree return null
*
* @param value include search key
* @return the value contain in the removed node
*/
public T remove(T value) {
RBTreeNode<T> dataRoot = getRoot();
RBTreeNode<T> parent = root;
while (dataRoot != null) {
int cmp = dataRoot.getValue().compareTo(value);
if (cmp < 0) {
parent = dataRoot;
dataRoot = dataRoot.getRight();
} else if (cmp > 0) {
parent = dataRoot;
dataRoot = dataRoot.getLeft();
} else {
if (dataRoot.getRight() != null) {
RBTreeNode<T> min = removeMin(dataRoot.getRight());
//x used for fix color balance
RBTreeNode<T> x = min.getRight() == null ? min.getParent() : min.getRight();
boolean isParent = min.getRight() == null;
min.setLeft(dataRoot.getLeft());
setParent(dataRoot.getLeft(), min);
if (parent.getLeft() == dataRoot) {
parent.setLeft(min);
} else {
parent.setRight(min);
}
setParent(min, parent);
boolean curMinIsBlack = min.isBlack();
//inherit dataRoot's color
min.setRed(dataRoot.isRed());
if (min != dataRoot.getRight()) {
min.setRight(dataRoot.getRight());
setParent(dataRoot.getRight(), min);
}
//remove a black node,need fix color
if (curMinIsBlack) {
if (min != dataRoot.getRight()) {
fixRemove(x, isParent);
} else if (min.getRight() != null) {
fixRemove(min.getRight(), false);
} else {
fixRemove(min, true);
}
}
} else {
setParent(dataRoot.getLeft(), parent);
if (parent.getLeft() == dataRoot) {
parent.setLeft(dataRoot.getLeft());
} else {
parent.setRight(dataRoot.getLeft());
}
//current node is black and tree is not empty
if (dataRoot.isBlack() && !(root.getLeft() == null)) {
RBTreeNode<T> x = dataRoot.getLeft() == null
? parent : dataRoot.getLeft();
boolean isParent = dataRoot.getLeft() == null;
fixRemove(x, isParent);
}
}
setParent(dataRoot, null);
dataRoot.setLeft(null);
dataRoot.setRight(null);
if (getRoot() != null) {
getRoot().setRed(false);
getRoot().setParent(null);
}
size.decrementAndGet();
return dataRoot.getValue();
}
}
return null;
}
/**
* fix remove action
*
* @param node
* @param isParent
*/
private void fixRemove(RBTreeNode<T> node, boolean isParent) {
RBTreeNode<T> cur = isParent ? null : node;
boolean isRed = isParent ? false : node.isRed();
RBTreeNode<T> parent = isParent ? node : node.getParent();
while (!isRed && !isRoot(cur)) {
RBTreeNode<T> sibling = getSibling(cur, parent);
//sibling is not null,due to before remove tree color is balance
//if cur is a left node
boolean isLeft = parent.getRight() == sibling;
if (sibling.isRed() && !isLeft) {//case 1
//cur in right
parent.makeRed();
sibling.makeBlack();
rotateRight(parent);
} else if (sibling.isRed() && isLeft) {
//cur in left
parent.makeRed();
sibling.makeBlack();
rotateLeft(parent);
} else if (isBlack(sibling.getLeft()) && isBlack(sibling.getRight())) {//case 2
sibling.makeRed();
cur = parent;
isRed = cur.isRed();
parent = parent.getParent();
} else if (isLeft && !isBlack(sibling.getLeft())
&& isBlack(sibling.getRight())) {//case 3
sibling.makeRed();
sibling.getLeft().makeBlack();
rotateRight(sibling);
} else if (!isLeft && !isBlack(sibling.getRight())
&& isBlack(sibling.getLeft())) {
sibling.makeRed();
sibling.getRight().makeBlack();
rotateLeft(sibling);
} else if (isLeft && !isBlack(sibling.getRight())) {//case 4
sibling.setRed(parent.isRed());
parent.makeBlack();
sibling.getRight().makeBlack();
rotateLeft(parent);
cur = getRoot();
} else if (!isLeft && !isBlack(sibling.getLeft())) {
sibling.setRed(parent.isRed());
parent.makeBlack();
sibling.getLeft().makeBlack();
rotateRight(parent);
cur = getRoot();
}
}
if (isRed) {
cur.makeBlack();
}
if (getRoot() != null) {
getRoot().setRed(false);
getRoot().setParent(null);
}
}
//get sibling node
private RBTreeNode<T> getSibling(RBTreeNode<T> node, RBTreeNode<T> parent) {
parent = node == null ? parent : node.getParent();
if (node == null) {
return parent.getLeft() == null ? parent.getRight() : parent.getLeft();
}
if (node == parent.getLeft()) {
return parent.getRight();
} else {
return parent.getLeft();
}
}
private boolean isBlack(RBTreeNode<T> node) {
return node == null || node.isBlack();
}
private boolean isRoot(RBTreeNode<T> node) {
return root.getLeft() == node && node.getParent() == null;
}
/**
* find the successor node
*
* @param node current node's right node
* @return
*/
private RBTreeNode<T> removeMin(RBTreeNode<T> node) {
//find the min node
RBTreeNode<T> parent = node;
while (node != null && node.getLeft() != null) {
parent = node;
node = node.getLeft();
}
//remove min node
if (parent == node) {
return node;
}
parent.setLeft(node.getRight());
setParent(node.getRight(), parent);
//don't remove right pointer,it is used for fixed color balance
//node.setRight(null);
return node;
}
/**
* 添加节点
*
* @param node
* @return
*/
private T addNode(RBTreeNode<T> node) {
node.setLeft(null);
node.setRight(null);
node.setRed(true);
setParent(node, null);
if (root.getLeft() == null) {
root.setLeft(node);
//root node is black
node.setRed(false);
size.incrementAndGet();
} else {
RBTreeNode<T> x = findParentNode(node);
int cmp = x.getValue().compareTo(node.getValue());
if (this.overrideMode && cmp == 0) {
T v = x.getValue();
x.setValue(node.getValue());
return v;
} else if (cmp == 0) {
//value exists,ignore this node
return x.getValue();
}
setParent(node, x);
if (cmp > 0) {
x.setLeft(node);
} else {
x.setRight(node);
}
fixInsert(node);
size.incrementAndGet();
}
return null;
}
/**
* find the parent node to hold node x,if parent value equals x.value return parent.
*
* @param x
* @return
*/
private RBTreeNode<T> findParentNode(RBTreeNode<T> x) {
RBTreeNode<T> dataRoot = getRoot();
RBTreeNode<T> child = dataRoot;
while (child != null) {
int cmp = child.getValue().compareTo(x.getValue());
if (cmp == 0) {
return child;
}
if (cmp > 0) {
dataRoot = child;
child = child.getLeft();
} else if (cmp < 0) {
dataRoot = child;
child = child.getRight();
}
}
return dataRoot;
}
/**
* red black tree insert fix.
*
* @param x
*/
private void fixInsert(RBTreeNode<T> x) {
RBTreeNode<T> parent = x.getParent();
while (parent != null && parent.isRed()) {
RBTreeNode<T> uncle = getUncle(x);
//need to rotate
if (uncle == null) {
RBTreeNode<T> ancestor = parent.getParent();
//ancestor is not null due to before before add,tree color is balance
if (parent == ancestor.getLeft()) {
boolean isRight = x == parent.getRight();
if (isRight) {
rotateLeft(parent);
}
rotateRight(ancestor);
if (isRight) {
x.setRed(false);
//end loop
parent = null;
} else {
parent.setRed(false);
}
ancestor.setRed(true);
} else {
boolean isLeft = x == parent.getLeft();
if (isLeft) {
rotateRight(parent);
}
rotateLeft(ancestor);
if (isLeft) {
x.setRed(false);
//end loop
parent = null;
} else {
parent.setRed(false);
}
ancestor.setRed(true);
}
} else {//uncle is red
parent.setRed(false);
uncle.setRed(false);
parent.getParent().setRed(true);
x = parent.getParent();
parent = x.getParent();
}
}
getRoot().makeBlack();
getRoot().setParent(null);
}
/**
* get uncle node
*
* @param node
* @return
*/
private RBTreeNode<T> getUncle(RBTreeNode<T> node) {
RBTreeNode<T> parent = node.getParent();
RBTreeNode<T> ancestor = parent.getParent();
if (ancestor == null) {
return null;
}
if (parent == ancestor.getLeft()) {
return ancestor.getRight();
} else {
return ancestor.getLeft();
}
}
/**
* 左旋
*
* @param node
*/
private void rotateLeft(RBTreeNode<T> node) {
RBTreeNode<T> right = node.getRight();
if (right == null) {
throw new java.lang.IllegalStateException("right node is null");
}
RBTreeNode<T> parent = node.getParent();
node.setRight(right.getLeft());
setParent(right.getLeft(), node);
right.setLeft(node);
setParent(node, right);
if (parent == null) {//node pointer to root
//right raise to root node
root.setLeft(right);
setParent(right, null);
} else {
if (parent.getLeft() == node) {
parent.setLeft(right);
} else {
parent.setRight(right);
}
//right.setParent(parent);
setParent(right, parent);
}
}
/**
* 右旋
* @param node
*/
private void rotateRight(RBTreeNode<T> node) {
RBTreeNode<T> left = node.getLeft();
if (left == null) {
throw new java.lang.IllegalStateException("left node is null");
}
RBTreeNode<T> parent = node.getParent();
node.setLeft(left.getRight());
setParent(left.getRight(), node);
left.setRight(node);
setParent(node, left);
if (parent == null) {
root.setLeft(left);
setParent(left, null);
} else {
if (parent.getLeft() == node) {
parent.setLeft(left);
} else {
parent.setRight(left);
}
setParent(left, parent);
}
}
/**
* 设置父节点
* @param node
* @param parent
*/
private void setParent(RBTreeNode<T> node, RBTreeNode<T> parent) {
if (node != null) {
node.setParent(parent);
if (parent == root) {
node.setParent(null);
}
}
}
/**
* debug method,it used print the given node and its children nodes,
* every layer output in one line
*
* @param root
*/
public void printTree(RBTreeNode<T> root) {
java.util.LinkedList<RBTreeNode<T>> queue = new java.util.LinkedList<RBTreeNode<T>>();
java.util.LinkedList<RBTreeNode<T>> queue2 = new java.util.LinkedList<RBTreeNode<T>>();
if (root == null) {
return;
}
queue.add(root);
boolean firstQueue = true;
while (!queue.isEmpty() || !queue2.isEmpty()) {
java.util.LinkedList<RBTreeNode<T>> q = firstQueue ? queue : queue2;
RBTreeNode<T> n = q.poll();
if (n != null) {
String pos = n.getParent() == null ? "" : (n == n.getParent().getLeft()
? " LE" : " RI");
String pstr = n.getParent() == null ? "" : n.getParent().toString();
String cstr = n.isRed() ? "R" : "B";
cstr = n.getParent() == null ? cstr : cstr + " ";
System.out.print(n + "(" + (cstr) + pstr + (pos) + ")" + "\t");
if (n.getLeft() != null) {
(firstQueue ? queue2 : queue).add(n.getLeft());
}
if (n.getRight() != null) {
(firstQueue ? queue2 : queue).add(n.getRight());
}
} else {
System.out.println();
firstQueue = !firstQueue;
}
}
}
public static void main(String[] args) {
RBTree<String> bst = new RBTree<String>();
bst.addNode("d");
bst.addNode("d");
bst.addNode("c");
bst.addNode("c");
bst.addNode("b");
bst.addNode("f");
bst.addNode("a");
bst.addNode("e");
bst.addNode("g");
bst.addNode("h");
bst.remove("c");
bst.printTree(bst.getRoot());
}
}
运行结果:
d(B)
b(B d LE) g(R d RI)
a(R b LE) e(B g LE) h(B g RI)
f(R e RI)
Process finished with exit code 0
此篇博客属于半成品,还有一些需要后续补充。