javascriptsettimeoutbubble-sort

Terminating Bubble Sort Algorithm when the dataset has been sorted


This function goes through the dataset and then sorts it in ascending order.

What its meant to do is stop when the list has been sorted. However, the !changed control flow statement terminates it early, resulting in only one iteration being done. How can I change the code so that the sorting ends when the whole dataset has been sorted?

// Sort the elements using Bubble Sort
function bubble_sort() {
    sort.addEventListener("click", function() {
        const dataList = document.querySelectorAll(".data");
        let delay = 0;

        for (let i = 0; i < dataList.length - 1; i++) {
            let changed  = false
            for (let j = 0; j < dataList.length - 1 - i; j++) {
                setTimeout(() => {
                    let value1 = parseInt(dataList[j].getAttribute("value"));
                    let value2 = parseInt(dataList[j + 1].getAttribute("value"));

                    // Highlight the current pair being compared
                    dataList[j].style.backgroundColor = "blue";
                    dataList[j + 1].style.backgroundColor = "blue";

                    if (value1 > value2) {
                        // Swap the heights and values
                        let tempHeight = dataList[j].style.height;
                        let tempValue = dataList[j].getAttribute("value");

                        dataList[j].style.height = dataList[j + 1].style.height;
                        dataList[j].setAttribute("value", dataList[j + 1].getAttribute("value"));

                        dataList[j + 1].style.height = tempHeight;
                        dataList[j + 1].setAttribute("value", tempValue);
                        changed = true
                    }

                    // Reset the color after comparison
                    setTimeout(() => {
                        dataList[j].style.backgroundColor = "black";
                        dataList[j + 1].style.backgroundColor = "black";
                    }, speed/2);

                }, delay);
                
                delay += speed;
            }
            if (!changed) {
                return;
            }
        }
    });
}

I tried to add a variable to keep track of whether the order has been changed. However, it is checking it early because the changed variable is executed later due to a delay.

I did try to add the setTimeout method:

setTimeout(() => {
    console.log(changed)
    if (!changed) {
        return;
    }
}, (dataList.length - i - 1) * delay);

but to no avail (maybe because my math was wrong)?


Solution

  • The problem is that setTimeout unlike sleep in Python, just schedules the code inside it to run after a certain delay, but by the time it executes the code has already finished. This can lead to unexpected behaviors.

    To solve this we can convert the loop into an async function and use await with setTimeout to control the timing. This way the code execution will be paused for the specific duration:

    // Helper function to create a delay
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    // Sort the elements using Bubble Sort
    async function bubble_sort() {
        sort.addEventListener("click", async function() {  // async function here
            const dataList = document.querySelectorAll(".data");
    
            for (let i = 0; i < dataList.length - 1; i++) {
                let changed = false;
                for (let j = 0; j < dataList.length - 1 - i; j++) {
                    let value1 = parseInt(dataList[j].getAttribute("value"));
                    let value2 = parseInt(dataList[j + 1].getAttribute("value"));
    
                    // Highlight the current pair being compared
                    dataList[j].style.backgroundColor = "blue";
                    dataList[j + 1].style.backgroundColor = "blue";
    
                    if (value1 > value2) {
                        // Swap the heights and values
                        let tempHeight = dataList[j].style.height;
                        let tempValue = dataList[j].getAttribute("value");
    
                        dataList[j].style.height = dataList[j + 1].style.height;
                        dataList[j].setAttribute("value", dataList[j + 1].getAttribute("value"));
    
                        dataList[j + 1].style.height = tempHeight;
                        dataList[j + 1].setAttribute("value", tempValue);
                        changed = true;
                    }
    
                    await sleep(speed); // Wait for 'speed' milliseconds
    
                    // Reset the color after comparison
                    dataList[j].style.backgroundColor = "black";
                    dataList[j + 1].style.backgroundColor = "black";
    
                    await sleep(speed / 2); // Wait before resetting the colors
                }
                if (!changed) {
                    break;
                }
            }
        });
    }