歸併排序

歸併排序

  歸併排序是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法的一個非常典型的應用,它包含歸(遞歸)並(合併)兩個操作。


原理

  先思考怎麼把兩個有序的序列A,B組合成一個新的有序序列C。
1. 取兩個序列A,B的第一個元素a1,b1 做比較,將較小元素放入序列C中並從原來的序列中移除,假設 a1<b1 ,我們把a1 放入C中並從序列A中移除它。
2. 這樣序列A中的第一個元素變爲a2 ,序列B中第一個元素還是b1 ,重複第1步直到A,B中某個序列的所有元素全被移除。
3. 將A,B中還存在元素的序列中的元素,按順序添加到序列C的後面,這樣就完成了兩個有序序列的合併。

  現在我們有一個亂序數組A,想把其中的元素排序,我們可以考慮把A從中值處分隔成兩個數組B和C,對B和C分別排序之後,將他們合併成一個用上面的方法合併成一個新的有序數組。
  我們發現,如果數組只有一個元素的話,那它肯定是一個有序數組,所以我們可以對B和C再進行拆分,對拆分出來的數組繼續拆分直到所有的子數組都只有一個元素爲止,這樣所有的子數組都是有序的,對它們兩兩進行合併,最後終將可以合併成一個有序的數組。

示例

  • 假設有數組 
    {3,5,4,2,1}
  • 第一次拆分 
    {3,5,4} {2,1}
  • 再一次拆分 
    {3,5} {4} {2} {1}
  • 再一次拆分 
    {3} {5} {4} {2} {1}
  • 合併   
    {3} {5}{3,5}
  • 合併   
    {3,5} {4}{3,4,5}
  • 合併   
    {2} {1}{1,2}
  • 合併   
    {3,4,5} {1,2}{1,2,3,4,5}

代碼

//合併有序數組
void mergeArray(int* arr, int left, int mid, int right, int* temp)
{
    int i = left, j = mid + 1;
    int k = 0;
    while(i <= mid && j <= right) {
        if(arr[i] < arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    while(i <= mid) {
        temp[k++] = arr[i++];
    }
    while(j <= right) {
        temp[k++] = arr[j++];
    }
    for(int p = 0; p < k; p++) {
        arr[left + p] = temp[p];
    }
}
//遞歸拆分數組爲元素只有1個的有序數組
void mergeSort(int* arr, int left, int right, int* temp)
{
    if(left < right) {
        int mid = (left + right) / 2;
        mergeSort(arr, left, mid, temp);
        mergeSort(arr, mid + 1, right, temp);
        mergeArray(arr, left, mid, right, temp);
    }
}
void mergeSort(int* arr, int len)
{
    int* temp = (int*)malloc(sizeof(int) * len);
    mergeSort(arr, 0, len - 1, temp);
}

時間複雜度

歸併排序的時間複雜度爲O(nlogn)

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