歸併排序

歸併排序

歸併排序是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併

歸併過程爲:比較a[i]和a[j]的大小,若a[i]≤a[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素a[j]複製到r[k]中,並令j和k分別加上1,如此循環下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的算法我們通常用遞歸實現,先把待排序區間[s,t]以中點二分,接着把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。

歸併操作

歸併操作(merge),也叫歸併算法,指的是將兩個順序序列合併成一個順序序列的方法。

如 設有數列{6,202,100,301,38,8,1}

初始狀態:6,202,100,301,38,8,1

第一次歸併後:{6,202},{100,301},{8,38},{1},比較次數:3;

第二次歸併後:{6,100,202,301},{1,8,38},比較次數:4;

第三次歸併後:{1,6,8,38,100,202,301},比較次數:4;

總的比較次數爲:3+4+4=11,;

逆序數爲14;

用途

排序

(速度僅次於快速排序,爲穩定排序算法,一般用於對總體無序,但是各子項相對有序的數列,應用見2011年普及複賽第3瑞士輪的標程)

求逆序對數

具體思路是,在歸併的過程中計算每個小區間的逆序對數,進而計算出大區間的逆序對數(也可以用樹狀數組來求解).

對於原始的數組2,1,3,8,5,7,6,4,10,在整個過程執行的是順序是途中紅色編號1-20。雖然我們描述中說的是程序先分解,再歸併,但實際過程是一邊分解一邊歸併,前半部分分先排好序,後半部分再排好,最後整個歸併爲一個完整的序列,途中的merge過程它所在層的兩個序列的merge過程:下圖展示了每個merge過程對作用於數組的哪部分(紅色)。

整個過程就像一個動態的樹,執行順序就是對樹的先序遍歷順序。

 

C代碼:

#include <stdio.h>

#include <stdlib.h>

 

void MergeArray(int a[], int temp[] , int start , int middle , int end)

{

     int i,j,s,m,e;

     i=start;

     s = start ;

     m = middle+1 ;

     e = end ;

    

     while((s <= middle)&&(m <= end))//因爲包含開始和結束字符,所以用 <=

     {

         if(a[s] < a[m])

         {

              temp[i++] = a[s++] ;

         }

        

         else

         {

              temp[i++] = a[m++] ;

         }

     }

    

     while(s <= middle)

     {

         temp[i++] = a[s++] ;

     }

    

     while(m <= end)

     {

         temp[i++] = a[m++] ;

     }

    

     for(j = start ; j <= end ; j++)

     {

         a[j] = temp[j];

     }   

}

 

void MergeSort(int a[],int temp[],int start ,int end)

{

     int middle ;

     if(start < end)

     {

         middle = (start + end)/2 ;

         MergeSort(a , temp , start , middle);//通過遞歸層層劃分,使左邊有序

         MergeSort(a , temp , middle+1 , end);//右邊有序

         MergeArray(a, temp , start , middle , end);//序列合併

     }

}

 

int main(int argc, char *argv[])

{

     int a[9] = {2,1,3,8,5,7,6,4,10};

     int temp[9] ;

     int i;

     MergeSort(a , temp , 0 ,8);

     for(i = 0 ; i <= 8 ; i ++)

     {

         printf("%d ",a[i]);

     }

     return 0;

}

 

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