初始化:在循环的第一次迭代之前,我们从一颗正常的红黑树开始,并新增了一个红色结点z。
这样在调用RB-INSERT-FIXUP之前,有:
a)z是红色结点。
b)如果p[z]是根,则p[z]是黑色。
c)红黑树的性质1)、3)和5)都成立。
但性质2)和4)有可能被违反,但不会同时被违反。
如果性质2)被违反,说明红色的根结点必然是新增的结点z,它是树中唯一的内结点。由于z的父结点和两个子结点都是黑色的哨兵(nil[T]),没有违反性质4)。所以,这种情况下,只违反性质2)
如果性质4)被违反,则由于z的子女是黑色的哨兵,并且这棵树在z新增之前,没有其他性质被违反,所以只可能是z和p[z]都是红结点,因为z不是根结点,因此性质2)一定满足。
保持:在while循环中需要考虑6种情况,但后面3种与前面3种是对称的,所以只讨论前面3种情况:
循环不变式的目标有两个:
(1)保证每一次循环后,性质1)、3)、5)不被违反;
(2)修正对性质4)的违反(当退出循环时,性质4)的违反应该已经被修正)。
在讨论3种情况之前,我们考虑一下在初始化步骤,性质2)被违反的情况,这时,z是红色的根结点,此时其父结点是黑色的哨兵(nil[T]),因此直接退出循环,进入循环终止步骤。这种情况下,显然在退出循环时,循环不变式保持了性质1)、3)和5)。并且性质4)也没有被违反,唯一违反的是性质2)。
情况1):z的叔叔y是红色的
上图,对于情况(a),z是其父结点的右子结点;对于情况(b),z是其父结点的左子结点。
从图中可以看出,在执行第5到第8行之后,性质1)和3)显然被保持,在修改父结点和叔父结点以及祖父结点后,从C出发的黒结点的高度没有变化,性质5)也是被保持。
此外,对于z,因为其父结点被设置为黑色,原来对性质4)的违反得以消除,但因为祖父结点被设置为红色,祖父结点和其父结点是有可能违反性质4)的,在程序的第8行,将新z设置为原来z的祖父节点,该新z的是红色的。
这样在下一轮循环开始之前,有:
a)z是红色结点。
b)如果p[z]是根,则p[z]是黑色。
c)红黑树的性质1)、3)和5)都成立。
但性质2)和4)有可能被违反,但不会同时被违反。
如果性质2)被违反,说明红色的根结点必然是新z结点。由于z的父结点和两个子结点都是黑色结点,没有违反性质4)。所以,这种情况下,只违反性质2)。
如果性质4)被违反,则由于新z的子女是黑色的结点,并且旧的z对性质4)的违反已经被修正,所以,只可能是新z和p[新z]都是红结点,因为新z不是根结点,因此性质2)一定满足。
这样我们就证明了,对于情况1)循环不变式的成立。
情况2):z的叔叔y是黑色的,而且z是右孩子
情况3):z的叔叔y是黑色的,而且z是左孩子
如上图,对于情况2),经过左旋后,转换成情况3),对于情况3),修改p[z]和p[p[z]的颜色后,进行了右旋,使得最终p[z]颜色是黑色。
下面来证明对于这两种情况下循环不变式的保持:
首先对于性质1)和3)显然保持,对于性质5),从图中可以看出,经过B结点的路径上的黑色结点个数没有变化,因此也是保持的。
这样在下一轮循环开始之前,有:
a)z是红色结点。
b)p[z]是黑色。
c)红黑树的性质1)、3)和5)都成立。
此时对性质4)的违反被修正,因为B取代了C的位置,且颜色都是黑色,不会违反性质4)。
此时性质2)也不会被违反,因为如果p[z]是根,那么因为p[z]是黑色结点,显然满足性质2),如果p[z]不是根结点,那么因为在进入这次循环之前不被违反,因而也不会被违反。
因此红黑树的五个性质全部满足,这样我们就证明了,对于情况2)和3)循环不变式的成立。并且,因为p[z]是黑色,因此当执行完情况3),循环一定终止。
终止:循环结束是因为p[z]是黑色的。(如果z是根,p[z]是黑哨兵nil[T]。)所以,在循环结束时,性质4)是满足的。根据循环不变式,性质1)、3)和5)应该保持,所以唯一可能违反的性质是性质2)。第16行将确保性质2)成立,并且这一操作不会破坏其他红黑树的性质,因此当调用RB-INSERT-FIXUP结束时,所有红黑树的性质都成立。