How to “pause” during merge sort to visualize JS p5js

南笙酒味 提交于 2019-12-11 06:02:05

问题


Im working on a sorting visualizer using p5.js, and I need to know if its possible to slow down merge sort so it can be drawn slower. Im currently trying to use the sleep function below to slow down they merge function, but I get

Uncaught TypeError: a.slice is not a function.

Am I just making a silly mistake, or am I approaching the problem incorrectly?

let rectWidth;
let depth = 0;

function setup() {
    let numOfRects = document.getElementById('numOfRects').value;
    let width = document.getElementById('canvas').offsetWidth;
    let height = document.getElementById('canvas').offsetHeight;
    let canvas = createCanvas(width, height);

    rectWidth = floor(width / numOfRects);

    canvas.parent('canvas');
    values = new Array(floor(width / rectWidth));

    for (let i = 0; i < values.length; i++) {
        values[i] = random(height);
    }

    frameRate(1);
}

function draw() {
    background(23);
    values = mergeSort(values, depth);
    depth++;
    for (let i = 0; i < values.length; i++) {
        stroke(0);
        fill(255);
        rect(i * rectWidth, height - values[i], rectWidth, values[i]);
    }

}


function mergeSort(a, d) {
    if (a.length <= 1) {
        return a;
    }

    d--;
    if (d < 1) {
        return (a);
    }
    var mid = Math.round((a.length / 2));
    var left = a.slice(0, mid);
    var right = a.slice(mid);

    let leArr = mergeSort(left, d);
    let riArr = mergeSort(right, d);
    return merge(leArr, riArr);
}

async function merge(left, right) {
    sorted = [];
    while (left && left.length > 0 && right && right.length > 0) {
        if (left[0] <= right[0]) {
            sorted.push(left.shift());
        } else {
            sorted.push(right.shift());
        }
    }

    await sleep(50);

    return sorted.concat(left, right);
}

async function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

回答1:


A sleep inside your merge algorithm makes no sense at all. Your draw function can just draw the final array which is returned by mergeSort. So even if you make the algorithm slower, you won't see any intermediate till mergeSort has not finished for the specified depth.

A possibility would be to do the Merge sort in a separate thread and to visualize in draw the current state of the array. But in this case you've to apply the sorting on the "original" array, rather than to create copies of the array (by slice) and to write them back to the original array at the end.

See the example:

let values = [];
let startSort = true;

function mergeSort(a) {
    // create copy of the array 
    copy = a.slice()
    // asynchronous sort the copy
    mergeSortSlice(copy, 0, copy.length);
    return;
}

async function mergeSortSlice(a, start, end) {
    if (end-start <= 1)
        return;
    
    var mid = Math.round((end+start) / 2);

    // wait till divides are sort 
    await mergeSortSlice(a, start, mid);
    await mergeSortSlice(a, mid, end);

     // merge divides
    let i = start, j = mid;
    while (i < end && j < end) {
        if (a[i] > a[j]) {
            let t = a[j]; a.splice(j, 1); a.splice(i, 0, t);
            j ++;
        }
        i ++;
        if (i==j) j ++;

        // copy back the current state of the sorting
        values = a.slice();
        
        // slow down
        await sleep(100);
    }

    // restart
    if (start == 0 && end == a.length) {
        await sleep(2000);
        startSort = true;
    }
}

async function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function setup() { 
    createCanvas(600, 190);
    frameRate(60);
}

let numOfRects = 15;
let rectWidth;
function draw() {
    if (startSort) {
        startSort = false;
        
        rectWidth = floor(width / numOfRects);
        values = new Array(floor(width / rectWidth));
        for (let i = 0; i < values.length; i++) {
            values[i] = random(height);
        }

        mergeSort(values);
    }

    background(23);
    stroke(0);
    fill(255);
    for (let i = 0; i < values.length; i++) {
        rect(i * rectWidth, height - values[i], rectWidth, values[i]);
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>


来源:https://stackoverflow.com/questions/58434991/how-to-pause-during-merge-sort-to-visualize-js-p5js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!