一、分治思想
利用分治思想解决问题,我们一般分三步走:
- 分解子问题
- 求解每个子问题
- 合并子问题的解,得出大问题的解
归并排序和快速排序就是用了这种思想。
二、归并排序
1.思路分析
- 分解子问题:将需要被排序的数组从中间分割为两半,然后再将分割出来的每个子数组各分割为两半,重复以上操作,直到单个子数组只有一个元素为止。
- 求解每个子问题:从粒度最小的子数组开始,两两合并、确保每次合并出来的数组都是有序的。(这里的“子问题”指的就是对每个子数组进行排序)。
- 合并子问题的解,得出大问题的解:当数组被合并至原有的规模时,就得到了一个完全排序的数组
2.排序过程演示
例:[8, 7, 6, 5, 4, 3, 2, 1]
-
首先重复地分割数组,整个分割过程如下:
[8, 7, 6, 5,| 4, 3, 2, 1] [8, 7,| 6, 5,| 4, 3,| 2, 1] [8,| 7,| 6,| 5,| 4,| 3,| 2,| 1]
-
接下来开始尝试解决每个子问题。将规模为1的子数组两两合并为规模为2的子数组,合并时确保有序
[7, 8,| 5, 6,| 3, 4,| 1, 2]
-
继续将规模为2的按照有序原则合并为规模为4的子数组:
[5, 6, 7, 8,| 1, 2, 3, 4]
-
最后将规模为4的子数组合并为规模为8的数组:
[1, 2, 3, 4, 5, 6, 7, 8]
3.代码实现
一直重复一个过程 分割、合并,涉及重复的可以采用递归。
归并排序在实现上依托的就是递归思想。
function mergeSort(arr) {
const len = arr.length
// 处理边界情况
if(len <= 1) {
return arr
}
// 计算分割点
const mid = Math.floor(len / 2)
// 递归分割左子数组,然后合并为有序数组
const leftArr = mergeSort(arr.slice(0