Bubble Sort Algorithm: explanation and Python code

In this article I'll answer the questions: What is the goal of the algorithm? What steps does it take? and How can it be implemented in Python code?

Goal

Given an array of unsorted values, we want to sort them so that they end up in ascending order.

For example, say we have the array [5, 4, 7, 6, 9] - we want to sort it so it will instead be in this order: [4, 5, 6, 7, 9]

Steps of the algorithm

  1. We will point to two consecutive values, starting with the first and second values in the array, and will compare the first item with the second item.
  2. Are they already in order? Good! If not (i.e. if the left value is greater than the right value), we need to swap their order.
  3. Now we need to move one cell to the right in the array and point to the next two consecutive values.
  4. We'll repeat steps 1 through 3 until the end of the array is reached or if we reach an already sorted value. So far we've done one passthrough of the array.
  5. After one passthrough we need to sort the remaining unsorted values, so we'll go back to the first two values in the array and repeat steps 1 through 4 until we have a passthrough that makes it through the array with no swaps. A passthrough without any swaps means the array is sorted!

2 kinds of steps in the algorithm

As we make a mental model of this algorithm, it's helpful to notice that there are two types of steps that are happening:

Comparisons: happen when we compare two numbers to see which is the greater value Swaps: happen when we swap two numbers with one another to sort them

Efficiency

As the number of elements increase, the number of steps for the algorithm to go through (i.e. the number of comparisons and swaps) increases exponentially. The big O notation of this algorithm's efficiency is O(N*2), a.k.a. quadratic time*

Code

Unfortunately, I wasn't able to come up with a full implementation of Bubble Sort on my own, so I'm quoting the code from A Common Sense Guide Data Structures and Algorithms by Jay Wengrow.

But first it's helpful to define for ourselves what goes into the algorithm and what should come out. The parameter of the function is an array to sort, and the function should return the sorted array.

def bubble_sort (array): 
    unsorted_until_index = len(array)-1
    is_sorted = False
    while not is_sorted: 
        is_sorted = True
        for i in range(unsorted_until_index): 
            if array[i] > array[i + 1]: 
                array[i], array[i + 1] = array[i+1], array[i]
                is_sorted = False
        unsorted_until_index -= 1
    return array

So what's actually happening in this code?

  1. We define the function, bubble_sort, which accepts an array as a parameter
  2. We need to keep track of the values which are already sorted, which will always be at the end of the array, so we define unsorted_until_index and set its value as len(array)-1. Why len(array)-1? We know that the last array item will be sorted when we start off, so we subtract 1 from the length of the array to get the index of that last item (because our array indexing starts at 0).
  3. Next we set is_sorted to False. What is going on here? We know that we need to iterate through steps 1-4 (comparing and swapping items, through as many passthroughs as we need) until we have no more unsorted items in the array. So we'll start this variable off at False to keep track of whether we need to keep passing through the array or not.
  4. We'll begin a while loop that continues while the array is not fully sorted.
  5. Here we start is_sorted off at True. This may seem a bit odd, but the idea here is that if we don't have to make any more swaps, then the array is fully sorted. We're about to check if we need to make a swap, in which case we'll be able to change the is_sorted value back to False (but I'm getting ahead of the code)
  6. We're going to start a for loop that covers all the values from the beginning of the array until the last value to check, which will be the last unsorted value. We get to use our unsorted_until_index variable here to find out the range that we'll be checking.
  7. We finally get to do our comparison: looping through the array left to be checked, if the element at array[i] is greater than the element at array[i+1], we'll...
  8. ...Swap the elements.
  9. If we needed to do a swap, that means the array is still unsorted, so we'll change is_sorted back to False to signal that we need another passthrough.
  10. We'll also decrement the value for unsorted_until_index by 1 because we know that the last elements in our array are already sorted
  11. If we get to a comparison where we don't have to make a swap, is_sorted will remain at True, meaning we can exit the while loop and finally return the sorted array. Yay!

Resources

You can find Wengrow's book, where the code for this article came from, here. Or, if you have access to O'Reilly Online, you can read it there.