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

0 0