合併排序(MERGE SORT)是又一類不同的排序方法,合併的含義就是將兩個或兩個以上的有序數據序列合併成一個新的有序數據序列,因此它又叫歸併算法。它的基本思想就是假設數組A有N個元素,那麼可以看成數組A是又N個有序的子序列組成,每個子序列的長度爲1,然後再兩兩合併,得到了一個 N/2 個長度爲2或1的有序子序列,再兩兩合併,如此重複,值得得到一個長度爲N的有序數據序列爲止,這種排序方法稱爲2路合併排序。
例如數組A有7個數據,分別是: 49 38 65 97 76 13 27,那麼採用歸併排序算法的操作過程如圖所示:
初始值 [49] [38] [65] [97] [76] [13] [27]
看成由長度爲1的7個子序列組成
第一次合併之後 [38 49] [65 97] [13 76] [27]
看成由長度爲1或2的4個子序列組成
第二次合併之後 [38 49 65 97] [13 27 76]
看成由長度爲4或3的2個子序列組成
第三次合併之後 [13 27 38 49 65 76 97]
歸併排序算法過程圖
合併算法的核心操作就是將一維數組中前後相鄰的兩個兩個有序序列合併成一個有序序列。合併算法也可以採用遞歸算法來實現,形式上較爲簡單,但實用性很差。
而逆序數就是左邊序列比右邊序列大的數對。設i和j兩個指針指向left和right序列,起始爲1,n1n2是序列的長度。當a數列插入k爲right數列中j時,逆序數增加爲n1 - i + 1。如第三次合併中13插入k=1時,ans+=4 - 1 + 1
{
if(p<r)
{
int q=(p+r)/2;
mergesort(a,p,q);
mergesort(a,q+1,r);
merge(a,p,q,r); //合併步驟 p<=left<=q q<right<=r;
}
}
void merge(long a[],int p,int q,int r)
{
int n1=q-p+1;
int n2=r-q;
int i,j,k;
long left[n1+1];
long right[n2+1];
for(i=1;i<=n1;i++)
left[i]=a[p+i-1];
for(j=1;j<=n2;j++)
right[j]=a[q+j];
left[n1+1]=1e9; //設置一個哨兵
right[n2+1]=1e9; //同上
i=1;
j=1;
for(k=p;k<=r;k++)
if(left[i]<right[j])
a[k]=left[i++];
else
{
a[k]=right[j++];
ans+=n1-i+1; //計數;
}