标签:sort 算法 时间 依次 需要 好的 new sort函数 load
归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为 {\displaystyle O(n\log n)} {\displaystyle O(n\log n)}(大O符号)。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
核心代码 ( 使用自顶向下 )
//合并两个数组,使得新数组有序
const __merge = (leftArr, rightArr) => {
const newArr = [];
while (leftArr.length && rightArr.length) {
if (leftArr[0] < rightArr[0]) {
newArr.push(leftArr.shift());
} else {
newArr.push(rightArr.shift());
}
}
//若rightArr比leftArr短,则将leftArr剩下的有序数字依次push
while (leftArr.length) {
newArr.push(leftArr.shift());
}
//若leftArr比rightArr短,则将rightArr剩下的有序数字依次push
while (rightArr.length) {
newArr.push(rightArr.shift());
}
return newArr;
}
//递归使用归并排序
const __mergeSort = (arr) => {
if (arr.length === 1) {
return arr;
}
const middle = Math.floor(arr.length / 2),
leftArr = arr.slice(0, middle),
rightArr = arr.slice(middle);
const sortedLeftArr = __mergeSort(leftArr);
const sortedRightArr = __mergeSort(rightArr);
return __merge(sortedLeftArr, sortedRightArr);;
}
测试实例使用50000的完全随机整数进行排序,结果显示归并排序比插入排序速度快。但是如果我们在一个数据完全有序的环境下,我们知道插入排序的时间复杂度会将为O(n),所以这种情况下归并排序的速度还会比插入排序的速度快吗?
测试代码如下
//在50000条完全有序的数据下,归并排序与插入排序速度比较
let n = 50000;
const arr = SortTestHelper.generateSortedArray(n);
const arr2 = SortTestHelper.cloneArr(arr);
SortTestHelper.testSort(‘inserction sort‘, insertionSort, arr, n);
mergeSort(arr2);
测试结果,归并排序耗时为 100ms-120ms,而插入排序耗时在 0ms-1ms之间。
回顾上面的归并排序的核心代码
//递归使用归并排序,对arr[l.....r]的范围进行排序
const __mergeSort = (arr) => {
if (arr.length === 1) {
return arr;
}
const middle = Math.floor(arr.length / 2),
leftArr = arr.slice(0, middle),
rightArr = arr.slice(middle);
const sortedLeftArr = __mergeSort(leftArr);
const sortedRightArr = __mergeSort(rightArr);
return __merge(__mergeSort(leftArr), __mergeSort(rightArr));
这里我们递归调用__mergeSort
,在对两个部分进行归并排序之后,我们没有管两个部分的顺序如何就直接调用__merge
函数。但是我们设想一下此时 sortedLeftArr
的最后一个元素值如果比sortedRightArr
第一个元素的值小,那么说明 sortedLeftArr
整体是比 sortedRightArr
小的( 因为归并过程__mergeSort
能确保当前的归并数组是有序的 ),那么我们就不需要__merge
,对于数组的合并我们使用concat
即可
//`sortedLeftArr`的最后一个元素值如果比`sortedRightArr`第一个元素的值小
//则这个arr就是有序的,不需要 __merge。
// __mergeSort函数确保sortedLeftArr和sortedRightArr是有序的
sortedLeftArr = [1,2,3,4,5,6]
sortedRightArr = [7,8,9,10]
优化后代码
//递归使用归并排序
const __mergeSort = (arr) => {
if (arr.length === 1) {
return arr;
}
const middle = Math.floor(arr.length / 2),
leftArr = arr.slice(0, middle),
rightArr = arr.slice(middle);
const sortedLeftArr = __mergeSort(leftArr);
const sortedRightArr = __mergeSort(rightArr);
//优化版本
//判断 sortedLeftArr的最后一个元素与sortedRightArr的第一个元素的大小
//若前者大,则只需要归并
//否则只需要concat返回,因为 [1,2,3,4,5] [6,7,8,9,10]
if (sortedLeftArr[sortedLeftArr.length - 1] > sortedRightArr[0]) {
return __merge(sortedLeftArr, sortedRightArr);
} else {
return sortedLeftArr.concat(sortedRightArr);
}
}
实测同样50000条完全有序的整数下,优化后的归并排序耗时约在 40ms-50ms
可以在归并排序到某个部分时候调用插入排序以加快排序的速度。但是上述归并排序的实现是基于二分法切割数组,最后一次比较两个归并好的数组的值大小。
标签:sort 算法 时间 依次 需要 好的 new sort函数 load
原文地址:https://www.cnblogs.com/jianzhihao/p/9348247.html