1. 程式人生 > >歸併排序(求逆序對)

歸併排序(求逆序對)

#include<bits/stdc++.h>
using namespace std;
void merge(int a[],int first,int mid,int last,int temp[])
{
	int i=first,j=mid+1;
	int m=mid,n=last;
	int k=0;
	while(i<=m&&j<=n)
	{
		if(a[i]<a[j])
		  temp[k++]=a[i++];
		else 
		  temp[k++]=a[j++];
	}
	while(i<=m)
	    temp[k++]=a[i++];
	while(j<=n)
	    temp[k++]=a[j++];
	for(i=0;i<k;i++)
	a[first+i]=temp[i];
}
void mergesort(int a[],int first,int last,int temp[])
{
	if(first<last)
	{
		int mid=(first+last)/2;
		mergesort(a,first,mid,temp);
		mergesort(a,mid+1,last,temp);
		merge(a,first,mid,last,temp);
	}
}
bool Mergesort(int a[],int n)
{
	int *p=new int[n];
	if(p==NULL)
	 return false;
	mergesort(a,0,n-1,p);
	delete[] p;
	return 1;
}
int main() 
{
	int n;
	int a[200]; 
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	Mergesort(a,n);
	for(int i=0;i<n;i++)
	{
		cout<<a[i]<<" ";
	}
	
	
	
	
	
	
	return 0;
}

求逆序對?

answer

比如將下面兩個區間排序

\qquad a_iai​ \quad mid=4mid=4 \quad a_jaj​

\quad 3\,4\,7\,93479 \qquad \qquad 1\,5\,8\,1015810

首先將右區間的 11 取出,放到r_krk​中,此時 11 是比每個a_iai​中的元素都小,也就是說此時i的指標指向a_1a1​的位置,此刻得到的逆序對的數量為 44 ; r_k= 1rk​=1 ;

然後再將a_iai​和a_jaj​比較(直到a_i<a_jai​<aj​),a_i<a_jai​<aj​ 將a_iai​的元素放到r_krk​中; r_k= 1\,3\,4rk​=134;

現在a_j>a_iaj​>ai​, ii 指向a_3a3​的位置,將 55 放到r_krk​中,得到的逆序對數量為 22 ; r_k= 1\,3\,4\,5rk​=1345

以此類推,直到進行完歸併排序,每次合併都會求出逆序對的數目,即mid-i+1mid−i+1,最後每次將ansans加上mid-i+1mid−i+1即可得到最後的答案;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1008611;
int a[maxn],temp[maxn];
int n;
long long ans=0;
void msort(int l,int r)
{
	if(l==r)  return ;
	
	int mid=(l+r)/2;
	int m=mid,n=r;
	msort(l,mid);
	msort(mid+1,r);
	int i=l,j=mid+1,k=0;
	while(i<=m&&j<=n)
	{
		if(a[i]<a[j]) 
		temp[k++]=a[i++];
		else {
			temp[k++]=a[j++];
			ans+=mid-i+1;
		}
	  }
	while(i<=m) temp[k++]=a[i++];
	while(j<=n) temp[k++]=a[j++];
	for(i=0;i<k;i++)
	{
		a[l+i]=temp[i];
	} 
	 
	  
	
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	msort(0,n-1);
	printf("%lld\n",ans);
	
	
	
	
	return 0;
}