Java Script Sorting algorithm visualizer

佐手、 提交于 2021-01-27 06:07:39

问题


k = []
len = 100;
time = true

cont = document.getElementsByClassName("cont")[0];
cont.innerHTML = "";
for (let i = 0; i < len; i++) {
    t = Math.round(Math.random() * 800 ) + 5
    k.push(t);
    cont.innerHTML += "<div class='block' style = 'height:" + t + "px'></div>"
}


function reset(){
    k = []
    cont.innerHTML = "";
    for (let i = 0; i < len; i++) {
        t = Math.round(Math.random() * 800 ) + 5
        k.push(t);
        cont.innerHTML += "<div class='block' style = 'height:" + t + "px'> </div>"
    }

}

function bubble(){
    function iloop(i){
        if(i < len){
        setTimeout(function(){
            function jloop(j){
                if(j < len){
                setTimeout(function(){
                    if (k[j] > k[j + 1]) {
                        let tmp = k[j];
                        k[j] = k[j + 1];
                        k[j + 1] = tmp;
                    }
                    cont.innerHTML = "";
                    for (let p = 0; p < len; p++) {
                        cont.innerHTML += "<div class='block' style = 'height:" + k[p] + "px'></div>"
                    }
                    j++;
                    jloop(j);
                }, 100);
                }
            }
            jloop(0);



            i++;
            iloop(i);
        }, 100);
        }
    }
    iloop(0);
}
.cont {
  width: 100%;
  height: 900px;
  display: block;
  background-color: pink;
  padding: 0px;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -ms-flex-line-pack: center;
  align-content: center; }
  .cont .block {
    display: inline-block;
    width: 10px;
    margin: auto 1px;
    background-color: red;
    font-size: 5px;
    bottom: 0px; }
<button class="reset" onclick="reset()">Reset Array
</button> 
<button class="bubble" onclick="bubble()">Bubble Sort
</button> 
<div class="cont"> 
 </div>

I am using this simple code to make a javascript visualizer for sorting algorithm but the problem is that it is very choppy and skips multiples frames while running even at a delay of 100ms. I have an i7 7700hq and gtx 1060 so I know that the problem is mostly not my laptop but my approach to it so what approach should I take

Here is a code pen version if your snippets are not working https://codepen.io/varunagarwal/pen/gOaQqbG

Edit: someone told me to make it a runnable snippet so there you go


回答1:


You have overlapping setTimeout timers, and a lot of them being scheduled. You only want to yield back to the browser when there's a change to show, and you only want to show a given change once.

Since you're using ES2015+, I'd probably use a generator function to do the sort, yielding when something changes:

function *sortGen() {
    for (let i = 0; i < len; ++i) {
        for (let j = 0; j < len; ++j) {
            if (k[j] > k[j + 1]) {
                let tmp = k[j];
                k[j] = k[j + 1];
                k[j + 1] = tmp;
                yield j; // *** Yield to caller, saying what changed
            }
        }
    }
}

Then the code calling it would call its next method, do the update, and then schedule callback for just before the next animation frame via requestAnimationFrame (unless you want to artificially slow it down, in which case setTimeout is fine). Animation frames happen 60 times/second (roughly every 16.666667ms) provided the browser isn't busy doing something else. Here's bubble using the generator from the sortGen function above:

function bubble() {
    const gen = sortGen();
    tick();

    function tick() {
        const result = gen.next();
        if (!result.done) {
            // *** No need to recreate all the elements, just reorder the ones that got swapped
            const el = cont.children[result.value];
            const next = el.nextElementSibling;
            el.parentElement.insertBefore(next, el);
            requestAnimationFrame(tick);
        }
    }
}

