排序算法-4(javascript) 归并排序的实现
2021-04-01 本文已影响0人
miao8862
归并排序实际是使用了分治再合并的思想:
-
分治:
它每轮会把数组分割成2分部分,如果分割的部分还很多数,可以按照这个方法继续分割,直到分割成简单序列(比如分割到剩最后一个数了,一个数的序列自然就是最简单的有序序列)。 -
合并:
这时候,对分割的最小部分开始,进行两两合并成有序序列,合并的实现方法是:- 创建一个左指针,指向一个分割的有序序列(比如是数组arr1, 长度为n)的初始位置0;
- 创建一个右指针,指向另一个分割的有序序列(数组arr2,长度为m)的初始位置0;
- 再创建一个m+n的空数组(res),用来存储此轮的有序结果;
- 比较两个指针的数,哪个小就放到res中,然后该指针右移;
- 重复4步骤操作,直到有一个有序序列已经全被放到到res中,另一个有序序列剩下的所有值就可以直接拼接在res后面了,这样一轮操作就结束了
- 然后,再对再一对分割部分重复做1-5步骤,直至所有分割部分都合并完,结束
下面通过例子来说明它的思想:
初始的无序数组:[ 8, 5, 4, 9, 6, 2, 1 ]
分割:
- 第1步,对半分,分成两组 [8, 5, 4, 9],[6, 2, 1],此时这两还不是有序数组
- 第2步,各自继续对半分,[8, 5, 4, 9]分成[8, 5]和[4, 9]; [6, 2, 1]被分割成[6, 2]和[1],发现除了[1]其它都发现还不是有序数组
- 第3步,各自继续对半分,[8, 5]分成[8]和[5],[4, 9]分成[4]和[9], [6, 2]分成[6]和[2],这下好了,所有的都是有序序列了[8],[5],[4],[9],[6],[2],[1]
合并: - 对各层最小部分进行合并[8],[5]合并成了有序序列[5, 8];[4],[9]合并成了有序序列[4, 9],[6]和[2]合并成了[2, 6],[1]这一步没有对象合并闲置
- 再向上一层合并,[5, 8]和[4, 9]合并成了[4, 5, 8, 9];[2, 6]和[1]合并成了[1, 2, 6]
- 再向上一层合并[4, 5, 8, 9] 和 [1, 2, 6] 合并成了 [1, 2, 4, 5, 6, 8, 9],此时,已经是个完整的有序序列了,结束
复杂度分析
- 时间复杂度:
- 分割过程每次步骤是n/2,所以时间复杂度为O(logn)
- 合并过程是遍历一个循环,O(n)
所以总的是O(nlogn)
- 空间复杂度:
要重新定义一个数组存放有结果,所以是O(n) - 稳定性:归并排序并不会改变相同元素的相对位置,所以是一个稳定的算法
代码实现
/**
* @description 递归实现归并排序
* @param arr: 初始的无序队列
* @return res: 被排好序的队列
*/
function mergeSort(arr) {
// 如果分割得只每剩一个值,自然已经是一个有序区间,直接返回
if(arr.length <= 1) return arr;
// 否则分割
let mid = 0;
mid = Math.floor((arr.length)/2)
console.log('mid:', mid);
// 左子序列
let left = arr.slice(0, mid)
// 递归获取左子序列的分割合并,得到最后一层的有序左子序列
left = mergeSort(left)
// 右子序列
let right = arr.slice(mid)
// 递归获取右子序列的分割合并,得到最后一层的有序右子序列
right = mergeSort(right)
return merge(left, right)
}
/**
* @description 合并算法
* @param left: 要被合并的有序数组1
* @param right: 要被合并的有序数组2
* @return arr: 被排序好的数组
*/
function merge(left, right) {
// 合并后存放的数组
let res = []
while(left.length && right.length) {
// 如果左子序列第1个数数比较小,弹出此数放到结果队列中
if(left[0] <= right[0]) {
res.push(left.shift())
// 否则,如果右子序列第1个数数比较小,弹出此数放到结果队列中
} else {
res.push(right.shift())
}
}
// 当一个子序列排序结束时,另一个子序列就不需要再遍历比较了,直接拼接到结果后
return res.concat(left, right)
}
// 查看所有结果
arr = [ 8, 5, 4, 9, 6, 2, 1 ]
let res = mergeSort(arr) // [1, 2, 4, 5, 6, 8, 9]
console.log("res:", res)
参考:
图灵社区:https://www.ituring.com.cn/book/miniarticle/62897
小象Web开发:https://baijiahao.baidu.com/s?id=1675262114341494342&wfr=spider&for=pc
排序算法系列文章传送门(未完,持续更新中):
排序算法-1(javascript) 冒泡、选择、插入、希尔排序的实现
排序算法-2(javascript) 快速排序的实现
排序算法-3(javascript) 堆排序的实现
排序算法-4(javascript) 归并排序的实现