排序算法的c++實現——歸並排序


    歸並排序是典型分治思想的代表——首先把原問題分解為兩個或多個子問題,然后求解子問題的解,最后使用子問題的解來構造出原問題的解。

    對於歸並排序,給定一個待排序的數組,首先把該數組划分為兩個子數組,然后對子數組進行排序(遞歸調用歸並排序),最后對兩個有序的子數組進行合並,使合並之后的數組為有序狀態。

    讓我們想想,把一個數組不斷地划分為子數組,不斷地划分......,不斷地划分......., 最后停止了划分不下去了。 此時子數組的元素有一個,它們本身就是有序的。接下來,我們就需要執行合並過程,不斷地一層層向上合並,........,  直到原數組。通過這個過程就會發現, 歸並排序的核心在於合並有序的子數組,而不是對子數組進行排序,因為最底層的子數組本身就是有序的,上一層子數組如果想要變成有序的,通過合並底層有序的子數組就可以得到, 最終我們使原數組變成了有序的,從而完成了排序操作。

 

說明幾點:

1. 歸並排序采用了分治思想,它的核心在於合並子問題的解而不是求解子問題(快速排序也采用了分治思想,但它的核心是在於求解子問題而不需要合並子問題的解)、

2. 歸並排序不是原址排序,它有排序過程中需要借助額外的內存空間。

3. 歸並排序為穩定排序(其實呢,具體還得看你怎么寫代碼,如果兩個數的值相等時,你不保持原順序都就會變成非穩定的了)

4. 歸並排序的時間復雜度為O(NlogN).

 

具體代碼如下:

  1   /***********************************************************************
  2   *   Copyright (C) 2019  Yinheyi. <chinayinheyi@163.com>
  3   *   
  4   * This program is free software; you can redistribute it and/or modify it under the terms
  5   * of the GNU General Public License as published by the Free Software Foundation; either 
  6   * version 2 of the License, or (at your option) any later version.
  7   
  8   *   Brief:    
  9   *   Author: yinheyi
 10   *   Email: chinayinheyi@163.com
 11   *   Version: 1.0
 12   *   Created Time: 2019年05月06日 星期一 22時22分57秒
 13   *   Modifed Time: 2019年05月09日 星期四 21時10分59秒
 14   *   Blog: http://www.cnblogs.com/yinheyi
 15   *   Github: https://github.com/yinheyi
 16   *   
 17   ***********************************************************************/
 18   
 19   
 20   // 歸並排序,分治法的典型代表: 將原問題分解了幾個子問題,解決子問題,再合並子問題的解,
 21   // 這樣就得到了原問題的解。
 22   // 分治本質上就是把原問題分解為幾個子問題來解決。
 23   // 快速排序也是分治思想來解決。
 24   //
 25   //
 26   // 歸並排序(merge-sort):
 27   // 1. 把一個待排序的數組分解為兩個子數組;
 28   // 2. 對兩個子數組進行排序(通過遞歸地調用自己來實現);
 29   // 3. 對兩個已經排序的數組進行合並。
 30   //
 31   // 分析:
 32   // 1. 一個數組一直分解下去,只到分解成只包含一個元素的子數組為止, 此時自然是有序的;
 33   // 2. 歸並排序的重點在於合並,而不是對子數組的排序。(快速排序與它恰恰相反,快速排序的
 34   // 重點是對子數組進行排序,而不是合並,因為它不需要合並了)
 35   //
 36   //
 37   #include <cstring>
 38   #include <iostream>
 39   typedef bool(*CompareFunc)(int, int);
 40   
 41   // 下面函數實現合並功能,輸入三個下標參數表示了兩個子數組, :[nStart_, nMiddle)和[nMiddle, nEnd)
 42   void Merge(int array[], int nStart_, int nMiddle_, int nEnd_, CompareFunc comp)
 43   {   
 44       if (array == nullptr || nStart_ >= nMiddle_ || nMiddle_ >= nEnd_)
 45           return;
 46       
 47       // 建立一個臨時數組存放中間數據
 48       int _nIndex = 0; 
 49       int* _pTempArray = new int[nEnd_ - nStart_];
 50       
 51       // 對兩個子數組進行合並
 52       int _nStartChange = nStart_;
 53       int _nMiddleChange = nMiddle_;
 54       while (_nStartChange < nMiddle_ && _nMiddleChange < nEnd_)
 55       {
 56           // 此處的if中比較語句的安排可以保持穩定排序的特性。
 57           if (comp(array[_nMiddleChange],  array[_nStartChange]))
 58           {
 59               _pTempArray[_nIndex] = array[_nMiddleChange];
 60               ++_nMiddleChange;
 61           }
 62           else
 63           {
 64               _pTempArray[_nIndex] = array[_nStartChange];
 65               ++_nStartChange;
 66           }
 67           ++_nIndex;
 68       }
 69       
 70       // 把不為空的子數組的元素追加到臨時數
 71       if (_nStartChange < nMiddle_)
 72       {
 73           memcpy(_pTempArray + _nIndex, array + _nStartChange, sizeof(int) * (nMiddle_ - _nStartChange));
 74       }
 75       else if (_nMiddleChange < nEnd_)
 76       {
 77           memcpy(_pTempArray + _nIndex, array + _nMiddleChange, sizeof(int) * (nEnd_ - _nMiddleChange));
 78       }
 79       else
 80       {
 81           /* do noting */
 82       }
 83   
 84       // 數據交換
 85       memcpy(array + nStart_, _pTempArray, sizeof(int) * (nEnd_ - nStart_));
 86   
 87       delete [] _pTempArray;
 88       _pTempArray = nullptr;
 89   }
 90   
 91   // 歸並排序功能實現函數
 92   void MergeSort(int array[], int nStart_, int nEnd_, CompareFunc comp)
 93   {
 94       // 數組指針為空,或者數組內的個數少於等於1個時,直接返回。
 95       if (nullptr == array ||  (nEnd_ - nStart_) <= 1)
 96           return;
 97   
 98       // 划分為兩個子數組並遞歸調用自身進行排序
 99       int _nMiddle = (nStart_ + nEnd_) / 2;
100       MergeSort(array, nStart_, _nMiddle, comp);
101       MergeSort(array, _nMiddle, nEnd_, comp);
102   
103       // 合並排序完成的子數組
104       Merge(array, nStart_, _nMiddle, nEnd_, comp);
105   }
106   
107   // 比較函數
108   bool less(int lhs, int rhs)
109   {
110       return lhs < rhs;
111   }
112   
113   // 打印數組函數
114   void PrintArray(int array[], int nLength_)
115   {
116       if (nullptr == array || nLength_ <= 0)
117           return;
118   
119       for (int i = 0; i < nLength_; ++i)
120       {
121           std::cout << array[i] << " ";
122       }
123   
124       std::cout << std::endl;
125   }
126   
127   /***************    main.c     *********************/
128 >>int main(int argc, char* argv[])
129   {
130       // 測試1
131       int array[10] = {1, -1, 1, 231321, -12321, -1, -1, 123, -213, -13};
132       PrintArray(array, 10);
133       MergeSort(array, 0, 10, less);
134       PrintArray(array, 10);
135   
136       // 測試2
137       int array2[1] = {1};
138       PrintArray(array2, 1);
139       MergeSort(array2, 0, 1, less);
140       PrintArray(array2, 1);
141   
142       // 測試3
143       int array3[2] = {1, -1};
144       PrintArray(array3, 2);
145       MergeSort(array3, 0, 2, less);
146       PrintArray(array3, 2);
147   
148       return 0;
149   }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM