Trie (Prefix Tree)

The trie data structure for strings: insert, search and prefix queries in O(length), counting words with a prefix, autocomplete, memory trade-offs and compressed tries.

A trie (from retrieval, also called a prefix tree) stores a set of strings so that each node represents a prefix. Words that share a beginning share the same path from the root. Autocomplete, spell checkers and IP routing tables all use tries.

rootcar* cart* carte* caret* catdog* doggateshala.com
A trie holding car, cart, care, cat and dog (* marks the end of a word)

Structure

  • Each node has up to Σ children (Σ = alphabet size, 26 for lowercase English), one per next character.
  • A flag marks nodes where a complete word ends (car ends at r even though cart continues).
  • The root represents the empty string.

Operations

OperationHowTime
Insert word wWalk down, creating missing nodes; mark the last nodeO(|w|)
Search wWalk down; succeed if every node exists and the last is markedO(|w|)
Starts-with prefix pWalk down p; succeed if every node existsO(|p|)
Count words with prefix pKeep a pass-count in each nodeO(|p|)
Delete wUnmark, then remove nodes that are no longer usedO(|w|)

The time depends only on the length of the string, not on the number of words stored. A hash table also gives O(|w|) lookups, but it cannot answer prefix queries or list words in sorted order.

Space: up to (total characters) × Σ pointers, which can be large. A compressed trie (radix tree) merges chains of single-child nodes into one edge labelled with a string. A suffix trie of a text holds all its suffixes and answers "is P a substring?" in O(|P|).

The code

public class Main {
    static class Node {
        Node[] next = new Node[26];
        boolean isWord;
        int passCount;                       // how many words pass through this node
    }

    static Node root = new Node();
    static int nodes = 1;

    static void insert(String w) {
        Node cur = root;
        for (char ch : w.toCharArray()) {
            int c = ch - 'a';
            if (cur.next[c] == null) { cur.next[c] = new Node(); nodes++; }
            cur = cur.next[c];
            cur.passCount++;
        }
        cur.isWord = true;
    }

    static Node walk(String s) {             // follow s from the root, or null
        Node cur = root;
        for (char ch : s.toCharArray()) {
            cur = cur.next[ch - 'a'];
            if (cur == null) return null;
        }
        return cur;
    }

    public static void main(String[] args) {
        for (String w : new String[]{"car", "cart", "care", "cat", "dog"}) insert(w);
        System.out.println("trie nodes (with root): " + nodes);
        for (String q : new String[]{"car", "ca", "cow"}) {
            Node n = walk(q);
            System.out.println(q + ": word? " + (n != null && n.isWord) + ", words with this prefix: " + (n == null ? 0 : n.passCount));
        }
    }
}
Output
trie nodes (with root): 10
car: word? true, words with this prefix: 3
ca: word? false, words with this prefix: 4
cow: word? false, words with this prefix: 0

GATE-style practice questions

GATE-styleNAT · numerical answer

The words "tea", "ten", "to", "in" and "inn" are inserted into an empty trie. How many nodes does it have, including the root?

Show answer and explanationAnswer: 9

root, t, e, a, n (ten), o, i, n (in), n (inn): 9 nodes.

GATE-styleMCQ · one correct answer

A trie stores n words over an alphabet of size Σ. The time to search for a word of length L is:

Show answer and explanationAnswer: B

The search follows one edge per character (with an array of children each step is O(1)), whatever the number of stored words.

GATE-styleMSQ · one or more correct answers

Which queries does a trie support efficiently but a hash table does not? (Select all that apply.)

Show answer and explanationAnswer: A, B

Both handle exact lookups and inserts; only the trie keeps the prefix structure and order.

GATE-styleNAT · numerical answer

A trie node uses an array of 26 child pointers. The words "a", "ab" and "abc" are stored. How many pointer slots (including null ones) are there in total, counting the root?

Show answer and explanationAnswer: 104

4 nodes (root, a, b, c) × 26 slots = 104, of which only 3 are used: tries trade memory for speed.