Heap queue (or heapq)

Heap data structure is mainly used to represent a priority queue. In Python, it is available using the heapq module. The property of this data structure in Python is that each time the smallest heap element is popped(min-heap). Whenever elements are pushed or popped, heap structure is maintained. The heap[0] element also returns the smallest element each time (min heap)

# importing "heapq" to implement heap queue
import heapq
 
# initializing list
li = [5, 7, 9, 1, 3]
 
# using heapify to convert list into heap
heapq.heapify(li)
 
# printing created heap
print ("The created heap is : ",(list(li)))

The created heap is

The created heap is :  [1, 3, 9, 7, 5]

There are three rules that determine the relationship between the element at the index k and its surrounding elements:

  1. Its first child is at 2*k + 1.
  2. Its second child is at 2*k + 2.
  3. Its parent is at (k - 1) // 2.

Note:The // symbol is the integer division operator. It always rounds down to an integer.

Appending and Popping Items Efficiently

Heappop

Since the root of the tree is the first element, you don’t need a dedicated function to read the smallest element nondestructively. The first element, a[0], will always be the smallest element.

To pop the smallest element while preserving the heap property, the Python heapq module defines heappop().

Here’s how to use heappop() to pop an element:

>>> import heapq
>>> a = [1, 2, 3, 5, 6, 8, 7]
>>> heapq.heappop(a)
1
>>> a
[2, 5, 3, 7, 6, 8]

Heap push

The Python heapq module also includes heappush() for pushing an element to the heap while preserving the heap property.

The following example shows pushing a value to a heap:

>>> import heapq
>>> a = [2, 5, 3, 7, 6, 8]
>>> heapq.heappush(a, 4)
>>> a
[2, 5, 3, 7, 6, 8, 4]
>>> heapq.heappop(a)
2
>>> heapq.heappop(a)
3
>>> heapq.heappop(a)
4

After pushing 4 to the heap, you pop three elements from it. Since 2 and 3 were already in the heap and are smaller than 4, they’re popped first.

The Python heapq module also defines two more operations:

  1. heapreplace() is equivalent to heappop() followed by heappush().
  2. heappushpop() is equivalent to heappush() followed by heappop().

Doing a max heap

In Python, the heapq module provides a heap queue algorithm. By default, heapq creates a min heap, which is a binary heap where the smallest element is always at the root. However, if you want to create a max heap (where the largest element is at the root), you can use a simple trick by negating the values when inserting into the heap.

import heapq 

class MaxHeap: 
	def __init__(self): 
		self.heap = [] 
	
	def push(self, value): 
		heapq.heappush(self.heap, -value) 
		
	def pop(self): 
		return -heapq.heappop(self.heap)

How to Identify Problems

A heap, as an implementation of a priority queue, is a good tool for solving problems that involve extremes, like the most or least of a given metric.

There are other words that indicate a heap might be useful:

  • Largest
  • Smallest
  • Biggest
  • Smallest
  • Best
  • Worst
  • Top
  • Bottom
  • Maximum
  • Minimum
  • Optimal

Top K frequent elements

By using a list of tuples where the first element is the key you want to heapify by.

import heapq

# get frequencies
def count_frequency(lst):
    frequency_dict = {}
    
    for element in lst:
        if element in frequency_dict:
            frequency_dict[element] += 1
        else:
            frequency_dict[element] = 1
    
    result = [(key, value) for key, value in frequency_dict.items()]
    return result

# Your original list
frequency_list = [(1, 3), (2, 2), (3, 9), (4, 8)]

# Convert the list of tuples to a list of tuples with the second element as the key
heapified_list = [(x[1], x) for x in original_list]

# Convert the list to a heap
heapq.heapify(heapified_list)

# Extract the original tuples from the heapified list
result_list = [x[1] for x in heapified_list]

# The original list is now heapified based on the second value of each tuple
print(result_list)

In this example, the key parameter is used to specify a custom function that extracts the second element of each tuple to determine the heap order. The heapify function then rearranges the list to satisfy the heap property based on the specified key.

This can be useful for problems o type top k most frequent or k less frequent