蒟蒻の常用排序算法总结


参考题单:洛谷【算法1-2】排序

update:2020/10/05 增加基数排序


有比较的排序

冒泡排序

基本思想

两个数比较大小,较大的数下沉,较小的数冒起来、

过程

比较相邻的两个数据,如果第二个数小,就交换位置

从后向前两两比较,一直到比较最前两个数据。最终最小数被交换到起始的位置

继续重复上述过程,依次将第2.3…n-1个最小数排好位置

时间复杂度

平均为 O ( n 2 ) O(n^2) O(n2)

C o d e 1 Code_1 Code1 未优化

#include<bits/stdc++.h>
using namespace std;
int n;
int a[10010];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			if(a[i]<a[j]){
				swap(a[i],a[j]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
    }
	return 0;
}

C o d e 2 Code_2 Code2 优化

#include<bits/stdc++.h>
using namespace std;
int n;
int a[10010];
bool f;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		f=false;
        for(int j=1;j<=i;j++){
			if(a[i]<a[j]){
				f=true;
                swap(a[i],a[j]);
			}
		}
        if(!f){
			break;
        }
	}
	for(int i=1;i<=n;i++){
		cout<<a[i]<<" ";
    }
	return 0;
}

例题

P1116 车厢重组

思路

使用冒泡排序思想,每交换一次cnt+1,最后输出cnt即可

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
int n;
int a[10010];
int cnt;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			if(a[i]<a[j]){
				swap(a[i],a[j]);
				cnt++;
			}
		}
	}
	cout<<cnt;
	return 0;
}

插入排序

基本思想:

在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

过程:

时间复杂度

平均为 O ( n 2 ) O(n^2) O(n2)

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
int n,a[110];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<n;i++){
		for(int j=i+1;j>0;j--){
			if(a[j]<a[j-1]){
				swap(a[j-1],a[j]);
			}else{
				break;
			}
		}
	}
	for(int i=1;i<=n;i++){
		printf("%d ",a[i]);
	}
	return 0;
}

选择排序

基本思想:

在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换;
……
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。

过程

时间复杂度

平均为 O ( n 2 ) O(n^2) O(n2)

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
int n,a[110];
int p;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	for(int i=1;i<n;i++){
		p=i;
		for(int j=i+1;j<=n;j++){
			if(a[j]<a[p]){
				p=j;
			}
		}
		if(p!=i){
			swap(a[i],a[p]);
		}
	}
	for(int i=1;i<=n;i++){
		printf("%d ",a[i]);
	}
	return 0;
}

归并排序

基本思想:

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

过程

img

时间复杂度

平均为 O ( n log ⁡ n ) O(n\log{n}) O(nlogn)

C o d e Code Code

void inversion(int *c,int l,int mid,int r){
	int i=l,j=mid+1,k=l;
	while(i<=mid&&j<=r)
		if(c[i]<=c[j])d[k++]=c[i++];
		else{
			d[k++]=c[j++];
		}
	while(i<=mid)
		d[k++]=c[i++];
	while(j<=r)
		d[k++]=c[j++];
	for(i=l;i<=r;i++)
		c[i]=d[i];
}
void merge(int *c,int l,int r){
	if(l<r){
		int mid=(l+r)/2;
		merge(c,l,mid);
		merge(c,mid+1,r);
		inversion(c,l,mid,r);
	}
}

例题

见“逆序对题解”

快速排序

基本思想:

  • 先从数列中取出一个数作为key值;
  • 将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;
  • 对左右两个小数列重复第二步,直至各区间只有1个数。

时间复杂度

平均为 O ( n log ⁡ n ) O(n\log{n}) O(nlogn)

C o d e Code Code

void quickSort(int a[],int l,int r){
     if(l>=r)
       return;
     int i = l; int j = r; int key = a[l];//选择第一个数为key
     while(i<j){
         while(i<j && a[j]>=key)//从右向左找第一个小于key的值
             j--;
         if(i<j){
             a[i] = a[j];
             i++;
         }
         while(i<j && a[i]<key)//从左向右找第一个大于key的值
             i++;
         if(i<j){
             a[j] = a[i];
             j--;
         }
     }
     //i == j
     a[i] = key;
     quickSort(a, l, i-1);//递归调用
     quickSort(a, i+1, r);//递归调用

无比较的排序

桶排序

基本思想:

首先创建数组A[MaxValue];然后将每个数放到相应的位置上(例如17放在下标17的数组位置);最后遍历数组,即为排序后的结果。

过程

img

时间复杂度

平均为 O ( n ) O(n) O(n)

空间复杂度

当序列中存在较大值时,BinSort 的排序方法会浪费大量的空间开销。

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
int n,a[110],x;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		a[x]++;
	}
	for(int i=1;i<=100;i++){
		while(a[i]!=0){
			printf("%d ",i);
			a[i]--;
		}
	}
	return 0;
}

基数排序

基本思想:

将整数按位数切割成不同的数字,然后按每个位数分别比较。

过程

将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

时间复杂度

平均为 O ( n ) O(n) O(n)

空间复杂度

大大优化了桶排序的做法,空间复杂度更小

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;
typedef long long ll;
int n,a[maxn];
int Gmax(int a[],int n){
	int ma=a[1];
	for(int i=2;i<=n;i++){
		ma=max(ma,a[i]);
	}
	return ma;
}
void countsort(int a[],int n,int exp){
	int output[n];
	int buckets[20]={0};
	for(int i=1;i<=n;i++){
		buckets[(a[i]/exp)%10]++;
	}
	for(int i=1;i<=9;i++){
		buckets[i]+=buckets[i-1]; 
	}
	for(int i=n;i>=1;i--){
		output[buckets[(a[i]/exp)%10]]=a[i];
		buckets[(a[i]/exp)%10]--;
	}
	for(int i=1;i<=n;i++){
		a[i]=output[i];
	}
}
void radixsort(){
	int exp;
	int max=Gmax(a,n);
	for(exp=1;max/exp>0;exp*=10){
		countsort(a,n,exp);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	radixsort();
	for(int i=1;i<=n;i++){
		printf("%d ",a[i]);
	}
	return 0;
}

STL

sort

sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。sort函数进行排序的时间复杂度为 O ( log ⁡ 2 n ) O(\log_{2}{n}) O(log2n),比冒泡之类的排序算法效率要高,sort函数包含在头文件为#include<algorithm>的c++标准库中。

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
int n,a[110];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+n+1);//sort(a+1,a+n+1,greater<int>())为逆序
	for(int i=1;i<=n;i++){
		printf("%d ",a[i]);
	} 
	return 0;
}
posted @ 2020-08-26 15:16  小罐猹  阅读(121)  评论(0编辑  收藏  举报