// sorts the items from L[i] through L[j]
void threewaysort(int[] L, int i, int j) {
if (L[i] > L[j]) swap (i, j);
if (j - i + 1 > 2) {
t = (j - i + 1) / 3;
threewaysort(L, i, j - t);
threewaysort(L, i + t, j);
threewaysort(L, i, j - t);
}
}
上面的代码将列表 L 从最小到最大排序。为了证明这种算法是正确的,我认为我们可以使用归纳法吗?提示是,呼叫threewaysort(L, 0, L.length-1)
实际上具有使 L 排序的副作用。
但是我目前仍处于归纳证明的步骤中。
答案 0 :(得分:3)
您确实可以使用归纳法。让我们使用符号 L i,j 表示从 L [i] 到 L [j] < / em>。
此归纳证明有两种基本情况:
j-i + 1 = 1
这意味着 L i,j 中只有一个元素,因此已经对其进行了排序。 if
的条件都不成立,因此什么也没发生:调用threewaysort(L, i, j)
后对 L i,j 进行排序。
j-i + 1 = 2
L i,j 中有两个元素。如果尚未排序,则第一个if
条件为true,并且对swap
的调用将有效地对 L i,j 进行排序。第二个if
条件为false。因此,在调用threewaysort(L, i, j)
我们得出了 j-i + 1> 2
的情况 L i,j 中现在至少包含3个元素。通过归纳证明,我们假设threewaysort
对于较小的子数组正常工作。
我们暂时忽略可能执行swap
的操作,而只关注第二个if
的正文,将执行 :
t 确保大于零。
进行了三个递归调用:在子数组 L i,jt ,L i + t,j 上,再在 L i,jt 。
让我们定义:
A = L i,i + t-1
B = L i + t,j-t
C = L j-t + 1,j
这些是 L i,j 的不重叠相邻范围。 A 和 C 的大小均为 t 。 B 的大小至少为 t (可以是 t , t +1或 t +2)。 我们还定义加号表示两个子数组的并集。因此, L i,j = A + B + C ,然后递归调用实际上对 A + B 进行排序, B + C ,然后再次 A + B 。
由于 t 严格为正,所以 A + B 和 B + C 是比 A + B + C < / em>,因此我们可以假设这些递归调用成功地对相应的子数组进行了排序(归纳前提)。
让我们看看在 A + B + C 中 t 最大值发生了什么。那些不在 C 中的变量将在第一次递归调用后以 B 结尾(回想一下 B 的大小至少为 t )。因此,我们可以确定 t 的最大值都在 B + C 中。因此,在第二次递归调用之后,我们可以确保所有 t 最大值只能在 C 中找到。
类似的事情发生在 A + B + C 中的 t 最小值。在第一次递归调用之后,它们都不能再位于 B 中,但这并没有帮助。在第二次递归调用之后,它们都不再位于 C 中。在第三次递归调用之后,它们都不可以在 B 中,因此它们都在 A 中。
总结一下,我们明白了:
这意味着 A + B + C 已排序。
这通过归纳完成了证明。
证明还表明,当数组的大小不同于2时,交换是可选的。因此,代码甚至是正确的:
void threewaysort(int[] L, int i, int j) {
if (j - i + 1 > 2) {
t = (j - i + 1) / 3;
threewaysort(L, i, j - t);
threewaysort(L, i + t, j);
threewaysort(L, i, j - t);
} else if (L[i] > L[j]) {
swap(L, i, j);
}
}
但是,按照原始代码中的描述进行交换平均会导致交换次数减少(但比较会更多)。
首先,我们注意到除递归调用外,所有其他语句均在恒定时间内执行。
第二,递归调用是在数组上进行的,数组的大小大约小三分之一。
因此,对于 n = j-i + 1 ,重复关系为:
f(n)= 3·f((2/3)n)
f(2)= f(1)= 1
如果扩大重复率,则会得到:
f(n)= 3 2 ·f((2/3) 2 n)= ... = 3 k ·f((2/3) k n)
当选择 k 使得(2/3) k n = 2 (或1)时,我们知道 f((2/3) k n)= 1 ,该因子可以从表达式中省略:
f(n)= 3 k
现在我们必须根据 n 解析 k :
(2/3) k n = 2
k = log 3/2 (n / 2)
k = log 3 (n / 2)/ log 3 (3/2)
k = 2.7 log 3 (n / 2)
所以,现在我们有了:
f(n)= 3 k
f(n)=(3 log 3 (n / 2)) 2.7
f(n)=(n / 2) 2.7
将时间复杂度设置为大约:
f(n)= O(n 2.7 )
...效率很低的排序算法;比气泡排序效率低。