不要为冒泡排序感到羞耻,它有它的位置。如果您的数据集较小,则很容易编写代码,并且如果操作正确(永远不要交换相等的元素),则很稳定。
如果您的数据大部分是通过在每次传递时交替方向进行排序的,它也可能会非常快。我知道你说它最初不是接近排序的,我说的是如果你排序然后坚持下去,它变成这样的可能性。在任何一种情况下,如果数据集的大小很小,那么它是否完全未排序并不重要。
尤其是如果,正如您在对另一个答案的评论中提到的那样,您的数据集大小约为 11。缺少明确的排序算法设计是故意可怕的,任何算法都可以轻松地足够快地处理这样的大小。
如果您的环境不提供稳定的排序,考虑到您的约束和属性,我会选择冒泡排序。
事实上,使用以下程序和time 实用程序,我发现用于qsort 和冒泡排序的CPU 时间只有在元素计数达到10,000 时才会开始产生影响。
即便如此,冒泡排序也只用了不到半秒。除非你每秒要进行很多次排序,否则这无关紧要。
#include <stdio.h>
#include <stdlib.h>
static int data[10000];
#define SZDATA (sizeof (*data))
#define NMDATA (sizeof (data) / sizeof (*data))
int compfn (const void *a, const void *b) {
if (*((int*)a) > *((int*)b))
return 1;
if (*((int*)a) < *((int*)b))
return -1;
return 0;
}
int main (void) {
int i, tmp, swapped, count;
for (i = 0; i < NMDATA; i++)
data[i] = (i * 3) % 11;
if (0) {
qsort (data, NMDATA, SZDATA, compfn);
} else {
swapped = 1;
count = NMDATA;
while (swapped) {
swapped = 0;
for (i = 1; i < count; i++) {
if (data[i] < data[i-1]) {
tmp = data[i];
data[i] = data[i-1];
data[i-1] = tmp;
swapped = 1;
}
}
count --;
}
}
//for (i = 0; i < NMDATA; i++)
//printf ("%10d\n", data[i]);
return 0;
}
通过改变data 数组和if (0) 语句的大小,我得到了以下结果(以毫秒为单位),每种情况运行五次:
Data size | qsort | bubble
----------+-------+-------
100 | 61 | 76
| 76 | 76
| 77 | 61
| 61 | 60
| 61 | 61 avg qsort = 67, bubble = 67
1000 | 77 | 93
| 61 | 45
| 76 | 77
| 77 | 76
| 76 | 77 avg qsort = 73, bubble = 74
| |
10000 | 92 | 414
| 77 | 413
| 61 | 413
| 76 | 405
| 61 | 421 avg qsort = 73, bubble = 413
我怀疑使用小数据集的快速冒泡排序之所以如此,是因为缺少函数调用。
要摆脱这一点的是,对于较小的数据集,算法的效率通常并不重要,因为像 big-O 这样的东西通常会随着数据集变大而相关。
但是,此测试是在 my 环境中完成的,您的环境可能会有很大差异。我建议在您的环境中执行相同的测量 - 实施冒泡排序,并且仅在必要时才考虑使用更复杂的算法。
根据评论者的建议,我使用srand(42) 重新运行测试,然后使用rand() 填充数组元素。在这种情况下,冒泡排序的结果仅略差一点,10,000 个元素的 642 对 413 毫秒和 1,000 个元素的 82 对 74 毫秒。
考虑到问题中的限制(元素数量少、排序不频繁、稳定性要求、空间复杂度低),我仍然更喜欢冒泡排序的简单性,而不是任何更复杂的算法。
不过,请记住我之前的建议:您需要在自己的自己的环境中计时。结果可能大不相同。您可以使用我提供的代码作为基线。说真的,如果您选择的任何方法都花费不到一秒钟的时间,那么对于您的目的来说,它可能已经绰绰有余了。