3.1.18

3.1.18 #

解答 #

设 key 为目标键。

算法初始时 lo = 0, hi = n - 1,数组已排序。

当找到目标键时,返回的下标 mid 显然是正确的。 (0…a[mid - 1] 都小于 a[mid],同时 a[mid] = key)

接下来证明:当目标键不存在时,lo 可以代表小于 key 的键的个数。

由算法内容,当循环退出时,一定有 lo 和 hi 交叉,即 lo > hi。

考虑最后一次循环,必然执行了 lo = mid + 1 或者 hi = mid - 1。

即最后一次循环之后 lo = mid + 1 > hi 或 hi = mid - 1 < lo。

又由于 mid = (lo + hi) / 2,代入有:

即(lo + hi) / 2 + 1 > hi 或(lo + hi) / 2 - 1 < lo

(lo - hi) / 2 + 1 > 0 或(hi - lo) / 2 - 1 < 0

(hi - lo) / 2 < 1

hi - lo < 2

由于 hi 和 lo 都是整数,故有 hi -lo <= 1

由算法的内容可以得出,最后一次循环时,

下标小于 lo 的元素都小于 key,下标大于 hi 的元素都大于 key

且下标小于 lo 的元素正好有 lo 个 (0…lo - 1)。

当 lo = hi 时,mid = lo

若 key > lo,则 lo = lo + 1,即 a[lo] 本身也小于 key。

若 key<lo,lo 不变,即 a[lo] 就是大于 key 的第一个元素。

当 lo = hi - 1 时,mid = lo

若 key > lo,则 lo = lo + 1 = hi,变为上一种情况。

若 key<lo,则 hi = lo - 1,a[lo] 是大于 key 的第一个元素。

综上,Rank() 是正确的。