← Все вопросы

Как реализовать бор (trie) для вставки и поиска строк, и сколько он ест памяти?

Задан 9 месяцев назад1.1к просмотров2 ответа
8

Нужна структура для множества строк с быстрой проверкой «есть ли такая строка / такой префикс». Понимаю, что это бор (trie), но не уверен, как лучше хранить детей — массивом или мапой — и как это влияет на память при алфавите из 26 букв.

2 ответа

13
✓ Принятый ответ — помог автору

Бор — дерево, где путь от корня до узла кодирует префикс. Каждый узел хранит переходы по символам и флаг «здесь кончается слово». Реализация массивом узлов (а не указателями) на CP быстрее и не течёт.

struct Trie {
    struct Node {
        array<int, 26> next;
        bool leaf = false;
        Node() { next.fill(-1); }
    };
    vector<Node> t{1};                      // корень = узел 0
    void insert(const string& s) {
        int v = 0;
        for (char ch : s) {
            int c = ch - 'a';
            if (t[v].next[c] == -1) {
                t[v].next[c] = t.size();
                t.emplace_back();
            }
            v = t[v].next[c];
        }
        t[v].leaf = true;
    }
    bool contains(const string& s) {
        int v = 0;
        for (char ch : s) {
            int c = ch - 'a';
            if (t[v].next[c] == -1) return false;
            v = t[v].next[c];
        }
        return t[v].leaf;
    }
};

Вставка/поиск — O(|s|) на строку, не зависят от числа строк. Память — O(суммарная длина · алфавит) в худшем случае: при алфавите 26 каждый узел — 26 интов. Если алфавит большой (Unicode, 10^5), массив next раздуется — тогда берите unordered_map<int,int> next (медленнее по константе, но память пропорциональна реальным рёбрам).

4

Совет по памяти: array<int,26> это 104 байта на узел. На 10^6 символов суммарной длины это до ~10^8 байт — может не влезть в лимит. Если боры большие, либо map/unordered_map на детей, либо сжатый бор (radix tree). На большинстве олимпиадных задач массив всё же предпочтительнее из-за константы — просто следите за лимитом памяти.

Ваш ответ

Войдите, чтобы ответить на вопрос.