做者:Abhilash Kakumanu翻譯:瘋狂的技術宅javascript
原文:https://stackabuse.com/merge-...前端
未經容許嚴禁轉載java
在本文中,咱們學習 Merge Sort 背後的邏輯,並用 JavaScript 實現。最後,在空間和時間複雜度方面將歸併排序與其餘算法進行比較。程序員
歸併排序使用分而治之的概念對給定的元素列表進行排序。它將問題分解爲較小的子問題,直到它們變得足夠簡單以致能夠直接解決爲止。面試
如下是歸併排序的步驟:算法
以數組 [4, 8, 7, 2, 11, 1, 3]
爲例,讓咱們看一下歸併排序是如何工做的:segmentfault
首先實現一個將兩個已排序子數組合併爲一個已排序數組的函數 merge()
。要注意着兩個子數組是已經被排好序的,這一點很是重要, merge()
函數只用於其進行合併。數組
能夠經過遍歷這兩個子數組來實現:服務器
function merge(left, right) { let arr = [] // 若是任何一個數組爲空,就退出循環 while (left.length && right.length) { // 從左右子數組的最小元素中選擇較小的元素 if (left[0] < right[0]) { arr.push(left.shift()) } else { arr.push(right.shift()) } } // 鏈接剩餘的元素,防止沒有把兩個數組遍歷完整 return [ ...arr, ...left, ...right ] }
在這個函數中,經過把兩個排好序的子數組(left
、right
)合併來得到一個排好序的大數組。首先,建立一個空數組。以後在 left
和 right
兩個子數組中最小元素中的較小的一個,並將其添加到空數組。咱們只須要檢查 left
和 right
子數組中的第一個元素,由於它們是已排好序的。微信
在這個過程當中,從子數組中刪除了被選擇的元素(經過 shift()
函數實現)。繼續這個過程,直到其中一個子數組變爲空。最後把非空子數組的剩餘元素(由於它們已經被排序)插入主數組的最後面。
如今有了合併兩個已排序數組的代碼,接下來爲實現歸併排序算法的最終代碼。這意味着要繼續分割數組,直到最終只包含一個元素的數組爲止:
function mergeSort(array) { const half = array.length / 2 if(array.length < 2){ return array } const left = array.splice(0, half) return merge(mergeSort(left),mergeSort(array)) }
在代碼中先肯定中點,並用 splice()
函數將數組分爲兩個子數組。若是元素數量爲奇數,則左側的元素數量會少一個。不斷的劃分數組,直到剩下單個元素的數組(array.length < 2
)。而後用以前實現的 merge()
函數合併子數組。
代碼實現後用前面的用例測試一下:
array = [4, 8, 7, 2, 11, 1, 3]; console.log(mergeSort(array));
輸出符合預期:
1,2,3,4,7,8,11
歸併排序的最差時間複雜度爲 $O(n\\log n)$,與快速排序的最佳情時間複雜度相同。歸併排序是目前最快的排序算法之一。
與快速排序不一樣,歸併排序不是in-place排序算法,這意味着除了輸入數組以外,它還會佔用額外的空間。這是由於咱們使用了輔助數組來存儲子數組。歸併排序的空間複雜度爲 $O(n)$。
歸併排序的另外一個優勢是很是適合多線程,由於每一個被劃分出的一半均可以單獨排序。另外一種常見的減小歸併排序運行時間的方法是在到達相對較小的子數組時(大約 7 個元素)使用插入排序。這是由於插入排序在處理小型或幾乎排好序的數組時表現很是好。
在本文中,咱們瞭解了Merge Sort算法背後的邏輯,並用 JavaScript 實現。它是基本排序算法之一,能夠幫助咱們更好的瞭解分治法策略。