-2

I'm trying to modify this solution to work for Bubble Sort, but I'm a bit out of my depth, especially with the whole async function business. The code works up to a point, but does not follow the exact pattern I would expect for Bubble Sort, and only partially sorts the array.

Can anyone help me out please?

let values = [];
let startSort = true;

function bubbleSort( a ) {
    // create copy of the array 
    clone = a.slice();
    // asynchronous sort the copy
    recursiveBubbleSort( clone, clone.length );
    return;
}

//Recursive Bubble Sort
async function recursiveBubbleSort( arr, n ) {
    //If there is only single element 
    //the return the array
    if ( n === 1 ) {
    return arr;
    }

    await recursiveBubbleSort( arr, n - 1 );

    //Swap the elements by comparing them
    for ( let j = 0; j < n - 1; j++ ) {
    if ( arr[j] > arr[j + 1] ) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
    }
    }

    // copy back the current state of the sorting
    values = arr.slice();

    // slow down
    await sleep( 500 );
}

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 );
    }

    bubbleSort( 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/1.1.9/p5.min.js"></script>
Robin Andrews
  • 3,514
  • 11
  • 43
  • 111

1 Answers1

0

In this answer I will not focus on how async and await work because that doesn't seem to be your goal. I'll show you how to make a working version of the bubble sort instead.

First let's get rid of this startSort variable you have: You use it to initialize your values and a better way to do it is to use the setup() function used by p5:

function setup() {
    createCanvas(600, 190);

    rectWidth = floor(width / numOfRects);
    // Generate the values
    values = new Array(floor(width / rectWidth));
    for (let i = 0; i < values.length; i++) {
        values[i] = random(height);
    }
    // The number of iterations is equal to the number of values
    n = values.length;
}

We first we fill your array with random values and define a global variable n which will hold the remaining number of iterations do to (which is the same as the number of values).

Then let's modify your bubble sort function. Here we don't need it to be recursive because, as I'll show later on, we will simply call it several times until we have done all the iterations.

// Bubble Sort
function bubbleSort(arr, n) {
    // If there is no remaining iterations do nothing
    if (n <= 1) {
        return 0;
    }

    // Swap the elements by comparing them
    for (let j = 0; j < n - 1; j++) {
        if (arr[j] > arr[j + 1]) {
            [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
        }
    }

    // We did one more iteration return the remaining number of iterations
    return n - 1;
}

There are 3 important things here:

  • The function modifies the arr in place: so when you call the function with an array you will have the result in the same array.
  • The function returns the remaining number of iterations do it (each call to the function is one iteration)
  • If you call it with n the number of remaining of iterations at 1 or 0 it will simply do nothing. Otherwise it will make one pass on the array.

Now you can change your draw() function. This function is called automatically by p5 X times by seconds (by default 60). So each time it is ran it will call the bubble sort function, updating the array and the number of remaining iterations:

function draw() {
    // Define the "speed" at which we do the iterations
    frameRate(10);
    background(23);
    stroke(0);
    fill(255);

    // Show the values
    for (let i = 0; i < values.length; i++) {
        rect(i * rectWidth, height - values[i], rectWidth, values[i]);
    }

    // Make one new iteration
    n = bubbleSort(values, n);
}

Note how we used frameRate() to call it less often to let the user see the different steps of the sort.

All you need is to declare your global variables at the beginning of your sketch, put everything together and you are good to go.

let values = [];
let numOfRects = 15;
let rectWidth;
let n;

You can see the complete code here you will notice that I did to more things in this implementation:

  • I extracted the code which puts new values in the array in it's own function resetArray()
  • I call this function in the setup() function to initialize the animation but also in draw() when n===0 so that when the array is sorted we generate new values to have an infinite animation.

A note about async and await. These functions are used to create asynchronous code in javascript. This is a whole topic which is not trivial for someone new to programming, you can read the doc here. Basically async is used to say that a function will take time to be executed and await is used to say to wait for the function to finish it's execution.

In the function you go inspiration from, this asynchronous code is used to put a delay between two calls to the bubbleSort function so that the user can see the different iterations. Here you don't really need it because p5 gives you the mechanism of draw() and frameRate() to handle that more easily.

statox
  • 2,827
  • 1
  • 21
  • 41
  • That is very helpful in some ways. However, my bigger goal, which I didn't mention, is the visualize the "minimum value with k-digit-swaps" problem, which is remarkably similar to bubble sort except that it uses backtracking to find the optimal solution. The bubble sort therefore almost certainly needs to be recursive, which is why I tried to base it on the recursive merge sort example. My hope was if I could get the version I have provided working correctly, it would be quite simple to add the backtracking. – Robin Andrews Dec 15 '20 at 11:28
  • Yeah I should have clarified in the comments before writing my answer but it would have been useful to specify that in your question. I think you should be able to "emulate" recursion with a stack of the states and keep the same idea of calling the function for each iteration from `draw()` – statox Dec 16 '20 at 12:58