前言
比较排序和非比较排序模板。
以下均不涉及排序原理, 纯粹就是代码。 代码非常简洁。
以下均是
C++代码(更偏向C)
实现,
看不懂怎么办? 复制代码给ChatGPT解读即可, 堆排序需要补数据结构堆的知识。
比较排序:冒泡排序,选择排序,插入排序,希尔排序,堆排序,归并排序,快速排序。
非比较排序:计数排序,基数排序,桶排序。
本篇目前更新比较排序模板。
测试链接:排序
冒泡排序
时间复杂度: O ( n 2 ) O(n^2) O(n2)。 不推荐使用。
#include<bits/stdc++.h>
using namespace std;
//测试链接:https://www.luogu.com.cn/problem/P1177
const int N = 1e6+10;//1e4数据量可以使用,>1e5会超时。
int q[N],n;
void bubbleSort(int *q,int n){
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1-i;j++){
if(q[j+1]<q[j]){
swap(q[j+1], q[j]);
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",q+i);
}
bubbleSort(q,n);
for(int i=0;i<n-1;++i){
printf("%d ",q[i]);
}
printf("%d\n",q[n-1]);
return 0;
}
选择排序
时间复杂度: O ( n 2 ) O(n^2) O(n2)。 不推荐使用。
#include<bits/stdc++.h>
using namespace std;
//测试链接:https://www.luogu.com.cn/problem/P1177
const int N = 1e6+10;
int q[N],n;
void selectionSort(int *q,int n){
int min_idx = 0;
for(int i=0;i<n-1;i++){
min_idx = i;
for(int j=i+1;j<n;++j){
if(q[j]<q[min_idx]) min_idx = j;
}
std::swap(q[min_idx],q[i]);
}
}
int main(){
scanf("%d", &n);
for(int i=0;i<n;i++){
scanf("%d", q+i);
}
selectionSort(q,n);
for(int i=0;i<n-1;++i){
printf("%d ",q[i]);
}
printf("%d\n",q[n-1]);
return 0;
}
插入排序
时间复杂度: O ( n 2 ) O(n^2) O(n2), 小数据量或者接近有序非常好用。
#include<bits/stdc++.h>
using namespace std;
//测试链接:https://www.luogu.com.cn/problem/P1177
const int N = 1e6+10;
int q[N], n;
void insertionSort(int *q,int n){
for(int i=1,j;i<n;i++){
j = i - 1;
int tmp = q[i];
while(j>=0&&q[j]>tmp){
q[j+1] = q[j];
j--;
}
q[j+1]=tmp;
}
}
int main(){
scanf("%d", &n);
for(int i=0;i<n;i++){
scanf("%d", q+i);
}
insertionSort(q,n);
for(int i=0;i<n-1;i++){
printf("%d ",q[i]);
}
printf("%d\n",q[n-1]);
return 0;
}
希尔排序
时间复杂度:平均
O
(
n
1.3
)
−
O
(
n
1.5
)
O(n^{1.3}) - O(n^{1.5})
O(n1.3)−O(n1.5), 最坏
O
(
n
2
)
O(n^2)
O(n2), 能通过测试。
时间复杂度取决于步长序列, 有多种选择方式可以自行了解一下。
优点是好写,运用插入排序的思想和步长序列。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int q[N],n;
void shellSort(int *q, int n) {
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int temp = q[i];
int j = i - gap;
while (j >= 0 && q[j] > temp) {
q[j+gap] = q[j];
j -= gap;
}
q[j+gap] = temp;
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=0;i<n;i++){
cin>>q[i];
}
shellSort(q,n);
for(int i=0;i<n-1;i++){
cout<<q[i]<<" ";
}
cout<<q[n-1]<<'\n';
return 0;
}
堆排序
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
优点:堆排序稳定,平均,最差,最好都是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn), 数组可以模拟堆, 原地排序。
不依赖数据。
缺点: 同等复杂度常数时间不如快速排序, 需要掌握数据结构堆的知识, 实现比较复杂(容易写错)。
#include<bits/stdc++.h>
using namespace std;
//测试链接:https://www.luogu.com.cn/problem/P1177
const int N = 1e6+10;
int q[N],n;
void heapify(int *q,int size,int i){
int l=i*2+1;
while(l<size){
int best = l+1<size&&q[l+1]>q[l]?l+1:l;
best = q[best]>q[i]?best:i;
if(best==i) return ;
std::swap(q[i],q[best]);
i = best;
l = i*2+1;
}
}
int main(){
scanf("%d", &n);
for(int i=0;i<n;i++){
scanf("%d", &q[i]);
}
for(int i=(n-1)>>1;i>=0;i--){
heapify(q,n,i);
}
int size = n;
while(size>0){
swap(q[0],q[--size]);
heapify(q,size,0);
}
for(int i=0;i<n-1;i++){
printf("%d ",q[i]);
}
printf("%d\n",q[n-1]);
return 0;
}
归并排序
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
优点:归并排序具有稳定性, 时间复杂度严格控制在
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
缺点:需要辅助数组。
#include<bits/stdc++.h>
using namespace std;
//测试链接:https://luogu.com.cn/problem/P1177
const int N = 1e6+10;
int q[N],n;
int help[N];//辅助数组
//时间复杂度:$O(nlogn)$
static void merge_sort(int *q,int l,int r){
if(l>=r) return ;
int m = l+((r-l)>>1);
//递归树高度O(logn)
merge_sort(q,l,m);
merge_sort(q,m+1,r);
//合并O(n)
//l,m,r
int a=l,b=m+1,i=l;
while(a<=m&&b<=r) help[i++]=q[a]<=q[b]?q[a++]:q[b++];
while(a<=m) help[i++]=q[a++];
while(b<=r) help[i++]=q[b++];
for(i=l;i<=r;i++) q[i] = help[i];
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",q+i);
merge_sort(q,0,n-1);
for(int i=0;i<n-1;i++) printf("%d ",q[i]);
printf("%d\n",q[n-1]);
return 0;
}
快速排序
掌握随机化取数的快速排序即可。
非常快, 时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn), 原地排序空间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
//快速排序模板
//1. 朴素快排和随机化快排
//2. 三向切分快排速度
#include<bits/stdc++.h>
using namespace std;
//测试链接:https://www.luogu.com.cn/problem/P1177
const int N = 1e6+10;
int n, q[N];
void quick_sort_class(int *q,int l,int r){
if(l>=r) return ;
int x = q[l+rand()%(r-l+1)];//q[l]随机取左区间的数
int i=l-1, j=r+1;
while(i<j){
do i++; while(q[i]<x);
do j--; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
quick_sort_class(q,l,j);
quick_sort_class(q,j+1,r);
}
//三向切分快排,应对大量重复值的情况。
int first ,last;
//int* q
static void quick_sort(int* q,int l,int r){
if(l>=r) return ;
int x = q[l+rand()%(r-l+1)];
first=l-1,last=r+1;
int i=l;
while(i<last){
if(q[i]==x) i++;
else if(q[i]<x) swap(q[++first],q[i++]);
else swap(q[--last],q[i]);
}
quick_sort(q,l,first);
quick_sort(q,last,r);
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",q+i);
}
quick_sort_class(q,0,n-1);//60分,会超时。随机化取数:100分
//quick_sort(q,0,n-1);//三向切分
for(int i=0;i<n-1;i++){
printf("%d ", q[i]);
}
printf("%d\n",q[n-1]);
return 0;
}
补充
非比较排序等期末考试结束, 写完模板就补充上。