歸並排序以及逆序對統計


歸並排序以及逆序對統計

1. 歸並排序

歸並排序利用分治的方法,將兩個有序數組進行合並,達到排目的。有序數組可以通過不停地將數組進行二分,最終得到一個數,認為此數組有序。然后將兩個一個數的數組進行合並,得到一個有序的有兩個數據的數組,然后返回上一層繼續合並,最終得到有序數列。

第一步:解決兩個有序數組合並

void mergeArray(int a[],int m, int b[], int n, int re[])    //a,b,合並到re;m,n分別為a,b數組的長度
{
	int i,j,k;		//給兩個數組分別設定一個指針,把兩個之中較小的放在re中,本次較小的指針后移
	i=j=k=0;
	while(i<m && j<n)									//合並相同長度的數據
	{
		if(a[i]>b[j])
			re[k++]=b[j++];
		else
			re[k++]=a[i++];
	}
	while(i<m)											//多出的部分直接復制在re中
		re[k++]=a[i++];
	while(j<n)											//多出的部分直接復制在re中
		re[k++]=b[j++];
}

第二步:歸並排序

void mergeArray(int a[],int left,int mid,int right, int tmp[])   
//合並a[left...mid],a[mid+1...right]
{
    int i=left,j=mid+1,k=0;
    int m=mid,n=right;
 	while(i<=m && j<=n)
	{
		if(a[i]>a[j])
			tmp[k++]=a[j++];
		else
			tmp[k++]=a[i++];
	}
	while(i<=m)
		tmp[k++]=a[i++];
	while(j<=n)
		tmp[k++]=a[j++];
    for(i=0;i<k;i++)    
 //本層合並完兩個有序數組,返回到上一層位置,作為上一層的有序數組的基礎,進而進行上一組的合並操作
        a[left+i]=tmp[i];
}
void mergeMain(int a[],int left, int right, int temp[])
{
    int mid;
    if(left<right)
    {
        mid=left+(right-left)/2;
        mergeMain(a,left,mid,temp);             //左邊遞歸二分數組
        mergeMain(a,mid+1,right,temp);          //右邊遞歸二分數組
        mergeArray(a,left,mid,right,temp);      //合並操作
    }
}
bool mergeSort(int a[],int n)
{
    int *re;
    re=new int[n];							   //一次性分配好空間,不能每次分配,釋放
    if(!re)                                    //檢查空間是否分配成功
        return false;
    mergeMain(a,0,n-1,re);
    delete[] re;
    re=NULL;                                    //空指針
    return true;
}

2. 逆序對

逆序對數量查找可以通過歸並排序的交換次數算出,在數組a[left...mid]和a[mid+1..right],left<= i <=mid, mid+1<= j< =right ,當滿足a[i] > a[j] 時存在逆序對,假設a[j]放在a[i]之前,則a[i]到a[mid](因為a數組為有序數組)的值都大於a[j],共有mid-i+1個逆序對,因此只需要在歸並排序中合並數組的時候稍加改動即可

int ans=0;														 //全局變量統計數目
void mergeArray(int a[],int left,int mid,int right, int tmp[])  
{
    int i=left,j=mid+1,k=0;
    int m=mid,n=right;
 	while(i<=m && j<=n)
	{
		if(a[i]>a[j])
        {
			tmp[k++]=a[j++];
//當a[i]>a[j]的時候,如果此時把a[j]放在a[i]前面,那么a[i]到a[mid]的值都大於a[j],因此在交換之前屬於逆序對
//左邊數組 9 8 7  右邊數組 1 2 3
//當把 1 放在 9 前面,那么9 8 7 都是 1 的逆序對,數量 mid-1+1
			ans+=mid-i+1;
        }
		else
			tmp[k++]=a[i++];
	}
	while(i<=m)
		tmp[k++]=a[i++];
	while(j<=n)
		tmp[k++]=a[j++];
    for(i=0;i<k;i++)  
        a[left+i]=tmp[i];
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM