歸併排序,咋歸併呢?

大家好,我是道哥,今天我們來聊歸併排序。

對於冒泡排序、插入排序和選擇排序而言,它們的平均時間複雜度都是 O(N*N),那麼,有沒有時間複雜度更低的排序呢?

當然有啊,比如我們今天要聊的歸併排序,它的時間複雜度是 O(N*logN),接下來,我們一起看看歸併排序的思路。

圖解歸併

有 5 個同學,他們的身高如下,需要按照身高進行排序:

步驟一:

先任意抓 2 個人出來比較,比如用 180cm 和 160cm 進行比較,得出的排序結果如下:

步驟二:

另外再抓 2 個進行比較,比如用 170cm 和 150cm 進行比較,得出的排序結果如下:

步驟三:

把剩下的 190cm 歸併到男生這一隊中,發現他比 150cm 高,所以要放在 150cm 的右邊,繼續比較發現他比 170cm 也高,所以繼續放到 170cm 的右邊,結果如下:

到此爲止,我們形成了如下兩個有序排序,即:

接下來的任務就是對這兩個有序的排隊進行歸併,也是歸併排序的核心,操作如下:

step1: 

把 150cm 的同學放到女生的排隊中,發現 150cm 比 160cm 小,所以放到最左邊,結果如下:

step2: 

把 170cm 的同學放到女生排隊中,從左到右逐個比較,最後發現他應該處在 160cm 和 180 之間,結果如下:

step3: 

把 190cm 的同學放到女生排隊中,從左到右逐個比較,最後發現他應該放到 180cm 之後,也就是處在最右邊,結果如下:

到此爲止,所有的同學排成了一隊,身高從低到高。從如上過程中,很容易體會到歸併的思路,這種排序就是歸併排序,其最重要的思想是:針對兩個有序的排列進行合併。

代碼實現

接下來,我們用 C++ 代碼來實現歸併排序:

#include<iostream>
using namespace std;
//有序表a[first...mid]和a[mid + 1...last]的歸併
void merge(int a[], int first, int mid, int last)
{
  int length = last - first + 1;
  int i = first;
  int j = mid + 1;
  int k = 0;
  int *p = new int[length];
  while(i <= mid && j <= last)
  {
    if(a[i] <= a[j]) 
    {
      p[k++] = a[i++];
    }
    else
    {
      p[k++] = a[j++];
    }
  }
  while(i <= mid)
  {
    p[k++] = a[i++];
  }
  while(j <= last)
  {
    p[k++] = a[j++];
  }
  for(k = 0; k < length; k++)
  {
    a[k + first] = p[k];
  }
  delete [] p;
  p = NULL;
}
// 遞歸地進行歸併排序
void mergeSort(int a[], int first, int last)
{
  int mid = (first + last) / 2;
  if(first < last)
  {
    mergeSort(a, first, mid);
    mergeSort(a, mid + 1, last);
    merge(a, first, mid, last);
  }
}
int main()
{
  int a[] = {160, 150, 180, 190, 170};
  int n = sizeof(a) / sizeof(a[0]);
  mergeSort(a, 0, n - 1);
  int i;
  for(i = 0; i < n; i++)
  {
    cout << a[i] << " ";
  }
  cout << endl;
  return 0;
}

經測試程序 OK, 結果爲:

150 160 170 180 190 

歸併排序是非常重要的算法,我們也會一步一個腳印,爭取每篇文章講清講透一件事,也希望大家閱讀後有所收穫,心情愉快。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/3bWP5NH695HX-ehy2Dkiqw