你要删除的节点x可分为三类:有两个子节点的,只有一个子节点的,以及没有子节点的。因为删除有两个子节点的状况能够转化为后两种状况(找到待删除节点的后继节点y,将该节点的值放在x处,x处的颜色不变,注意这时候既没有破坏二叉搜索树的性质,也没有破坏红黑树关于节点颜色的性质,咱们只要接着删除节点y便可,而节点y最多只会有一个子节点。)
只有一个子节点时,用该子节点代替删除节点的位置(保留子节点本身的颜色和值),只有一个子节点时,直接删除便可。若是删除的节点是红色,那么就万事大吉了, 由于删除一个红色节点不会破坏红黑树关于节点颜色的性质,而上述全部的删除操做也不会破坏二叉搜索树的性质。删除该红色节点后仍是一个合法的红黑树。
若是删除的节点是一个黑色节点,那么就须要进行接下来的处理:
因为删除操做,某些路径上会少一个黑色节点。在此咱们假设,删除的节点为x,删除x后代替x位置的是节点y(当x没有子节点时,y就是是个null,然而算法导论里将全部unll节点称之为叶节点,并具备黑色颜色,这样处理确实方便了不少,这里和普通的树的定义不一样,注意)。
咱们假设y节点除了自己的颜色外,另外又携带有一个黑色颜色,这样咱们就将某些路径上少一个黑色节点的矛盾等价为某一节点具备两个颜色的矛盾。那么咱们如何处理这个拥有两个颜色的节点y呢?
<1.若是y的颜色为红+黑,那么直接去掉红色颜色,不破坏红黑树性质。
<2.若是y是根节点(那么颜色必定是黑+黑),那么直接去掉一个黑色,这时全部路径上的黑色节点都少了1,但都相等,也不破坏红黑树性质。
根据这两条性质,咱们须要处理的矛盾节点就是黑+黑色的(只要一碰到红+黑就用状况1处理,完成删除)
接下来开始分类讨论,这里咱们不妨假设节点y是其父节点的左节点(相反状况所有对称处理)。
状况1,y的兄弟节点b是红色,那么y的父节点和b的两个孩子都是黑色,这时对父节点作左旋操做并交换父亲节点和b的颜色,目的是让y的兄弟节点变为黑色(旋转后y的兄弟节点变成了b的左孩子,是黑色的)。
状况2,y的兄弟节点b是黑色,b的两个孩子都是黑色,这时咱们将y的兄弟节点b设置为红色,并将y携带的黑色传递给它的父亲节点。(对于b的两个孩子来讲,其父亲虽然变成了红色,可是其祖父节点额外多了一个黑色,所以路径上的黑色节点个数仍是不变。)这时其父亲节点自己的颜色不定,若是自己是红色的,那么用<1. 处理,万事,若是父亲仍是黑色的,那么仍是落入了如今讨论的这几种状况中,继续处理。
状况3,y的兄弟节点b是黑色,b的左孩子是红色,右孩子是黑色,y的父亲节点颜色不定,这时对b作右旋,并交换b和其左孩子的颜色。目的是将y的兄弟节点的右孩子变为红色。
状况4,y的兄弟节点b是黑色,b的右孩子是红色,左孩子颜色不定,y的父节点颜色不定,这时对y的父亲节点作左旋,并交换y和b的颜色。注意,对于y来讲,父亲节点到y的这条路径上会多一个黑色节点,咱们恰好用y携带的那个黑色抵消,对于b到其右孩子这条路径上会少一个黑色节点,咱们将b的右孩子由红色设置为黑色。完事,黑色被抵消掉了。
(关于父子的描述都是旋转以前的关系,这样更清楚一点。另外稍微分析一下旋转操做以后如何交换节点颜色会保持几个路径上的黑色节点数量不变,这一点应该不难)。算法
状况1在向状况3和4转变,状况2在向<1, <2和状况3和4转变,状况3在向状况4转变,而状况4条件下经过一次旋转能够抵消掉这个黑色。把握住这个核心逻辑。搜索