← System Design Simulator

Trie Visualization for Coding Interviews

By Rahul Kumar · Senior Software Engineer · Updated · Category: Trees

Prefix tree: insert words, search, prefix lookup.

Concept

A trie, or prefix tree, is a rooted tree where every edge is labeled with a single character and every path from the root to a marked node spells out a stored string. The structure makes three operations extremely cheap: inserting a word in O(L), checking if a word is present in O(L), and asking whether any stored word starts with a given prefix in O(L), where L is the length of the query, independent of how many words are in the trie. That prefix-in-query-length property is why tries underlie autocomplete, spell-checkers, IP routing tables, dictionary compression, and the Aho-Corasick multi-pattern matcher. The trade-off is memory: a naive trie with a 26-way children array per node spends a lot of space on sparse letters. Production code uses HashMaps, sorted arrays, or compressed ternary or radix variants to cut the overhead. The basic insight is unchanged: branch on the next character and you can walk character-by-character through every prefix relationship in the set.

Trie — Interactive Simulator

Runs fully client-side in your browser; no sign-up. Or open full screen →

Launch the interactive Trie visualization — animated algorithm, step-through, and live data-structure updates.

How it works

Every node stores a mapping from character to child node and a boolean flag indicating whether a word ends at this node. Insert walks the tree from the root, following or creating child edges for each character of the input word, and marks the terminal node as end-of-word. Contains walks the same path but returns true only if the final node exists AND its end-of-word flag is set; a prefix match without terminal flag means the query is a prefix of some stored word but is not itself stored. StartsWith is even simpler: walk as far as the prefix extends and return true if every character was found, regardless of the terminal flag. Delete requires more care and usually runs as a recursive post-order: if the current node's children map is empty after the descendant delete and this node is not itself a word end, the node can be removed from its parent. Variations abound. A compressed trie (radix tree) collapses chains of single-child nodes into edges labeled with substrings, trading fixed O(L) per operation for much lower memory on sparse data. A ternary search trie replaces the wide children array with a small BST per node, which is slower per step but extremely compact.

Implementation

Trie with insert, contains, and startsWith using a HashMap of children
import java.util.HashMap;
import java.util.Map;

public class Trie {
    static class TrieNode {
        final Map<Character, TrieNode> children = new HashMap<>();
        boolean endOfWord;
    }

    private final TrieNode root = new TrieNode();

    /** Insert word into the trie. */
    public void insert(String word) {
        if (word == null) throw new IllegalArgumentException("word cannot be null");
        TrieNode node = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            node = node.children.computeIfAbsent(c, k -> new TrieNode());
        }
        node.endOfWord = true;
    }

    /** True iff word is stored as a complete word. */
    public boolean contains(String word) {
        TrieNode node = walk(word);
        return node != null && node.endOfWord;
    }

    /** True iff any stored word begins with the given prefix. */
    public boolean startsWith(String prefix) {
        return walk(prefix) != null;
    }

    private TrieNode walk(String s) {
        TrieNode node = root;
        for (int i = 0; i < s.length(); i++) {
            node = node.children.get(s.charAt(i));
            if (node == null) return null;
        }
        return node;
    }

    /** Remove word if present. Returns true if a word was actually removed. */
    public boolean delete(String word) {
        return delete(root, word, 0);
    }

    private boolean delete(TrieNode node, String word, int depth) {
        if (depth == word.length()) {
            if (!node.endOfWord) return false;
            node.endOfWord = false;
            return node.children.isEmpty();
        }
        char c = word.charAt(depth);
        TrieNode child = node.children.get(c);
        if (child == null) return false;
        boolean shouldPrune = delete(child, word, depth + 1);
        if (shouldPrune) {
            node.children.remove(c);
            return !node.endOfWord && node.children.isEmpty();
        }
        return false;
    }
}

Complexity

Common pitfalls

Key design decisions & trade-offs

Practice problems

Interview follow-ups

Why it matters

Trie is a core part of the Trees toolkit. If you are preparing for a technical interview at a top-tier company or teaching a course, a working visualization is the fastest path from "I read about it" to "I understand it".

Related