1. 程式人生 > >【歸並排序】my merge_sort 整理

【歸並排序】my merge_sort 整理

img soft event 技術 pan 空間復雜度 步驟 href 都是

  merge_sort是分治法的一個典型應用。這裏有一張《各類排序算法時間、空間復雜度對比表》,從表中可以看得出,merge_sort(歸並排序算法)是比較穩定的算法,使用較廣泛。求逆序對也是很好用的。

分治過程概括圖:藍色的原始數組,運用merge_sort以後為有序的綠色數組

技術分享圖片

我的理解:主要想說二路歸並(大佬請忽略)

技術分享圖片

  1. merge() 是二路歸並的階段,簡單來說是有序表的合並。這時有兩段:左段 al~amid 和右段 amid+1~ar ,轉移數組 c 的下標從 cnt=0 開始,定義左右兩段的下標分別為 i 、j ,且 i 指向 al ,j 指向 amid+1

。現在不停地比較 ai 與 aj 的值大小,總是將較小(以升序為例,降序稍加修改,就改三四處)的一個值賦給 c 數組,如果 ai 較小 ( aj 的話,後面改為 j ),則 i 和 cnt 均 加 1,直到兩段其中有一段的長度為零(下標到結尾)。最後,將長度不為零的一段剩下的a值全部給 c 數組,merge() 函數完成。在 a 數組的值給到 c 數組的過程中,我們總是選最小的。實際上,左段和右段都是有序的(或者如圖一的第一行綠色只有一個元素),我們每次兩兩比較又總是取較小的加入 c 數組,所以 c 中的值是嚴格的由小到大。最後從 cnt=0 開始回給到 a 後,新的 a 數組順序也是嚴格的由小到大。

對應code:

技術分享圖片
const int M=1e5+5;
int a[M];

void Merge(int l,int m,int r)
{
    int c[r-l+1];
    int i=l,j=m+1;
    int cnt=0;
    while(i<=m&&j<=r)
    {
        if(a[i]<=a[j])
            c[cnt++]=a[i++];
        else
            c[cnt++]=a[j++];
    }
    while(i<=m)
        c[cnt
++]=a[i++]; while(j<=r) c[cnt++]=a[j++]; for(int k=0;k<cnt;k++) a[l++]=c[k]; }
merge()

  2.sort() 內部使用遞歸,遞歸邊界:各有序表長度為 1 ,數組分兩段進行,然後逐步返回,返回過程調用merge()。最終得到有序表a[ ];

對應code:

技術分享圖片
void mergesort(int l,int r)
{
    if(l==r)/*!< 遞歸邊界 */
        return;
    int m=(l+r)/2;/*!< 遞歸步驟 */
    mergesort(l,m);
    mergesort(m+1,r);
    Merge(l,m,r);/*!< 二路歸並 */
}
mergesort()

那麽整個算法:

技術分享圖片
 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 const int M=1e5+5;
 6 int a[M];
 7 
 8 void Merge(int l,int m,int r)
 9 {
10     int c[r-l+1];
11     int i=l,j=m+1;
12     int cnt=0;
13     while(i<=m&&j<=r)
14     {
15         if(a[i]<=a[j])
16             c[cnt++]=a[i++];
17         else
18             c[cnt++]=a[j++];
19     }
20     while(i<=m)
21         c[cnt++]=a[i++];
22     while(j<=r)
23         c[cnt++]=a[j++];
24     for(int k=0;k<cnt;k++)
25         a[l++]=c[k];
26 }
27 
28 void mergesort(int l,int r)
29 {
30     if(l==r)/*!< 遞歸邊界 */
31         return;
32     int m=(l+r)/2;/*!< 遞歸步驟 */
33     mergesort(l,m);
34     mergesort(m+1,r);
35     Merge(l,m,r);/*!< 二路歸並 */
36 }
Merge sort

PS:這裏有兩歸並可解的題:洛谷【P1177】 模板 快速排序 和 洛谷【P1908】逆序對,供測試。

【歸並排序】my merge_sort 整理