为了证明程序不会出现溢出错误,我们在不变式中添加条件 0 <= l <= n 和 -1 <= u <=n,这样我们就可以限定 l+u 的范围了。这两个条件还可以用于证明不会访问数组边界之外的元素。如果像书中 9.3 节一样定义假想的边界元素 x[-1] 和 x[n],那么我们就能将 mustbe(l,u)形式化地定义为 x[l-1] 和 x[u+1]>t。
l = -1; u = n
while l+1 != u
m = (l + u) / 2
if x[m] < t
l = m
else
u = m
p = u
if p >= n || x[p] != t
p = -1
如果 t 在 x 中,那么将 p 置为 t 第一次出现的下标;如果 t 不在数组中,则将 p 置为 -1。
while x != 1 do
if even(x)
x = x / 2
else
x = 3 * x + 1
如果你解决了这个问题,请到最靠近的数学系申请一个博士学位。
由于每一步都使得罐中的豆子减少一粒,所以该过程能够终止。我们每一步都从咖啡罐中拿掉零个或者两个白色豆子,所以白色豆子的奇偶性保持不变。因此,当且仅当罐中最初的白色豆子个数为奇数时,最后留下的豆子才可能是白色的。
构成梯级的线段在 y 方向上是递增的,因此我们可以通过二分搜索来找到包含给定点的两条线段。搜索中的基本比较说明了点在给定线段的下方、里面还是上方。应如何编写该函数?
i = 512
l = -1
if x[511] < t
l = 1000 - 512
while i != 1
i = i / 2
if x[l+i] < t
l = l + i
p = l + i
if p > 1000 || x[p] != t
p = -1
程序代码将确保 i 总是 2 的幂。该性质很容易保持,但是一开始难以获得(因为数组的大小 n 等于 1 000)。因此在程序的开始部分先使用了赋值语句和 if 语句,以确保初始的搜索范围大小为 512,即小于 1 000 的数中最大的 2 的幂。这样 l 和 l+1 一起要么表示 -1…511,要么表示488…1 000。使用这个新的范围表示方法转换初始的二分搜索程序。
因为 i 在程序中只有 10 个互不相同的值,所以我们可以将它们全部写在代码中,从而避免在运行时重复计算。代码如下:
l = -1
if (x[511] < t) l = 1000 - 512
if (x[l+256] < t) l += 256
if (x[l+128] < t) l += 128
if (x[l+64] < t) l += 64
if (x[l+32] < t) l += 32
if (x[l+16] < t) l += 16
if (x[l+8] < t) l += 8
if (x[l+4] < t) l += 4
if (x[l+2] < t) l += 2
if (x[l+1] < t) l += 1
p = l + 1
if p > 1000 || x[p] != t
p = -1
i = 0
while i < n
a[i] = b[i] + c[i]
i = i + 1
max = x[0]
i = 1
while i < n do
if x[i] > max
max = x[i]
i = i + 1
i = 0
while i < n && x[i] != t
i = i + 1
if i >= n
p = -1
else
p = i
function exp(x, n)
pre n >= 0
post result = x ^ n
if n = 0
return 1
else if even(n)
return square(exp(x, n/2))
else
return x * exp(x, n-1)
int binarysearch(DataType x[], int n)
单独使用该函数,不要调用其他任何递归函数。参考答案 11.14中把数组指针传递给 swap 函数的递归函数。