一.歸並排序的優缺點(pros and cons)
耗費心思來理解它,總要有個理由吧:
- 歸並排序的效率達到了巔峰:時間復雜度為O(nlogn),這是基於比較的排序算法所能達到的最高境界
- 歸並排序是一種穩定的算法(即在排序過程中大小相同的元素能夠保持排序前的順序,3212升序排序結果是1223,排序前后兩個2的順序不變),這一點在某些場景下至關重要
- 歸並排序是最常用的外部排序方法(當待排序的記錄放在外存上,內存裝不下全部數據時,歸並排序仍然適用,當然歸並排序同樣適用於內部排序...)
缺點:
- 歸並排序需要O(n)的輔助空間,而與之效率相同的快排和堆排分別需要O(logn)和O(1)的輔助空間,在同類算法中歸並排序的空間復雜度略高
P.S.本文只討論最原始的“兩路歸並”,多路的與之類似
二.內部原理
首先要知道歸並排序的思想是:分治法,與快速排序的思想一樣
算法思想:無序 -> 部分有序 -> 整體有序
歸並排序中“分”與“合”的過程是結合在一起的,即每一趟都在做“分”與“合”的工作,並不是先“分”完再“合”(“分”很簡單,不就是一直二分二分直到不可再分唄,額,這么想就錯了,分完就合不起來了,切記“分”與“合”是結合在一起的)
用一幅圖來解釋歸並排序的過程就足夠了:
說明:P1與P2比較,將較大(小)者裝入P,然后P1或者P2右移(裝了誰就移誰),最后P右移
比如要對數組a[n]做升序排序,那么具體過程如下:
- 申請兩個長度都為n/2的輔助空間,把a數組裝進去,前一半裝進L,后一半裝進R
- 按照說明中的方式做一輪比較(P從A移動到C,一趟結束)
現在想想我們做完一趟排序得到了什么?
- 達成了部分有序(前一半 < 后一半,對吧?)
- 除此之外,我們很自然的把待排序序列一分為二,為遞歸做好了准備
還不夠清晰?那么還有幾句話:
- 圖示的過程解釋了為什么需要長度為n的輔助空間
- 只要L和R各自內部都有序(同升序或者同降序),那么只需要再經過一趟歸並,排序就完成了(仔細想想,沒錯吧?)
- 排序部分就是合並部分(還記得上面提過的那句話嗎?“分”與“合”的過程是結合在一起的,千萬不能分開想,否則你會發現合不起來了...)
三.實現細節
如果上面的解釋還不夠清晰,那么我們來舉個例子,一步步分析:
假定待排序序列為a[] = {3, 2, 1, 4},那么具體過程是這樣的:
P.S.如果待排序序列是奇數個怎么辦?這是問題嗎?無非是拆得的前一半比后一半少一個而已,單趟循環控制是由P指針來做的,不存在某個P1沒有與之配對的P2可以比的問題
四.總結
歸並排序多用於需要外部排序的場景,除此之外當內部排序需要保證穩定性時也采用歸並排序(不要求穩定性的內部排序一般采用快排或者堆排序,前者在待排序序列基本有序時效率低,后者堆的維護是個問題)