9.3 Stacks, Queues, and Dictionaries (Maps)
Key Takeaways
- A stack is last-in, first-out (LIFO): push adds to the top and pop removes the most recently added item.
- A queue is first-in, first-out (FIFO): enqueue adds at the back and dequeue removes the item that has waited longest.
- A dictionary (map) stores key–value pairs with unique keys; storing a value under an existing key replaces the old value.
- Undo features, matching parentheses, and the call stack use stacks; waiting lines, print jobs, and breadth-first search use queues; ID lookups and word counts use dictionaries.
- Hash-table dictionaries give O(1) average lookup, insertion, and removal, degrading to O(n) if many keys collide.
What this competency asks
ETS asks you to be familiar with dictionaries/maps, stacks, and queues:
- Identify a data structure based on a description of its behavior or appropriate use.
- Given goals, constraints, or context, identify the most appropriate data structure.
- Trace code that uses a particular data structure.
ETS's sample question describes three situations: cars lining up at a car wash, contestants given unique ID numbers, and tennis balls loaded into and removed from the top of a can. It asks which structure models each. The answer is queue, dictionary, stack. Every question of this type is solved by asking "which item comes out next?" or "how is an item found?"
Abstract data types
An abstract data type (ADT) is defined by its behavior, meaning the operations it supports and what they guarantee, not by how it is stored. A stack could be built from an array or from a linked list. The user sees only push and pop. This is abstraction applied to data (Section 4.1).
Stacks: last in, first out
A stack works like a stack of plates or a can of tennis balls: you add and remove only at the top.
| Operation | Effect |
|---|---|
push ( x ) | Put x on top |
pop ( ) | Remove and return the top item |
peek ( ) | Return the top item without removing it |
isEmpty ( ) | Report whether the stack is empty |
Popping an empty stack is an error (underflow). All of these operations take O(1) time.
Uses: undo and redo; the browser Back button; matching brackets (push each opening symbol, and pop and compare at each closing symbol); evaluating expressions; and the call stack, which tracks procedure calls and recursion (Section 6.3).
Queues: first in, first out
A queue works like a waiting line: items join at the back and leave from the front.
| Operation | Effect |
|---|---|
enqueue ( x ) | Add x at the back |
dequeue ( ) | Remove and return the front item |
peek ( ) | Return the front item without removing it |
isEmpty ( ) | Report whether the queue is empty |
Uses: print jobs, customer-service lines, keyboard input buffers, scheduling tasks in the order they arrive, messages between programs, and breadth-first search, which explores a graph level by level.
An array-based queue avoids shifting elements by keeping front and back indexes that wrap around with the remainder operator, back ← ( back + 1 ) % capacity. This design is called a circular buffer.
Dictionaries (maps)
A dictionary (also called a map or associative array) stores key → value pairs.
| Operation | Effect |
|---|---|
put ( key, value ) | Store the pair; if the key already exists, replace its value |
get ( key ) | Return the value for the key, or indicate it is absent |
containsKey ( key ) | Report whether the key is present |
remove ( key ) | Delete the pair |
Keys are unique, but values need not be. Two students can have the same grade, but not the same student ID.
Uses: looking up a record by ID, counting word frequencies (the key is the word and the value is its count), caching results, configuration settings, and translating codes to names.
Most dictionaries are hash tables. A hash function converts the key into an array position, so get and put take O(1) on average. When two keys land in the same position (a collision), the table stores both, for example in a short list at that position. If a poor hash function sends many keys to the same position, operations degrade toward O(n). Tables grow and redistribute their entries when they get too full.
Choosing the right structure
| Description in the question | Structure |
|---|---|
| "The most recent item is handled first" | Stack |
| "Items are handled in the order they arrived" | Queue |
| "Find the item by its unique label, ID, or name" | Dictionary |
| "Reverse the order of the items" | Stack (push all, then pop all) |
| "Items enter at one end and leave from the other" | Queue |
| "Items enter and leave through the same opening" | Stack |
| "Access the item at position k" | Array or list |
Tracing practice
Stack S ← new Stack ( )
Queue Q ← new Queue ( )
S.push ( 10 )
S.push ( 20 )
Q.enqueue ( S.pop ( ) ) // S: [10] Q: [20]
S.push ( 30 ) // S: [10, 30]
Q.enqueue ( 40 ) // Q: [20, 40]
S.push ( Q.dequeue ( ) ) // dequeue returns 20; S: [10, 30, 20]; Q: [40]
int val ← S.pop ( ) // val = 20
Write the contents after every line, and mark which end is the top of the stack and which is the front of the queue. Most tracing errors come from popping the wrong end.
Word counting with a dictionary
Map counts ← new Map ( )
for each word w in the text
if ( counts.containsKey ( w ) )
counts.put ( w, counts.get ( w ) + 1 )
else
counts.put ( w, 1 )
end if
end for
For the text "to be or not to be," the final pairs are to → 2, be → 2, or → 1, not → 1. (The for each line is informal. ETS code would loop over an index.)
Complexity summary
| Structure | Add | Remove | Find by key or position |
|---|---|---|---|
| Stack | O(1) push | O(1) pop (top only) | Only the top is accessible |
| Queue | O(1) enqueue | O(1) dequeue (front only) | Only the front is accessible |
| Dictionary (hash table) | O(1) average | O(1) average | O(1) average by key |
| Array | — | — | O(1) by index; O(n) to search by value |
A stack S and a queue Q start empty. What is the value of val after these operations?
S.push ( 10 )
S.push ( 20 )
Q.enqueue ( S.pop ( ) )
S.push ( 30 )
Q.enqueue ( 40 )
S.push ( Q.dequeue ( ) )
int val ← S.pop ( )
Which structures best model these situations, in order? (1) Documents sent to a shared printer are printed in the order they were sent. (2) A school looks up each locker's combination by its locker number. (3) A drawing app's "undo" removes the most recent change first.
A search algorithm explores a road map level by level from a starting town, visiting all towns one road away before any that are two roads away. Which structure should hold the towns waiting to be visited?
A dictionary maps student IDs to grade levels. It already contains 1042 → 10. What happens after grades.put ( 1042, 11 )?