上篇博客我們主要聊了堆排序的相關內容,本篇博客,我們就來聊一下歸並排序的相關內容。歸並排序主要用了分治法的思想,在歸並排序中,將我們需要排序的數組進行拆分,將其拆分的足夠小。當拆分的數組中只有一個元素時,則這個拆分的數組是有序的。然后我們將這些有序的數組進行兩兩合並,在合並過程中進行比較,合並生成的新的數組仍然是有序的。然后再次將合並的有序數組進行合並,重復這個過程,知道整個數組是有序的。
下方我們先給出兩個有序數組合並的示意圖以及代碼,然后給出歸並排序的相關內容。歸並排序其實就是拆分+合並。廢話少說,開始今天的內容。
一、合並兩個有序數組
在本篇博客的第一部分我們先給出合並兩個有序數組的示意圖以及相關代碼,在歸並排序時,我們會使用到此部分的內容。下方會給出兩個有數數組的合並,並且會給出相應的代碼實現。
1.有序數組合並的示意圖
因為兩個有序數組在合並后的新的數組仍然是有序的,所以我們需要對有序數組中的元素進行比較。每次從兩個數組中取出最小的那個元素,然后將兩個元素進行比較,將最小的那個元素放入到新的數組中。下方就是有序數組合並的示意圖。
-
首先從兩個有序數組中取出最小的值,如下所示。我們將9和10取出后進行比較,將較小的9存入我們新的數組中。
-
重復上個步驟,如果有一個數組中的元素被取完,將另一個數組中剩余的元素直接追加到我們的新的數組中即可。
2.代碼實現
根據上述示意圖給出相關的代碼實現並不困難,下方就是上述過程的代碼實現。下方這個mergeArray()函數,就是將兩個有序數組合並成一個新的有序數組的具體代碼實現。mergeArray()的兩個參數就是即將合並的兩個有序數組,而返回值就是合並后新的有序的數組。代碼比較簡單,在此就不做過多贅述了。
二、歸並排序
上述實現完兩個有序數組合並成新的有序數組完畢后,接下來就該歸並排序出場了。在歸並排序過程中,會使用到上述的內容。因為我們將無序數列進行分割后,就會不斷調用上述的合並代碼,將小的有序的數組合並成較大的有序數組,再次合並,直到我們原始的數組是有序的為止。下方會給出相應的示意圖以及歸並排序的Swift代碼實現。
1.歸並排序示意圖
下方就是我們歸並排序的示意圖,稍后的代碼實現也是根據下方的示意圖來寫的。所以對下方示意圖的充分理解還是很有必要的。在下方示意圖中,從上往下就是我們歸並排序的整個過程。我們需要排序的序列為[62, 88, 58, 47, 62, 35, 73, 51, 99, 37, 93]。下方是對每一步的解析:
- 首先我們將需要排序的序列進行拆分,拆分成足夠小的數組。也就是拆分的數組中只有一個元素。無序數組拆分的所有數組因為其中只含有一個元素,所以都是有序的。我們就可以對這些有序的小數組進行合並了。
- 將拆分的多個有序數組調用第一部分實現的mergeArray()函數進行兩兩合並,合並后的新數組仍然是有序的。我們再次對這些合並產生的數組進行兩兩合並,直到所有被拆分的數組有重新被合並成一個大數組位置。這個重新合並生成的數組就是有序的,也就是歸並排序所產生的有序序列。
下方就是拆分+多次合並的詳細過程,最終我們得到的就是一個有序序列。如下所示:
2、上述過程的代碼實現
根據上述的示意圖,我們給出相應的代碼實現應該是比較容易的。就是將我們的無序數組進行拆分,然后進行多次合並,最后合並成一個大的有序數組。下方代碼就是對上述過程的描述。
- 在下方代碼中的第一個框中就是將我們的無序數組進行拆分。被拆分的小的有序的數組存入到tempArray中,便於我們下方遍歷進行合並。
- 第二個框就是對tempArray中被拆分的數組進行遍歷,在遍歷的過程中進行兩兩合並,將合並的數組再次存入到tempArray中,直到tempArray中只含有一個數組為止。
而tempArray最終的數組就是歸並排序的最終結果。下方是整個過程,代碼並不復雜。
上述代碼的實現在有些數據結構的教程上是使用遞歸實現的,即使是不使用遞歸實現也比上述代碼要麻煩。
三、測試用例
對上述代碼的測試我們仍然會使用到我們之前的測試用例,因為上述排序類仍然遵循我們之前定義的SortType協議。下方就是本篇博客的測試用例,也是所有排序方式的測試用例。這個MergeSort類就是我們歸並排序的類。
上述用例的輸出結果如下,從輸出結果中,我們就能明顯的看出拆分和合並的整個過程。如下所示:
本篇博客對堆排序的介紹就先到這兒,下篇博客我們將會介紹“快速排序”的詳細內容。本篇博客的相關代碼依然會在github上進行分享,下方是github分享地址,如下所示:
github代碼分享地址:https://github.com/lizelu/DataStruct-Swift/tree/master/AllKindsOfSort