Hello! Welcome to your next lesson in our module on "Algorithms: Sorting, Searching, and Design."
Introduction
In our previous lesson, we explored linear and binary search algorithms. A key takeaway was that binary search is incredibly fast, but it only works on sorted data. This raises a crucial question: how do we get data sorted in the first place?
Today, we begin to answer that question by diving into the world of sorting algorithms. Sorting is a fundamental operation in computer science, and understanding how different sorting methods work is essential for your GATE preparation.
Your learning outcome for this lesson is to: Implement and analyze simple sorting algorithms: bubble sort and insertion sort.
We will cover:
- The logic, implementation, and analysis of Bubble Sort.
- The logic, implementation, and analysis of Insertion Sort.
- How to analyze their efficiency (time and space complexity) using Big-O notation for best, average, and worst-case scenarios.
- A comparison of their performance to understand their practical trade-offs.
Let's get started with one of the most well-known sorting algorithms.
1. Bubble Sort: The "Sinking" Stone Approach
Bubble sort is a simple sorting algorithm that works by repeatedly stepping through the list, comparing each pair of adjacent items, and swapping them if they are in the wrong order. With each pass through the list, the next largest element "bubbles up" (or sinks) to its correct position at the end of the unsorted portion.
Imagine a series of stones of different weights in water; the heaviest ones will sink to the bottom first. Bubble sort works in a similar way.

