红黑树java实现

3/8/2017来源:ASP.NET技巧人气:2008

老搞不清左旋右旋是往哪边转,索性写成哪个方向的子节点上浮

/** * * 总结:红黑树的难点在于插入和删除后的对于树规则的修复, * 在新增时主要采取的策略是上浮插入的红色节点,当遇到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); 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; } } }