Trie (Prefix Tree)
A tree-shaped data structure for efficient string storage, search, and prefix matching.
The Mathematics
Prefix trees, shared prefixes, and search complexity
Prefix Tree Definition
A trie (prefix tree) is a rooted tree where each edge is labeled with a character from an alphabet . Each node represents a prefix:
Words sharing a common prefix share the same path from the root. End-of-word is marked with a boolean flag at the terminal node.
Shared Prefixes
The key advantage: words with common prefixes share nodes. For words and , the shared prefix path has length:
This saves space compared to storing each word independently. For example, "cat", "car", "card" share the prefix "ca".
Complexity Analysis
For a word of length :
Both operations are independent of the total number of stored words . Space in the worst case:
Trie vs. Hash Table
Hash tables offer average lookup but don't support prefix queries. Tries enable prefix search, autocomplete, and lexicographic ordering — all in time.
See It Work
Building a trie from words: cat, car, card, do, dog
Initialize: empty trie with just the root node.
The Code
Bridge from prefix tree operations to Python implementation
Mathematical Formulation
Each node maps characters to child nodes (branching factor up to |Σ|)
Boolean flag marking whether this node completes a word
Trie starts with an empty root (represents empty prefix "")
Insert processes each character of the word sequentially
Create a new node if the character path doesn't exist yet
After inserting all characters, mark the last node as end-of-word
Search is O(m) — independent of how many words are stored
Python Implementation
class TrieNode:
def __init__(self):
self.children = {} # Map: char -> TrieNode
self.is_end = False # Marks end of a word
class Trie:
def __init__(self):
self.root = TrieNode() # Empty root node
def insert(self, word):
node = self.root # Start at root
for char in word: # Traverse each character
if char not in node.children:
node.children[char] = TrieNode() # Create if missing
node = node.children[char] # Move to child
node.is_end = True # Mark end of word
def search(self, word):
node = self.root
for char in word:
if char not in node.children:
return False # Character not found
node = node.children[char]
return node.is_end # True only if full word exists