Question presented to candidate: "Everyone says use a deque instead of a list for a queue. Why? What does a deque look like in memory in CPython, and what does that layout make cheap and what does it make expensive?"
What a strong answer should cover:
- Layout: a doubly linked list of fixed-size blocks (64 item slots each in CPython), plus
leftblock/leftindexandrightblock/rightindexpointing at the two ends; never one big contiguous array. - Cost:
append,appendleft,pop,popleftare O(1) and never move other items or callrealloc; a new block is allocated only every 64 pushes on a side. - Contrast with
list:list.pop(0)andinsert(0, x)shift every element (O(n)), but a list indexes any position in O(1) whiledeque[i]walks blocks, so the middle is O(n). - Extras that fall out of the layout:
maxlen(bounded, evicts from the opposite end),rotate(k), no slicing, and "deque mutated during iteration" detection. - Why blocks instead of one node per item: far less pointer overhead and far fewer
malloccalls; spare blocks are kept on a small free list. - Thread safety: the docs describe appends and pops from either end as thread-safe.
Code / implementation expected: Optional β demonstrating O(1) ends vs list.pop(0), maxlen, or sketching the block structure.