Javascript 如何通过带有交换的数组直观地显示合并排序算法?
我在使用我的算法尝试直观地显示合并排序过程时遇到问题。对于我过去的数组,我可以将交换与Bubblesort等算法一起使用,但合并排序更难,因为它是递归算法。我曾考虑将merge函数中的元素推送到另一个数组中,但它不会按排序顺序返回,并且最后与排序数组进行比较不是真正的mergesort。如果有人能帮我,那就太棒了。以下是我目前的算法:Javascript 如何通过带有交换的数组直观地显示合并排序算法?,javascript,reactjs,Javascript,Reactjs,我在使用我的算法尝试直观地显示合并排序过程时遇到问题。对于我过去的数组,我可以将交换与Bubblesort等算法一起使用,但合并排序更难,因为它是递归算法。我曾考虑将merge函数中的元素推送到另一个数组中,但它不会按排序顺序返回,并且最后与排序数组进行比较不是真正的mergesort。如果有人能帮我,那就太棒了。以下是我目前的算法: export const doMergeSort = (array) => { function merge(leftArr, rightArr){
export const doMergeSort = (array) => {
function merge(leftArr, rightArr){
const output = [];
let leftIndex = 0;
let rightIndex = 0;
while(leftIndex < leftArr.length && rightIndex < rightArr.length){
const leftEl = leftArr[leftIndex];
const rightEl = rightArr[rightIndex];
if(leftEl < rightEl){
output.push(leftEl);
leftIndex++;
}
else{
output.push(rightEl);
rightIndex++;
}
}
return ( [...output, ...leftArr.slice(leftIndex), ...rightArr.slice(rightIndex)]);
};
function mergeSort(array) {
if(array.length <= 1){
return array;
}
const middleIndex = Math.floor(array.length / 2);
const leftArr = array.slice(0, middleIndex);
const rightArr = array.slice(middleIndex, array.length);
return merge(
mergeSort(leftArr),
mergeSort(rightArr),
);
}
return mergeSort(array);
}
export default mergeSortAnimations;
export const doMergeSort=(数组)=>{
函数合并(leftArr、rightArr){
常量输出=[];
设leftIndex=0;
设rightIndex=0;
while(leftIndex if(array.length这是我不久前做的事情。使用单个对象跟踪每个函数级别的数组,所有这些都封装在一个类似闭包的环境中。还使用生成器,以便在每次交换之间暂停
const getMergeSortGenerator = (object: SortingVisualizerController) => {
// Doing this so that I can pause at any swap for a while using
// setTimeout, or setInterval
function* mergeSortGenerator(start: number, end: number) {
if (start === end) {
return;
}
const mid = Math.floor((start + end) / 2);
// Merge sort on first half
for (const _ of mergeSortGenerator(start, mid)) {
yield;
}
// Merge sort on second half
for (const _ of mergeSortGenerator(mid + 1, end)) {
yield;
}
// Merge both the halves
for (const _ of merge(start, mid, mid + 1, end)) {
yield;
}
// Plot array after each merge.
object.plotArray();
}
// Standard merge algorithm
function* merge(start1: number,
end1: number,
start2: number,
end2: number) {
const newArray = []; // Why? Explained below
let index1 = start1;
let index2 = start2;
// Keep merging while the both sub-arrays have elements
while (index1 <= end1 && index2 <= end2) {
if (object.array[index1] < object.array[index2]) {
newArray.push(object.array[index1++]);
} else {
newArray.push(object.array[index2++]);
}
// Mark the swap color as red
object.color[index1] = object.color[index2] = "red";
// Plot the swap
plotArray(newArray, start1, index1, index2, end1);
// Reset the swap color
object.color[index1] = object.color[index2] = "white";
yield;
}
// If first sub-array has elements left, just add
// them directly
while (index1 <= end1) {
newArray.push(object.array[index1++]);
object.color[index1] = "red";
plotArray(newArray, start1, index1, index2, end1);
object.color[index1] = "white";
yield;
}
// If second sub-array has elements left, just add
// them directly
while (index2 <= end2) {
newArray.push(object.array[index2++]);
object.color[index2 - 1] = "red";
plotArray(newArray, start1, index1, index2, end1);
object.color[index2 - 1] = "white";
yield;
}
// I could not do this in-place because doing each swap
// in-place would mean that, I have to shift other elements
// by 1 to left and that would be a bit tricky to handle.
// So, I managed swaps in the different array, and when the merge
// was completed, I substituted the swaps back in the original
// array.
newArray.forEach((value, index) => {
object.array[index + start1] = value;
});
}
function plotArray(
array: number[],
startOfFirstHalf: number,
index1: number, // First half sorted till this index
index2: number, // Second half sorted till this index
endOfFirstHalf: number,
) {
// Need this because I am using an intermediate array to
// perform the merge.
const visualizingArray = [
...object.array.slice(0, startOfFirstHalf),
...array.slice(0, array.length),
...object.array.slice(index1, endOfFirstHalf + 1),
...object.array.slice(index2, object.array.length),
];
object.plotArray(visualizingArray);
}
return mergeSortGenerator(0, object.array.length - 1);
};
export default class SortingVisualizerController {
arraySize = 166;
minimumHeightOfPipe = 2;
selectedSortAlgorithm = "merge";
animationRunning = false;
constructor(canvasEl: HTMLCanvasElement) {
this.color = [];
this.array = [];
// Canvas is just a class that has some utility functions for drawing on the canvas.
// Find more about it here: https://github.com/vighnesh153/canvas-api-illustrations/blob/master/src/models/canvas.ts
this.canvas = new Canvas(canvasEl);
this.randomizeArray();
}
isArraySorted() {
let prev = -Infinity;
let isSorted = true;
this.array.forEach((value) => {
if (value < prev) {
isSorted = false;
}
prev = value;
});
return isSorted;
}
startAnimation() {
if (this.isArraySorted()) {
return;
}
this.animationRunning = true;
const generatorObject = getMergeSortGenerator(this);
const timer = 30;
this.interval = setInterval(() => {
// Keep yielding, so that we pause after each swap
if (generatorObject.next().done) {
this.stopAnimation();
}
}, timer);
}
clearBackground() {
const {width, height} = this.canvas;
this.canvas.drawFilledRect(0, 0, width, height, "black");
}
generateRandomArray() {
this.array = [];
this.color = [];
const maxHeight = this.canvas.height - 50;
const { floor, random } = Math;
for (let i = 0; i < this.arraySize; i++) {
this.array.push(floor(random() * maxHeight) + 20);
this.color.push("white");
}
}
plotArray(array?: number[]) {
if (array === undefined) {
array = this.array;
}
this.clearBackground();
array.forEach((height: number, index: number) => {
const x = index * 3;
const y = this.canvas.height - value;
const width = 2;
const color = this.color[index];
this.canvas.drawFilledRect(x, y, width,
height + this.minimumHeightOfPipe, color);
});
}
randomizeArray() {
this.generateRandomArray();
this.plotArray();
}
stopAnimation() {
this.animationRunning = false;
clearInterval(this.interval);
this.resetColor();
this.plotArray();
}
resetColor() {
this.color.forEach((v, i) => {
this.color[i] = "white";
});
}
}
const getMergeSortGenerator=(对象:SortingVisualizationRController)=>{
//这样做,我就可以暂停在任何交换一段时间使用
//setTimeout或setInterval
函数*mergeSortGenerator(开始:编号,结束:编号){
如果(开始==结束){
返回;
}
const mid=数学楼层((开始+结束)/2);
//上半部分合并排序
用于(合并或发电机的常数(开始,中间)){
产量
}
//下半部分合并排序
用于(合并器生成器的常数(中间+1,结束)){
产量
}
//合并两半
用于(合并常数(开始、中间、中间+1、结束)){
产量
}
//每次合并后打印数组。
plotArray();
}
//标准合并算法
函数*合并(开始1:编号,
end1:数字,
开始2:编号,
(完){
const newArray=[];//为什么?解释如下
设index1=start1;
设index2=start2;
//在两个子数组都有元素时保持合并
while(index1{
常数x=指数*3;
const y=this.canvas.height-值;
常数宽度=2;
const color=this.color[index];
这个.canvas.drawFilledRect(x,y,width,
高度+管道的最小高度(颜色);
});
}
randomizeArray(){
这个.generateRandomArray();
这个.plotArray();
}
停止动画(){
this.animationRunning=false;
clearInterval(这个.interval);
这是resetColor();
这个.plotArray();
}
重置颜色(){
this.color.forEach((v,i)=>{
此.color[i]=“白色”;
});
}
}