Python Min Heap Implementation: A Step-by-Step Tutorial

Introduction

Python is a powerful programming language that offers various data structures to store and manipulate data efficiently. One of these data structures is the heap, which is a tree-based data structure that maintains the heap property. A heap can be either a max-heap or a min-heap, depending on whether the highest or lowest element is at the root.

In this tutorial, we will focus on implementing a min-heap in Python. A min-heap is a binary tree where each parent node is smaller than its children. This means that the smallest element is always at the root of the heap.

We will start by discussing the basic operations of a min-heap, such as inserting an element and removing the minimum element. Then we will implement these operations step-by-step in Python, using an array-based representation of the heap.

By the end of this tutorial, you will have a solid understanding of how to implement and use a min-heap in Python for efficient data storage and manipulation.

Why use a Min Heap?

A min heap is a data structure that allows for efficient retrieval of the smallest element in a collection. This is useful in situations where you need to repeatedly access the smallest element, such as implementing a priority queue.

For example, let’s say you are developing an application that processes tasks with different priorities. You want to ensure that the highest priority task is processed first. By using a min heap to store the tasks, you can easily retrieve the highest priority task in constant time, without having to iterate through the entire collection every time.

In addition to prioritization, min heaps are also useful for sorting algorithms such as Heapsort. They provide a way to efficiently sort a collection of elements in ascending order.

Overall, using a min heap can significantly improve the performance of certain algorithms and data structures by providing efficient access to the smallest element in a collection.

How does a Min Heap work?

A Min Heap is a binary tree data structure where each parent node has at most two children and the value of each parent node is smaller than or equal to its children. In other words, the root node always holds the minimum value in the heap.

When a new element is added to the heap, it is added to the next available position at the bottom level of the heap, and then it is swapped with its parent if its value is smaller than its parent’s value. This process continues until either the new element is at the root node or its parent’s value is smaller than or equal to its own value.

Similarly, when an element is removed from the heap, the last element at the bottom level of the heap replaces it, and then it is swapped with its smallest child until it reaches a position where it is smaller than both of its children or it becomes a leaf node. This process ensures that the root node always holds the minimum value in the heap.

Here’s an example of how a Min Heap works:


# creating an empty Min Heap
heap = []

# adding elements to the Min Heap
heap.append(5)
heap.append(3)
heap.append(8)
heap.append(2)
heap.append(1)

# printing out the Min Heap
print(heap)

# removing elements from the Min Heap
heap.remove(1)
heap.remove(5)

# printing out the updated Min Heap
print(heap)

In this example, we first create an empty Min Heap and add five elements to it. The resulting heap would look like this:


[1, 2, 8, 5, 3]

Notice that the root node holds the minimum value (i.e., 1). We then remove two elements from the heap (i.e., 1 and 5), and we end up with an updated heap that looks like this:


[2, 3, 8]

Again, the root node holds the minimum value (i.e., 2), and the heap maintains its property that each parent node is smaller than or equal to its children.

Implementing a Min Heap in Python

A min heap is a binary tree data structure where the parent node is always less than or equal to its children. This property makes it useful for implementing priority queues and sorting algorithms. In this tutorial, we will learn how to implement a min heap in Python.

To implement a min heap in Python, we can use a list to store the binary tree. The first element of the list represents the root node of the tree. For any node at index i, its left child is at index 2i+1 and its right child is at index 2i+2.

Here’s an implementation of a min heap class in Python:


class MinHeap:
    def __init__(self):
        self.heap = []

    def parent(self, i):
        return (i-1)//2

    def insert(self, k):
        self.heap.append(k)
        i = len(self.heap) - 1
        while i != 0 and self.heap[self.parent(i)] > self.heap[i]:
            self.heap[self.parent(i)], self.heap[i] = self.heap[i], self.heap[self.parent(i)]
            i = self.parent(i)

    def extract_min(self):
        if len(self.heap) == 0:
            return None
        elif len(self.heap) == 1:
            return self.heap.pop()
        else:
            root = self.heap[0]
            self.heap[0] = self.heap.pop()
            i = 0
            while (2*i+1 < len(self.heap) and 
                   (self.heap[i] > self.heap[2*i+1] or 
                    (2*i+2 < len(self.heap) and 
                     self.heap[i] > self.heap[2*i+2]))):
                if (2*i+2 < len(self.heap) and 
                    self.heap[2*i+2] < self.heap[2*i+1]):
                    self.heap[i], self.heap[2*i+2] = self.heap[2*i+2], self.heap[i]
                    i = 2*i+2
                else:
                    self.heap[i], self.heap[2*i+1] = self.heap[2*i+1], self.heap[i]
                    i = 2*i+1
            return root

