2 min read

Tries (Prefix Trees)

A Trie (pronounced "try") or Prefix Tree is a tree-based data structure used to efficiently store and retrieve keys in a dataset of strings. It is particularly effective for problems involving string prefixes.

1. The Structure

Unlike a binary search tree, nodes in a Trie do not store their associated key. Instead, a node's position in the tree defines the key with which it is associated.

  • Root: Represents an empty string.
  • Edges: Represent characters.
  • Nodes: Often contain a boolean flag (e.g., isEndOfWord) to indicate if the path from the root to this node forms a complete word.

2. Operations

Insert

To insert a word, we start at the root and walk down the tree, following the edges corresponding to each character in the word. If an edge doesn't exist, we create a new node. At the last character, we mark the node as isEndOfWord.

Similar to insert, we traverse down the tree. If we can follow the path for all characters and the final node is marked isEndOfWord, the word exists.

This is the Trie's superpower. We traverse down the tree. If we can follow the path for all characters, then the prefix exists in the Trie, regardless of the isEndOfWord flag.

3. Complexity

  • Time Complexity: $O(L)$ for insert, search, and prefix search, where $L$ is the length of the word. This is often faster than a Hash Table ($O(L)$ on average) because there are no hash collisions.
  • Space Complexity: Can be high ($O(AL)$ where $A$ is alphabet size and $L$ is average length) if there are many words with no common prefixes. However, it saves space when storing many words with the same prefix (e.g., "inter", "interest", "internet").

4. Implementation (Python)

class TrieNode:
    def __init__(self):
        self.children = {} # Map char -> TrieNode
        self.is_end_of_word = False

class Trie:
    def __init__(self):
        self.root = TrieNode()

    def insert(self, word: str) -> None:
        node = self.root
        for char in word:
            if char not in node.children:
                node.children[char] = TrieNode()
            node = node.children[char]
        node.is_end_of_word = True

    def search(self, word: str) -> bool:
        node = self.root
        for char in word:
            if char not in node.children:
                return False
            node = node.children[char]
        return node.is_end_of_word

5. Use Cases

  1. Autocomplete: Suggesting words as you type.
  2. Spell Checkers: Quickly verifying if a word is in the dictionary.
  3. IP Routing: Longest prefix matching.

programming/algorithms programming/dictionaries-and-maps programming/graph-theory-basics