学习过2-3树以后就知道应怎样去理解红黑树了,若是直接看「算法导论」里的红黑树的性质,是看不出因此然。咱们也看看一颗二分搜索树知足红黑的性质:html
1.每一个节点或是红色的,或是黑色的;java
2.根节点是黑色的;算法
3.每一个叶子节点(NIL)是黑色的;segmentfault
4.若是一个节点是红色的,则它的两个子节点都是黑色的;ide
5.对每一个节点,从该节点到其全部后代叶子节点的简单路径上,均包含相同数目的黑色节点。学习
若是说前面4个还算理解,那第5个性质又是怎么去理解呢?此时咱们借着2-3树去理解基本的红黑树,固然我会在后几篇文章介绍2-3-4树以及基于2-3-4树的红黑树。动画
抛开上面二分搜索树知足红黑的性质,咱们知道2-3树不是二叉树,咱们把它转换成一颗二叉树,2-节点很好转,3-节点转二叉却有两种,以下图:spa
红黑是指被指向节点的连接颜色,对于一颗2-3树,由于3-节点的存在有不少不一样的二叉树的表示,因此咱们只考虑左倾的状况。3d
红黑树的定义是含有红黑连接并知足下列条件的二分搜索树:htm
1.红连接均为左链接;
2.没有任何一个节点同时和两条红连接相连;
3.该树是完美黑色平衡的,即任意空连接到根节点的路径上的黑连接数量相同(和2-3树等价的,任意节点到其叶子节点的高度都是相同的)。
由于2-3树不存在永久的4-节点,4-节点终归要分解的(在2-3-4树中,为了更好地插入和删除,4-节点只存在于叶子节点,非叶子节点和2-3树同样的),因此在2-3树中没有任何一个节点能同时和两条红连接相连。对于第3条,2-3树自己是绝对平衡的,将3-节点转成二叉只增长了左红连接,其余黑连接没有什么变化,依然是黑色平衡的。
查找命中和二分搜索树同样,从根节点开始,若是查找命中则返回,不然比它小的进行左递归查找,比它大的进行右递归查找,直到查找为空。
写插入元素和删除元素以前,仍是要先介绍一下旋转和颜色转换。
在插入或者删除操做中可能会出现右倾或者两条连续的红连接,在向上变换的过程当中(恢复)都要调整为左倾。
假设有一条红色的右连接须要转为左连接,以下图所示:
这个操做叫作左旋转,右连接变成左连接,意味着被红连接指向的节点会变成红色,根节点默认是黑色。
右旋转也同样,不过在左倾红黑树中,只有出现两条连续红色的左链接才会进行右旋转,以下图:
颜色转换是用在临时4-节点上的,无论是向下变换仍是向上变换。
插入元素也须要先进行查找命中,查找未命中则在此节点(NIL)插入一个元素,是在红黑树底下插入一个红色节点,插入元素默认是红色节点。
若是红黑树目前是一颗空树,能够直接存储一个元素做为节点,而后该节点变成黑色。若是不是一颗空树,插入元素分两种状况:向2-节点插入新元素和向3-节点插入新元素。
向2-节点插入新元素很简单,若是新元素小于父节点的元素,直接插入红色的节点便可;若是新元素大于父节点的元素,则产生一个红色右连接,插完以后进行向上变换,在向上变换的过程当中(修复红黑树的性质)须要进行左旋转,将右连接变成左连接,知足左倾红黑树的性质。
1.新元素小于3-节点最小值
2.新元素位于3-节点最小值和最大值之间
3.新元素大于3-节点最大值
插入元素只有向上变换的过程,目的是为了知足红黑性质。
删除元素既有向下变换也有向上变换:向下变换是为了树底下有一个被红连接指向的节点能够被删除,不影响黑色平衡;向上变换是为了修复基于2-3树的左倾红黑树。
删除元素有4个原则:
1.删除元素的当前节点不能是2-节点;
2.向下变换不为2-节点;
3.从树底部删除节点;
4.向上变换,消除右倾和4-节点。
删除元素借鉴了以前学的二分搜索树删除元素的思想,二分搜索树删除元素分为删除最小元素、删除最大元素和删除任意元素三种状况:删除最小元素是一直递归它的左孩子,直到左孩子为空才进行删除;删除最大的元素则相反;若是是删除任意的元素须要进行命中查找,找到了就取右子树的最小值替换掉待删除元素,而后进行右子树的删除最小元素。
红黑树删除元素也是同样的,不过是多了向下变换和向上变换的过程。由于是左倾红黑树,删除最小元素是最合适的。
「算法4」里的红黑树介绍了删除最小键这一小节,虽没有很详细地介绍,但给出了沿着左连接向下变换的三种状况:
1.若是当前节点(父节点位置)的左子节点不是2-节点,完成;
2.若是当前节点(父节点位置)的左子节点是2-节点而左子节点的兄弟节点不是2-节点,则左子节点借它的兄弟节点的一个键过来;
3.若是当前节点(父节点位置)的左子节点和左子节点的兄弟节点都是2-节点,将左子节点、当前节点和左子节点的兄弟节点合并成一个临时的4-节点,使当前节点由3-节点变成2-节点或则4-节点变成3-节点。
删除最大节点思路也是同样的,不过这是左倾红黑树,对删除最大节点益处不大,甚至向下转换的时候左倾调整为右倾,向上转换balance还要将右倾调整为左倾。
在前面学习了删除最小节点,删除任意节点天然就很简单了。咱们若是要删除一个节点,首先进行命中查找,查找到这个待删除元素,将右子树的最小值替换掉这个待删除元素,指向待删除节点的连接颜色不能被改变。而后进行右子树的删除最小元素。
在命中查找过程当中,须要沿着左连接或沿着右连接进行向下转换。前面删除最小元素就是沿着左连接向下转换的。
沿着右连接向下转换也分三种状况:
1.若是当前节点(父节点位置)的右子节点不是2-节点,将左倾转换成右倾;
2.若是当前节点(父节点位置)的右子节点是2-节点而右子节点的兄弟节点不是2-节点,则右子节点借它的兄弟节点的一个键过来;
3.若是当前节点(父节点位置)的右子节点和右子节点的兄弟节点都是2-节点,将右子节点、当前节点和右子节点的兄弟节点合并成一个临时的4-节点,使当前节点由3-节点变成2-节点或则4-节点变成3-节点。
阅读原文可查看算法4里的RedBlackTree.java源码
喜欢本文的朋友,欢迎关注公众号「算法无遗策」,收看更多精彩内容