c++實現歸併排序

本次用c++實現歸併排序,代碼來自慕課網實戰課程,算法與數據結構,我在學習過程中記錄下來方便以後看。

    c++
    template<typename  T>
void __merge(T arr[], int l, int mid, int r){

    // 經測試,傳遞aux數組的性能效果並不好
    T aux[r-l+1];
    //複製數組開闢新的空間注意有i個偏移量
    for( int i = l ; i <= r; i ++ )
        aux[i-l] = arr[i];

    int i = l, j = mid+1;
    for( int k = l ; k <= r; k ++ ){
//先判斷索引的合法性
        if( i > mid )   { arr[k] = aux[j-l]; j ++;}
        else if( j > r ){ arr[k] = aux[i-l]; i ++;}
        else if( aux[i-l] < aux[j-l] ){ arr[k] = aux[i-l]; i ++;}
        else                          { arr[k] = aux[j-l]; j ++;}
    }
}

// 遞歸使用歸併排序,對arr[l...r]的範圍進行排序
//本測試例子中“————”開頭的函數表示私有函數
//使用遞歸進行二分
template<typename T>
void __mergeSort(T arr[], int l, int r){

    if( l >= r )
        return;

    int mid = (l+r)/2;
    __mergeSort(arr, l, mid);
    __mergeSort(arr, mid+1, r);
    __merge(arr, l, mid, r);
}

template<typename T>
void mergeSort(T arr[], int n){

    __mergeSort( arr , 0 , n-1 );
}
nt main() {

    int n = 50000;

    // 測試1 一般性測試
    cout<<"Test for Random Array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
    int* arr1 = SortTestHelper::generateRandomArray(n,0,n);
    int* arr2 =SortTestHelper::copyIntArray(arr1, n);
    SortTestHelper::testSort("Merge Sort",     mergeSort,     arr2, n);

    delete[] arr1;
    delete[] arr2;

    cout<<endl;


    // 測試2 測試近乎有序的數組
    int swapTimes = 100;
    cout<<"Test for Random Nearly Ordered Array, size = "<<n<<", swap time = "<<swapTimes<<endl;
    arr1 = SortTestHelper::generateNearlyOrderedArray(n,swapTimes);
    arr2 = SortTestHelper::copyIntArray(arr1, n);
    SortTestHelper::testSort("Merge Sort",     mergeSort,     arr2, n);

    delete(arr1);
    delete(arr2);

    return 0;
}


//輔助函數
/*srand和rand()配合使用產生僞隨機數序列。rand函數在產生隨機數前,需要系統提供的生成僞隨機數序列的種子,
rand根據這個種子的值產生一系列隨機數。如果系統提供的種子沒有變化,每次調用rand函數生成的僞隨機數序列都是一樣的。
srand(unsigned seed)通過參數seed改變系統提供的種子值,從而可以使得每次調用rand函數生成的僞隨機數序列不同,
從而實現真正意義上的“隨機”。通常可以利用系統時間來改變系統的種子值,即srand(time(NULL)),
可以爲rand函數提供不同的種子值,進而產生不同的隨機數序列*/
amespace SortTestHelper {

    int *generateRandomArray(int n, int range_l, int range_r) {

        int *arr = new int[n];
//生成隨機數函數,srand需要一個時間種子。來保證每次生成的序列不一樣
        srand(time(NULL));
        for (int i = 0; i < n; i++)
            arr[i] = rand() % (range_r - range_l + 1) + range_l;
        return arr;
    }

    int *generateNearlyOrderedArray(int n, int swapTimes){

        int *arr = new int[n];
        for(int i = 0 ; i < n ; i ++ )
            arr[i] = i;

        srand(time(NULL));
        for( int i = 0 ; i < swapTimes ; i ++ ){
            int posx = rand()%n;
            int posy = rand()%n;
            swap( arr[posx] , arr[posy] );
        }

        return arr;
    }

    int *copyIntArray(int a[], int n){

        int *arr = new int[n];
        copy(a, a+n, arr);
        return arr;
    }

    template<typename T>
    void printArray(T arr[], int n) {

        for (int i = 0; i < n; i++)
            cout << arr[i] << " ";
        cout << endl;

        return;
    }

    template<typename T>
    bool isSorted(T arr[], int n) {

        for (int i = 0; i < n - 1; i++)
            if (arr[i] > arr[i + 1])
                return false;

        return true;
    }

    template<typename T>
    void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {

        clock_t startTime = clock();
        sort(arr, n);
        clock_t endTime = clock();
        cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;

        assert(isSorted(arr, n));

        return;
    }

};

2017,3.2更新
前面的排序過程都是從上到下的遞歸過程,本次更新從下往上迭代在某些場景中很快,比如說沒有使用用數組下標獲取數組值的過程,這個在鏈表排序中很有用。

//其中i+sz<n爲了防止越界,下面的最小值函數也是爲了防止最後一組不足i+sz+sz的情況
for(int sz=1;sz<=n;sz+=sz){
    for(int i=0;i+sz<n;i+=sz+sz){
    //對arr[i....i+sz-1]和arr[i+sz......i+sz+sz-1]
        __merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1);}
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章