合并函数
// 合并函数
const merge = (arr, l, m, r) => {
// 辅助数组
let help = [];
// 辅助数组下标
let i = 0;
// 两个指针分别指向需要合并的两个数组
let p1 = l;
let p2 = m + 1;
// 两个数组都没有越界
while (p1 <= m && p2 <= r) {
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
// p2越界
while (p1 <= m) {
help[i++] = arr[p1++];
}
// p1越界
while (p2 <= r) {
help[i++] = arr[p2++];
}
// 拷贝回去
for (let i = 0; i < help.length; i++) {
arr[l + i] = help[i]; // 这个 l 很重要
}
};
合并思路:
定义一个辅助数组,和三个指针(一个指向辅助数组,一个指向数组1,一个指向数组2),进行比较赋值给辅助数组并进行指针移动。值得注意的是拷贝回去的时候是要从l左指针上开始拷贝
写法1 递归写法
递归函数
// 排序函数
const fn = (arr, l, r) => {
if (l == r) return;
let mid = l + ((r - l) >> 1);
fn(arr, l, mid);
fn(arr, mid+1, r);
merge(arr, l, mid, r);
};
思路
将数组一分为二,分别递归排序,在合并幅值回去
递归终止条件:数组只有一个数自带顺序
写法2 迭代写法
// 迭代写法
if (arr == null || arr.length < 2) return;
let N = arr.length;
let step = 1; // 步长
while (step < N) {
let L = 0;
while (L < N) {
// 找到中间值
let M = L + step - 1;
if (M >= N) { // 没有右边就跳过
break;
}
let R = Math.min(M + step, N - 1); // 有右边就看看够不够步长,不够步长就剩下的全部进行合并
merge(arr, L, M, R);
L = R + 1; // 从R在开始
}
if (step > N / 2) {
break;
}
step *= 2;
}
思路
定义一个步长,对数组从左往右,逐次以步长进行分为左右数组进行合并
特殊情况:
没有右边,跳过留给下一个循环合并
有右边,但是不够步长,直接合并