AI Skill Report Card

Using Heapq for Priority Queues

A90·Aug 22, 2026·Source: Web
14 / 15
Python
import heapq # Build a min-heap in place from a list data = [5, 7, 9, 1, 3] heapq.heapify(data) # data is now heap-ordered, data[0] is smallest heapq.heappush(data, 4) # push new item, maintain heap invariant smallest = heapq.heappop(data) # pop and return smallest item # Get n largest/smallest without fully sorting nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] print(heapq.nlargest(3, nums)) # [42, 37, 23] print(heapq.nsmallest(3, nums)) # [-4, 1, 2]
Recommendation
Add an example showing lazy deletion pattern in full working code, since it's referenced twice but never demonstrated
14 / 15

Progress:

  • Step 1: Decide if you need a full priority queue, a one-off top-k query, or a merge operation
  • Step 2: Choose the right heapq function(s) for the task
  • Step 3: For priority queues with ties/mutability, wrap items as tuples (priority, counter, item)
  • Step 4: For max-heap behavior, negate priorities (heapq only implements min-heap)
  • Step 5: Test edge cases — empty heap, equal priorities, updating/removing entries

Core functions:

FunctionPurpose
heapify(x)Transform list into a heap, in-place, O(n)
heappush(heap, item)Push item, maintain invariant, O(log n)
heappop(heap)Pop smallest item, O(log n)
heappushpop(heap, item)Push then pop, more efficient than separate calls
heapreplace(heap, item)Pop then push, faster but pop happens before push (heap never empty briefly)
merge(*iterables, key=None, reverse=False)Merge sorted inputs into single sorted generator
nlargest(n, iterable, key=None)n largest elements, use when n is small relative to iterable
nsmallest(n, iterable, key=None)n smallest elements

Choosing between approaches:

  • n == 1: use min()/max() — faster
  • n small, iterable large: use nlargest/nsmallest
  • n ≈ len(iterable): use sorted(iterable)[:n] — faster than heap approach
  • Repeated push/pop over time: use heappush/heappop directly on a heap list
Recommendation
Consider a brief note on time complexity comparison table to reinforce the 'choosing between approaches' section
18 / 20

Example 1: Priority queue with stable ordering and tie-breaking

Input: Tasks with priorities, need FIFO order for equal priorities

Python
import heapq import itertools counter = itertools.count() pq = [] def add_task(task, priority=0): entry = (priority, next(counter), task) heapq.heappush(pq, entry) def pop_task(): priority, count, task = heapq.heappop(pq) return task add_task('write code', priority=2) add_task('write spec', priority=1) add_task('create tests', priority=1)

Output: pop_task() calls return 'write spec', 'create tests', 'write code' — priority order, FIFO within same priority.

Example 2: K largest elements from a stream

Input: stream = [3, 1, 4, 1, 5, 9, 2, 6], need top 3

Python
import heapq print(heapq.nlargest(3, stream))

Output: [9, 6, 5]

Example 3: Merging multiple sorted logs by timestamp

Input: Several already-sorted iterables of log entries

Python
import heapq log1 = [1, 4, 7] log2 = [2, 5, 8] log3 = [3, 6, 9] merged = list(heapq.merge(log1, log2, log3))

Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Example 4: Max-heap via negation

Input: Need largest-first pop behavior

Python
import heapq nums = [3, 1, 4, 1, 5, 9] heap = [-n for n in nums] heapq.heapify(heap) largest = -heapq.heappop(heap) # 9

Output: largest == 9

Recommendation
Could add a short example combining heapq with a custom class using __lt__ for object priority queues
  • Use tuples (priority, item) for ordered heap entries; ensure items are comparable or add a tiebreaker (e.g., a counter) to avoid comparing non-orderable items when priorities tie.
  • For max-heaps, negate numeric priorities rather than writing a custom comparator (heapq has no key/reverse param for push/pop).
  • heapify() is O(n) — always prefer it over repeated heappush calls when building from an existing list.
  • Use heapreplace instead of heappop + heappush when you always want to maintain a fixed heap size (e.g., sliding window top-k).
  • For mutable/updatable priority queues (need to change priority of existing item), mark old entries as invalid and push new one instead of trying to remove mid-heap — heaps don't support efficient arbitrary removal.
  • heapq.merge() is lazy (returns iterator) — good for merging large sorted files/streams without loading everything into memory.
  • Don't assume the heap list is fully sorted — only heap[0] is guaranteed to be the smallest; use heapq.heapify + repeated heappop, or just sorted(), if you need a fully sorted result.
  • Don't use heapq for max-heap directly — there's no built-in max-heap; negate values or wrap in a class with reversed __lt__.
  • Don't call heappush/heappop on a list that wasn't heapified first — behavior is undefined on non-heap-ordered lists.
  • Don't try to update priority of an existing item in place — mutating a heap element doesn't re-sort the heap; use the "lazy deletion" pattern (push new entry, mark old as removed, skip removed entries on pop).
  • Avoid nlargest/nsmallest when n is close to the full length of the iterable — plain sorted() is more efficient in that case.
  • Remember comparisons happen on full tuples — if priorities tie and items aren't comparable (e.g., dicts), you'll get a TypeError; always include a unique tiebreaker.
0
Grade AAI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
14/15
Workflow
14/15
Examples
18/20
Completeness
19/20
Format
15/15
Conciseness
14/15