我需要设计一种算法,该算法将对仅包含数字-1,0,1的数组进行排序,而不使用任何临时变量或数组,并且仅使用交换,所以我想出了以下方法:如果是O(n)。
#include <stdio.h>
#define MAXSIZE 10
int main()
{
int array[MAXSIZE];
int i, j, num = 8, temp;
int list[] = {-1,0,-1,0,1,1,0,1};
int size = sizeof(list)/sizeof(list[0]);
for (int i = 1; i < size; i++) {
if (list[i] < list[i - 1]) {
list[i] = list[i] + list[i - 1];
list[i - 1] = list[i] - list[i - 1];
list[i] = list[i] - list[i - 1];
i = 0;
}
}
printf("Sorted array is...\n");
for (int i = 0; i < size; i++)
{
printf("%d\n", list[i]);
}
}
答案 0 :(得分:5)
该算法绝对不是O(n)。
进行交换时,您正在将i
设置为0
。最坏的情况是O(n ^ 2)。
答案 1 :(得分:1)
@RSahu正确说明了算法的原因是,您将计数器重置为0,这意味着您最多可以进行1+2+...+n
次迭代。
这是一个展示线性时间来处理数组的小例子:
#include <iostream>
#include <array>
using namespace std;
int main() {
array<int,10> A{-1, 0, -1, 0, 1, 1, 0, 1, 0, -1};
int i=0,j=0, k=9;
while(j!=k) {
if(A[j] == 0) {
++j;
}
else if(A[j] == -1) {
swap(A[i], A[j]);
++i; ++j;
}
else {
swap(A[j], A[k]);
--k;
}
}
for(auto ai : A)
cout << ai << " ";
cout << endl;
}
您可以在线观看there。
它如何工作?我们维护三个计数器i
,j
和k
,它们的不变量为:
[0, i)
是-1
[i, j)
是0
(k, n-1)
是+1
[
表示包含范围,而)
或(
表示包含范围。
最初
i=j=0
和'k = n-1`。不变式受到尊重。
第一种情况
if(A[j] == 0) {
++j;
}
A[j]
的值为0,因此我们可以递增j
,并且不变式仍然成立。
第二种情况
else if(A[j] == -1) {
swap(A[i], A[j]);
++i; ++j;
}
由于i
是排他性约束,因此我们要向-1
的先前范围添加-1
,并且需要增加i
。如果范围[i, j)
不为空,则0
已复制到位置j
,我们必须递增j
。如果范围为空,则我们有i==j
,并且随着我们增加i
,我们还必须增加j
来保持不变。我们可以得出结论,在此步骤之后,不变式仍然成立。
第三种情况
else {
swap(A[j], A[k]);
--k;
}
A[j]
是0
,我们可以将其交换为A[k]
的值并递减k
,不变式将成立。
终止和正确性
最后一点是证明程序将终止。每个步骤之一:
-递增j
-递减k
因此,j
和k
之间的距离每步将减少1。
j
和k
之间的距离最初为n-1
,并且每步减小一。因此最多将有n-1
个步骤。每个步骤执行一次交换。最多会有n-1
个交换。
程序结束时,不变式将保持不变:
0
到i
排除,所有-1
i
到j==k
排除,所有0
j==k
到n-1
排除,所有+1