说红黑树之前,首先有必要理解各种树的概念。这里有一篇写得很好相关概念的介绍,并且有相关操作的算法代码实现
https://www.cnblogs.com/kuotian/p/5333956.html
红黑树是一种自平衡二叉查找树。
1.红黑树的性质:
一般的,红黑树,满足以下性质,即只有满足以下全部性质的树,我们才称之为红黑树:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。
2.红黑树的数据结构的定义
public class RBTreeNode<T extends Comparable<T>> {
private RBTNode<T> mRoot; // 根结点
private static final boolean RED = false;
private static final boolean BLACK = true;
public class RBTNode<T extends Comparable<T>> {
boolean color; // 颜色
T key; // 关键字(键值)
RBTNode<T> left; // 左孩子
RBTNode<T> right; // 右孩子
RBTNode<T> parent; // 父结点
public RBTNode(T key, boolean color, RBTNode<T> parent, RBTNode<T> left, RBTNode<T> right) {
this.key = key;
this.color = color;
this.parent = parent;
this.left = left;
this.right = right;
}
}
}
3.红黑树的各种操作的时间复杂度
能保证在最坏情况下,基本的动态几何操作的时间均为O(logn)
4.红黑树与AVL树比较
- 红黑树不追求"完全平衡",即不像AVL那样要求节点的
|balFact| <= 1
,它只要求部分达到平衡,但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。 - 就插入节点导致树失衡的情况,AVL和RB-Tree都是最多两次树旋转来实现复衡rebalance,旋转的量级是O(1)
删除节点导致失衡,AVL需要维护从被删除节点到根节点root这条路径上所有节点的平衡,旋转的量级为O(logN),而RB-Tree最多只需要旋转3次实现复衡,只需O(1),所以说RB-Tree删除节点的rebalance的效率更高,开销更小! - AVL的结构相较于RB-Tree更为平衡,插入和删除引起失衡,如2所述,RB-Tree复衡效率更高;当然,由于AVL高度平衡,因此AVL的Search效率更高啦。
- 针对插入和删除节点导致失衡后的rebalance操作,红黑树能够提供一个比较"便宜"的解决方案,降低开销,是对search,insert ,以及delete效率的折衷,总体来说,RB-Tree的统计性能高于AVL.
- 故引入RB-Tree是功能、性能、空间开销的折中结果。
AVL更平衡,结构上更加直观,时间效能针对读取而言更高;维护稍慢,空间开销较大。
红黑树,读取略逊于AVL,维护强于AVL,空间开销与AVL类似,内容极多时略优于AVL,维护优于AVL。
基本上主要的几种平衡树看来,红黑树有着良好的稳定性和完整的功能,性能表现也很不错,综合实力强,在诸如STL的场景中需要稳定表现。 - 总结:实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。
5.红黑树相对于哈希表,在选择使用的时候有什么依据?
权衡三个因素: 查找速度, 数据量, 内存使用,可扩展性。
总体来说,hash查找速度会比map快,而且查找速度基本和数据量大小无关,属于常数级别;而map的查找速度是log(n)级别。并不一定常数就比log(n) 小,hash还有hash函数的耗时,明白了吧,如果你考虑效率,特别是在元素达到一定数量级时,考虑考虑hash。但若你对内存使用特别严格, 希望程序尽可能少消耗内存,那么一定要小心,hash可能会让你陷入尴尬,特别是当你的hash对象特别多时,你就更无法控制了,而且 hash的构造速度较慢。
红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。
在实际的系统中,例如,需要使用动态规则的防火墙系统,使用红黑树而不是散列表被实践证明具有更好的伸缩性。Linux内核在管理vm_area_struct时就是采用了红黑树来维护内存块的。红黑树通过扩展节点域可以在不改变时间复杂度的情况下得到结点的秩。
6.如何扩展红黑树来获得比某个结点小的元素有多少个?
这其实就是求节点元素的顺序统计量,当然任意的顺序统计量都可以需要在O(lgn)时间内确定。
在每个节点添加一个size域,表示以结点 x 为根的子树的结点树的大小,则有
size[x] = size[[left[x]] + size [right[x]] + 1;
这时候红黑树就变成了一棵顺序统计树。
利用size域可以做两件事:
1). 找到树中第i小的结点;
2).确定某个结点之前有多少个结点,也就是我们要解决的问题;
7.红黑树java实现
import java.util.Scanner;
public class DRBTree<T extends Comparable<T>> {
private RBNode<T> mroot;
private static final boolean RED = false;
private static final boolean BLACK = true;
public class RBNode<T extends Comparable<T>>{
private boolean color;
private T key;
private RBNode<T> parent;
private RBNode leftChild;
private RBNode rightChild;
public RBNode(boolean col,T key,RBNode paret,RBNode leftChild,RBNode rightChild){
this.color = col;
this.key = key;
this.parent = parent;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public T getKey() {
return this.key;
}
}
public RBNode<T> parentOf(RBNode<T> node){
if(node!=null) {
return node.parent;
}
return null;
}
public boolean colorOf(RBNode<T> node){
if(node!=null) {
return node.color;
}
return BLACK;
}
public void setParent(RBNode<T> node,RBNode<T> parent) {
if(node!=null) {
node.parent = parent;
}
}
public void setColor(RBNode<T> node,boolean color) {
if(node!=null) {
node.color = color;
}
}
public boolean isRed(RBNode<T> node) {
return (node!=null&&node.color == RED)?true:false;
}
public boolean isBlack(RBNode<T> node) {
return !isRed(node);
}
public void setRed(RBNode<T> node) {
if(node!=null) {
node.color = RED;
}
}
public void setBlack(RBNode<T> node) {
if(node!=null) {
node.color = BLACK;
}
}
//寻找为key值的节点
public RBNode<T> search(T key,RBNode<T> node){
if(node!=null) {
int com = key.compareTo(node.key);
if(com<0) {
return search(key,node.leftChild);
}else if(com>0) {
return search(key,node.rightChild);
}else {
return node;
}
}
return null;
}
//寻找后继节点,即大于该节点的最小节点
public RBNode<T> min(RBNode<T> node){
if(node.leftChild == null) {
return node;
}
while(node.leftChild!=null) {
node = node.leftChild;
}
return node;
}
public RBNode successor(RBNode<T> node) {
if(node.rightChild !=null) {
return min(node.rightChild);
}
RBNode<T> y = node.parent;
while((y!=null)&&(y.rightChild == node)) {
node = y;
y = y.parent;
}
return y;
}
//对某个节点进行左旋
public void leftRonate(RBNode<T> x) {
RBNode<T> y = x.rightChild;
if(y.leftChild!=null) {
y.leftChild.parent = x;
}
x.rightChild = y.leftChild;
y.leftChild = x;
y.parent = x.parent;
if(x.parent!=null) {
if(x.parent.leftChild == x) {
x.parent.leftChild = y;
}else {
x.parent.rightChild = y;
}
}else {
this.mroot = y;
}
x.parent = y;
}
//对某个节点进行右旋
public void rightRonate(RBNode<T> x) {
RBNode<T> y = x.leftChild;
if(y.rightChild!=null) {
y.rightChild.parent = x;
}
y.parent = x.parent;
x.leftChild = y.rightChild;
y.rightChild = x;
if(x.parent!=null) {
if(x.parent.leftChild == x) {
x.parent.leftChild = y;
}else {
x.parent.rightChild = y;
}
}else {
this.mroot = y;
}
x.parent = y;
}
//红黑树添加修复
public void insertFixUp(RBNode<T> node) {
RBNode<T> parent,gparent;
while(((parent = parentOf(node))!=null)&&isRed(parent)) {
gparent = parentOf(parent);
if(gparent.leftChild == parent) {
RBNode<T> uncle = gparent.rightChild;
if(isRed(uncle)){
setBlack(parent);
setBlack(uncle);
setRed(gparent);
node = gparent;
continue;
}else {
if(parent.rightChild == node) {
leftRonate(parent);
RBNode<T> temp = node;
node = parent;
parent = temp;
}
setBlack(parent);
setRed(gparent);
rightRonate(gparent);
}
}else {
RBNode<T> uncle = gparent.leftChild;
if(isRed(uncle)) {
setBlack(parent);
setBlack(uncle);
setRed(gparent);
node = gparent;
continue;
}else {
if(parent.leftChild == node) {
rightRonate(parent);
RBNode<T> temp = node;
node = parent;
parent = temp;
}
setBlack(parent);
setRed(gparent);
leftRonate(gparent);
}
}
}
if(mroot == node) {
setBlack(node);
}
}
//红黑树删除修复
public void deleteFixUp(RBNode<T> node,RBNode<T> parent) {
RBNode<T> other;
while(isBlack(node)&&node!=this.mroot) {
if(parent.leftChild == node) {
other = parent.rightChild;
if(isRed(other)) {
setRed(parent);
setBlack(other);
leftRonate(parent);
continue;
}else {
if(isBlack(other.leftChild)&&isBlack(other.rightChild)) {
setRed(other);
node = parent;
parent = parentOf(node);
}else if(isRed(other.leftChild)&&isBlack(other.rightChild)) {
setRed(other);
setBlack(other.leftChild);
rightRonate(other);
}else if(isRed(other.rightChild)) {
setColor(other,colorOf(parent));
setBlack(parent);
setBlack(other.rightChild);
leftRonate(parent);
break;
}
}
}else {
other = parent.leftChild;
if(isRed(other)) {
setBlack(other);
setRed(parent);
rightRonate(parent);
continue;
}else {
if(isBlack(other.leftChild)&&isBlack(other.rightChild)) {
setRed(other);
node = parent;
parent = parentOf(node);
}else if(isRed(other.rightChild)&&isBlack(other.leftChild)) {
setRed(parent);
setBlack(other.rightChild);
leftRonate(other);
}else if(isRed(other.leftChild)) {
setColor(other, colorOf(parent));
setBlack(parent);
setBlack(other.leftChild);
rightRonate(parent);
break;
}
}
}
}
setBlack(node);
}
//红黑树添加操作
public void insert(RBNode<T> node) {
int com;
RBNode<T> x = this.mroot;
RBNode<T> y = null;
while(x!=null) {
y = x;
com = node.key.compareTo(x.key);
if(com<0) {
x=x.leftChild;
}else{
x=x.rightChild;
}
}
node.parent = y;
if(y!=null) {
com = node.key.compareTo(y.key);
if(com<0) {
y.leftChild = node;
}else {
y.rightChild = node;
}
}else {
this.mroot = node;
}
setRed(node);
insertFixUp(node);
}
public void insert(T key) {
RBNode<T> node = new RBNode<T>(BLACK,key,null,null,null);
if(node!=null) {
insert(node);
}
}
//红黑树删除操作
public void delete(RBNode<T> node) {
RBNode<T> child,parent,replace;
boolean color = true;
if(node.leftChild!=null&&node.rightChild!=null) {
replace = successor(node);
parent = parentOf(replace);
child = replace.rightChild;
color = colorOf(replace);
if(node == parentOf(replace)) {
parent = replace;
}else {
if(child!=null) {
setParent(child,parentOf(replace));
}
replace.parent.leftChild = child;
replace.rightChild = node.rightChild;
setParent(node.rightChild,replace);
}
setParent(replace, parentOf(node));
replace.leftChild = node.leftChild;
setParent(node.leftChild,replace);
setColor(replace,colorOf(node));
if(parentOf(node)!=null) {
if(node.parent.leftChild==node) {
node.parent.leftChild = replace;
}else {
node.parent.rightChild = replace;
}
}else {
this.mroot = replace;
}
if(color==BLACK){
deleteFixUp(child, parent);
}
}else {
if(node.leftChild!=null) {
replace = node.leftChild;
}else {
replace = node.rightChild;
}
parent = parentOf(node);
if(parent!=null) {
if(parent.leftChild==node) {
parent.leftChild = replace;
}else {
parent.rightChild = replace;
}
}else {
this.mroot = replace;
}
setParent(replace, parent);
color = colorOf(node);
child = replace;
if(color==BLACK) {
deleteFixUp(child, parent);
}
}
}
public void delete(T key) {
RBNode<T> node;
if((node=search(key,this.mroot))!=null) {
delete(node);
}
}
//前序遍历
public void preOrder(RBNode<T> node) {
if(node!=null) {
System.out.print(node.key+" ");
preOrder(node.leftChild);
preOrder(node.rightChild);
}
}
public void preOrder() {
preOrder(this.mroot);
}
//中序遍历
public void inOrder(RBNode<T> node) {
if(node!=null) {
inOrder(node.leftChild);
System.out.print(node.key+" ");
inOrder(node.rightChild);
}
}
public void inOrder() {
inOrder(this.mroot);
}
//后序遍历
public void postOrder(RBNode<T> node) {
if(node!=null) {
postOrder(node.leftChild);
postOrder(node.rightChild);
System.out.print(node.key+" ");
}
}
public void postOrder() {
postOrder(this.mroot);
}
//打印红黑树
public void print(RBNode<T> node,int direction) {
if(node!=null) {
if(direction == 0) {
System.out.printf("%2d(%s) is root\n",node.key,node.color==false?"R":"B");
}else {
System.out.printf("%2d(%s) is %s child 父节点 %2d\n",node.key,node.color==false?"R":"B",direction==-1?"left":"right",node.parent.key);
}
print(node.leftChild,-1);
print(node.rightChild,1);
}
}
public void print() {
print(this.mroot,0);
}
public static void main(String[] args) {
DRBTree<Integer> tree = new DRBTree<Integer>();
int[] a = {10,20,30,40,50,60,70,80,90};
//红黑树添加测试
for(int i=0;i<a.length;i++) {
tree.insert(a[i]);
}
System.out.print("前序遍历: ");
tree.preOrder();
System.out.print("\n中序遍历: ");
tree.inOrder();
System.out.print("\n后序遍历: ");
tree.postOrder();
System.out.println();
tree.print();
System.out.print("\n输入要删除的节点:");
Scanner scan = new Scanner(System.in);
int key = scan.nextInt();
//红黑树删除测试
tree.delete(key);
System.out.println();
tree.print();
}
}
参考资料
https://www.jianshu.com/p/37436ed14cc6
https://www.cnblogs.com/wuchanming/p/4444961.html