Data Structures & Algorithms

Bubble sort

Bubble sort is a popular but inefficient sorting algorithm, and it is easily outperformed by other sorting algorithms like insertion sort, quicksort. The algorithm takes in an unordered sequence of numbers as input and produces a sorted sequence of numbers as output.

The idea behind the algorithm is simple: repeatedly compare adjacent elements in an array and swap them if they are not in sorted order. The algorithm repeats the above process until all the elements in the array are sorted. In each iteration of the algorithm, the algorithm compares all pairs of adjacent elements. The adjacent elements are swapped if they are not in sorted order.

Example:

Let the initial array be [5, 4, 9, 3, 7, 6].

First iteration:
Compare the elements in index 1 and 2: 5, 4. They are not in sorted order. Swap them.
Array = [4, 5, 9, 3, 7, 6].
Compare the elements in index 2 and 3: 5, 9. They are in sorted order. Don’t swap.
Array = [4, 5, 9, 3, 7, 6].
Compare the elements in index 3 and 4: 9, 3. They are not in sorted order. Swap them.
Array = [4, 5, 3, 9, 7, 6].
Compare the elements in index 4 and 5: 9, 7. They are not in sorted order. Swap them.
Array = [4, 5, 3, 7, 9, 6].
Compare the elements in index 5 and 6: 9, 6. They are not in sorted order. Swap them.
Array = [4, 5, 3, 7, 6, 9]
The array after the first iteration is [4, 5, 3, 7, 6, 9].
The below table describes the complete sorting process, including other iterations. For brevity, only the steps in which swapping occurs are shown.

First iteration:
     [5, 4, 9, 3, 7, 6]
     [4, 5, 9, 3, 7, 6]
     [4, 5, 3, 9, 7, 6]
     [4, 5, 3, 7, 9, 6]
     [4, 5, 3, 7, 6, 9]
Second iteration:
     [4, 3, 5, 7, 6, 9]
     [4, 3, 5, 6, 7, 9]
Third iteration:
     [3, 4, 5, 6, 7, 9]

Source code: Bubble Sort

def bubble_sort(arr, n):
    for i in range(0, n):
            for j in range(0, n-1):
            # If the pair is not in sorted order
            if arr[j] > arr[j+1]:
        # Swap the pair to make them in sorted order
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

if __name__ == "__main__":
    arr = [5, 4, 9, 7, 3, 6]
    n = len(arr)
    arr = bubble_sort(arr, n)
    print (arr)

Explanation: The algorithm has two loops. The first loop iterates over the array n times and the second loop n-1 times. In each iteration of the first loop, the second loop compares all pairs of adjacent elements. If they are not sorted, the adjacent elements are swapped to make them in sorted order. The maximum number of comparisons required to assign an element to its right position in sorted order is n-1 because there are n-1 other elements. Since there are n elements and each element takes maximum n-1 comparisons; the array gets sorted in O(n^2) time. Hence, the worst-case time complexity is O(n^2). The best time complexity in this version of bubble sort is also O(n^2) because the algorithm does not know that it is completely sorted. Hence, even though it is sorted, the algorithm keeps comparing the elements resulting in the time complexity of O(n^2).

Part 2 (Optional): Optimised Bubble Sort

The above algorithm can be optimised if we could stop comparison when all the elements get sorted. This can be done by using an additional flag variable that says the algorithm when to stop.

def optimised_bubble_sort(arr, n):
    not_sorted = True
    while(not_sorted):
        not_sorted = False
        for i in range(0, n-1):
        # If the pair is not in sorted order
                if arr[i] > arr[i+1]:
            # Swap them
                    arr[i], arr[i+1] = arr[i+1], arr[i]
            # Remember that the array was not sorted
            # at the beginning of the iteration
                    not_sorted = True
    return arr

if __name__ == "__main__":
    arr = [5, 4, 9, 7, 3, 6]
    n = len(arr)
    arr = optimised_bubble_sort(arr, n)
    print (arr)

In the above algorithm, the flag variable not_sorted remains true as long as a swap occurs in an iteration of the inner for loop. This optimised version of bubble sort requires one additional iteration after the array is sorted to check whether the array is sorted or not.

The best-case time complexity of this algorithm is O(n). This occurs when all the elements of the input array are already in sorted order, and it requires one iteration to check if the array is in sorted order or not.

About the author

Arun Palaniappan