归并排序: 将序列首先进行分解,分解到每组只有一个元素,然后对这相邻两组进行合并,知道合并为一整个序列,时间复杂度:
nlog2n
,整个思路类似于Shell排序。
再看归并排序之前我们首先看一下将两个有序的序列合并为一个序列:
function MergeTwiceSort (arr1, arr2) {
var len1 = arr1.length,
len2 = arr2.length,
i = 0,
j = 0,
k = 0,
arr = Array(len1 + len2);
while (i < len1 && j < len2) {
if (arr1[i] < arr2[j]) {
arr[k++] = arr1[i++];
} else {
arr[k++] = arr2[j++];
}
}
while (i < len1) {
arr[k++] = arr1[i++];
}
while (j < len2) {
arr[k++] = arr2[j++];
}
return arr;
}
这个如果懂了的话,那证明我们就已经懂得了归并排序的归并排序合并,那下面我们来看拆分,我们将gap
作为我们每组的个数,组成的新排好序的数组的元素数那么就为2 * gap
,我们举一个例子来说明一下:
假若我们需要排序的数组为[1, 4, 44, 5, 0, 8, 10]
gap = 1
1,4
为一组5,44
为一组 0, 8
为一组10
为一组
gap = 2
1, 4, 5, 44
为一组0, 8, 10
为一组
gap = 4
1, 4, 5, 44, 0, 8, 10为一组
还有一个mid
也就是每组的中间值,这个值为i + gap - 1
,也就是在合并时,我们将mid
前看为一组,mid
后看为一组,两组都是有序数组,这就可以应用我们上面的那个合并函数,下面来看完整的代码:
function MergeSort (arr) {
for (var gap = 1, len = arr.length; gap < len; gap *= 2) {
MergeResolve(arr, gap, len);
}
function MergeResolve (arr, gap, length) {
var i;
for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap) {
MergeArray(arr, i, i + gap - 1, i + 2 * gap - 1);
}
// 假若后面的个数小于前待排序数组的元素个数
if (i + gap - 1 < length) {
MergeArray(arr, i, i + gap - 1, length - 1);
}
}
function MergeArray (arr, first, mid, last) {
var m = mid,
n = last,
i = first,
j = mid + 1,
k = 0,
temp = [];
while (i <= m && j <= n) {
if (arr[i] < arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= m) {
temp[k++] = arr[i++];
}
while (j <= n) {
temp[k++] = arr[j++];
}
for (i = 0; i < k; i++) {
arr[first + i] = temp[i];
}
}
}