Heaps in Python: heapq as a Priority Queue, and Finding the K Largest

Python’s heapq module turns a plain list into a binary min-heap in place, where heap[0] is always the smallest element. This post heapifies a list and pops it in order, then writes a k_largest function using a size-k min-heap and checks it against the standard library’s heapq.nlargest.

The code

import heapq


def k_largest(nums, k):
    # Keep a min-heap of size k: the smallest of the k largest seen so far
    # sits at heap[0]. Any new number bigger than that gets swapped in.
    heap = nums[:k]
    heapq.heapify(heap)
    for n in nums[k:]:
        if n > heap[0]:
            heapq.heapreplace(heap, n)
    return sorted(heap, reverse=True)


nums = [15, 3, 42, 8, 23, 4, 16, 99, 1, 7]

print("=== heapq as a priority queue ===")
heap = nums[:]
heapq.heapify(heap)
print("original list:", nums)
print("after heapify, heap[0] (smallest):", heap[0])

popped = []
while heap:
    popped.append(heapq.heappop(heap))
print("popped one at a time:", popped)

print("\n=== k-largest via a size-k min-heap ===")
for k in [1, 3, 5]:
    print(f"k_largest(nums, {k}) ->", k_largest(nums, k))

print("\n=== heapq.nlargest for comparison ===")
for k in [1, 3, 5]:
    print(f"heapq.nlargest({k}, nums) ->", heapq.nlargest(k, nums))

heapq.heapify rearranges heap in place so heap[0] is the minimum; repeated heappop calls drain it in ascending order. k_largest seeds a size-k heap from the first k numbers, then for every remaining number swaps it in via heapreplace whenever it beats the current minimum of that heap.

Running it

Real output:

=== heapq as a priority queue ===
original list: [15, 3, 42, 8, 23, 4, 16, 99, 1, 7]
after heapify, heap[0] (smallest): 1
popped one at a time: [1, 3, 4, 7, 8, 15, 16, 23, 42, 99]

=== k-largest via a size-k min-heap ===
k_largest(nums, 1) -> [99]
k_largest(nums, 3) -> [99, 42, 23]
k_largest(nums, 5) -> [99, 42, 23, 16, 15]

=== heapq.nlargest for comparison ===
heapq.nlargest(1, nums) -> [99]
heapq.nlargest(3, nums) -> [99, 42, 23]
heapq.nlargest(5, nums) -> [99, 42, 23, 16, 15]

After heapify, heap[0] was 1, the smallest value in the list, and popping one at a time produced [1, 3, 4, 7, 8, 15, 16, 23, 42, 99] — fully ascending. The hand-written k_largest matched heapq.nlargest exactly at every tested k (1, 3, and 5): both returned [99], [99, 42, 23], and [99, 42, 23, 16, 15].

Takeaway

The run showed heapq.heapify + repeated heappop draining a list in sorted order, and a size-k min-heap approach to k_largest producing output identical to heapq.nlargest across k=1, 3, and 5 on the same input.