歸併排序-自頂向下/自底向上


author: i.sshe
email: [email protected]
github: https://github.com/isshe


歸併排序[二路]

  1. 歸併排序是將要排序數組遞歸地分成兩半分別排序,然後將結果合併起來,完成排序.
  2. 歸併排序是最理想的直接排序算法(運行時間與NlogN成正比),執行過程具有穩定性.
  3. 歸併排序可以處理數百萬甚至更大規模的數組, 這是插入排序或選擇排序做不到的.

  4. 歸併排序示意圖:
    這裏寫圖片描述
      1). 把前面部分元素和後面部分元素比較,小的放入結果數組.(注意此處的前半部分/後半部分已經排好序了)

  5. 可以把後半部分倒序, 兩部分數組中最大的元素充當觀察哨, 這樣可以減少判斷.
    代碼可以從

    這裏寫圖片描述

    變爲

    這裏寫圖片描述

  6. 合併代碼
void merge(int *a, int *b, int lo, int mid, int hi)
{
     int    i = lo;
     int    j = mid + 1;
     int    k = 0;

     //copy a[lo..hi] to b[lo..hi].
     for (k = lo; k <= hi; k++)
     {
         b[k] = a[k];
     }

     for (k = lo; k <= hi; k++)
     {
          if (i > mid)          //到達邊緣
          {
              a[k] = b[j];
              j++;
          }
          else if (j > hi)    //到達邊緣
          {
              a[k] = b[i];
              i++;
          }
          else if (b[i] > b[j])
          {
               a[k] = b[j];
               j++;
          }
          else          //b[i] < b[j]
          {
               a[k] = b[i];
               i++;
          }
     }
}

自頂向下的歸併排序

  1. 軌跡圖
    這裏寫圖片描述
      1). 排序E,M, 排序G,R,
      2). 合併在一起.
      3). 以此反覆.
  2. 依賴樹
    這裏寫圖片描述
  3. 代碼
void top_down_merge_sort(int *a, int *b, int lo, int hi)
{
    if(lo >= hi)
    {
         return ;
    }

    int mid = (lo + hi) / 2;        //
    top_down_merge_sort(a, b, lo, mid);
    top_down_merge_sort(a, b, mid+1, hi);
    merge(a, b, lo, mid, hi);
}

改進

  1. 對小規模子數組(長度小於15左右)使用插入排序, 可以縮短10%-15%的運行時間.
  2. 測試數組是否有序:添加一個判斷條件, 如果a[mid]<=a[mid+1],則認爲數組已經有序並跳過merge()方法.(<<算法 第四版>>p175頁,不懂)
  3. 不將元素複製到輔助數組: 要做到這一點需要調用兩種排序方法, 一種將數據從輸入數組排序到輔助數組, 一種將數據從輔助數組排序到輸入數組.(<<算法 第四版>>p175頁,不懂)

自底向上的歸併排序

歸併排序的另一種方法是: 兩兩歸併子數組.
1. 軌跡圖
這裏寫圖片描述
注意:sz=1中, 奇數位置的總比偶數位置的短!
2. 歸併結果圖:
這裏寫圖片描述
3. 代碼

void bottom_up_merge_sort(int *a, int *b, int len)
{
     int    sz = 0;             //size:間隔:2, 4, 8...
     int    lo = 0;
     int    hi = 0;
     int    N = len;

     for (sz = 1; sz < N; sz = sz + sz)       //1+1=2, 2+2=4...控制間隔
     {
         for (lo = 0; lo < N - sz; lo += sz + sz)      //控制次數
         {
             hi = (lo + sz + sz -1) < (N - 1) ? (lo + sz + sz -1) : (N -1);
              merge(a, b, lo, lo+sz-1, hi);
         }
     }
}

3. 自底向上的歸併排序適合用於鏈表組織的數據.

歸併排序告訴我們:當能夠用其中一種方法解決一個問題的時候,你都應該試試另一種!

參考資料:
1. <<算法第四版>>
2. <<算法:C語言實現1-4部分>>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章