📅  最后修改于: 2023-12-03 15:23:23.583000             🧑  作者: Mango
合并排序是一种十分常见的排序算法,其主要思路是将待排序的序列不断划分成更小的子序列,然后再将这些子序列逐一合并以生成最终的排序结果。虽然合并排序的时间复杂度较小,但是对于较大的数据集,其执行效率也会相应变低。为了更好地理解合并排序的过程,我们可以通过可视化实现来更直观地展示排序的过程。
首先,我们需要实现一个合并排序的函数。以下是一个基本的合并排序实现,其中 mergeSort(arr)
函数接收一个待排序的数组,并将其划分成多个长度为 1 的子序列,然后依次进行两两合并,直到最终生成完整的有序数组。
function mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(i < left.length ? left.slice(i) : right.slice(j));
}
接下来,我们需要将合并排序的过程可视化出来,以便更好地理解算法的执行过程和效率。在可视化中,我们可以通过不同颜色的条形图来表示不同元素的大小,并在每次合并后将相应部分的条形图颜色变化以表示排序的顺序变化。以下是一个基本的合并排序可视化实现示例:
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
function draw(arr) {
const bw = 10; // 每个条形图的宽度
const gap = 5; // 两个条形图之间的间隔
const bh = canvas.height - 10; // 条形图的高度
const bwgap = bw + gap; // 两个条形图加起来的宽度
context.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
context.fillStyle = '#000'; // 设置画笔颜色为黑色
for (let i = 0; i < arr.length; i++) {
const bh2 = bh * (arr[i] / Math.max(...arr)); // 计算条形图的高度
context.fillRect(i * bwgap, canvas.height - bh2, bw, bh2); // 绘制条形图
}
}
async function mergeSortVisual(arr) {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
const leftSorted = await mergeSortVisual(left);
const rightSorted = await mergeSortVisual(right);
const result = await mergeVisual(leftSorted, rightSorted);
return result;
}
async function mergeVisual(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
draw([...result, ...left.slice(i), ...right.slice(j)]);
await new Promise(resolve => setTimeout(() => resolve(), 10)); // 异步等待 10ms
}
return result.concat(i < left.length ? left.slice(i) : right.slice(j));
}
const data = Array.from({ length: 50 }, () => Math.floor(Math.random() * 100) + 1); // 生成长度为 50 的随机数据
mergeSortVisual(data);
在以上代码中,我们将生成的随机数据通过 mergeSortVisual()
函数进行排序,并利用 draw()
函数在每次排序后重新绘制条形图以实现可视化效果。为了避免程序在可视化过程中执行过快导致效果不清晰,我们在每次排序后通过 await new Promise(resolve => setTimeout(() => resolve(), 10))
表示程序暂停 10ms 再继续执行。
通过合并排序可视化的实现,我们更加清晰地掌握了合并排序算法的执行过程。同时,我们也将可视化作为一种更好地理解算法的手段,并通过 JavaScript 实现了一个简易的可视化程序。