Search in structures
Search cost depends as much on the data structure as on the algorithm. This lesson previews how lookups work in the structures you will build later, and where each one cannot help.
Learning goals
- Compare lookup cost across BSTs, hash tables, heaps, tries and graphs
- Choose the right structure for exact, ordered, prefix and reachability queries
- Explain why a heap is a poor choice for membership tests
Prerequisites
BST lookup
A binary search tree keeps smaller keys on the left and larger keys on the right, so a lookup is binary search on a linked structure: compare, then go left or right.
The cost is O(h) for tree height h. A balanced tree such as Java's TreeMap (a red-black tree) guarantees O(log n). An unbalanced BST built from sorted input degenerates into a list with O(n) lookups.
1Node find(Node root, int key) {2Node cur = root;3while (cur != null && cur.key != key) {4cur = key < cur.key ? cur.left : cur.right;5}6return cur; // null if absent7}
Average
O(log n)
Worst
O(n) unbalanced
Space
O(1)
Hash lookup
A hash table computes hash(key) to jump straight to a bucket, so expected lookup is O(1) regardless of n. Java's HashMap and HashSet work this way and need consistent equals() and hashCode().
Hashing gives up order: there are no floor, ceiling or range queries. Adversarial or poorly distributed keys raise collision costs. Since Java 8, HashMap turns long collision chains into trees, bounding the worst case at O(log n) per bucket.
| Need | Use |
|---|---|
| Exact lookup only | HashMap / HashSet |
| Exact lookup plus order or range | TreeMap / TreeSet |
| Static data, many lookups, low memory | Sorted array + binary search |
Average
O(1)
Worst
O(log n) Java 8+ bucket trees
Space
O(n)
Heap membership limitations
A heap only guarantees that each parent is ordered relative to its children. That makes reading the minimum (or maximum) O(1), but says nothing about where any other value is, so contains must scan: PriorityQueue.contains is O(n).
If you need both priority access and fast membership, pair the heap with a HashSet or HashMap of positions, which is how indexed priority queues for Dijkstra work.
Worst
O(n) membership
Space
O(1)
Trie prefix search
A trie stores strings character by character along tree edges. Looking up a word or checking a prefix takes O(L) for a string of length L, independent of how many words are stored.
Tries power autocomplete and spell-checkers, and they make “all words with prefix p” queries natural, which hash tables cannot do.
1boolean startsWith(TrieNode root, String prefix) {2TrieNode cur = root;3for (char c : prefix.toCharArray()) {4cur = cur.children[c - 'a'];5if (cur == null) return false;6}7return true;8}
Worst
O(L)
Space
O(total characters)
Graph reachability
“Can I get from A to B?” is a search over a graph instead of a list. Breadth-first search (BFS) or depth-first search (DFS) visits each vertex and edge at most once, in O(V + E).
Track visited vertices, because graphs can contain cycles. BFS also returns the fewest-edges path in an unweighted graph.
1boolean reachable(List<List<Integer>> adj, int src, int dst) {2boolean[] seen = new boolean[adj.size()];3Deque<Integer> queue = new ArrayDeque<>(List.of(src));4seen[src] = true;5while (!queue.isEmpty()) {6int u = queue.poll();7if (u == dst) return true;8for (int v : adj.get(u)) {9if (!seen[v]) { seen[v] = true; queue.add(v); }10}11}12return false;13}
Worst
O(V + E)
Space
O(V)
Practice ladder
Now try it yourself
Easy
- Two-sum with a HashMap
- Search in a BST
Medium
- Implement a trie with insert, search and startsWith
- Find whether a path exists in a graph
Advanced
- Design a structure with O(1) insert, delete, contains and getRandom
- Kth smallest element in a BST
Key takeaways
- Hash tables give O(1) expected exact lookups but no ordering.
- Balanced trees give O(log n) lookups plus floor, ceiling and ranges.
- Heaps are for priority access, not membership; tries are for prefixes; BFS/DFS answer reachability.