The `MinHeap` class has three methods: `__init__`, `insert`, and `extract_min`. The `__init__` method initializes an empty list to store the binary tree. The `insert` method adds a new element to the heap and maintains the min heap property by swapping elements as necessary. The `extract_min` method removes and returns the minimum element from the heap while maintaining the min heap property.

With this implementation, we can create a new min heap object and insert elements into it like this:


heap = MinHeap()
heap.insert(5)
heap.insert(3)
heap.insert(7)
heap.insert(1)
print(heap.heap)  # prints [1, 3, 7, 5]

We can also extract the minimum element from the heap like this:


min_element = heap.extract_min()
print(min_element)  # prints 1
print(heap.heap)    # prints [3, 5, 7]

Step by Step Breakdown of Implementing a Min Heap in Python

Step 1: Creating the Heap Class

In this tutorial, we will learn how to implement a Min Heap in Python. A heap is a special type of tree-based data structure that satisfies the heap property. In a Min Heap, the parent node is always smaller than or equal to its child nodes.

To create a Min Heap in Python, we will first define a class named Heap. This class will have two methods:

1. __init__ method: This method will initialize an empty list to store the heap elements.
2. insert method: This method will insert a new element into the heap and maintain the heap property.

Here’s how we can define our Heap class:


class Heap:
    def __init__(self):
        self.heap = []

    def insert(self, val):
        pass

In the above code, we have defined an empty list called `heap` in the constructor of our Heap class. We have also defined an insert method that takes a single argument `val` which is the value to be inserted into the heap.

Notice that we have left the implementation of the insert method empty for now. We will fill it in later in this tutorial.

Now that we have created our Heap class, let’s move on to the next step: inserting elements into our Min Heap.

Step 2: Implementing the Insert Method

Now that we have initialized our heap with an empty list and defined the parent, left_child, and right_child helper functions, we can move on to implementing the insert method. The insert method will allow us to add new elements to the heap while maintaining the heap property.

Here’s how the insert method works:

1. First, we append the new element to the end of the list. This ensures that the heap is always a complete binary tree.
2. Next, we compare the new element with its parent. If it is smaller than its parent, we swap them until the heap property is restored.
3. We repeat step 2 until either the new element is larger than its parent or it becomes the root of the tree.

Let’s see how this looks in code:


def insert(self, value):
    self.heap.append(value)
    current_index = len(self.heap) - 1
    parent_index = self.parent(current_index)

    while parent_index is not None and self.heap[current_index] < self.heap[parent_index]:
        self.heap[current_index], self.heap[parent_index] = self.heap[parent_index], self.heap[current_index]
        current_index = parent_index
        parent_index = self.parent(current_index)

The insert method takes a single argument `value` which represents the value to be inserted into the heap. We first append this value to the end of our heap list using `self.heap.append(value)`.

Next, we initialize two variables `current_index` and `parent_index`. `current_index` represents the index of our newly added value in our list and `parent_index` represents its parent’s index.

We then start a while loop that continues until either `parent_index` is `None` (meaning we have reached the root of our tree) or our new value is greater than or equal to its parent. Inside this loop, we check if our new value is less than its parent. If it is, we swap the two values, update our `current_index` to its parent’s index, and calculate the new `parent_index`.

Once the while loop has completed, our new value has been inserted into the heap in the appropriate position while maintaining the heap property.

Step 3: Implementing the Extract Minimum Method

In a min heap, the root node always contains the minimum value of the heap. The extract minimum operation is used to remove and return the minimum element from the heap. After the minimum element is removed, the remaining elements in the heap must be restructured to maintain the heap property.

Here are the steps to implement the extract minimum method:

1. Check if the heap is empty. If it is, throw an error or return None.
2. Store the root node’s value in a variable. This will be returned later.
3. Replace the root node with the last leaf node in the heap.
4. Remove the last leaf node from the heap.
5. Heapify downwards starting from the new root node to maintain the heap property.

Let’s implement this method in Python:


