| |

8: Tries

A trie stores strings character-by-character. Strings with common prefixes share paths. Operations are O(k)O(k) where kk is string lengthโ€”independent of how many strings are stored.


Data Structure

TrieNode:
  - key: Key
  - val: Object  # non-None marks end of word
  - children: Dictionary[String, TrieNode]

Trie:
  - root: Optional[TrieNode]

Operations

Insert

insert(key, val):
    node = root
    for char in key:
        if char not in node.children:
            node.children[char] = TrieNode(char, None)
        node = node.children[char]
    node.val = val  # mark end of word
get(key):
    node = root
    for char in key:
        if char not in node.children:
            return None
        node = node.children[char]
    return node if node.val is not None else None
starts_with(prefix):
    node = root
    for char in prefix:
        if char not in node.children:
            return False
        node = node.children[char]
    return True

Autocomplete

autocomplete(prefix):
    node = root
    for char in prefix:
        if char not in node.children:
            return []
        node = node.children[char]
    return collect_all_words(node, prefix)

Runtime

OperationTime
InsertO(k)O(k)
SearchO(k)O(k)
DeleteO(k)O(k)
Prefix searchO(k)O(k)
AutocompleteO(k+m)O(k + m)

kk = string length, mm = total chars in results.

Space: O(nโ‹…k)O(n \cdot k) worst case, better with shared prefixes.


Trie vs Hash Table vs BST

TrieHash TableBST
SearchO(k)O(k)O(k)O(k) avgO(klogโกn)O(k \log n)
Prefix searchO(k)O(k)O(nk)O(nk)complex

Tries win for prefix operations.


Key Insight

Operations depend on string length kk, not on number of strings nn. Prefix operations are trivial: walk to the prefix node, and all descendants are matches.