0
点赞
收藏
分享

微信扫一扫

算法:归并排序(MERGE-SORT)

含义

归并排序采用,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

首选是『』,将一个数组反复分为两个小数组,直到每个数组都只有一个元素(所以这里可以采用递归);

其实是『』,从最小数组开始,两两数组按大小顺序合并(左数组元素 left[0]与右数组元素right[0]依次比较,哪个比较小就将哪个数组的值放入新数组,然后再继续比较left[0]和right[1],或者是left[1]和right[0]。可以看出数组left,right都只需遍历一遍,所以对两个有序数组的排序的时间复杂度为O(n)。当有一个为空数组时,剩下一个肯定都是比新数组元素大的元素,直接放到新数组就好)

下面是图解:
在这里插入图片描述
时间复杂度分析:分的过程需要三步:log8 = 3,而每一步都需要遍历一次8个元素,所以8个元素共需要运行 8log8 次指令,那么对于 n 个元素,时间复杂度为 O(nlogn)。

合并相邻有序子序列(治)

在这里插入图片描述在这里插入图片描述

// 分:
function mergeSort(arr) { 定义拆分函数
	let len = arr.length;
	if (len < 2) {
		return arr;
	}
	let mid = Math.floor(len/2) // 数组长度/2
	let left = arr.slice(0, mid) // slice 方法返回一个新数组,slice(start, end),
								// 而 splice(index-数组位置, num-添加或删除的元素个数, item1, ...itemX-元素)会改变原来的数组
	let right = arr.slice(right, len)
	let mergeSortLeft = mergeSort(left) // 递归调用当前方法继续对数组进行拆分
	let mergeSortRight = mergeSort(right)
}
// 治:
const merge = (left, right) => { // 合并左右数组
	const result = [] 
	while(left.length && right.length) { // 必须两个数组都有元素再这样比较
		if (left[0] <= right[0]) { // 相等时也要加入此条件,不然排序会乱 
			result.push(left.shift()) // 将数组中第一个元素放入新数组中并在原来数组中删除这个元素
									  // shift()方法用于移除数组中的第一个值,并返回此元素,
		} else {
			result.push(right.shift())
		}
	}

	// 将剩余元素全部推进新数组
	while (left.length) {
		result.push(left.shift())
	}
	while (right.length) {
		result.push(right.shift())
	}
	// 或者也可以这样
	if (left.length) {
		result.push(...left)
	}
	if (right.length) {
		result.push(...right)
	}
}
	

归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

举报

相关推荐

0 条评论