算法 - 歸併排序

介紹

歸併排序:歸併字面意思“迴歸 ”“合併 ”,把有序的兩個或者多個序列合併爲一個序列。該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。那麼什麼是分治法呢?

分治法

分治法:將原問題分解爲幾個規模較小但類似於原問題的子問題,遞歸的求解這些子問題,然後在合併這些子問題的解來建立原問題的解。

分治模式在每層遞歸都有三個步驟:

  • 分解:把原問題分解若干子問題;
  • 解決:把若干子問題解決;
  • 合併:把若干問題的解合併。

歸併分析

歸併排序的核心思想採用分治法。我們通過一個例子來深入的認識。比如現在有一組數 [30, 55, 65, 40, 25, 80, 26, 35],對這些數通過分治法的思想解決排序,遵循三個原則:

  • 分解:把需要排序的一組數分解爲若干序列,例如[30, 55] , [65, 40] ……;
  • 解決:把分解的若干序列按照規則排序,例如從小到大:[30, 55] , [40 65]……;
  • 合併:在把若干有序子序列合併爲一組數,就完成我們的排序。

下面我們將通過圖解來理解這個過程:

代碼實現

實現歸併排序,這裏分爲兩步,方便理解: 第一步:實現兩個有序序列合併;第二步:實現一組數據的排序

實現兩個有序序列合併

例如:兩個數組 a[min … mid] 和 b[mid … max] 實現有序合併

//將有序數組a[]和b[]合併到c[]中  
-(void) mergeArray(firArr:Array, secArr:Array, finshArr:Array){  
    firArrCount = firArr.count;
    secArrCount = secArr.count;
    int i, j, k;  
    i = j = k = 0;  

    while (i < firArrCount && j < secArrCount)  
    {  
        if (firArr[i] < secArr[j]) { 
            finshArr[k++] = firArr[i++]; 
        }else {
            finshArr[k++] = secArr[i++]; 
        }
    }  

    while (i < firArrCount)  
        finshArr[k++] = firArr[i++];  

    while (j < secArrCount)  
        finshArr[k++] = secArr[i++];  
}  

以上這段代碼比較好理解,題目中只要是兩個有序的兩個數組都可以完成排序,下面我們將實現一組數據的排序。

實現一組數據的排序

例如:現在有數組a[n],使用歸併排序完成排序

//實現一組數的排序我們需要對以上兩個有序數組排序的代碼進行修改添加參數,參數其實就是使用二分法完成數組的分解(也就是分治法的分解原理)
//實現排序合併
-(void) mergeArray(arr:NSArray, first:int, mid:int, last:int, tempArr:NSArray){  
    int i = first, j = mid + 1;  
    int m = mid,   n = last;  
    int k = 0;  

    while (i <= m && j <= n)  
    {  
        if (a[i] <= a[j])  
            tempArr[k++] = a[i++];  
        else  
            tempArr[k++] = a[j++];  
    }  

    while (i <= m)  
        tempArr[k++] = a[i++];  

    while (j <= n)  
        tempArr[k++] = a[j++];  

    for (i = 0; i < k; i++)  
        a[first + i] = tempArr[i];  
}  
//用遞歸採用分治法中的分解對數據分解成若干子序列然後排序
-(void) mergeSort(arr:NSArray, first:int, last:int, tempArr:NSArray)  {  
    if (first < last)  
    {  
        int mid = (first + last) / 2;  
        mergeSort(arr, first, mid, tempArr);    //左邊有序  
        mergeSort(arr, mid + 1, last, tempArr); //右邊有序  
        mergeArray(arr, first, mid, last, tempArr); //再將二個有序數列合併  
    }  
}  
  對數組a[n]排序
  -(void)test{

      //創建完成排序數組
      NSMutableArray *finshArr = [[NSMutableArray alloc] initWithCapacity:n];
      //對a[n]排序
      mergeSort(a, 0, n - 1, finshArr);
  }

以上代碼是Objective-c語言編寫,以上代碼沒有運行,知識按照思路書寫完成,我最近的項目已經使用swift一年多了,以後我將以swift形式編寫僞代碼。

PS

以上我們對歸併排序介紹原理和代碼實現,那麼這個排序的效率怎麼樣呢,我們又將如何使用科學有效的方法對一個算法進行分析,來讓我們更好的理解算法?

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