红黑树简介
红黑树一种自平衡的二叉树,先了解一下什么是二叉树把。
二叉树的性质
在二叉树的第I层上最多有2i-1(i>=1)
二叉树中如果深度为K,那么该二叉树最多有2k-1个节点(k>=1)
n0 = n1+1 其中n0表示度数为0的节点数,n1表示度数为2的节点数
在完全二叉树中,具有n个节点的完全二叉树的深度为[log2n]+1,其中[log2n]是向下取整
若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点有如下特性:
(1) 若 i=1,则该结点是二叉树的根,无双亲, 否则,编号为 [i/2] 的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子结点。
在了解二叉树的性质后,再来了解一下红黑树的性质
红黑树性质
性质1:每个节点要么是黑色,要么是红色。
性质2:根节点是黑色。
性质3:每个叶子节点(NIL)是黑色。
性质4:每个红色结点的两个子结点一定都是黑色。
性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
红黑树是自平衡的二叉树,由上图可以看出来虽然左右子树的层数不一样,但是从任一节点到每个子节点都包含相同数量的黑色节点。
红黑树的自平衡操作
红黑树通过三种操作来实现自平衡分别是
左旋:以X做为支点(旋转节点),其右子结点变为旋转节点的父结点,右子节点的左子节点变为旋转节点的右子节点,左节结点保持不变。
右旋:以X做为支点(旋转节点),其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变。
变色:红变黑,黑变红
左旋
右旋
从上图可以发现
左旋只影响旋转节点和其右子节点的结构。
右旋只影响旋转节点和其左子节点的结构。
红黑树查找
因为红黑树就只是能够自平衡的二叉树,它与二叉树的区别主要在于插入,因此它的查找于二叉树是一样一样的。
- 把根节点设为当前节点,从根节点开始查找。
- 如果当前节点为空,直接返回null
- 如果当前节点与查找key相等,直接返回当前节点
- 如果当前节点大于查找key,则设置当前节点的左子节点为当前节点,重复步骤2
- 如果当前节点小于查找key,则设置当前节点的右子节点为当前节点,重复步骤2
红黑树插入
红黑树的插入分为两部分,第一部分于一般的二叉树插入一样,第二部分就是自平衡。
- 从根节点开始查找。
- 若根节点为空,那么插入节点作为根节点,结束。
- 若根节点不为空,那么把根节点作为当前节点。
- 若当前节点为null,返回当前节点的节结点,结束。
- 若当前节点key等于查找key,那么该key所在节点就是插入节点,更新节点的值,结束。
- 若当前节点key大于查找key,把当前节点的左子节点设置为当前节点,重复步骤4
- 若当前节点key小于查找key,把当前结点的右子结点设置为当前节点,重复步骤4
插入的节点默认都是红色的,因为为红色不见得会破坏红黑树平衡,但是如果为黑色,那么黑节点多1,打破平衡,就必须要做自平衡了。
红黑树自平衡
红黑树代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
| package com.czj.shiro.redblcaktree;
import java.util.Random; import java.util.Stack;
public class RBTree<T extends Comparable>{
public static final boolean RED=false;
public static final boolean BLACK=true;
private RBNode<T> headNode;
public static class RBNode<T extends Comparable>{ private T key;
private boolean color;
private RBNode<T> leftNode;
private RBNode<T> rightNode;
private RBNode<T> parentNode;
}
public void insert(RBNode<T> node){ int tmp=0; RBNode<T> x=this.headNode; RBNode<T> y=null;
while(x!=null){ y=x; tmp=x.key.compareTo(node.key); if (tmp==1){ x=x.leftNode; }else if(tmp==-1){ x=x.rightNode; }else { return; } } node.parentNode=y; if (y!=null){ tmp=y.key.compareTo(node.key); if (tmp==1){ y.leftNode=node; }else if(tmp==-1){ y.rightNode=node; }else { return; } }else { this.headNode=node; }
node.color=RED;
}
private void fix(RBNode<T> node){ RBNode<T> parent,uncle,gParent; while ((parent=parentOf(node))!=null&&isRed(node)){ gParent=parentOf(parent); if((uncle=isUncle(node))!=null&&isRed(uncle)){ parent.color=BLACK; uncle.color=BLACK; gParent.color=RED; node=gParent; continue; }
if(gParent.leftNode==parent){
if (parent.rightNode==node){ leftRotate(parent); RBNode<T> tmp=node; node=parent; parent=tmp; }
gParent.color=RED; parent.color=BLACK; rightNode(gParent); }else { if (parent.leftNode==node){ rightNode(parent); RBNode<T> tmp=node; node=parent; parent=tmp; }
gParent.color=RED; parent.color=BLACK; leftRotate(gParent); } } this.headNode.color=BLACK; }
public RBNode<T> parentOf(RBNode<T> node){ return node.parentNode; }
public boolean isRed(RBNode<T> node){ return node.color==RED; }
public RBNode<T> isUncle(RBNode<T> node){ RBNode<T> parentNode=node.parentNode; if (parentNode==null){ return null; }
if (parentNode.leftNode==null||parentNode.rightNode==null){ return null; } if (parentNode.leftNode==node){ return parentNode.rightNode; }else{ return parentNode.leftNode; } }
public void leftRotate(RBNode<T> node){ RBNode<T> rightNode=node.rightNode; node.rightNode=rightNode.leftNode;
if (rightNode.leftNode!=null) rightNode.leftNode.parentNode=node; rightNode.parentNode=node.parentNode;
if (node.parentNode==null){ this.headNode=rightNode; }else { if (node.parentNode.leftNode==node){ node.parentNode.leftNode=rightNode; }else { node.parentNode.rightNode=rightNode; } }
rightNode.leftNode=node; node.parentNode=rightNode; }
public void rightNode(RBNode<T> node){ RBNode<T> leftNode=node.leftNode; node.leftNode=leftNode.rightNode; if (leftNode.rightNode!=null){ leftNode.rightNode.parentNode=node; }
leftNode.parentNode=node.parentNode;
if (node.parentNode==null){ this.headNode=leftNode; }else { if (node.parentNode.leftNode==node){ node.parentNode.leftNode=leftNode; }else { node.parentNode.rightNode=leftNode; } } leftNode.rightNode=node; node.parentNode=leftNode; }
public void inOrder(){ Stack<RBNode<T>> stack=new Stack<>(); RBNode<T> node=this.headNode; while(node!=null||!stack.isEmpty()){ while(node!=null){ stack.push(node); node=node.leftNode; } if (!stack.isEmpty()){ RBNode<T> nNode=stack.pop(); System.out.println("值:"+nNode.key); node=nNode.rightNode; } } }
public static void main(String[] args) { RBTree<Integer> rbTree=new RBTree<>(); Random random=new Random(); RBNode<Integer> rbNode=null; for (int i=0;i<=100;i++){ rbNode = new RBNode<>(); rbNode.key=random.nextInt(1000); rbTree.insert(rbNode); } rbTree.inOrder(); } }
|