1. 程式人生 > 其它 >二路歸併 c++實現

二路歸併 c++實現

技術標籤:演算法C++演算法排序演算法

二路歸併

  1. 時間複雜度。CBA(基於比較)的排序演算法的最好的複雜度是o(nlogn),最壞情況o(n^2) 歸併排序的演算法即使在最壞情況下複雜度都是O(nlogn)
  2. 歸併演算法是分治策略的應用

1)將待排序序列一分為二,時間o(1)
2)對於劃分的子序列,分別遞迴排序 ----分 2o(n/2)
3)當子序列分別有序,合併有序子序列 —治 o(n)
T(n) = 2
T(n / 2) + o(n)
這個遞推式的結果可以數學方面計算,最終是o(nlogn)
[4, 8,68, 8, 32, 7, 98] 為例
[4, 8, 68, 8] [32, 7, 98]

[4, 8][68, 8] [32, 7], [98]
[4], [8],[68], [8], [32], [7], [98] 分到單序列,子序列有序
[4, 8][8, 68] [7,32], [98] 合
[4, 8,8, 68] [7,32, 98] 合
[4, 7, 8,8, 32, 68, 98] 合

  1. 演算法實現

    //有序子序列的合併部分
    void merge(int *a, int low, int mid, int high)
    {
        int * A = a + low;
        int lb = mid - low;
        //只申請一半的空間,防止合併的時候覆蓋
        int
    * B = new int[lb]; for (int i = 0; i < lb; i++) { B[i] = A[i]; } int lc = high - mid; int * C = a + mid; for (int i = 0, j = 0, k = 0; (j < lb || k < lc);) { // ||處短路求值, lc <=k 當C已經全部合併入A,將B拷貝到A if ((j < lb) && ((lc <= k)
    || (B[j] <= C[k]))) { A[i++] = B[j++]; } // lb <=j 當B已經全部合併入A,將剩下的C全部拷貝到A if ((k < lc) && ((lb <= j) || (C[k] < B[j]))) { A[i++] = C[k++]; } } } //遞迴部分 void mergeSort(int *a, int low, int high) { if (high - low < 2) { return; } int mid = (high + low) >> 1; mergeSort(a, low, mid); mergeSort(a, mid, high); merge(a, low, mid, high); }

    圖示在這裡插入圖片描述

  2. 精簡實現。因為C在A中,沒有單獨申請空間,所以當B合併完畢的時候,程式就可以結束,C不再拷貝

    void merge(int *a, int low, int mid, int high)
    {
        int * A = a + low;
        int lb = mid - low;
        int * B = new int[lb];
        for (int i = 0; i < lb; i++)
        {
            B[i] = A[i];
        }
        int lc = high - mid;
        
        int * C = a + mid;
        //精簡實現,因為C在A中,沒有單獨申請空間,所以當B合併完畢的時候,程式就可以結束,C不再拷貝
        /*for (int i = 0, j = 0, k = 0; (j < lb || k < lc);)
        {
            if ((j < lb) && ((lc <= k) || (B[j] <= C[k])))
            {
                A[i++] = B[j++];
            }
            if ((k < lc) && ((lb <= j) || (C[k] < B[j])))
            {
                A[i++] = C[k++];
            }
        }*/
    
        for (int i = 0, j = 0, k = 0; j < lb;)
        {
            //上面已經有j<lb判定可以刪除重複的
            if ((lc <= k) || (B[j] <= C[k]))
            {
                A[i++] = B[j++];
            }
            //執行完B的合併,不再拷貝C
            if ((k < lc) && (C[k] < B[j]))
            {
                A[i++] = C[k++];
            }
        }
    
    }