排序算法总结(持续更新)

1.归并排序(同时求逆序数)

代码是POJ - 2299的代码,归并思想是二分的思想,从其正中间(与快排不一样)分开两端,将两边分别排序,然后归并,归并由于两边都是扫一遍就可以实现,所以是O(N),由于区间是不断二分,所以总共有O(logN)层,这样粗略地一分析,总的复杂度就是O(NlogN),有一个小小的细节,由于我们觉得从大到小排序,比较方便求逆序数,所以我们要使归并的两段都是从大到小排序的。这里有一个疑问,我能不能在填充tem数组的时候按从大到小填充,等到取出tem里面数据的时候从小到大往原数组里面放呢?其实是不行的,因为,如果从小到大放的话,那么这一段序列递归到上一层的时候,是假定从大到小排序,并使用基于从大到小的算法进行新的归并,也就是说前后要保持排序的一致性,不过如果不求逆序数,那当然按照从小到大排序也不错,不过就算我们按照从大到小排序了,反正知道长度n,倒着输出就好了

代码:

#include<iostream>
using namespace std;
typedef long long ll;
const int num=500010;
int a[num],tem[num];
ll sum;
void Merge(int a[],int s,int mid,int e,int tem[]){
	int p=0,pi=s,pj=mid+1;
	while(pi<=mid&&pj<=e){
		if(a[pi]<a[pj]){
			tem[p++]=a[pj++];
		}
		else if(a[pi]>=a[pj]){
			tem[p++]=a[pi++];sum+=(e-pj+1);
		}
	}
	while(pi<=mid)tem[p++]=a[pi++];
	while(pj<=e)tem[p++]=a[pj++];
	for(int i=0;i<e-s+1;i++){ 
		a[s+i]=tem[i];
	}
}
void MergeSort(int a[],int s,int e,int tem[]){
	if(s<e){
		int mid=s+(e-s)/2;
		MergeSort(a,s,mid,tem);
		MergeSort(a,mid+1,e,tem);
		Merge(a,s,mid,e,tem);
	}
}
int main(){
	int n;cin>>n;
	while(n!=0){
		sum=0;
		for(int i=0;i<n;i++){
			cin>>a[i];
		}
		MergeSort(a,0,n-1,tem);
		cout<<sum<<endl;
		cin>>n;
	}	
	return 0;
}
2.快速排序

猜你喜欢

转载自blog.csdn.net/qq_41333528/article/details/80273545
今日推荐