快速排序
快速排序的思想是,先找一个基准(一般是最左边的数),然后把比这个数小的移动到它的左边,把比这个数大的移动到它的右边,然后继续对左子数组和右子数组进行同样的操作,直到某个子数组只有一个元素为止。
// 快速排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void quick_sort(int l, int r) {
if(l >= r) return ;
int tmp = a[l];
int i = l, j = r;
while(i != j) {
while(a[j] >= tmp && i < j) j--;
while(a[i] <= tmp && i < j) i++;
if(i < j) swap(a[i], a[j]);
}
swap(a[l], a[i]);
quick_sort(l, i - 1);
quick_sort(i + 1, r);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
quick_sort(1, n);
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
上面是一般做法,但是这样会出现一个问题,假设给定的数组已经是排好序的,而基准又是第一个元素,那么这些元素都会移动到右子数组中,而左子数组没有元素,这样的复杂度会是O(n^2)的,所以我们要随机选择基准。随机数函数rand(),头文件stdlib.h
// 快速排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void quick_sort(int l, int r) {
if(l >= r) return ;
int x = rand() % (r - l + 1) + l;
swap(a[x], a[l]);
int tmp = a[l];
int i = l, j = r;
while(i != j) {
while(a[j] >= tmp && i < j) j--;
while(a[i] <= tmp && i < j) i++;
if(i < j) swap(a[i], a[j]);
}
swap(a[l], a[i]);
quick_sort(l, i - 1);
quick_sort(i + 1, r);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
quick_sort(1, n);
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
插入排序
// 插入排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void insert_sort() {
for(int i = 2; i <= n; i++) {
int j, tmp = a[i];
for(j = i - 1; j >= 1; j--) {
if(a[j] <= a[i]) break;
}
for(int k = i; k > j + 1; k--)
a[k] = a[k - 1];
a[j + 1] = tmp;
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
insert_sort();
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
归并排序
先把数组分成两个数组,把子数组排好序,再把两个数组合并起来,对于子数组,执行同样的操作,直到某个子数组只有一个元素。对于合并操作,我们已经把子数组排好序了,那么就需要遍历两个子数组,比较两个子数组当前的元素,把小的放到前面。
// 归并排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], tmp[N];
void merge(int l, int r) {
if(l >= r) return ;
int mid = (l + r) >> 1;
merge(l, mid);
merge(mid + 1, r);
int pos = l;
int l1 = l, r1 = mid + 1;
while(l1 <= mid && r1 <= r) {
if(a[l1] <= a[r1]) {
tmp[pos++] = a[l1];
l1++;
} else {
tmp[pos++] = a[r1];
r1++;
}
}
while(l1 <= mid) {
tmp[pos++] = a[l1];
l1++;
}
while(r1 <= r) {
tmp[pos++] = a[r1];
r1++;
}
for(int i = l; i <= r; i++)
a[i] = tmp[i];
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
merge(1, n);
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
堆排序
先把给定的数组建立一个最大堆,然后交换第一个元素和最后一个元素,继续调整堆,执行n-1次就可以了。
// 堆排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N];
void down(int x, int num) { // 当前父节点,堆中可操作的节点数
int tmp = a[x];
while(1) {
int i = x * 2;
if(i > num) break;
if((i < num) && a[i] < a[i + 1]) i++;
if(tmp >= a[i]) break;
a[x] = a[i];
x = i;
}
a[x] = tmp;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = n / 2; i >= 1; i--) // 建立最大堆
down(i, n);
for(int i = n ; i > 1; i--) {
swap(a[i], a[1]);
down(1, i - 1);
}
for(int i = 1; i <= n; i++)
printf("%d%s", a[i], i == n ? "\n" : " ");
return 0;
}
桶排序
开一个num数组,某个数x每出现一次,那么就把num[x]++,最后按从小到大的顺序遍历,把出现过的数输出就可以了。但这只是简单的桶排序,适用于整数且范围较小的。
// 桶排序
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], num[N];
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
num[a[i]]++;
}
int cnt = 0;
for(int i = 0; i < N; i++) {
for(int j = 1; j <= num[i]; j++) {
if(cnt > 0) printf(" ");
printf("%d", i);
cnt++;
}
}
printf("\n");
return 0;
}