C/C++ Arena

Step 6 of 6

Challenge: a trie for autocomplete

A trie (from retrieval, often said "try") stores strings character by character. Each node has up to 26 children, one per letter, and a flag marking where a complete word ends. Words that share a prefix share the path for it:

root
 └ c
   └ a
     ├ r *        "car"
     │ └ t *      "cart"
     └ t *        "cat"

So "which words start with ca?" only needs to walk two nodes, then look below, no matter how many other words the trie holds. Search boxes, spell checkers and network routers use tries.

#include <array>
#include <iostream>
#include <memory>
#include <string>

struct Node {
    std::array<std::unique_ptr<Node>, 26> next;   // one slot per letter
    bool end = false;
};

void insert(Node& root, const std::string& w) {
    Node* n = &root;
    for (char c : w) {
        auto& child = n->next[c - 'a'];
        if (!child) child = std::make_unique<Node>();
        n = child.get();
    }
    n->end = true;
}

void print_all(const Node& n, std::string& prefix) {
    if (n.end) std::cout << prefix << " ";
    for (int i = 0; i < 26; i++) {                 // 'a' to 'z': alphabetical order
        if (n.next[i]) {
            prefix.push_back(char('a' + i));
            print_all(*n.next[i], prefix);
            prefix.pop_back();                     // undo before trying the next letter
        }
    }
}

int main() {
    Node root;
    for (const char* w : {"cat", "car", "cart", "dog", "do"}) insert(root, w);
    std::string prefix;
    print_all(root, prefix);
    std::cout << "\n";
}
car cart cat do dog 

How it works

Your task's extras

Your task

Write class Trie for lowercase words:

Inserting the same word twice counts it once.

Challenge 2

Add bool erase(const std::string& w) to the trie: if the word is stored, unmark its end and subtract 1 from pass along its path, so count_prefix stays right. Nodes can stay allocated. Return whether the word was there.

Challenge 3

Write std::string longest_common_prefix(const std::vector<std::string>& words) using a trie: insert every word, then walk down from the root while the current node has exactly one child and isn't the end of a word. Return "" for an empty list.

Previous: A binary heap by hand