def extract_min(self):
    if not self.heap:
        return None
    
    # Store minimum value
    min_val = self.heap[0]
    
    # Replace root with last leaf
    last_leaf = self.heap.pop()
    if self.heap:
        self.heap[0] = last_leaf
    
        # Heapify downwards
        self._heapify_down(0)
    
    return min_val

In this implementation, we first check if the heap is empty and return None if it is. Otherwise, we store the value of the root node (minimum value) in a variable `min_val`. We then replace the root node with the last leaf node in the heap and remove that last leaf node from the heap using `pop()`.

If there are still nodes remaining in our heap after removing `last_leaf`, we start at index 0 (the new root) and perform a downward heapification using `_heapify_down()` to maintain our min-heap property.

Finally, we return `min_val`, which was stored earlier as our extracted minimum value.

Now that we have implemented all three methods for our min heap, we can test them out to ensure they work correctly.

Step 4: Testing the Min Heap Implementation

Now that we have implemented the `MinHeap` class, it’s time to test it out and make sure it works as expected. We will create a few test cases to check if the heap maintains the minimum heap property and if the methods are working correctly.

First, let’s create an instance of `MinHeap` and insert some elements into it:


min_heap = MinHeap()
min_heap.insert(5)
min_heap.insert(9)
min_heap.insert(1)
min_heap.insert(3)

Now, let’s check if the minimum element is at the root of the heap:


assert min_heap.get_min() == 1

Next, let’s remove the minimum element and check if the next minimum element is at the root:


min_heap.remove_min()
assert min_heap.get_min() == 3

We can also test if the `remove_min` method removes the minimum element correctly and adjusts the heap accordingly:


min_heap.remove_min()
assert min_heap.get_min() == 5

min_heap.remove_min()
assert min_heap.get_min() == 9

assert min_heap.is_empty() == True

Finally, let’s test if the `is_empty` method works as expected:


assert min_heap.is_empty() == True

min_heap.insert(7)
assert min_heap.is_empty() == False

If all these test cases pass without any assertion errors, then our implementation of `MinHeap` is correct.

Conclusion

In this tutorial, we have explored the concept of a Min Heap and how it can be implemented in Python. We started by discussing what a heap is and how it differs from other data structures like arrays and linked lists.

We then went on to explain the properties of a Min Heap, including the fact that the root of the heap is always the minimum element. We also covered the functions that can be performed on a Min Heap, such as inserting elements, deleting elements, and extracting the minimum element.

Next, we provided a step-by-step guide on how to implement a Min Heap in Python. We covered the two main approaches: using a list or using a class. For each approach, we provided code examples and explained how to perform each function on the heap.

Finally, we discussed some use cases for Min Heaps, including sorting algorithms and graph algorithms. Overall, we hope this tutorial has provided you with a solid understanding of Min Heaps and how they can be implemented in Python.
Interested in learning more? Check out our Introduction to Python course!


How to Become a Data Scientist PDF

Your FREE Guide to Become a Data Scientist

Discover the path to becoming a data scientist with our comprehensive FREE guide! Unlock your potential in this in-demand field and access valuable resources to kickstart your journey.

Don’t wait, download now and transform your career!


Pierian Training
Pierian Training
Pierian Training is a leading provider of high-quality technology training, with a focus on data science and cloud computing. Pierian Training offers live instructor-led training, self-paced online video courses, and private group and cohort training programs to support enterprises looking to upskill their employees.

You May Also Like

Data Science, Tutorials

Guide to NLTK – Natural Language Toolkit for Python

Introduction Natural Language Processing (NLP) lies at the heart of countless applications we use every day, from voice assistants to spam filters and machine translation. It allows machines to understand, interpret, and generate human language, bridging the gap between humans and computers. Within the vast landscape of NLP tools and techniques, the Natural Language Toolkit […]

Machine Learning, Tutorials

GridSearchCV with Scikit-Learn and Python

Introduction In the world of machine learning, finding the optimal set of hyperparameters for a model can significantly impact its performance and accuracy. However, searching through all possible combinations manually can be an incredibly time-consuming and error-prone process. This is where GridSearchCV, a powerful tool provided by Scikit-Learn library in Python, comes to the rescue. […]

Python Basics, Tutorials

Plotting Time Series in Python: A Complete Guide

Introduction Time series data is a type of data that is collected over time at regular intervals. It can be used to analyze trends, patterns, and behaviors over time. In order to effectively analyze time series data, it is important to visualize it in a way that is easy to understand. This is where plotting […]