(Hoare划分的正确性)本章中的PARTITION算法并不是其最初的版本。下面给出的是最早由C. R. Hoare所设计的划分算法:
a. 试说明HOARE-PARTITION在数组A = {13, 19, 9, 5, 12, 8, 7, 4, 11, 2, 6, 21}上的操作过程,并说明在每一次执行第4~14行while循环时数组元素的值和辅助变量的值。
后续的三个问题要求读者仔细论证HOARE-PARTITION的正确性。在这里假设子数组至少包含2个元素,试证明下列问题:
b. 下标和可以使我们不会访问在子数组以外的数组的元素。
c. 当HOARE-PARTITION结束时,它返回的值满足。
d. 当HOARE-PARTITION结束时,中的每一个元素都小于或等于中的元素。
在7.1节的PARTITION过程中,主元(原来存储在中)是与它所划分的两个分区分离的。与之对应,在HOARE-PARTITION中,主元(原来存储在中)是存在于分区或中的。因为有,所以这一划分总是非平凡的。
e. 利用HOARE-PARTITION,重写QUICKSORT算法。
解
a.
b.
虽然下标和分别被初始化为和,但是在第一轮while迭代中,会被先加1,而会被先减1,这样下标和分别从和开始。所以在迭代开始,下标和没有超出数组范围。
由于以首个元素作为划分主元,所以在第一轮while迭代中,会停留在,而会一直向左移动,直到遇到一个小于或等于的元素。下面分两种情况说明:
1) 如果在向左移动的过程中一直没有遇到小于或等于的元素,那么会一直向左移动直到为止,因为满足的停止条件。此时,由于一直停留在的位置,所以,故while迭代退出。在这个过程中,和都没有超出数组的范围。
2) 如果遇到了一个小于或等于的元素 (该元素不为),那么与 (即) 交换。这说明在下标的左侧至少有一个小于或等于的元素,并且在下标的右侧至少有一个大于或等于的元素,这可保证和在移动过程中不会超出数组范围。
c.
在第一轮while迭代中,下标一定会停留在,而下标分2种情况:
1) 如果在位置停留下来了,此时有 (因为已经假设数组元素不少于2个),那么交换和,继续进行第二轮while迭代。在第二轮while迭代中,一定至少向左移动一个位置,故一定有。
2) 如果没有在位置停留,而是继续向左移动,此时也有。
再根据b的结论,不会超出数组范围,故。所以一定满足。
d.
先给出循环不变式:在每轮while迭代开始之前,中的元素都小于或等于,并且中的元素都大于或等于。这个循环不变式应该不难证明,这里省略证明过程。
下面分析while迭代的终结时的情况。在while迭代中,代码第5 ~ 7行的repeat迭代和第8~10行的repeat迭代结束时,必然有中的元素都小于或等于中的元素。在最后一次while迭代中,repeat迭代结束后,必然有或。如果,那么必然有,由于中的元素都小于或等于中的元素,将加入,于是有 (即) 中的元素都小于或等于中的元素。如果,那么,于是有中的元素都小于或等于中的元素。
e.
代码链接:https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter07/Problem_7-1