Skip to content

Trie Search

Search for a string key in a prefix tree by following character transitions.

Trie search locates a key by following a path defined by its characters. Each edge corresponds to one symbol from the alphabet. A node represents a prefix of stored keys.

Search cost depends on the key length, not on the number of stored keys.

Problem

Given a trie root and a string key s, determine whether s exists as a stored key.

Return true if present, otherwise false.

Structure

Each node contains:

fieldmeaning
childrenmap from character to child node
is_terminalmarks the end of a stored key

A path from the root to a node corresponds to a prefix of some key.

Algorithm

Start at the root. For each character in the string, follow the corresponding child pointer. If any character transition is missing, the key is absent. After processing all characters, check the terminal flag.

trie_search(root, s):
    node = root

    for c in s:
        if c not in node.children:
            return false
        node = node.children[c]

    return node.is_terminal

Example

Insert keys:

key
“cat”
“car”
“dog”

Trie structure:

(root)
  ├─ c
  │   └─ a
  │       ├─ t (terminal)
  │       └─ r (terminal)
  └─ d
      └─ o
          └─ g (terminal)

Search for "car":

stepcharaction
1cgo to child c
2ago to child a
3rgo to child r
end-terminal true

Search for "cap" fails at character p.

Correctness

Each node represents exactly one prefix. Following the sequence of characters in the key leads to the unique node representing that prefix.

If at any step a character transition does not exist, no stored key has that prefix, so the key is absent. If all characters are consumed and the node is marked terminal, the key exists. If the node is not terminal, the prefix exists but not as a complete key.

Complexity

Let LL be the length of the key.

casetime
searchO(L)O(L)

Space complexity for search is constant:

versionspace
iterativeO(1)O(1)
recursiveO(L)O(L)

When to Use

Trie search is useful when:

  • keys are strings or sequences
  • prefix queries are important
  • many keys share common prefixes
  • lookup time should depend on key length rather than number of keys

Compared to hash tables, tries support ordered traversal and prefix operations.

Implementation

class TrieNode:
    def __init__(self):
        self.children = {}
        self.is_terminal = False

def trie_search(root, s):
    node = root

    for c in s:
        if c not in node.children:
            return False
        node = node.children[c]

    return node.is_terminal
type TrieNode struct {
	Children   map[rune]*TrieNode
	IsTerminal bool
}

func TrieSearch(root *TrieNode, s string) bool {
	node := root

	for _, c := range s {
		next, ok := node.Children[c]
		if !ok {
			return false
		}
		node = next
	}

	return node.IsTerminal
}