您的位置:首页 > 其它

我的第一篇博客——红黑树的基本操作

2016-04-07 19:18 351 查看
RBTree是相对平衡的二叉查找树(bst),与AVL平衡二叉树相比,其”平衡“程度没有那么严格,因而在维护红黑树结构时需要较小的代价,总体性能较好(但是在有特殊查找要求时,考虑使用AVL_tree也是一个不错的选择。)下面我将写写RBTree的性质与基本操作:

首先来简单定义RBTree的节点,方便叙述

class RBTreeNode{
int key;
int color; //颜色值   1:BLACK 2:RED
RBTreeNode p;  //父节点
RBTreeNode left;  //左孩子
RBTreeNode right; //右孩子
}


然后来了解RBTree的性质(专业定义请看算法导论红黑树章节)

1. root.color == BLACK  //根节点颜色为黑
2. node.color == BLACK OR RED   //每个节点的颜色为黑色或红色
3. if n.color == RED  //一个节点为红色,则两个孩子(非空的话)颜色为黑色
n.left.color == BLACK
n.right.color == BLACK
4. node--->leaf 的路径上黑色节点数目相同 //任一节点到其叶子节点的路径上黑色节点的数目相同


由RBTree的性质,其颜色约束可以把RBTree的高度限制在log2^n以内,达到到降低时间复杂度的目的。

好了,现在就来看看基本的insert/delete/search 操作,因为RBTree是基于bst的,其search操作与bst的search一样,insert/delete也是在bst的insert/delete操作的基础上改进。由于intsert/delete时可能破坏RBTree的结构,所以需要维持其结构,一般通过改变相关节点的颜色或旋转来维护。

认识旋转操作:leftRotate(X)/rightRotate(Y)



分析insert操作(插入的节点颜色为红色,用n表示)

1. n == root //空树时插入,只破坏性质1

n.color = BLACK; return;

2. n != root //非空树时插入

a. if n.p == BLACK return; //性质1-4均没有被破坏

b. if n.p == RED //直接破坏了性质3,需要维护,在维护过程中只需关注n以及n的父亲·爷爷·叔叔,其中P:父亲 G:爷爷 U:叔叔,情况如下



由于前两种情况(LL/LR)与后两情况(RR/RL)镜面对称,讨论前两情况即可,代码实现时left与right互换即可。于是我们来看看前两情况的各种着色可能及应对策略

P.color=BLACK; U.color=BLACK; G.color=RED; N=G;进入下一次迭代



rightRotate(G); P.color=BLACK; G.color=RED;进入下一次迭代



leftRotate(P); N<->P; rightRotate(G); P.color=BLACK; G.color=RED;进入下一次迭代



注意迭代终止条件为:上述1或2.a //while(n!=root && n.p.color==BLACK)

分析delete操作(删除节点为min,链接到n.p的节点为con)

1.删除点颜色为红色,return;

2.不为黑色则,把链接接上去的节点看成既具有自己的colo属性,也有一额外的“黑色”用来提高黑色节点数目,现在只要想办法把这个“黑色”转为某节点的color属性即可:

1. if con.color ==RED

con.color = BLACK; return;

2.关注con 及其父亲·叔叔·侄儿,情况如下:(灰色表示颜色不确定)



下面给出部分函数java代码实现:

class RBTreeNode{
final static int BLACK = 1,RED = 0;
int key;
int color; //颜色值   1:BLACK 0:RED
RBTreeNode p;  //父节点
RBTreeNode left;  //左孩子
RBTreeNode right; //右孩子
RBTreeNode(int key,int color,RBTreeNode p,RBTreeNode left,RBTreeNode right){
this.key = key;
this.color = color;
this.p = p;
this.left = left;
this.right = right;
}
}

