标签:归并 子序列 new ret char 算法 har 如何 oct
对一个等待排序的数组A,以及排序函数sort,以及合并两个有序数组的函数merge。则 sort(A) = merge(sort(A1), sort(A2)),上面这个推导公式看起来是满足递归算法的重复条件。举个例子:
function sort(arr) {}
function merge(arr1, arr2) {}
// sort 的终止条件为数组arr长度为1
sort([1, 3, 9, 4]) = merge(sort([1, 3]), sort([9, 4]))
sort([1, 3, 9, 4]) = merge(
sort(merge(sort([1], sort[2]))),
sort(merge(sort([9], sort[4]))),
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>归并排序</title>
</head>
<body>
<script>
/**
* 将两个排好序的数组合并成一个新数组
* 时间复杂度 O(n)
*/
function merge(lArr, rArr) {
var result = []
while(lArr.length > 0 && rArr.length > 0) {
if (lArr[0] < rArr[0]) {
result.push(lArr.shift())
} else {
result.push(rArr.shift());
}
}
// 剩下的也要合并进去
result = result.concat(lArr).concat(rArr);
return result;
}
function msort(arr) {
// 递归排序的终止条件是,当前这个数组的长度为1,因为只有一个,那么肯定是排好序的
if (arr.length === 1) {
return arr
}
// 当然你可以将终止条件改为数组长度为2, 但是要确保返回的数组是有序的
// if (arr.length === 2) {
// if (arr[0] > arr[1]) {
// var t = arr[1]
// arr[1] = arr[0]
// arr[0] = t;
// }
// return arr
// }
// 分割成两个数组
var middle = Math.floor(arr.length / 2);
var lArr = arr.slice(0, middle);
var rArr = arr.slice(middle);
// 这两个数组如何排序, merge也是排序函数
return merge(msort(lArr), msort(rArr))
}
var items = [9, 7, 3, 5]
var res = msort(items)
console.log(res)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>归并排序</title>
</head>
<body>
<script>
function merge_pass(arr, temp, l, m, r) {
let lEnd = m - 1;
let pos = l;
while(l <= lEnd && m < r) {
if (arr[l] > arr[m]) {
temp[pos] = arr[m];
m++;
pos++;
} else {
temp[pos] = arr[l];
l++;
pos++;
}
}
while (l > lEnd && m < r) {
temp[pos] = arr[m++];
pos++;
}
while (l <= lEnd && m >= r) {
temp[pos] = arr[l++];
pos++;
}
}
function merge_sort(arr) {
let temp = [];
let N = arr.length;
let length = 1; // 子序列长度, 默认为1
let t; // 迭代次数
for(t = 0; Math.pow(2, t) < N;) {
// 将当前的分组各自排序
let l;
let guard = t % 2 === 0;
for(l = 0; l < N; l += length * 2) {
// l 为左侧数组的起始位置
// r 为右侧数组的边际
let r = (l + 2 * length) > N ? N : (l + 2 * length);
let m = (l + length) > N ? N : (l + length);
merge_pass(
guard ? arr : temp,
guard ? temp : arr,
l, m, r
);
}
// 下一轮比较
length = 2 * length;
t++;
}
if (t % 2 === 0) {
return arr
}
return temp
}
var arr = [9, 7, 3, 5, 4]
var res = merge_sort(arr)
console.log(res)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>归并排序</title>
</head>
<body>
<script>
function mergePass(arr = []) {
let temp = new Array(arr.length);
let N = arr.length;
let length = 1; // 将每个元素看作是相邻的数组长度为1。
let t; // 迭代深度。
for (t = 0; Math.pow(2, t) < N; t++ , length *= 2) { // 每次跳过的长度翻倍。
const even = t % 2 === 0; // 复用 arr 和 temp 来回赋值。
for (let left = 0; left < N; left += 2 * length) { // 左边数组起始位置 left 从0开始。
const middle = left + length < N ? left + length : left;
const right = left + (2 * length) < N ? left + (2 * length) : N;
merge(
even ? arr : temp,
even ? temp : arr,
left, middle, right
); // 合并每两个相邻的数组
}
}
if (t % 2 === 0) {
return arr;// 返回arr
}
return temp; // 返回 temp 。
}
function merge(arr, temp, left, middle, right) {
debugger;
// 通过右边数组的起始位置得到左边数组的结束位置。
const leftEnd = middle - 1;
while (left <= leftEnd && middle < right) {
// 如果‘指针’没有越界。
if (arr[left] > arr[middle]) {
// 如果左边数组第一个元素比右边数组第一个元素大。
// 将右边数组最小的放入有序数组 temp(初始值为空)。
temp[left + (middle - leftEnd - 1)] = arr[middle++];
} else {
// 将左边数组最小的放入有序数组 temp(初始值为空)。
temp[left + (middle - leftEnd - 1)] = arr[left++];
}
}
while (left > leftEnd && middle < right) {
// 如果左边数组放完了,右边数组还有元素。
temp[left + middle - leftEnd - 1] = arr[middle++];
// 那么依次将右边数组剩余的元素放入 temp。
}
while (left <= leftEnd && middle >= right) {
// 如果右边数组放完了,左边数组还有元素
temp[left + middle - leftEnd - 1] = arr[left++];
// 那么依次将左边数组剩余的元素放入 temp 。
}
debugger;
}
var items = [9, 7, 3, 5]
var res = mergePass(items)
console.log(res)
</script>
</body>
</html>
标签:归并 子序列 new ret char 算法 har 如何 oct
原文地址:https://www.cnblogs.com/gaollard/p/12326065.html