v9.1.1
Menu

Chapter 12: Advanced Data Structures

Week 12

Master advanced data structures that unlock efficient solutions to complex problems: Union Find for dynamic connectivity, Tries for prefix-based string operations, LRU Cache for O(1) eviction, and Segment Trees for range queries. These structures appear frequently in system design and competitive programming.

Topics
6
Demos
6
Min read
31

Chapter Overview

Advanced data structures go beyond arrays, hash maps, and trees to solve specialized problems with optimal efficiency. Each structure in this chapter addresses a specific class of problems that would be significantly harder or slower to solve with basic data structures.

Union Find (Disjoint Set Union) maintains a partition of elements into non-overlapping sets, supporting near-constant-time merge and membership queries. It is the backbone of Kruskal's algorithm, network connectivity, and image segmentation.

Trie (Prefix Tree) stores strings character by character in a tree, enabling prefix searches, autocomplete, and dictionary lookups in time proportional to the word length rather than the dictionary size.

LRU Cache combines a hash map with a doubly linked list (or Python's OrderedDict) to provide O(1) get and put operations with automatic eviction of the least recently used entry when capacity is exceeded.

Segment Tree supports both range queries (sum, min, max over a subarray) and point updates in O(log n) time, making it indispensable for problems where the underlying array changes frequently.

This chapter covers:

  • Union Find: Path compression, union by rank, connected components
  • Trie: Insert, search, prefix matching, and autocomplete via DFS
  • LRU Cache: OrderedDict-based O(1) implementation
  • Segment Tree: Build, query, and update operations

Chapter Roadmap

Click any topic to jump in

Interactive demo
1
Union Find (DSU)

Path compression + union by rank gives amortized $O(\alpha(n))$ per operation.

Find with Path CompressionUnion by Rank
Builds on previous
2
Connected Components

Static counting via DFS/DSU; dynamic connectivity via link-cut trees.

Static Component CountingDynamic Connectivity
Multiple approaches

Each tackles a different aspect

3
Trie

$O(L)$ insert and search for prefix queries, independent of dictionary size.

Trie Node StructureInsert and Search Operations
4
Autocomplete with Tries

DFS from prefix nodes and precomputed top-k lists for fast ranked suggestions.

DFS from Prefix NodeTop-K Suggestions
Multiple approaches

Each tackles a different aspect

5
LRU Cache

$O(1)$ get/put via hashmap + doubly linked list (or OrderedDict).

OrderedDict ApproachHash Map + Doubly Linked List
6
Segment Tree

$O(\log n)$ range queries and point updates on any associative aggregate.

Tree Structure and BuildingRange Query and Point Update

Topics

6 topics in this chapter

A social network records friendships as they happen and must answer, at any moment, whether two users are linked through some chain of friends. Running BFS for every question costs time proportional to the whole graph, and with millions of questions that is far too slow. What we need is a structure that merges groups cheaply and names the group of any element almost instantly.

The previous chapter ended with Partition Equal Subset Sum, where the work was a table of reachable totals. This chapter turns from DP to data structures built for one kind of query, and Union Find comes first. It stores each group as a tree in a parent array: every element points to a parent, and the root names the group. Two elements are in the same group exactly when their roots match, and merging two groups needs only one pointer change, from one root to the other. The danger is height. Careless merging can build a long chain, and then each root lookup walks the whole chain.

We first make lookups fast with path compression, which flattens paths as they are walked. Then we keep trees shallow with union by rank.

Definition

A Union Find (disjoint-set union) structure maintains a partition of nn elements into disjoint sets. find(x) returns the representative root of x's set, and union(x, y) merges the two sets. With path compression and union by rank, a sequence of mm operations costs O(m α(n))O(m\,\alpha(n)), where α\alpha is the inverse Ackermann function, at most 4 for any practical nn.

In this topic

  1. 1Find with Path Compression
  2. 2Union by Rank
1 of 2
Find with Path Compression

find(x) follows parent pointers from x until it reaches a root, a node with parent[r] = r, and returns that root. Its cost is the number of hops, so a tall tree makes every lookup slow. Path compression repairs this during the walk: after the root is known, every node visited on the way is re-pointed directly at the root. The work is paid once, and later finds on any of those nodes take a single hop. Ranks are left unchanged, so they become upper bounds on height. Compression alone gives O(log⁡n)O(\log n) amortized per operation; combined with union by rank it gives O(α(n))O(\alpha(n)).

Mathematical Intuition

Path compression makes every node on the find path point directly to the root. Combined with union by rank, it gives amortized complexity O(α(n))O(\alpha(n)) per operation, where α\alpha is the inverse Ackermann function. For all practical nn (even n=265536n=2^{65536}), α(n)≤4\alpha(n) \leq 4, so operations are effectively constant time.

Example:

Given parent = [0, 0, 1, 1, 3], what does the tree look like after calling find(4) with path compression?

2 of 2
Union by Rank

union(x, y) finds both roots and, if they differ, makes one root the parent of the other. Which one matters. Linking a tall tree under a short root makes every node in it one level deeper. Union by rank keeps a rank per root, an upper bound on its height, and always hangs the lower-rank root under the higher-rank one, so no node gets deeper. Only when ranks are equal does the new root's rank grow by one. A root of rank kk then has at least 2k2^k nodes in its tree, so height is at most log⁡2n\log_2 n even without compression. Union by size, which compares node counts, gives the same bound.

Mathematical Intuition

Union by rank attaches the shorter tree under the taller tree's root, which keeps the tree depth at O(log⁡n)O(\log n) without path compression. With both heuristics, Tarjan proved the amortized bound O(α(n))O(\alpha(n)) per operation; omitting either one degrades to O(log⁡n)O(\log n) amortized, and omitting both gives O(n)O(n) worst case. Rank is an upper bound on height, not exact height, since path compression only shrinks trees.

Example:

Two sets have roots A (rank 2) and B (rank 1). How does union by rank merge them?