您的位置:首页 > 编程语言 > Java开发

红黑树java实现

2017-03-07 16:49 113 查看
老搞不清左旋右旋是往哪边转,索性写成哪个方向的子节点上浮

/**
*
* 总结:红黑树的难点在于插入和删除后的对于树规则的修复,
*  在新增时主要采取的策略是上浮插入的红色节点,当遇到cpg连成一条线 并且 cp为红色的情况  我们可以交换 pg 颜色上浮 p,因为上浮的颜色是r 并不会破坏树的结构
*  在删除时主要才去的策略是让 要么可以涂红b的黑色让问题移到p上,要么将p的右侧想办法弄成r 以至于我们交换黑色的b和红色的p之后填充了另一侧的黑色,然后将原来
*  右侧的子节点涂黑,不让右侧的节点数发生变化
*  注意点:红黑树要么单支黑p红c,要么有两个子节点
*
*
*@author Zhouk
*@date 2017年3月7日 下午3:40:23
*@describtion BRTree
**/
public class BRTree<T> {

private Node<T> root;

public void insert(int index ,T value){
if(root==null){
root = new Node<T>(index, value, false);
}else{
insertByStep(root,index,value);
}
}
private Node<T> insertByStep(Node<T> currentParent,int index,T value){
if(index>currentParent.index){
Node<T> rightChild=currentParent.rightChild;
if(rightChild==null){
Node<T> insertNode=new Node<T>(index, value,true);
insertNode.parent=currentParent;
currentParent.rightChild=insertNode;
//对于新增节点需要进行 fixed操作
fixedAfterInsert(insertNode);
return insertNode;
}else if(rightChild.index==index){
rightChild.value=value;
return rightChild;
}else{
return insertByStep(rightChild, index, value);
}
}else{
Node<T> leftChild=currentParent.leftChild;
if(leftChild==null){
Node<T> insertNode=new Node<T>(index, value,true);
insertNode.parent=currentParent;
currentParent.leftChild=insertNode;
//对于新增节点需要进行 fixed操作
fixedAfterInsert(insertNode);

4000
return insertNode;
}else if(leftChild.index==index){
leftChild.value=value;
return leftChild;
}else{
return insertByStep(leftChild, index, value);
}
}
}

/**
* 添加核心思想是将红色 节点上浮
* 但是 在
*          b                      b
*      r:p     b    =>        r:c    b
*   b      r:c             r:p
*                      b
*  或者
*          b                      b
*      b      r:p    =>      b      r:c
*          r:c   b                     r:p
*                                          b
*
*    这两种 情况 下   结果中的是 r:p 不符合 要求 但是出现了 红色节点下沉的情况  需要特殊处理
*    我们需要将 r:c 涂黑  结果是  r:c 下 黑 多出一个
*    于是 我们将 root的b 涂红   结果 是   root 另外一个分支   少了一个黑
*    我们将   现在是 黑的 r:c 上浮   解决问题
*    要注意的是
*    那么 要满足的条件就是 之前的root 节点 接手的那个 节点 必然需要时黑色
*    不然 root已经被涂红 下移  那么 会出现 两个 假如 r:c 交给他的节点是红色就会出现错误
*    在r:c 是root 左支 时候 交给 root的 是r:c 的rightChild
*    在r:c 是root 右支时交给 root的的是 r:c的 leftChild
*    总结如下:
*    //p:parent g:grandfatehr  c:child u:uncle
*
*    1:u:b p:r为g:b左支  c:r为p:r左支:     涂黑 p  涂红g 上浮 p=>complete
*    2:u:b p:r为g:b左支  c:r为p:r右支:   上浮c   p 为 新的 c  转到 情况1
*    3:u:b p:r为g:b右支  c:r为p:r左支:    上浮 c   p 为新的c  转到情况4
*    4:u:b p:r为g:b右支  c:r为p:r右支    涂黑 p 涂红 g 上浮p =>complete
*
*
*    剩余情况 就是p:r u:r(p必然是r ,如果为 b 那么 已经结束)
*    那么 涂黑   p 和 u   涂红 g   g为新的 c   可能不满足情况
* @param currentNode
*/
private void fixedAfterInsert(Node<T> currentNode){
//如果当前节点是root节点 那么 无论什么颜色直接涂黑
if(currentNode.parent==null){
currentNode.color=false;
}
//如果插入节点的父节点 的颜色为黑  那么 什么也不做 返回
if(!currentNode.parent.color){
return;
}
//如果 父节点 为红色  此时必然有祖父节点
else{
//如果叔父节点为 黑色
Node<T> uncleNode=getParentAnotherChild(currentNode.parent);
if(uncleNode==null||!uncleNode.color){
//判断 位置
Node<T> parent=currentNode.parent;
Node<T> grandParent=parent.parent;
if(grandParent.index>parent.index){
//情况1
if(parent.index>currentNode.index){
grandParent.color=true;
parent.color=false;
leftChildFloat(parent);
}
//情况2
else{
rightChildFloat(currentNode);
fixedAfterInsert(currentNode.leftChild);
}
}else{
//情况3
if(parent.index>currentNode.index){
leftChildFloat(currentNode);
fixedAfterInsert(currentNode.rightChild);
}
//情况4
else{
grandParent.color=true;
parent.color=false;
rightChildFloat(parent);
}
}

}
//如果叔父节点为红色
else{
//将 父亲节点 和叔父节点颜色涂黑   祖父节点涂红 重新开始 fixed操作
uncleNode.color=false;
currentNode.parent.color=false;
currentNode.parent.color=true;
fixedAfterInsert(currentNode.parent.parent);
}
}
}

public boolean remove(int i){
Node<T> removeNode=find(i);
if(removeNode==null)return false;
//假如删除的不是叶子节点 需要进行fixed操作
deleteAndFixed(removeNode);
return true;
}

/**
* @param removeNode 待删除的节点
* 定义待删除节点 为 r 定义 右侧最小节点的  s
* s 可能存在 右支但是 不可能有左支
* 我们交换s和r 的 index 和 value
* 现在假如 s为红色 那么并 不影响平衡
* 但如果 s 为 黑色 那么 原来 s 位置 现在 r 位置就少了一个黑色
* 我们需要让 现在 r的右侧移动一个黑色过来 再删掉r
* 如果 r的兄弟节点 b 为红色 直接上浮 b ,b 和p(父节点)交换颜色,
*
*
* 交换颜色 上浮的实质:
*
*          因为  g 节点会移动到另一侧 但是颜色是p的颜色
*
*          假如p是b,g是r 那么 移动后 g移动过的一侧多了原来p的颜色b(用于删除时填充b)
*          而现在 原来p这一侧的root变成了 r 少了个b (原来c未移动的子节点为红色 ,我们可以直接涂黑 达到平衡)
*          //这就需要 假如左节点上浮 需要 孩子的左孩子为 红色
*                    假如 右节点上浮 需要孩子的右孩子为红色
*           (删除时仅仅存在这种情况 ,被删除的是右侧最小节点,都是左边少)
*          假如p是r,g是b 那么 移动后 g移动过的一侧多了 r (无所谓)
*          而现在 原来p这一侧的root变成b   也无所谓
*          //所以假如在p是r g是b的情况下 我们可以随意交换移动
*          (就像新增时调整一样,可以用来调整连续r的问题)
*
*
*  解决一侧少一个黑的方法
*  0:假如兄弟节点为红 那么 上浮兄弟节点交换 b和p的颜色 那么原来兄弟节点的子节点
*  (红色的子节点 ,必为黑)
*  变成现在的兄弟节点  进入其余b为黑的情况
*  1:假如b 为黑  那么 我需要将当前b的右孩子变成红色
*          1.1假如左右还是都是黑色 那么 涂红b p为新的c
*          1.2假如左侧是红色 右侧是黑色  那么把左侧的红色移动到右侧    (交换b和其左侧的黑色 然后上浮左侧子节点)
*              左侧子节点 为新的b 其右侧为原来的b颜色为原来左侧的颜色r 转入1.3
*          1.3假如左侧是右侧是红色     那么 那么我们可以交换p和g颜色 上浮p 涂黑右侧子节点  达到平衡
*
*
*  删除存在的特殊情况:
*  删除的是root节点  直接删了
*  要么是单支黑p红c直接将g的child指向c c的parent指向g
*  假如删除的是叶子节点 直接进入fix操作
*/
private void deleteAndFixed(Node<T> removeNode){
//假如是根节点
if(removeNode.parent==null){
root=null;
return;
}
//叶子节点的情况
if(removeNode.leftChild==null&&removeNode.rightChild==null){
fixedAfterDelete(removeNode);
if(removeNode.index<removeNode.parent.index){
removeNode.parent.leftChild=null;
}else{
removeNode.parent.rightChild=null;
}
}
//黑色红单支的情况
else if(removeNode.rightChild==null){
Node<T> parent=removeNode.parent;
Node<T> leftChild=removeNode.leftChild;
if(parent.index>removeNode.index){
parent.leftChild=leftChild;
leftChild.parent=parent;
leftChild.color=false;
}else{
parent.rightChild=leftChild;
leftChild.parent=parent;
leftChild.color=false;
}
}else  if(removeNode.leftChild==null){
Node<T> parent=removeNode.parent;
Node<T> rightChild=removeNode.rightChild;
if(parent.index>removeNode.index){
parent.leftChild=rightChild;
rightChild.parent=parent;
rightChild.color=false;
}else{
parent.rightChild=rightChild;
rightChild.parent=parent;
rightChild.color=false;
}
}
//双子节点的情况
else{
Node<T>  finalRemoveNode=removeNode.rightChild;
while(finalRemoveNode.leftChild!=null){
finalRemoveNode=finalRemoveNode.leftChild;
}
//如果是红色 不做操作
if (finalRemoveNode.color) {
return;
}else{
removeNode.value=finalRemoveNode.value;
removeNode.index=finalRemoveNode.index;
fixedAfterDelete(finalRemoveNode);
}
if(finalRemoveNode.index<finalRemoveNode.parent.index){
finalRemoveNode.parent.leftChild=null;
}else{
finalRemoveNode.parent.rightChild=null;
}
}
}

private void fixedAfterDelete(Node<T> finalRemoveNode){
//如果兄弟节点为黑色  注意 兄弟节点不可能为null  为null时当前节点必为红色
Node<T> brother=getParentAnotherChild(finalRemoveNode);
//如果brother为红色
if(brother.color){
brother.color=false;
brother.parent.color=true;
rightChildFloat(brother);
//任然处理当前节点
fixedAfterDelete(finalRemoveNode);
}else{
//子节点全黑
if(!isRed(brother.leftChild)&&!(isRed(brother.rightChild))){
//brother 涂红
brother.color=true;
fixedAfterDelete(brother.parent);
}else if(isRed(brother.leftChild)){
brother.leftChild.color=false;
brother.color=true;
leftChildFloat(brother.leftChild);
}else{
brother.color=false;
brother.parent.color=true;
rightChildFloat(brother);
brother.leftChild.color=false;
}

}
}

private boolean isRed(Node<T> node){
return node!=null&&node.color;
}

public Node<T> find(int i){
if(root==null)return null;
return findByStep(root,i);
}
public Node<T> findByStep(Node<T> currentParent,int i){
if(currentParent.index>i){
Node<T> leftChild=currentParent.leftChild;
if(leftChild==null)return null;
if(leftChild.index==i)return leftChild;
return findByStep(leftChild,i);
}else{
Node<T> rightChild=currentParent.rightChild;
if(rightChild==null)return null;
if(rightChild.index==i)return rightChild;
return findByStep(rightChild,i);
}
}
/**
* 返回兄弟节点
* @param currentNode
* @return
*/
private  Node<T> getParentAnotherChild(Node<T> currentNode){
if(currentNode==null||currentNode.parent==null){
return null;
}
if(currentNode.index<currentNode.parent.index){
return currentNode.parent.rightChild;
}else{
return currentNode.parent.leftChild;
}
}

/**
* 左侧孩子 上浮
* @param itemNode 孩子节点
*/
private void leftChildFloat(Node<T> itemNode){
Node<T> parent=itemNode.parent;
Node<T> grandParent=parent.parent;
Node<T> right=itemNode.rightChild;
parent.parent=itemNode;
itemNode.rightChild=parent;
parent.leftChild=right;
if(right!=null){
right.parent=parent;
}
itemNode.parent=grandParent;
if(grandParent!=null){
if(grandParent.index>itemNode.index){
grandParent.leftChild=itemNode;
}else{
grandParent.rightChild=itemNode;
}
}
}
/**
* 右侧孩子上浮
* @param itemNode 孩子节点
*/
private void rightChildFloat(Node<T> itemNode){
Node<T> parent=itemNode.parent;
Node<T> grandParent=parent.parent;
Node<T> left=itemNode.leftChild;
parent.parent=itemNode;
itemNode.leftChild=parent;
parent.rightChild=left;
if(left!=null){
left.parent=parent;
}
itemNode.parent=grandParent;
if(grandParent!=null){
if(grandParent.index>itemNode.index){
grandParent.leftChild=itemNode;
}else{
grandParent.rightChild=itemNode;
}
}
}

public static class Node<T>{
int index;
T value;
Node<T> parent;
Node<T> leftChild;
Node<T> rightChild;
/**
* red:true,black:false
*/
boolean color;
public Node(int index, T value, boolean color) {
super();
this.index = index;
this.value = value;
this.color = color;
}

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