--- tags: 演算法, LeetCode disqus: HackMD --- # 合併排序(Merge Sort) > 此演算法為**Divide and Conquer**又稱為分而治之的經典範例 如下圖所示,合併排序是將原始數組不斷地二分分割,直到各個子數組都只剩下一個元素,然後再將這些子數組合併在一起排序,最後得到有序的數組。 ![](https://i.imgur.com/Zlsy1ml.gif) ## 虛擬碼 首先,如果傳入的數組長度小於等於`1`,則直接返回數組本身。如果不是,則將數組分為左半部分和右半部分,分別遞迴調用`mergeSort()`函數排序,最後將兩個排序好的數組合併在一起。 ```pseudocode= function mergeSort(arr): if arr.length <= 1: return arr else: mid = arr.length / 2 left = arr[0...mid] right = arr[mid...end] return merge(mergeSort(left), mergeSort(right)) ``` 在`merge()`函數中,創建一個空的結果數組,然後不斷將左半部分和右半部分的第一個元素進行比較,將較小的元素添加到結果數組中,直到左半部分或右半部分全部添加到結果數組中。最後將剩餘的元素添加到結果數組中。 ```pseudocode= function merge(left, right): result = [] while left and right are not empty: if left[0] < right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) return result + left + right ``` ## 程式碼 ```javascript= function merge(left, right) { let result = []; while (left.length > 0 && right.length > 0) { if (left[0] < right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } return result.concat(left, right); } function mergeSort(arr) { if (arr.length <= 1) return arr; let mid = Math.floor(arr.length / 2); let left = arr.slice(0, mid); let right = arr.slice(mid); return merge(mergeSort(left), mergeSort(right)); } let sortArr = mergeSort([1,4,5,2,3,8,7,9,10]); console.log(sortArr); // [1, 2, 3, 4, 5, 7, 8, 9, 10] ``` ## 複雜度 ### 時間複雜度 $O(nlogn)$ 因為每次將數組分成兩半進行排序,並且在合併的過程中需要遍歷整個數組,所以時間複雜度是`O(n log n)`。 ### 空間複雜度 $O(n)$ 因為需要額外創建兩個數組來存儲左半部分和右半部分,所以空間複雜度是`O(n)` ## 實戰 [912. Sort an Array](https://leetcode.com/problems/sort-an-array/) 給你一個整數陣列`nums`,請將陣列以升序排列並返回。您必須在`O(nlog(n))`時間複雜度內解決此問題,並使用較小的空間複雜度。 ![](https://i.imgur.com/FK8DZ1A.jpg) ### code ```javascript= /** * @param {number[]} nums * @return {number[]} */ var sortArray = function(nums) { function merge(left, right){ let result = [] while(left.length > 0 && right.length > 0){ if (left[0] > right[0]){ result.push(right.shift()) } else { result.push(left.shift()) } } return result.concat(left, right) } if (nums.length <= 1) return nums let mid = Math.floor(nums.length / 2) let left = nums.slice(0, mid) let right = nums.slice(mid) return merge(sortArray(left), sortArray(right)) }; ``` ## 來源 [資料結構與演算法 (JavaScript)](https://www.udemy.com/course/algorithm-data-structure/) > [name=@joe94113] [time=Tue, JAN 30, 2023 10:00 PM] [color=#907bf7]