(You could make it an async generator and use a for-await-of loop, but I don't think it really buys you much.)

Here's a live example; I've also included some comments in the code making other suggestions:

"use strict"; // *** Use strict mode

// *** Declare your variables (the old code relied on The Horror of Implicit Globals, which
// strict mode fixes)
let k = []; // *** Consistently use semicolons (or consistently rely on ASI)
let len = 100;
let time = true;

const cont = document.getElementsByClassName("cont")[0];
// *** Don't duplicate code, just use `reset`
reset();

function reset(){
    k = [];
    // *** Never use += on `innerHTML`
    let html = "";
    for (let i = 0; i < len; i++) {
        // *** Declare your variables
        const t = Math.round(Math.random() * 800 ) + 5;
        k.push(t);
        html += makeBlock(t);
    }
    cont.innerHTML = html;
}

function makeBlock(value) {
    return "<div class='block' style = 'height:" + value + "px'></div>";
}

function *sortGen() {
    for (let i = 0; i < len; ++i) {
        for (let j = 0; j < len; ++j) {
            if (k[j] > k[j + 1]) {
                let tmp = k[j];
                k[j] = k[j + 1];
                k[j + 1] = tmp;
                yield j; // *** Yield to caller, saying what changed
            }
        }
    }
}

function bubble() {
    const gen = sortGen();
    tick();

    function tick() {
        const result = gen.next();
        if (!result.done) {
            // *** No need to recreate all the elements, just reorder the ones that got swapped
            const el = cont.children[result.value];
            const next = el.nextElementSibling;
            el.parentElement.insertBefore(next, el);
            requestAnimationFrame(tick);
        }
    }
}
.cont {
  width: 100%;
  height: 900px;
  display: block;
  background-color: pink;
  padding: 0px;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -ms-flex-line-pack: center;
  align-content: center;
} /* *** Don't hide closing } at the end of a line */
.cont .block {
  display: inline-block;
  width: 10px;
  margin: auto 1px;
  background-color: red;
  font-size: 5px;
  bottom: 0px;
} /* *** Don't hide closing } at the end of a line */
<button class="reset" onclick="reset()">Reset Array
</button> 
<button class="bubble" onclick="bubble()">Bubble Sort
</button> 
<div class="cont"> 
</div>

Also on CodePen.

For what it's worth, the async generator approach looks something like this:

const nextFrame = cb => new Promise(resolve => {
    requestAnimationFrame(() => {
        cb();
        resolve();
    });
});

function bubble() {
    (async () => {
        for await (const value of sortGen()) {
            await nextFrame(() => {
                const el = cont.children[value];
                const next = el.nextElementSibling;
                el.parentElement.insertBefore(next, el);
            });
        }
    })()
    .catch(error => {
        // Handle/report error here...
        console.error(error);
    });
}

"use strict"; // *** Use strict mode

// *** Declare your variables (the old code relied on The Horror of Implicit Globals, which
// strict mode fixes)
let k = []; // *** Consistently use semicolons (or consistently rely on ASI)
let len = 100;
let time = true;

const cont = document.getElementsByClassName("cont")[0];
// *** Don't duplicate code, just use `reset`
reset();

function reset(){
    k = [];
    // *** Never use += on `innerHTML`
    let html = "";
    for (let i = 0; i < len; i++) {
        // *** Declare your variables
        const t = Math.round(Math.random() * 800 ) + 5;
        k.push(t);
        html += makeBlock(t);
    }
    cont.innerHTML = html;
}

function makeBlock(value) {
    return "<div class='block' style = 'height:" + value + "px'></div>";
}

function *sortGen() {
    for (let i = 0; i < len; ++i) {
        for (let j = 0; j < len; ++j) {
            if (k[j] > k[j + 1]) {
                let tmp = k[j];
                k[j] = k[j + 1];
                k[j + 1] = tmp;
                yield j; // *** Yield to caller, saying what changed
            }
        }
    }
}

const nextFrame = cb => new Promise(resolve => {
    requestAnimationFrame(() => {
        cb();
        resolve();
    });
});

function bubble() {
    (async () => {
        for await (const value of sortGen()) {
            await nextFrame(() => {
                const el = cont.children[value];
                const next = el.nextElementSibling;
                el.parentElement.insertBefore(next, el);
            });
        }
    })()
    .catch(error => {
        // Handle/report error here...
        console.error(error);
    });
}
.cont {
  width: 100%;
  height: 900px;
  display: block;
  background-color: pink;
  padding: 0px;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -ms-flex-line-pack: center;
  align-content: center;
} /* *** Don't hide closing } at the end of a line */
.cont .block {
  display: inline-block;
  width: 10px;
  margin: auto 1px;
  background-color: red;
  font-size: 5px;
  bottom: 0px;
} /* *** Don't hide closing } at the end of a line */
<button class="reset" onclick="reset()">Reset Array
</button> 
<button class="bubble" onclick="bubble()">Bubble Sort
</button> 
<div class="cont"> 
</div>

Also on CodePen.



来源:https://stackoverflow.com/questions/61884893/java-script-sorting-algorithm-visualizer

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