Bubble Sort in JS: Explanation and Implementation

A full guide to implementing your own sorting function using vanilla JS

ยท

5 min read

Bubble Sort in JS: Explanation and Implementation

This article is the first of my ongoing series about sorting algorithms and implementing them in JavaScript. If you want to learn something more in JavaScript, drop a comment. Let's get into it!

Why bubble sort?

Bubble sort is a kinda weird name for a pretty serious sorting algorithm in the tech world. The reason it is named so is because of how it works - the larger values bubble up the dataset, leaving the smaller values behind.

How it works

So let's say our list is as follows:

[29, 10, 14, 37, 15]

We start by comparing the first two elements of this list, 29 and 10. 29 is greater, so we bubble it up, swapping its position with that of 10. Our list now -

[10, 29, 14, 37, 15]

Now that we bubbled 29 up, we compare it again, this time with 14. It's again bigger, so we bubble it up again. However, in the next comparison, it's not bigger than 37. So our "pointer" gets transferred to 37, which then gets compared and swapped with 15. The list now:

[10, 14, 29, 15, 37]

It's not quite sorted yet, but we're closer than last time.

We start the process all over again now. The "pointer" is on 10. 10 is lesser than 14, and 14 is lesser than 29, so the pointer is 29 now. 29 is greater than 15, so their positions get swapped. However, it's less than the last element 37, so our list is sorted like this:

[10, 14, 15, 29, 37]

But how will our code understand that it's sorted? Let's implement the algorithm first and let's tackle this problem later.

The Pseudocode

Pseudocode is a must every time you solve a problem. It helps clarify the problem without writing (and worrying) about the actual syntax. Here's what my pseudocode looks like for implementing bubble sort:

  • Start looping from the end of the array to the second item of the array with a variable containing the index called i

  • Start a loop inside the previous loop with a variable called j from the beginning until i-1

  • If arr[j] is greater than arr[j+1], swap their values

  • Return the sorted array

Why do we have an outer loop which starts from the end? Well, with every iteration we're able to successfully sort the largest value that we find, which we bubble up. Hence, that element doesn't need to be moved, so we can loop from the start until the element before the sorted part of the array.

If I failed to clarify this, bear with me, the code will make you understand.

A quick note

If you want to visualize sorting algorithms like the bubble sort, head over to this link. There's a brilliant visualization on that site to help you understand these algorithms.

The Code

Here's the code. The explanation is right below it.

function bubbleSort(arr) {
    const swap = (arr, idx1, idx2) => {
        [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]]
    };

    for (let i = arr.length; i > 0; i--) {
        for (let j = 0; j < i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1)
            }
        }
    }
    return arr
}

We have defined a function named bubbleSort() which takes in an array as a parameter and returns a sorted array. There's another function inside bubbleSort(), named swap() which takes in an array, and two indexes. This function carries out the swapping of two elements in the array. It uses the ES2015 syntax of array destructuring to swap the positions.

Next, we have a loop with the variable i, which, as we discussed, looped from the end to the beginning, reducing the length of the array that needs to be sorted every time. We also have a nested loop with the variable j inside.

We check whether or not arr[j] is greater than arr[j+1], or in other words, whether it is larger than its next element. If so, we use our swap() function to swap the places.

In the end, we just return the sorted array.

An Optimization

In many cases, our loop with the variable i does not need to run as many times, as the array might get sorted before it. If you check my example at the beginning of the article, you'll notice that we finish sorting the array way before the loop ends. Also, we're running a loop inside the main loop as well, which further takes away time.

How do we solve this issue?

Well, if the array is perfectly sorted, then on the next iteration there will be no swaps at all. So we can use a variable called noSwaps to keep track of whether or not any swaps were made. If so, we can break out of the loop early to save time and computer memory. Here's the optimized code:

function bubbleSort(arr) {
    const swap = (arr, idx1, idx2) => {
        [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]]
    };
    let noSwaps
    for (let i = arr.length; i > 0; i--) {
        noSwaps = true
        for (let j = 0; j < i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j, j + 1)
                noSwaps = false
            }
        }
        if (noSwaps) break
    }
    return arr
}

This optimized code won't make much of a difference in time and space complexity for small datasets like ours, but on a large scale, it matters.


If you enjoyed this article, leave a like. I highly appreciate any feedback from you, so write a comment too! If you'd like to learn more about algorithms and data structures, check out the series this article is part of.

ย