public class RBTree {
private RBTreeNode root;
RBTree(){ root = null;}
void leftRotate(RBTreeNode x){//左旋转
RBTreeNode y = x.right;
if(x == root)
root = y;
else {
if(x.p.left ==x)
x.p.left = y;
else
x.p.right = y;
}
y.p = x.p;
x.right = y.left;
y.left = x;
x.p = y;
if(x.right != null)
x.right.p = x;
}
void rightRotate(RBTreeNode x){//右旋转
RBTreeNode y = x.left;
if(x == root)
root = y;
else {
if(x.p.left ==x)
x.p.left = y;
else
x.p.right = y;
}
y.p = x.p;
x.left= y.right;
y.right = x;
x.p = y;
if(x.left !=null)
x.left.p = x;
}
void fixUpInsert(RBTreeNode n){   //插入后维持性质
while(root != n && n.p.color == RBTreeNode.RED){
if(n.p.p.left == n.p){  //LL LR
if( n.p.right !=null &&
n.p.right.color == RBTreeNode.RED){
//情况2.1
n.p.color = RBTreeNode.BLACK;
n.p.color = RBTreeNode.BLACK;
n.p.p.color = RBTreeNode.RED;
n = n.p.p;
}
else {
if(n.p.right == n){
leftRotate(n.p);
n = n.left;
}
rightRotate(n.p.p);
n.p.color = RBTreeNode.BLACK;
n.p.right.color = RBTreeNode.RED;
}
}
else{   //RR RL
if( n.p.left !=null &&
n.p.left.color == RBTreeNode.RED){
n.p.color = RBTreeNode.BLACK;
n.p.color = RBTreeNode.BLACK;
n.p.p.color = RBTreeNode.RED;
n = n.p.p;
}
else {
if(n.p.left == n){
rightRotate(n.p);
n = n.right;
}
leftRotate(n.p.p);
n.p.color = RBTreeNode.BLACK;
n.p.left.color = RBTreeNode.RED;
}
}
}
root.color = RBTreeNode.BLACK;
}
void fixUpDelete(RBTreeNode n){ //删除后维持性质
//自己根据delete分析码出来吧
}
void insert(int key){  //插入操作
if(root == null){  //空树时插入
root = new RBTreeNode(key,RBTreeNode.BLACK,null,null,null);
}
else{  //非空树时插入
RBTreeNode temRoot = root;
RBTreeNode temRootPa =null;
boolean markL = false;
while(temRoot !=null){  //找到即将插入的位置
markL = false;
if(temRoot.key > key){
temRootPa = temRoot;
temRoot = temRoot.left;
markL = true;
}
else {
temRootPa = temRoot;
temRoot = temRoot.right;
}
}
if(markL){
temRootPa.left = new RBTreeNode(key,RBTreeNode.RED,temRootPa,null,null);
fixUpInsert(temRootPa.left);  //插入后维持性质
}
else {
temRootPa.right = new RBTreeNode(key,RBTreeNode.RED,temRootPa,null,null);
fixUpInsert(temRootPa.right);  //插入后维持性质
}
}
}
RBTreeNode getMin(RBTreeNode tem){
while(tem.left != null)
tem = tem.left;
return tem;
}
void delete(int key){
RBTreeNode temRoot = root;
while(temRoot !=null){  //寻找要删除的节点
if(temRoot.key > key)
temRoot = temRoot.left;
else if(temRoot.key < key)
temRoot = temRoot.right;
else break;
}
if(temRoot == null) return; //没有找到要删除的节点
if(temRoot.left !=null && temRoot.right !=null){  //待删除节点有两个孩子
RBTreeNode min = getMin(temRoot.right); //找到右子树中最小元素节点
temRoot.key = min.key; //把待删除点转移到右子树中最小元素节点
if(min.p.right == min) min.p.right = min.right;  //删除min节点
else min.p.left = min.right;
fixUpDelete(min.right);  //删除后维持性质
}
else {
RBTreeNode con = (temRoot.left != null ? temRoot.left : temRoot.right);
//确定连接上去的节点
if(temRoot ==root) //待删点为root
root = con;
else{

if(temRoot.p.left == temRoot)
temRoot.p.left =con;
else temRoot.p.right = con;
}
fixUpDelete(con);   //删除后维持性质
}
}
}


h
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: