给出一个有n(n<=1000000)个数的数列a,请对该数列从小到大进行排序(数列a中所有数都是正整数,且不大于1000000)。
我们这次也使用洛谷作为评测工具(C++14 O2),对一些排序算法进行测试,测试数据分为子任务1和子任务2。
冒泡排序
冒泡排序是一种稳定的排序算法,这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
冒泡排序的最好情况(即数列已经有序)的时间复杂度为O(n),最坏情况和平均情况为O(n^2)。
代码如下:
[C++] 纯文本查看 复制代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[1000005];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[ i ]);
}
bool swapped = false; // 是否交换过
do {
swapped = false; // 初始化
for (int i = 1; i < n; i++) { // 注意这里的循环条件是i<n,因为是将第i个数和第i+1个数比较
if (a[ i ] > a[i + 1]) {
swap(a[ i ], a[i + 1]); // 如果第i个数大于第i+1个数,交换
swapped = true; // 标记为交换过
}
}
} while (swapped); // 交换过,则继续进行排序,否则退出(已经有序)
for (int i = 1; i <= n; i++) {
printf("%d ", a[ i ]);
}
return 0;
}
测试结果如下图所示:
选择排序
选择排序的时间复杂度为 O(n^2),排序过程如下:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
[C++] 纯文本查看 复制代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[1000005];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[ i ]);
}
for (int i = 1; i < n; i++) {
int minn = i; // 将最小数位置设为未排序数列中的第一个数的位置
for (int j = i + 1; j <= n; j++) { // i之前是排序数列,所以从i+1开始
if (a[j] < a[minn]) { // 如果第j个数比之前找到的最小数小
minn = j; // 则把最小数的位置设为第j个数的位置
}
}
swap(a[ i ], a[minn]); // 将最小数放到排序数列中的最后一个位置
}
for (int i = 1; i <= n; i++) {
printf("%d ", a[ i ]);
}
return 0;
}
测试结果(比冒泡排序快了很多):
插入排序
最好情况时间复杂度为 O(n),最坏情况和平均情况为 O(n^2)。
代码:
[C++] 纯文本查看 复制代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[1000005];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[ i ]);
}
for (int i = 2; i <= n; i++) {
int k = a[ i ]; // 确定待排序的数
for (int j = i - 1; j >= 1; j--) { // i之前是排序序列,所以从i-1开始倒着循环向前比较
if (a[j] > k) { // 如果第j个数大于待排序的数
a[j + 1] = a[j]; // 插入
a[j] = k;
}
else break; // 如果第j个数小于等于待排序的数,说明已经放到了正确的位置,不用再排序了
}
}
for (int i = 1; i <= n; i++) {
printf("%d ", a[ i ]);
}
return 0;
}
测试结果(比选择排序又更快了):
希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
代码:
[C++] 纯文本查看 复制代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int a[1000005];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[ i ]);
}
for (int gap = (1 + n) / 2; gap > 0; gap /= 2)
for (int i = gap; i <= n; i++)
for (int j = i - gap; j > 0 && a[j] > a[j + gap]; j -= gap)
swap(a[j], a[j + gap]);
for (int i = 1; i <= n; i++) {
printf("%d ", a[ i ]);
}
return 0;
}
测试结果(已经通过了Subtask #1):
|