1. 程式人生 > >算法導論學習筆記(2)-歸並排序

算法導論學習筆記(2)-歸並排序

mar 今天 iostream 介紹 font 額外 遞歸 size dsm

今天學習了算法導論上的歸並排序算法,而且完畢了在紙上寫出偽代碼,曾經就學過歸並可是理解的不夠透徹。

前還一直困惑:為什麽明明歸並排序比快排的時間復雜度更穩定。為什麽庫函數不用歸並而用快排。如今知道原因了,由於歸並排序必須開額外的空間。並且空間開銷還比較大,以下介紹算法:

首先,歸並排序用到了分治的思想。把大數據分成若幹個小數據,然後再分別對小數據進行處理,最後把小數據

合並成大數據。

其次。歸並排序用到了一個最重要的特點。就是把兩組已經排序的數據合並成一組有序數據,而且該過程的時間復

雜度為O(n)。

最後,算法便出來了,對於一個數組A[n]來說,我們要對他進行排序,首先,我們如果A[0~n/2]和A[n/2+1,n-1]為

有序序列,那麽。我們就能夠在O(n)的時間內排好序,但是。問題是,A[0~n/2]和A[n/2+1,n-1]並非有序序列,於是我們就要將他們都變成有序序列,怎樣變呢?我們再分別對A[0~n/2]和A[n/2+1,n-1]進行排序就可以,對於A[0~n/2]來說,我們運用和以上同樣的方法,把他分成A[0~n/2/2]和A[n/2+1,n/2],然後假設這兩個數組均為有序序列的話,那麽就能夠把它們合並起來,然後在返回到上一層了。那麽怎樣才幹推斷他們為有序呢?當僅僅有一個元素的時候這個元素便是有序的。所以,僅僅須要遞歸到元素個數為1。然後再返回合並就可以。

以下是對以下下代碼中的merge()(合並)函數正確性的證明:

1.當第一次循環叠代的時候,i = L, A[L, i-1]為空。是有序的序列(空也算有序序列),而且含有i-L=0個LA[n1],RA[n2]的最小的數,這時c1 = c2 = 0, LA[c1]和RA[c2]均為彼此數組中的最小的元素。

2.如果第i次叠代的時候LA[c1] <= RA[c2], 這時LA[c1]便是還沒有被拷貝到A中的最小的元素。此時A中含有i-L個最小的元素。當運行A[i] = LA[c1]時,A中便含有i-L+1個最小的元素,然後添加c1和i進行下一次叠代。如果第一次時LA[c1] > RA[c2]。運行相似的過程。

3.循環結束後,i = r+1, 此時A中含有i-L = r-L+1個最小的元素。恰好是l~r全部的元素,而且已排好序,證畢。

//insertion_sort
#include <iostream>
using namespace std;
const int inf = (1<<28);

void print(int* A, int n)
{
    for (int i = 0; i < n; i++) {
        cout << A[i] << " ";
    }
    cout << endl;
}
void merge(int *A, int l, int m, int r)
{
    int n1 = m-l+1, n2 = r-m;
    int lA[(const int)(n1+1)], rA[(const int)(n2+1)];
    for (int i = 0; i < n1; i++) {
        lA[i] = A[i+l];
    }
    for (int i = 0; i < n2; i++) {
        rA[i] = A[m+1+i];
    }
    lA[n1] = rA[n2] = inf;
    int c1 = 0, c2 = 0;
    for (int i = l; i <= r; i++)
    {
        if (lA[c1] <= rA[c2]) {
            A[i] = lA[c1++];
        }
        else {
            A[i] = rA[c2++];
        }
    }
}
void merge_sort(int *A, int l, int r)
{
    if (l < r)
    {
        int m = (l + r) / 2;
        merge_sort(A, l, m);
        merge_sort(A, m+1, r);
        merge(A, l, m, r);
    }
}
int main()
{
    int A[10] = {43,2,53,1,8,29,52,4,8,10};
    
    cout << "before sorted: ";
    print(A, 10);
    
    merge_sort(A, 0, 10);
    
    cout << "after sorted: ";
    print(A, 10);
    
    return 0;
}




算法導論學習筆記(2)-歸並排序