采用分治的办法将各个已经排序好的序列合并到一起
算法流程:
1、将序列切分成左右两个部分,然后继续对左右序列切分直到不能切分
2、对切分后的序列采用合并两个排序序列的办法两两合并
代码
首先我们写个合并两个有序序列的办法,这里我们实现对一个的[p, q]位置和[m, n] **进行合并 (q + 1 = m)
function merge(nums, p, q, m, n){let left = nums.slice(p, q + 1),right = nums.slice(m, n + 1)let x = 0, y = 0, i = 0while(x < left.length && y < right.length){if(left[x] <= right[y]){nums[p + i++] = left[x++]}else{nums[p + i++] = right[y++]}}while(x < left.length) nums[p + i++] = left[x++]while(y < right.length) nums[p + i++] = right[y++]return nums}
利用递归自定到底切分,然后自底而上进行合并
function MergeSort(nums, l, r){if(l == r) returnlet mid = (l + r) / 2 | 0 // 切分MergeSort(nums, l, mid)MergeSort(nums, mid + 1, r)merge(nums, l, mid, mid + 1, r) // 合并return nums}
时间复杂度(O(nlog(n)))
空间复杂度(O(n)) (不算栈空间的话)
当然我们可以不用递归来实现,用迭代来实现
算法流程:
1、以2、4、8、16…等长度来对原序列进行遍历
2、对每个范围内的元素,前半部分和后半部分进行两两归并
代码
**
function MergeSort(nums){let len = nums.lengthfor (let size = 1; size < len; size *= 2) {for (let low = 0; low < len - size; low += 2 * size) {merge(nums, low, low + size - 1, low + size, Math.min(low + 2 * size - 1, len - 1))}}return nums}
合并逻辑:
如长度为10的数组
第一次对(0、1),(2、3),(4,、5),(6、7),(8、9)进行合并
第二次对(0、1、2、3),(4,、5、6、7),(8、9)进行合并
第三次对(0、1、2、3、4,、5、6、7),(8、9)进行合并
第四次对(0、1、2、3、4,、5、6、7、8、9)进行合并
