Algorithm 如何证明递归算法的正确性 //对从L[i]到L[j]的项目进行排序 无效三向排序(int[]L,int i,int j){ 如果(L[i]>L[j])交换(i,j); 如果(j-i+1>2){ t=(j-i+1)/3; 三向排序(L,i,j-t); 三向排序(L,i+t,j); 三向排序(L,i,j-t); } }
上面的代码将列表L从最小到最大排序。为了证明这个算法是正确的,我想我们可以用归纳法吗?提示是,调用Algorithm 如何证明递归算法的正确性 //对从L[i]到L[j]的项目进行排序 无效三向排序(int[]L,int i,int j){ 如果(L[i]>L[j])交换(i,j); 如果(j-i+1>2){ t=(j-i+1)/3; 三向排序(L,i,j-t); 三向排序(L,i+t,j); 三向排序(L,i,j-t); } },algorithm,Algorithm,上面的代码将列表L从最小到最大排序。为了证明这个算法是正确的,我想我们可以用归纳法吗?提示是,调用threewaysort(L,0,L.length-1)实际上有使L排序的副作用 但我目前正陷于归纳法证明的步骤中。你确实可以使用归纳法。让我们使用符号Li,j来表示子数组,其中包含从L[i]到L[j]的项 基本情况 此归纳证明有两种基本情况: j-i+1=1 这意味着Li,j中只有一个元素,因此它已经被排序了。如果条件为true,则两者都不,因此不会发生任何事情:Li,j在调用threewayso
threewaysort(L,0,L.length-1)
实际上有使L排序的副作用
但我目前正陷于归纳法证明的步骤中。你确实可以使用归纳法。让我们使用符号Li,j来表示子数组,其中包含从L[i]到L[j]的项 基本情况 此归纳证明有两种基本情况:
,因此不会发生任何事情:Li,j在调用threewaysort(L,i,j)
后进行排序
If
条件为true,对swap
的调用将有效地对Li,j进行排序。如果条件为false,则第二个。所以Li,j在调用threewaysort(L,i,j)
threewaysort
对于较小的子阵列正确工作
我们暂时忽略可能执行的交换
,只关注第二个的主体(如果
),该主体将被执行:
t保证大于零
进行了三个递归调用:子数组Li,j-t,Li+t,j,以及Li,j-t
让我们定义一下:
A=Li,i+t-1B=Li+t,j-t
C=Lj-t+1,j 这些是Li,j的非重叠相邻范围。A和C的尺寸都是t。B的大小至少为t(可以是t、t+1或t+2)。 让我们定义加号来表示两个子数组的并集。然后Li,j=A+B+C,递归调用实际上是对A+B,B+C进行排序,然后再对A+B进行排序 由于t是严格正的,A+B和B+C比A+B+C小,因此我们可以假设这些递归调用成功地对相应的子数组进行排序(归纳前提) 让我们看看A+B+C中的t最大值会发生什么情况。在第一次递归调用后,不在C中的值将最终在B中(回想一下,B的大小至少是t)。因此,我们确定t最大值都在B+C中。在第二次递归调用之后,我们可以确定所有这些t最大值都只能在C中找到 A+B+C中的t最小值也会发生类似的情况。在第一次递归调用之后,它们中的任何一个都不能再位于B中,但这并没有真正的帮助。在第二次递归调用之后,它们中的任何一个都不能再使用C语言了。在第三次递归调用之后,它们都不能在B中,因此它们都在A中 总结一下,我们得到:
- A被排序(因为在最后一次递归调用之后A+B被排序)
- B已排序(相同原因)
- C已排序(因为在第二次递归调用之后,B+C已排序,而在第三次调用期间未触及C)
- A具有来自A+B+C的最小值
- C具有A+B+C中的最大值
- B具有来自A+B+C的剩余值
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)=32·f((2/3)2n)=3k·f((2/3)kn) 当k的选择使得(2/3)kn=2(或1)时,我们知道f((2/3)kn)=1,并且该系数可以从表达式中省略: f(n)=3k 现在我们必须用n来解析k: (2/3)kn=2
k=log3/2(n/2)
k=log3(n/2)/log3(3/2)
k=2.7log3(n/2) 因此,现在我们有: f(n)=3k
f(n)=(3log3(n/2))2.7
f(n)=(n/2)2.7 将时间复杂度设置为: f(n)=O(n2.7)
。。。相当低效的排序算法;效率低于气泡排序。您确实可以使用归纳法。让我们使用符号Li,j来表示子数组,其中包含从L[i]到L[j]的项 基本情况 此归纳证明有两种基本情况:
,因此不会发生任何事情:Li,j在调用threewaysort(L,i,j)
后进行排序
If
条件为true,对swap
的调用将有效地对Li,j进行排序。如果条件为false,则第二个。所以Li,j在调用threewaysort(L,i,j)