To see the mechanics of this process in detail, let's watch a step-by-step walkthrough.
L-3.6: How Bubble Sort Works | Performance of Bubble Sort | All Imp Points with Example | Algorithm
This video from Gate Smashers provides a methodical demonstration of how Bubble Sort works. Pay close attention to the concept of 'passes' and how the largest unsorted element finds its final position in each pass.
Watch from 00:21 to 04:52. This section explains the core algorithm, showing how elements are compared and swapped to sort an array. Follow the state of the array after each pass.
Python Implementation
Now that you've seen how it works conceptually, let's implement it in Python. A common implementation uses two nested loops: the outer loop controls the number of passes, and the inner loop performs the adjacent comparisons and swaps.
For a comprehensive look at the code and its explanation, we'll turn to a detailed article.
The article 'Sorting Algorithms in Python' from Real Python provides a clean, well-commented implementation of Bubble Sort. It also includes a useful optimization.
Read the section titled 'The Bubble Sort Algorithm in Python'. Focus on the subsection 'Implementing Bubble Sort in Python' to understand the code. Note the use of the already_sorted flag, which allows the algorithm to terminate early if the list becomes sorted before all passes are complete.
Here is the code from the article for your reference:
def bubble_sort(array):
n = len(array)
for i in range(n):
# Create a flag that will allow the function to terminate early
already_sorted = True
# The inner loop performs the comparisons. The range shrinks
# with each pass because the largest elements are already sorted.
for j in range(n - i - 1):
if array[j] > array[j + 1]:
# Swap the elements
array[j], array[j + 1] = array[j + 1], array[j]
# If a swap occurred, the list is not yet sorted
already_sorted = False
# If no swaps occurred in a pass, the array is sorted
if already_sorted:
break
return array
# --- Example Usage ---
my_list = [10, 9, 11, 6, 15, 2]
print(f"Original list: {my_list}")
sorted_list = bubble_sort(my_list)
print(f"Sorted list: {sorted_list}")
Analysis of Bubble Sort
Analyzing an algorithm's efficiency is a critical skill for the GATE exam. We need to understand its time and space complexity.
-
Time Complexity:
The two nested loops are the key. The algorithm performs approximately comparisons, which, in Big-O notation, simplifies to .- Worst Case: . This occurs when the list is in reverse order.
- Average Case: . For a randomly ordered list.
- Best Case: . This occurs when the list is already sorted, and we use the
already_sortedflag optimization. The algorithm makes a single pass through the list to confirm it's sorted and then terminates.
-
Space Complexity:
Bubble sort only requires a few variables to keep track of indices and a temporary variable for swapping (though Python's tuple-swappinga, b = b, ahides this). It does not create any new data structures proportional to the input size. This makes its space complexity , or constant space. It's an in-place sorting algorithm.
For a more rigorous mathematical derivation of the time complexity, which is highly relevant for your engineering background and GATE prep, please watch the next segment of the Gate Smashers video.
L-3.6: How Bubble Sort Works | Performance of Bubble Sort | All Imp Points with Example | Algorithm
This segment provides a mathematical breakdown of why Bubble Sort's worst-case time complexity is O(n^2). Understanding this derivation is important.
Watch from 04:52 to 08:20. Follow the logic of counting the comparisons in each pass to arrive at the final complexity.
Test your understanding!
Given the list [7, 3, 2, 5], what is the state of the list after the first two passes of the outer loop (i=0 and i=1) in the bubble_sort function?
Show answer
Initial List: [7, 3, 2, 5]
Pass 1 (i=0):
- Compare 7 and 3. Swap. List becomes
[3, 7, 2, 5]. - Compare 7 and 2. Swap. List becomes
[3, 2, 7, 5]. - Compare 7 and 5. Swap. List becomes
[3, 2, 5, 7]. - The largest element, 7, is now at the end.
After Pass 1: [3, 2, 5, 7]
Pass 2 (i=1):
- Compare 3 and 2. Swap. List becomes
[2, 3, 5, 7]. - Compare 3 and 5. No swap. List is
[2, 3, 5, 7]. - The inner loop stops here (range is
n-i-1, so4-1-1=2iterations for j). The second largest element, 5, is now in its correct place.
After Pass 2: [2, 3, 5, 7]
(Note: The list is already sorted, but the algorithm doesn't know this until it completes another pass without any swaps).
2. Insertion Sort: Sorting Cards in Your Hand
Insertion sort is another simple algorithm that builds the final sorted list one item at a time. It's similar to how many people sort a hand of playing cards. You take one card at a time and insert it into its correct position within the cards you've already sorted.
The algorithm maintains a sorted sublist at the beginning of the array. It takes the first element from the unsorted part and "inserts" it into the correct position in the sorted sublist by shifting larger elements one position to the right.
Sorting: Bubble, Insertion, Selection, Merge, Quick, Counting Sort - DSA Course in Python Lecture 10
This video by Greg Hogg gives a quick and clear animation of how Insertion Sort works. It's a great way to visualize the process of building the sorted sub-array.
Watch from 04:23 to 06:59. Observe how the algorithm iterates through the list, picking a 'key' element and shifting other elements to make space for it in the sorted portion.
Python Implementation and Analysis
Like Bubble Sort, Insertion Sort is straightforward to implement and has a quadratic time complexity in the average case. However, as we'll see, it has some performance advantages.
Let's return to the Real Python article to study the implementation and analysis of Insertion Sort.
Read the section 'The Insertion Sort Algorithm in Python'. Pay attention to: The Python implementation and how the while loop is used to shift elements. The Big O runtime complexity analysis for best, worst, and average cases. The comparison with Bubble Sort and the practical timing results shown in the article.
Here is the code from the article for your reference:
def insertion_sort(array):
# Loop from the second element (index 1) to the end
for i in range(1, len(array)):
# The element we want to position correctly
key_item = array[i]
# Initialize j to the index before the key_item
j = i - 1
# Run through the sorted portion (left side) and shift
# all elements greater than key_item to the right.
while j >= 0 and array[j] > key_item:
array[j + 1] = array[j]
j -= 1
# Insert the key_item in its correct location
array[j + 1] = key_item
return array
# --- Example Usage ---
my_list = [10, 9, 11, 6, 15, 2]
print(f"Original list: {my_list}")
sorted_list = insertion_sort(my_list)
print(f"Sorted list: {sorted_list}")
Analysis of Insertion Sort
-
Time Complexity:
- Worst Case: . Occurs when the array is sorted in reverse order. The inner
whileloop has to shift every element in the sorted sublist for each new key. - Average Case: . For a random list.
- Best Case: . Occurs when the array is already sorted. The inner
whileloop condition (array[j] > key_item) is immediately false for every element, so only the outer loop runs.
- Worst Case: . Occurs when the array is sorted in reverse order. The inner
-
Space Complexity:
Like bubble sort, insertion sort is an in-place algorithm that requires only a constant amount of extra memory. Its space complexity is .
Bubble Sort vs. Insertion Sort
Even though both algorithms have an average time complexity of , insertion sort generally performs better in practice. Why?
- Fewer Swaps: Bubble sort performs a swap every time two adjacent elements are out of order. Insertion sort only shifts elements and performs a single insertion for each key item.
- Adaptive Nature: Insertion sort is highly efficient for data that is already "mostly sorted." If the list is nearly in order, the inner loop rarely runs, and the performance approaches .
The timing experiments in the Real Python article you read clearly demonstrate this practical performance difference.
Conclusion
Congratulations! You have now implemented and analyzed two of the most fundamental sorting algorithms. While they may not be the most efficient for large datasets, they provide an essential foundation for understanding more complex algorithms.
Key Takeaways:
- Bubble Sort works by repeatedly swapping adjacent elements. It's simple to understand but generally inefficient.
- Time Complexity: on average.
- Space Complexity: .
- Insertion Sort works by building a sorted sublist and inserting elements into it. It's also simple and is generally more efficient than bubble sort in practice.
- Time Complexity: on average, but in the best case, making it adaptive.
- Space Complexity: .
- Analyzing algorithms in terms of their best, average, and worst-case scenarios is crucial for making informed decisions.
Preview of the Next Lesson:
The complexity of bubble and insertion sort makes them impractical for sorting large lists. For your GATE exam and real-world applications, you'll need faster methods. In the next lesson, we will explore advanced sorting algorithms that use a "divide and conquer" strategy to achieve a much better time complexity. You will implement and analyze merge sort and quick sort, two of the most important and efficient sorting algorithms in computer science.