2021年7月25日星期日

Hoare Partition正确性证明

先上伪代码

HOARE-PARTITION(A, p, r)
    x = A[any number in p..r]
    i = p - 1
    j = r + 1
    while true
        repeat
            j = j - 1
        until A[j] ≤ x
        repeat
            i = i + 1
        until A[i] ≥ x
        if i < j
            exchange A[i] with A[j]
        else return j 

提醒

与Lomuto Partition不同,在Hoare Partition中,pivot元素是包含在分出的两个区中的。

Hoare Partition的作用效果是:给定一个pivot元素,将数组分为两个区域,其中一个区域的值总是不大于另一区域的值。这个算法不能保证pivot元素位于何处。

正确性证明

约定

  1. p小于等于r
  2. 分出的两个区中可能有一个是空的
  3. a..b表示从a到b,inclusive;a>b则代表空集,其中一切性质成立

首先是几个循环不变式

1)在整个循环中我们不会进行A[i]操作,其中i<p;也不会进行A[j]操作,其中j>r

初始化:进入while循环前i=p-1,j=p+1,在第一次A[i]和A[j]前i=p,j=r,所以A[i]操作访问A[p],A[j]操作访问A[r]。

保持:i随循环递增,j随循环递减,所以A[i]操作不可能访问p之前的元素,A[j]操作不可能访问r之后的元素。

2)在整个循环中我们不会进行A[i]操作,其中i>r;也不会进行A[j]操作,其中j<p

初始化同1。

保持:只需证“在整个循环中A[i..r]总包含不小于x的元素,在整个循环中A[p..j]总包含不大于x的元素”。以下证明前者,后者请读者自证。

2.1)在整个循环中A[i..r]总包含不小于x的元素

初始化显然(x是A中的一个元素)。

保持:当i和j停下(由初始化可知必至少停一次)且i<j时,此时A[i]与A[j]交换,不小于x的A[i]被交换到后方,从而维持了循环不变式。

终止:当i和j停下且i不小于j时,循环结束。

3)在整个循环中A[p..i]不大于x,A[j..r]不小于x

读者自证不难。

证明正文

由(1)和(2)知i,j总在p..r内。

由(3)知每次i<j的迭代中A[p..i]中的任意元素小于或等于A[j..r]中的任意元素。

在最后一次迭代中,A[p..i]中除A[i]外的任意元素小于或等于A[j..r]中除A[j]外的任意元素。

而此时i不小于j,则:

当i=j时,易得A[i]=A[j]=x(由i和j移动的终止条件直接可得),则A[p..i]中的任意元素小于或等于A[j..r]中的任意元素,则A[p..j]中的任意元素小于或等于A[j+1..r]中的任意元素。

当i>j时,A[p..j]中的任意元素(显然,不包含A[i])小于或等于A[j+1..r]中的任意元素(显然,也不包含A[j])。

参考文章

没有评论:

发表评论