06 RedBlackTree
来源:互联网 发布:青岛知行国际是真的吗 编辑:程序博客网 时间:2024/06/01 19:51
简介
红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
它的统计性能要好于平衡二叉树(有些书籍根红黑树据作者姓名,Adelson-Velskii和Landis,将其称为AVL-树),因此,红黑树在很多地方都有应用。在C++ STL中,很多部分(包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。其他平衡树还有:AVL,SBT,伸展树,TREAP 等等。
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点(NIL节点,空节点)是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。
因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
要知道为什么这些特性确保了这个结果,注意到性质4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。
[以上信息来自于百度]
其在jdk中经典的使用在于TreeMap, jdk1.8 中对于HashMap加入了红黑树相关的优化 [如果某个桶中的记录过 大的话(当前是TREEIFY_THRESHOLD = 8),HashMap会动态的使用一个专门的treemap实现来替换掉它。这样做的结果会更好,是O(logn),而不是糟糕的O(n)。]
其实对于这个数据结构, 我现在就只记得他的添加元素, 删除元素需要维护其性质的话, 情况比较多, 比较复杂, 还有其适合于查找[给定的元素, 比给定元素大的最小元素, 比给定元素小的最大的元素] 或者 以及需要将输入构造为有序的序列的场景
下面的参考代码是参考 “http://www.cnblogs.com/fanzhidongyzby/p/3187912.html” 的来编写的
至于 其他的介绍, 这里就不介绍了, 因为有很多相关的播客嘛, 这个当时可是花了我三四天的时间啊。。
参考中 也有一些不错的播客,
jdk 中TreeMap的实现是相当简洁优雅的。。
参考代码
/** * file name : Test18BRTree.java * created at : 9:12:45 PM Jun 1, 2015 * created by 970655147 */package com.hx.test04;import com.hx.util.Log;import com.hx.util.Tools;public class Test18BRTree { // 红黑树 // 参考 : http://www.cnblogs.com/fanzhidongyzby/p/3187912.html public static void main(String []args) {// int[] arr = new int[] {34, 18, 28, 22, 32, 38, 27, 19, 17, 11, 38, 37, 48, 48, 6 }; int[] arr = new int[] {34, 18, 28, 22 }; BlackRedTree brt = new BlackRedTree(); for(int i=0; i<arr.length; i++) { brt.add(arr[i]); } Log.log(brt); } // 红黑树// 1.节点是红色或黑色。 // 2.根是黑色。 // 3.所有叶子(外部节点)都是黑色。 // 4.每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点) // 5.从每个叶子到根的所有路径都包含相同数目的黑色节点。 static class BlackRedTree { // 根节点 Node root; // 初始化 public BlackRedTree() { root = null; } // 添加一个元素 先插入在检查是否需要转动结点 // 如果root为null 则说明该树还没有结点 新建一个root结点, 设置其颜色为BLACK // 否则 插入一个结点 在检查是否 需要扭转结点 来使得满足其性质 public void add(int val) { if(root == null) { root = new Node(); root.setColor(Node.BLACK); root.val = val; } else { Node node = root; Node newNode = insert(val); fixAfterInsert01(newNode);// fixAfterInsert02(newNode); } } public void remove(int val) { Node[] tmp = delete(val); // 如果没有找到对应值的结点, 或者该节点为root 并且没有左右孩子 // 不知道delete中对tmp的控制 和这里的确保deleted不为叶子结点的控制是否有问题, 一会儿再来看看吧 if(tmp != null) { fixAfterDelete01(tmp[0], tmp[1]); } } // 移除结点node // 方式二 : 将node结点的左子树的最大结点[或者右子树的最小节点] 替换掉node, 然后该结点的左子树接到该节点的父节点上 private Node remove1(Node node) { if(isLeft(node) ) { return removeForNode1Left(node); } else { return removeForNode1Right(node); } } // 删除root结点 方式一 : 找出root结点左孩子的最大值 替换掉root结点, 然后该结点的左子树接到该节点的父节点上 private Node removeForRoot0(Node node) { return removeForNode1Left(root); } // 删除root结点 方式二 : 将root结点的右子树的最小结点 替换掉root, 然后该结点的右子树接到该节点的父节点上 private Node removeForRoot1(Node node) { return removeForNode1Right(root); } // 删除结点 方式二[Left] : 找出左孩子的最大值 替换掉删除结点, 然后该结点的左子树接到该节点的父节点上 private Node removeForNode1Left(Node node) { Node nodeLeftMax = getMaxNode(node.left); node.val = nodeLeftMax.val; if(nodeLeftMax.parent == node) { node.left = nodeLeftMax.left; if(nodeLeftMax.left != null) { nodeLeftMax.left.parent = node; } } else { nodeLeftMax.parent.right = nodeLeftMax.left; if(nodeLeftMax.left != null) { nodeLeftMax.left.parent = nodeLeftMax.parent; } } return nodeLeftMax; } // 删除root结点 方式二[Right] : 将node结点的右子树的最小结点 替换掉node, 然后该结点的右子树接到该节点的父节点上 private Node removeForNode1Right(Node node) { Node nodeRightMin = getMinNode(node.right); node.val = nodeRightMin.val; if(nodeRightMin.parent == node) { node.right = nodeRightMin.right; if(nodeRightMin.right != null) { nodeRightMin.right.parent = node; } } else { nodeRightMin.parent.left = nodeRightMin.right; if(nodeRightMin.right != null) { nodeRightMin.right.parent = nodeRightMin.parent; } } return nodeRightMin; } // 获取node结点的最大子节点 private Node getMaxNode(Node node) { Node tmp = node; while(tmp.right != null) { tmp = tmp.right; } return tmp; } // 获取node结点的最小子节点 private Node getMinNode(Node node) { Node tmp = node; while(tmp.left != null) { tmp = tmp.left; } return tmp; } // 遍历树 获取val对应的结点 public Node get(int val) { Node node = root; while(node != null) { if(val < node.val ) { node = node.left; } else if(val > node.val ) { node = node.right; } else { return node; } } return null; } // 检查是否需需要扭转结点 来满足其性质 // 令cur为加入的结点, parent为加入结点的父节点, gParent为加入节点的祖父节点, uncle为cur的舅舅结点[父节点的兄弟结点] // 如果cur结点不是root 并且是红色 // 如果parent 是黑色的 则直接返回, 插入当前结点 没有破坏红黑树的性质 // 否则 这时候就说明了gParent节点不为空[因为parent节点为红色 不可能是root结点] // 这是候 获取uncle结点 // 如果uncle结点为红色的时候[uncle结点为空 视为黑色] 设置gParent结点为红色, uncle, parent结点为黑色, 令更新cur为gParent结点 继续下一次的循环 // 如果uncle结点为 黑色 这时候有四种情况[因为uncle为黑色 调整之后 cur结点为black 所以会跳出while] // 1) 如果parent结点是gParent结点的左结点 并且cur结点是parent结点的左结点 这时候将parent结点右旋转 并设置parent为黑色, 设置parent的两个子节点为红色 // 2) 如果parent结点是gParent结点的右结点 并且cur结点是parent结点的右结点 这时候将parent结点左旋转 并设置parent为黑色, 设置parent的两个子节点为红色 // 3) 如果parent结点是gParent结点的左结点 并且cur结点是parent结点的右结点 这时候先将cur结点左旋转, 在讲cur结点右旋转 并设置cur为黑色, 设置cur的两个子节点为红色 // 4) 如果parent结点是gParent结点的右结点 并且cur结点是parent结点的左结点 这时候先将cur结点右旋转, 在讲cur结点左旋转 并设置cur为黑色, 设置cur的两个子节点为红色 // 参考 : http://blog.163.com/fulei.20030727@126/blog/static/300662212007112205334389/ private void fixAfterInsert01(Node newNode) { Node parent, gParent; Node cur = newNode; //we should fix until it is black colored while(cur != root && isRed(cur) ) { parent=cur.parent; if(parent.isBlack() ) { //that's fine, the insertion will not change any black height, and will not violate any rule. return; } gParent = parent.parent;//we can assume the p is not null now. Node uncle = getUncle(parent); if(uncle != null && uncle.isRed() ) { //re-coloring gParent.setColor(Node.RED); uncle.setColor(Node.BLACK); parent.setColor(Node.BLACK); //now the g maybe conflict with its parent; cur = gParent; } else { if(isLeft(parent) ) { if(isRight(cur)) { //this case we should do left rotation, and then it will transform to next case leftRotate(cur); //transformed to next case // cur = cur.left; } else { cur = parent; } rightRotate(cur); } else { if(isLeft(cur)) { //this case we should do right rotation, and then it will transform to next case rightRotate(cur); //transformed to next case // cur = cur.right; } else { cur = parent; } leftRotate(cur); } cur.setColor(Node.BLACK); setNodeToColorIfNotNull(cur.left, Node.RED); setNodeToColorIfNotNull(cur.right, Node.RED); } } root.setColor(Node.BLACK); } // 思路 和上面基本一致, 不过这里面部分代码是 我之前自己敲的, 而上面是 参考网上一位网友的作品 // 这个算法 我是没有完成的, 是参考过上面的代码之后 改进的 // 我的主要的漏洞在于 对于叔叔结点为红色的处理,我不知要需要循环/ 递归 处理, 所以我当时的处理方式 就是直接旋转gParent结点了,,, 擦 没有参考别人的东西, 要思考多久才能想出来.... private void fixAfterInsert02(Node newNode) { while(newNode != root && isRed(newNode)) { Node last = newNode.parent; // 如果 加入结点的父节点为黑色 说明满足BRTree的条件 if(last.isBlack() ) { break; } else { Node uncle = getUncle(last); // 如果叔叔结点时红色 if(uncle != null && uncle.isRed()) { last.parent.setColor(Node.RED); last.setColor(Node.BLACK); uncle.setColor(Node.BLACK); newNode = last.parent; // 更新gParent, parent, uncle结点的颜色 并旋转gParent结点 [思路就错了,,,] // Node lpParent = last.parent.parent; // // if(lpParent != null) { // last.transColor(); // last.parent.transColor(); //// Node uncle = getUncle(last); // if(uncle != null) { // uncle.transColor(); // } // // lpParent.transColor(); // lpParent.parent.transColor(); // if(isLeft(lpParent) ) { // if(lpParent.parent != null) { // transColorForAllSubTree(lpParent.parent.right); // } // rightRotate(lpParent); // } else { // if(lpParent.parent != null) { // transColorForAllSubTree(lpParent.parent.left); // } // leftRotate(lpParent); // } // } else { // if(last.isRed) { // newNode.setColor(Node.BLACK); // } // } // useless 当现在 root结点的左子树和右子树 深度相差大于1的时候 将其深度大的一方向深度小的一方旋转.. // int maxLeft = this.getMaxDepth(root.left, 0); // int maxRight = this.getMaxDepth(root.right, 0); //// Log.log(maxLeft, maxRight); // if(maxLeft > maxRight + 1) { // root.transColor(); // root.left.transColor(); // rightRotate(root.left); // } else if(maxRight > maxLeft + 1) { // root.transColor(); // root.right.transColor(); // leftRotate(root.right); // } // 如果叔叔结点时黑色 } else { if(isLeft(last) && isLeft(newNode) ) { rightRotate(last); newNode = last; } else if(isRight(last) && isRight(newNode) ) { leftRotate(last); newNode = last; } else if(isLeft(last) && isRight(newNode) ) { leftRotate(newNode); rightRotate(newNode); } else { rightRotate(newNode); leftRotate(newNode); } newNode.setColor(Node.BLACK); setNodeToColorIfNotNull(newNode.left, Node.RED); setNodeToColorIfNotNull(newNode.right, Node.RED); } } // end of while } root.setColor(Node.BLACK); } // 删除结点之后的调整操作 // 如果删除结点是红色 则不影响性质 // 否则 deleted 结点必然只有一个孩子结点 或者没有子节点[详见delete方法] // 获取deleted 结点的子节点 // 如果其 没有子节点 则加入一个临时结点 该临时结点的父节点指向deleted的父节点[主要是为了之后的调整操作占一个位置] // 然后进行调整根据son结点是parent结点的左孩子 或者右孩子进行调整 // 最后 如果添加了临时结点 则 删除临时结点 private void fixAfterDelete01(Node tar, Node deleted) { if(deleted.isRed()) { return ; } else { Node son = null; boolean isLeft = false; boolean isSonExists = false; son = getSonIfOnlyOneNode(deleted); if(son != null) { isSonExists = true; isLeft = isLeft(son); // 处理删除结点没有孩子的情况 添加一个临时结点 } else { Node tmpNode = new Node(deleted.parent, -1); tmpNode.setColor(Node.BLACK); isLeft = deleted.val < deleted.parent.val; if(isLeft) { deleted.parent.left = tmpNode; } else { deleted.parent.right = tmpNode; } son = tmpNode; } // 如果删除的结点是黑色 并且其孩子结点是红色, 直接领该孩子结点为黑色 即调整完毕 if(son.isRed() ) { son.setColor(Node.BLACK); return ; }// Log.log(son); if(isLeft ) { fixAfterDelete01Left(son); } else { fixAfterDelete01Right(son); }// Log.log(son);Log.horizon(); // 如果删除的结点 没有子节点, 则这里最后的时候 删除临时结点 if(!isSonExists) { if(isLeft ) { son.parent.left = null; } else { son.parent.right = null; } } } } // 如果son是parent结点的左结点 调整方案如下 // 先获取parent, sibling结点[相对于son结点] // 步骤1 : 如果sibling结点是红色 则将sibling结点和parent结点互换颜色, 并对sibling结点进行左旋转操作, 更新sibling结点 // 步骤2 :如果sibling的左右子节点均为黑色[sibling结点为空也算] 设置sibling结点的颜色为黑色, 并调整son结点为其父节点 // 如果现在的son结点为红色, 则说明调整完成 返回 // 否则更新parent, sibling结点 继续循环, 执行步骤1, 步骤2, ... // 如果son结点回溯到了 root结点 则调整完成 // 步骤3 : 如果sibling的左右子节点不全为黑色, 如果sibling的子节点 左红右黑 将sibling左子结点设置为黑色, 并设置sibling结点的颜色为红色, 并将sibling左子结点右旋转, 更新sibling结点 // 步骤4 :此时sibling结点的右节点必然为红[可能经过步骤3的处理, 也可能没有] 将sibling结点的右子节点设置为黑色, 交换sibling, parent结点的颜色, 在讲sibling结点左旋转, 完成调整 // 参考 : http://www.cnblogs.com/fanzhidongyzby/p/3187912.html private void fixAfterDelete01Left(Node son) { // 接下来的情况是删除结点为黑色 并且son结点为黑色的情况 Node parent = son.parent; Node sibling = getUncle(son); while(son != root) { // step 1 : 如果son的兄弟结点为红色的话 交换sibling和parent的颜色 并将sibling结点左旋转 // 更新sibling结点为son现在的兄弟节点 if(sibling.isRed() ) { boolean isRed = parent.isRed(); parent.setColor(sibling.isRed() ); sibling.setColor(isRed ); leftRotate(sibling); sibling = getUncle(son); } // step 2 : 如果 sibling的左右结点均为黑色 if(sibling == null || (isBlack(sibling.left) && isBlack(sibling.right)) ) { sibling.setColor(Node.RED); son = son.parent; if(son.isRed() ) { son.setColor(Node.BLACK); return ; } parent = son.parent; sibling = getUncle(son); } else { break; } } // son 结点回溯到了root结点 直接返回 if(son == root) { return ; } // step 3 : sibling的子节点不是全黑色 而是左红右黑 if(isRed(sibling.left) && isBlack(sibling.right) ) { setNodeToColorIfNotNull(sibling.left, Node.BLACK); sibling.setColor(Node.RED); rightRotate(sibling.left); sibling = getUncle(son); } // step 4 : 处理w右子节点y为红色的情况,此时w的左子节点x可黑可红 setNodeToColorIfNotNull(sibling.right, Node.BLACK); boolean isRed = parent.isRed(); parent.setColor(sibling.isRed() ); sibling.setColor(isRed ); leftRotate(sibling); } // 如果son是parent结点的右结点 调整方案和son为parent结点的左结点的调整是对称的, 所以逻辑基本一致 private void fixAfterDelete01Right(Node son) { // 接下来的情况是删除结点为黑色 并且son结点为黑色的情况 Node parent = son.parent; Node sibling = getUncle(son); while(son != root) { // step 1 : 如果son的兄弟结点为红色的话 交换sibling和parent的颜色 并将sibling结点左旋转 // 更新sibling结点为son现在的兄弟节点 if(sibling.isRed() ) { boolean isRed = parent.isRed(); parent.setColor(sibling.isRed() ); sibling.setColor(isRed ); rightRotate(sibling); sibling = getUncle(son); } // step 2 : 如果 sibling的左右结点均为黑色 if(sibling == null || (isBlack(sibling.left) && isBlack(sibling.right)) ) { sibling.setColor(Node.RED); son = son.parent; if(son.isRed() ) { son.setColor(Node.BLACK); return ; } parent = son.parent; sibling = getUncle(son); } else { break; } } // son 结点回溯到了root结点 这说明调整完成 直接返回 if(son == root) { return ; } // step 3 : sibling的子节点不是全黑色 而是左红右黑 if(isRed(sibling.right) && isBlack(sibling.left) ) { setNodeToColorIfNotNull(sibling.left, Node.RED); sibling.setColor(Node.BLACK); leftRotate(sibling.right); sibling = getUncle(son); } // step 4 : 处理w右子节点y为红色的情况,此时w的左子节点x可黑可红 setNodeToColorIfNotNull(sibling.left, Node.BLACK); boolean isRed = parent.isRed(); parent.setColor(sibling.isRed() ); sibling.setColor(isRed ); rightRotate(sibling); } // 获取deleted结点的子节点 优先获取左子结点 private Node getSonIfOnlyOneNode(Node deleted) { return deleted.left != null ? deleted.left : deleted.right; } // 将node结点视为红色的情况 private boolean isRed(Node node) { return node != null && node.isRed(); } // 将node结点视为黑色的情况 private boolean isBlack(Node node) { return node == null || node.isBlack(); } // 设置 node结点的颜色为isRed private void setNodeToColorIfNotNull(Node node, boolean isRed) { if(node != null) { node.setColor(isRed); } } // 以二叉排序树的规则 将val插入树中 不做任何其他操作 // 返回 插入的结点 private Node insert(int val) { Node node = root; Node last = null; while(node != null) { last = node; if(val < node.val ) { node = node.left; } else if(val > node.val ) { node = node.right; } else { Log.log(val + " is already exists..."); return null; } } Node newNode = null; if(val < last.val) { newNode = new Node(last, val); last.left = newNode; } else { newNode = new Node(last, val); last.right = newNode; } return newNode; } // 删除val对应的结点 返回需要删除的结点 和真正删除的结点 private Node[] delete(int val) { Node node = get(val); if(node == null) { Log.log("val " + val + " is no exist..."); return null; } Node[] tmp = new Node[2]; tmp[0] = node; tmp[1] = node; if(node.parent == null) { if(isLeaf(node)) { root = null; tmp = null; } else if(node.left != null) { tmp[1] = removeForRoot0(node); } else if(node.right != null) { tmp[1] = removeForRoot1(node); } return tmp; } else { if(isLeaf(node)) { if(isLeft(node)) { node.parent.left = null; } else { node.parent.right = null; } } else if(node.left != null && node.right != null) {// remove0(node); tmp = new Node[2]; tmp[0] = node; tmp[1] = remove1(node); } else if(node.left != null) { if(isLeft(node)) { node.parent.left = node.left; node.left.parent = node.parent; } else { node.parent.right = node.left; node.left.parent = node.parent; } } else if(node.right != null) { if(isLeft(node)) { node.parent.left = node.right; node.right.parent = node.parent; } else { node.parent.right = node.right; node.right.parent = node.parent; } } return tmp; } }// // 更新整棵子树的结点的颜色// private void transColorForAllSubTree(Node node) {// node.transColor();// if(node.left != null) {// transColorForAllSubTree(node.left);// }// if(node.right != null) {// transColorForAllSubTree(node.right);// }// } // 右旋转last结点 private void rightRotate(Node last) { Node lpParent = last.parent.parent; boolean pIsLeft = false; if(lpParent != null ) { pIsLeft = isLeft(last.parent); } last.parent.parent = last; last.parent.left = last.right; if(last.right != null) { last.right.parent = last.parent; } last.right = last.parent; last.parent = lpParent; if(lpParent == null ) { root = last; } else { if(pIsLeft) { lpParent.left = last; } else { lpParent.right = last; } } } // 左旋转last结点 private void leftRotate(Node last) { Node lpParent = last.parent.parent; boolean pIsLeft = false; if(lpParent != null ) { pIsLeft = isLeft(last.parent); } last.parent.parent = last; last.parent.right = last.left; if(last.left != null) { last.left.parent = last.parent; } last.left = last.parent; last.parent = lpParent; if(lpParent == null ) { root = last; } else { if(pIsLeft) { lpParent.left = last; } else { lpParent.right = last; } } } // 获取整棵树的最大深度 public int getMaxDepth() { return getMaxDepth(root, 0); } // assistMethod private int getMaxDepth(Node node, int depth) { if(node == null) { return depth; } int maxLeft = -1, maxRight = -1; if(node.left != null) { maxLeft = getMaxDepth(node.left, depth+1); } else { maxLeft = depth; } if(node.right != null) { maxRight = getMaxDepth(node.right, depth+1); } else { maxLeft = depth; } return Tools.getMax(maxLeft, maxRight); } // 判断 node结点是否是叶子结点 public boolean isLeaf(Node node) { return node.left == null && node.right == null; } // 判断 node结点是否是其父节点的左孩子 public boolean isLeft(Node node) { return node == node.parent.left; } // 判断 node结点是否是其父节点的右孩子 public boolean isRight(Node node) { return node == node.parent.right; } // 获取 node结点的兄弟结点 public Node getUncle(Node node) { if(node.parent == null) { return null; } return node == node.parent.left ? node.parent.right : node.parent.left; } // 中序遍历 获取node的子树的字符串表示[得到的是一个有序序列] 存于sb中 public void headFirstForString(Node node, StringBuilder sb) { if(node == null) { sb.append("null"); } else { if(node.left != null) { headFirstForString(node.left, sb); } sb.append(node.val + " color: " + node.getColor() + " ; ");// sb.append(node.val + " "); if(node.right != null) { headFirstForString(node.right, sb); } } } // Debug public String toString() { StringBuilder sb = new StringBuilder(); headFirstForString(root, sb); return sb.toString(); } } // Node static class Node { // red, black的字符串表示 // red, black的颜色表示 private static final String RED_STR = "red"; private static final String BLACK_STR = "black"; private static final boolean RED = true; private static final boolean BLACK = false; // val 表示数据, parent表示该节点的父节点, isRed表示是否是红色 // left, right 表示该节点的左孩子, 右孩子 int val; boolean isRed; Node parent; Node left, right; // 初始化 public Node() { isRed = RED; } public Node(Node parent, int val) { this(); set(parent, null, null, val); } public Node(Node parent, Node left, Node right, int val) { this(); set(parent, left, right, val); } public Node(Node other) { this.isRed = other.isRed; set(other.parent, other.left, other.right, other.val); } // setter public void set(Node parent, Node left, Node right, int val) { this.val = val; this.parent = parent; this.left = left; this.right = right; } // 当前结点是否是红色 public boolean isRed() { return isRed; } // 当前结点是否是黑色 public boolean isBlack() { return !isRed; } // 更新当前结点的颜色 public void setColor(boolean isRed) { this.isRed = isRed; } // 更新其颜色 为其他颜色 (红 -> 黑), (黑 -> 红) public void transColor() { isRed = !isRed; } // 获取当前结点的颜色字符串表示 private String getColor() { if(isRed) { return RED_STR; } else { return BLACK_STR; } } // Debug public String toString() { return "val : " + val + " color : " + getColor(); } }}
效果截图
参考
http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html [算法,红黑树] –2015.06.01
http://www.cnblogs.com/fanzhidongyzby/p/3187912.html [红黑树 非常好]
http://blog.csdn.net/ujs_abc/article/details/2069950 [红黑树]
http://blog.163.com/fulei.20030727@126/blog/static/300662212007112205334389/ [红黑树的实现] –2015.06.02
- 06 RedBlackTree
- 算法导论示例-RedBlackTree
- 红黑树(RedBlackTree)实现
- 编程练习——红黑树(RedBlackTree)
- 红黑树与C实现算法 - RedBlackTree.c
- RedBlackTree 红黑树——接力写
- 红黑树(RedblackTree)上--增加节点
- 红黑树(RedBlackTree),平衡树(BalancedTree),SkipList 的实现
- RedBlackTree(红黑树)--一种自平衡(最优)的二叉搜索树算法
- 06
- 06
- 06
- 06
- 06 ???
- 06-06-06
- 06-06-06
- 2011-06-06 21:06:06
- 2005-06-06工作计划
- 索引器
- 操作系统--计算机概述
- 前端框架-拿来就是用,一点不费劲!
- Python---os
- Python:映像和集合类型
- 06 RedBlackTree
- Python---serial
- OC基础---初始化方法
- hdu HDU Today2112
- 成员变量、局部变量和全局变量
- [IOS]SQLite3常用语句
- Python---class and iter
- 【LVL1_6_c】 指针数组 数组指针 的区别(仅仅是初步学习理解)
- OC基础----查看苹果帮助文档