1、红黑树概述
红黑树是一种近似平衡的树,没有像AVL树那样严格的平衡,但是AVL树为了保证它的绝对平衡,对插入和删除的效率有一定的影响,而红黑树插入和删除的效率就要高的多。同时,它又是一颗二叉查找树,使得它查找的效率也很高,查找的时间复杂度为O(logn),所以红黑树要优于AVL树。
2、红黑树特性
- 根结点为黑
- 结点为红或黑
- 不能有连续的两个红结点(红结点的子结点必须为黑)
- 任一结点到它们子孙结点的所有路径上黑结点的数量相等
- 叶子结点为黑(这里的叶子结点指的是null结点)
3、补充特性
- 最长路径上的结点数量不大于最短路径上结点数量的两倍
- 若结点只有一个子结点,则子结点的子结点为叶子结点,且子结点为红
4、左旋
步骤:
- 把5号结点变红,7号结点变黑
- 使5号结点的右孩子指向6号结点,6号结点的父节点设为5号结点
- 使5号结点的父结点指向7号结点,7号结点的父节点设为5号结点的父结点
- 使7号结点的左孩子指向5号结点,5号结点的父节点设为7号结点
5、右旋
步骤:
- 把5号结点变红,3号结点变黑
- 使5号结点的左孩子指向4号结点,4号结点的父节点设为5号结点
- 使5号结点的父结点指向3号结点,3号结点的父节点设为5号结点的父结点
- 使3号结点的右孩子指向5号结点,5号结点的父节点设为3号结点
6、查找
public TreeNode find(int key){
if(!this.leaf&&this.key==key){
return this;
}else if(this.key<key&&!this.leaf){
return this.right.find(key);
}else if(this.key>key&&!this.leaf){
return this.left.find(key);
}else{
return this;
}
}
说明:此处具有二分查找的思想,只不过是从数据结构的层面实现的,从一个结点开始往下找,如果比key大,则从左边递归寻找,如果比key小,则从右边递归寻找,如果找到叶子节点还没找到就结束,叶子结点指的是null结点
7、插入
从红黑树的性质可知,插入的结点只能是红结点,因为如果插入黑结点势必会造成树的不平衡,而插入红结点则不一定会造成树的不平衡,具体的操作分为以下几种情况:
情形1:插入结点为红,插入结点的父结点为黑
插入后不用进行任何处理
情形2:插入结点为红,插入结点的父节点为红
情形2.1:插入结点的父结点是祖父结点的左孩子,祖父结点的右孩子,也就是插入结点的叔叔结点为红
把父结点和叔叔结点变黑,祖父结点变红,以祖父结点为当前结点,继续进行平衡处理,处理完成后需把根结点变黑
情形2.2:插入结点的父结点是祖父结点的左孩子,叔叔结点为黑,根据红黑树的性质,此时叔叔结点只能为叶子结点
情形2.2.1:插入结点是父结点的右孩子
以父结点为旋转结点进行左旋,然后再以祖父结点进行右旋,平衡处理完成
情形2.2.2:插入结点是父结点的左孩子
以祖父结点为旋转结点进行右旋,平衡处理完成
说明:以上是处理插入结点的父结点是祖父结点的左孩子的情况,如果插入结点的父结点是祖父结点的右孩子,只需把上面的操作反过来即可
8、删除
红黑树的删除与普通二叉树的删除不同,它的原理是找到删除结点的后继结点或子结点来替换掉这个结点,由此也就把这个结点从红黑树中删除了,至于为何会这样做,一切都是为了使平衡操作更加简单,以下是具体的删除操作步骤:
情形1:删除结点只有一个子结点
由红黑树的性质可知,该删除结点只能为黑,且删除结点的子结点只能为红,子结点的子结点只能为叶子结点,此时只要让子结点的父结点指向删除结点的父结点,父结点指向删除结点的子结点即可完成删除操作,因为删掉了一个黑结点,红黑树不再平衡,所以还需要把删除结点的子结点变为黑才能使树重新平衡
情形2:删除结点只有叶子结点,且删除结点为红
因为删除结点为红,删除不影响树的平衡,而且删除结点只有叶子结点,叶子结点只能为黑,所以只要让叶子结点的父结点指向删除结点的父结点,父结点指向叶子结点即可完成删除操作
情形3:删除结点只有叶子结点,且删除结点为黑
首先让叶子结点的父结点指向删除结点的父结点,父结点指向叶子结点,即先把删除结点从树中删掉
情形3.1:叶子结点为父结点的左孩子,叶子结点的兄弟结点为红
以父结点为旋转结点进行左旋,重新判断叶子结点的兄弟结点的颜色,然后根据不同颜色进行不同的处理
情形3.2:叶子结点为父结点的左孩子,叶子结点的兄弟结点为黑,兄弟结点的左结点为黑,兄弟结点的右结点为黑
把兄弟结点变红,以叶子结点的父结点为当前结点,重新进行平衡处理
情形3.3:叶子结点为父结点的左孩子,叶子结点的兄弟结点为黑,兄弟结点的左结点为红,兄弟结点的右结点为黑
先以兄弟结点为旋转结点进行右旋,然后再把父结点的颜色赋给兄弟结点,父结点变黑,兄弟结点的右结点变黑,以父结点为旋转结点进行左旋,平衡处理完成
情形3.4:叶子结点为父结点的左孩子,叶子结点的兄弟结点为黑,兄弟结点的左结点颜色未知,兄弟结点的右结点为红
把父结点的颜色赋给兄弟结点,父结点变黑,兄弟结点的右结点变黑,以父结点为旋转结点进行左旋,平衡处理完成
情形4:删除结点有两个子结点
先找到删除结点的后继结点,然后用后继结点替换掉删除结点,由红黑树的性质可知,后继结点只能有一个子结点或只能有叶子结点,所以接下来就以后继结点为当前结点,继续进行上面3种情形的处理
说明:以上是叶子结点为父结点的左孩子的情况,如果叶子结点是父结点的右孩子,只需要把上面的操作反过来即可
9、源码
package com.yc.redblacktree;
import java.text.SimpleDateFormat;
import java.util.Date;
public class RedBlackTreeDemo {
public static void main(String[] args) {
//测试代码
RedBlackTree tree = new RedBlackTree();
/*
tree.add(5, 'a');
tree.add(7, 'e');
tree.add(1, 'f');
tree.add(3, 'c');
tree.add(2, 'g');
tree.add(6, 'b');
tree.add(4, 'd');
tree.delete(1);
tree.delete(2);
tree.delete(3);
tree.delete(4);
tree.delete(5);
tree.delete(6);
// tree.delete(7);
tree.infixOrder();
System.out.println();
tree.preOrder();
System.out.println();
tree.sufixOrder();*/
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = format.format(date);
System.out.println(dateStr);
for(int i=0;i<10000000;i++){
tree.add((int) (Math.random()*10000000), 'a');
}
Date date2 = new Date();
String date2Str = format.format(date2);
System.out.println(date2Str);
for(int i=0;i<10000000;i++){
tree.delete((int) (Math.random()*10000000));
}
Date date3 = new Date();
String date3Str = format.format(date3);
System.out.println(date3Str);
}
}
class TreeNode{
int key;//键
char value;//值
TreeNode parent;//父节点
TreeNode left;//左孩子
TreeNode right;//右孩子
boolean red;//是否为红色
boolean black;//是否为黑色
boolean leaf;//是否为叶子节点
/**
* 有参构造
* @param key
* @param value
*/
public TreeNode(int key,char value){
this.key = key;
this.value = value;
}
/**
* 无参构造
*/
public TreeNode(){}
/**
* 添加平衡
* @param tree
*/
public void addBalance(RedBlackTree tree){
while(this.parent!=null&&this.parent.red){
if(this.parent==this.parent.parent.left){
if(this.parent.parent.right.red){
this.parent.black = true;
this.parent.red = false;
this.parent.parent.right.black = true;
this.parent.parent.right.red = false;
this.parent.parent.red = true;
this.parent.parent.black = false;
this.parent.parent.addBalance(tree);
break;
}else if(this==this.parent.right){
this.parent.rotateLeft(tree);
this.parent.rotateRight(tree);
break;
}else{
this.parent.parent.rotateRight(tree);
break;
}
}else{
if(this.parent.parent.left.red){
this.parent.black = true;
this.parent.red = false;
this.parent.parent.left.black = true;
this.parent.parent.left.red = false;
this.parent.parent.red = true;
this.parent.parent.black = false;
this.parent.parent.addBalance(tree);
break;
}else if(this==this.parent.left){
this.parent.rotateRight(tree);
this.parent.rotateLeft(tree);
break;
}else{
this.parent.parent.rotateLeft(tree);
break;
}
}
}
if(this.parent==null){
this.black = true;
this.red = false;
tree.root = this;
}
}
/**
* 左旋变颜色
* @param tree
*/
public void rotateLeft(RedBlackTree tree){
TreeNode temp = this.right;
temp.red = false;
temp.black = true;
this.red = true;
this.black = false;
temp.parent = this.parent;
if(this.parent!=null&&this==this.parent.left){
temp.parent.left = temp;
}else if(this.parent!=null){
temp.parent.right = temp;
}
this.right = temp.left;
temp.left.parent = this;
this.parent = temp;
temp.left = this;
if(temp.parent==null){
tree.root = temp;
}
}
/**
* 左旋不变颜色
* @param tree
*/
public void rotateLeftNoColor(RedBlackTree tree){
TreeNode temp = this.right;
temp.parent = this.parent;
if(this.parent!=null&&this==this.parent.left){
temp.parent.left = temp;
}else if(this.parent!=null){
temp.parent.right = temp;
}
this.right = temp.left;
temp.left.parent = this;
this.parent = temp;
temp.left = this;
if(temp.parent==null){
tree.root = temp;
}
}
/**
* 右旋变颜色
* @param tree
*/
public void rotateRight(RedBlackTree tree){
TreeNode temp = this.left;
temp.black = true;
temp.red = false;
this.red = true;
this.black = false;
temp.parent = this.parent;
if(this.parent!=null&&this==this.parent.left){
temp.parent.left = temp;
}else if(this.parent!=null){
temp.parent.right = temp;
}
this.left = temp.right;
temp.right.parent = this;
temp.right = this;
this.parent = temp;
if(temp.parent==null){
tree.root = temp;
}
}
/**
* 右旋不变颜色
* @param tree
*/
public void rotateRightNoColor(RedBlackTree tree){
TreeNode temp = this.left;
temp.parent = this.parent;
if(this.parent!=null&&this==this.parent.left){
temp.parent.left = temp;
}else if(this.parent!=null){
temp.parent.right = temp;
}
this.left = temp.right;
temp.right.parent = this;
temp.right = this;
this.parent = temp;
if(temp.parent==null){
tree.root = temp;
}
}
/**
* 寻找结点
* @param key
* @return
*/
public TreeNode find(int key){
if(!this.leaf&&this.key==key){
return this;
}else if(this.key<key&&!this.leaf){
return this.right.find(key);
}else if(this.key>key&&!this.leaf){
return this.left.find(key);
}else{
return this;
}
}
/**
* 中序遍历
*/
public void infixOrder(){
if(this.leaf){
return;
}
this.left.infixOrder();
System.out.println("key="+this.key+" value="+this.value);
this.right.infixOrder();
}
/**
* 先序遍历
*/
public void preOrder(){
if(this.leaf){
return;
}
System.out.println("key="+this.key+" value="+this.value);
this.left.preOrder();
this.right.preOrder();
}
/**
* 后序遍历
*/
public void sufixOrder(){
if(this.leaf){
return;
}
this.left.sufixOrder();
this.right.sufixOrder();
System.out.println("key="+this.key+" value="+this.value);
}
/**
* 删除平衡
* @param tree
*/
public void deleteBalance(RedBlackTree tree) {
while(this.parent!=null&&!this.red){
if(this==this.parent.left){
if(this.parent.right.red){
this.parent.rotateLeft(tree);
if(this.parent.right.leaf){
break;
}
}
if(this.parent.right.black&&(this.parent.right.left.black||this.parent.right.left.leaf)&&(this.parent.right.right.black||this.parent.right.right.leaf)){
this.parent.right.red = true;
this.parent.right.black = false;
this.parent.deleteBalance(tree);
return;
}else if(this.parent.right.black&&this.parent.right.left.red&&(this.parent.right.right.black||this.parent.right.right.leaf)){
this.parent.right.rotateRight(tree);
}
if(this.parent.right.black&&this.parent.right.right.red){
this.parent.right.right.black = true;
this.parent.right.right.red = false;
this.parent.right.red = this.parent.red;
this.parent.right.black = this.parent.black;
this.parent.black = true;
this.parent.red = false;
this.parent.rotateLeftNoColor(tree);
return;
}
}else{
if(this.parent.left.red){
this.parent.rotateRight(tree);
if(this.parent.left.leaf){
break;
}
}
if(this.parent.left.black&&(this.parent.left.left.black||this.parent.left.left.leaf)&&(this.parent.left.right.black||this.parent.left.right.leaf)){
this.parent.left.red = true;
this.parent.left.black = false;
this.parent.deleteBalance(tree);
return;
}else if(this.parent.left.black&&(this.parent.left.left.black||this.parent.left.left.leaf)&&this.parent.left.right.red){
this.parent.left.rotateLeft(tree);
}
if(this.parent.left.black&&this.parent.left.left.red){
this.parent.left.left.black = true;
this.parent.left.left.red = false;
this.parent.left.red = this.parent.red;
this.parent.left.black = this.parent.black;
this.parent.black = true;
this.parent.red = false;
this.parent.rotateRightNoColor(tree);
return;
}
}
}
this.red = false;
this.black = true;
if(this.parent==null){
tree.root = this;
}
}
/**
* 寻找后继结点
* @param key
* @return
*/
public TreeNode findBack(int key) {
if(this.left.leaf){
return this;
}else{
return this.left.findBack(key);
}
}
}
class RedBlackTree{
//根结点
TreeNode root;
/**
* 中序遍历
*/
public void infixOrder(){
if(root!=null){
root.infixOrder();
}
}
/**
* 先序遍历
*/
public void preOrder(){
if(root!=null){
root.preOrder();
}
}
/**
* 后序遍历
*/
public void sufixOrder(){
if(root!=null){
root.sufixOrder();
}
}
/**
* 删除
* @param key
*/
public synchronized void delete(int key){
if(root==null){
return;
}
TreeNode findNode = root.find(key);
if(findNode.leaf){
return;
}else{
TreeNode y = null;
if(!findNode.left.leaf&&!findNode.right.leaf){
y = findNode.right.findBack(key);
}else{
y = findNode;
}
TreeNode x = null;
if(!y.left.leaf){
x = y.left;
}else{
x = y.right;
}
x.parent = y.parent;
if(y.parent!=null&&y==y.parent.left){
y.parent.left = x;
}else if(y.parent!=null){
y.parent.right = x;
}else{
root = x;
}
if(y!=findNode){
findNode.value = y.value;
}
if(y.black){
if(x.red){
x.black = true;
x.red = false;
}else{
x.deleteBalance(this);
}
}
}
}
/**
* 添加
* @param key
* @param value
*/
public synchronized void add(int key,char value){
if(root==null){
root = new TreeNode(key, value);
root.black = true;
TreeNode lLeaf = new TreeNode();
lLeaf.leaf = true;
TreeNode rLeaf = new TreeNode();
rLeaf.leaf = true;
root.left = lLeaf;
lLeaf.parent = root;
root.right = rLeaf;
rLeaf.parent = root;
return;
}
TreeNode findNode = root.find(key);
if(!findNode.leaf){
findNode.value = value;
}else{
TreeNode insertNode = new TreeNode(key,value);
insertNode.red = true;
if(key<findNode.parent.key){
insertNode.left = findNode;
insertNode.parent = findNode.parent;
findNode.parent.left = insertNode;
findNode.parent = insertNode;
TreeNode rLeaf = new TreeNode();
rLeaf.leaf = true;
insertNode.right = rLeaf;
rLeaf.parent = insertNode;
}else{
insertNode.right = findNode;
insertNode.parent = findNode.parent;
findNode.parent.right = insertNode;
findNode.parent = insertNode;
TreeNode lLeaf = new TreeNode();
lLeaf.leaf = true;
insertNode.left = lLeaf;
lLeaf.parent = insertNode;
}
if(insertNode.parent.red){
insertNode.addBalance(this);
}
}
}
}
10、总结
红黑树很复杂,这些都是我的个人理解,如果有不对的地方大家可以指出来,一起学习一起进步