假设我想对大小为n的整数数组进行排序。假设我有交换方法
我的冒泡排序实施是否正确?
for(int i=0;i<n;i++)
for (int j=0;j<n;j++)
if (array[i]<array[j]) swap(array[i], array[j]);
(我只是想知道它是否正确,我不关心效率低下)
答案 0 :(得分:1)
降序排序不正确..
考虑array = [2, 1]
,输出[1, 2]
您可以通过将j=0
更改为j=i+1
for(int i=0;i<n;i++)
for (int j=i+1;j<n;j++)
if (array[i]<array[j]) swap(array[i], array[j]);
但升序排序 是正确的。
这里简单的证明:
假设在输出for循环的每个步骤后我们都有a[0] <= a[1] <= ... <= a[i-1] <= a[i]
,我们称之为 suppose_i
i = 0
时是正确的
如果 suppose_i 对于 0&lt; = i&lt; M <= N 。在i = M
时,我们有a[0] <= a[1] <= ... <= a[M - 2] <= a[M - 1]
。内循环j
从0到M后,我们得到a[0] <= a[1] <= ... <= a[M - 2] <= a[M - 1] <= a[M]
。当从M + 1到N-1继续内循环j
时,[M]将变得更大。所以 suppose_i 对i = M
也是正确的。
答案 1 :(得分:1)
是的,这是对的。证明可以按照以下方式构建。
总是当j-loop(内部)完成时(所以j = n,i将作为下一个op增加),则a [i]是max,而[i]之前的部分是按升序排列的(证明如下)。所以当外循环即将完成时i = n-1然后a [i]是max,并且直到索引i的项被排序(并且由于前面的项都没有大于max)所以整个数组订购。
为了证明在j循环之后a [i]总是最大是简单的:我在j循环中没有改变,如果j遇到大于a [i]的项目则将其带到[i]由于j扫描了整个数组,因此它不可能包含大于a [i]的元素。
要证明我订购的物品是完全归纳的。我们将使用上述关于[i]最大的声明 对于i = 0平凡(没有前面的元素)。 a [0]是最大值,“它是有序的” i = 1(只是为了好玩):1个项目到[0](不关心它的值,它不能大于最大值),a [1]是最大值。所以[0..1]排序。
现在,如果在i = k结束的j循环后满足这些论文,则会发生以下情况:
我&lt; - k + 1
假设当前项目a [i] = q。
j扫描[]到k。由于k是最大值,它将被交换到i。我之外的物品还没有被打扰。因此,基本上max会向上移动一个,所以一个项目,特别是q被添加到数组的第一部分。我们来看看如何:
排序到max的部分由j扫描,直到它在索引m处找到大于a [i]的项目。 (在最坏的情况下会找到[i-1]。)对m到m的项目进行排序。现在将在此处插入[i],范围[m..i-1]中的所有项目将向上移动一个。由于m是插入[i]的正确位置,因此在移动后将订购[0..i]。现在唯一要证明的是[m..i]中的j循环真的执行了一个移动:
在开始时,序列a [i],a [m..i-1]被排序,因此在该间隔中的每个比较将触发交换:a [i]总是a [j..i]中的最小值部分。交换(i与j)将使第j个位于正确的位置(最小项目位于前面)并且j步进到间隔的剩余部分。
所以j到达i = k + 1(这里没有交换)并且[k + 1]是最大值,所以在这个j循环中没有更多的交换,所以最后一个[0..k + 1]被排序。
所以最后如果论文保持i = k,那么它们在j循环后保持i = k + 1。我们已经建立了它们在1个j循环后保持i = 0,并且从i循环显示总共将有n个j循环因此这些论文适用于i = n-1这正是我们所承诺的在第一段证明。