Week 35 · Phase 4 — The Toolbox
LIFO vs. FIFO — two restricted-access containers, an enormous range of uses.
Photo · Monika Borys / Unsplash
Some data structures are powerful precisely because they restrict what you can do with them. Sounds backwards — until you see how clean the resulting code is. Two siblings today: the stack (last in, first out) and the queue (first in, first out). They differ only in which end you take from, but that one bit of difference shows up everywhere in computing.
Like a stack of plates: you push a new plate on top, and you take from the top. The most-recently-added thing is the next one out. Operations:
All O(1). Easy to implement on top of a vector — push at the back, pop from the back.
std::stack<int> s;
s.push(10);
s.push(20);
s.push(30);
s.top(); // 30
s.pop(); // removes 30
s.top(); // 20
Where stacks show up:
Like a line at the bakery: first one in is first one served. Operations:
All O(1) with the right backing — the standard library uses std::deque internally.
std::queue<int> q;
q.push(10);
q.push(20);
q.push(30);
q.front(); // 10
q.pop(); // removes 10
q.front(); // 20
Where queues show up:
What if "first in" is the wrong order? std::priority_queue orders by priority: highest-priority item comes out first, regardless of insertion order. Internally it's a heap — a tree where each parent is bigger than its children — giving O(log n) push and pop.
Used heavily in Dijkstra's shortest-path, A* pathfinding, scheduler with priorities, top-K problems, and event simulation. Whenever the answer to "what's next?" depends on more than insertion order, you want a priority queue.
Every AI training pipeline has at least two queues in it: the data loader queue (one thread reading files from disk, others batching them, the GPU thread popping ready batches), and the gradient queue (in distributed training, accumulated gradients flow through a queue to a parameter server). The throughput of an entire training cluster is limited by how well those queues are designed.
Stacks: every recursive function in a transformer's autograd graph is, ultimately, the C++ runtime's call stack. The chef has been pushing and popping the whole time.
Two operations each, three lines of code, half of computing.
std::stack<char> to write a bracket-matching function. Push opens; pop on close, comparing.std::queue<Node*> to write breadth-first search on a graph.std::priority_queue<int> to find the top 100 of 1,000,000 numbers in O(n log k) time. Beats sorting the whole array (O(n log n)).One last data structure for Phase 4 — and the most general of them all. Beyond rows and chains and stacks, beyond ordered keys and unordered keys, lies the structure that captures arbitrary relationships between things.
Week 36 is Trees & Graphs.
Photo free under the Unsplash license. Stack of plates · Monika Borys.