← Все вопросы

Как построить обратный (инвертированный) индекс позиций каждого слова в боре?

Задан 1 месяц назад1.3к просмотров2 ответа
7

Есть текст из слов, нужно по слову быстро отдавать список позиций его вхождений (как обратный индекс в поисковике). Думаю строить бор, где в листе слова хранится список позиций. Это разумно или лучше просто unordered_map<string, vector<int>>? Когда бор реально выигрывает?

2 ответа

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

Для чистого «слово → список позиций» обычно достаточно unordered_map<string, vector<int>>: вставка O(|word|) на хеш + amortized, запрос O(|word|). Бор выигрывает в двух случаях:

  1. Префиксные запросы: «все позиции слов, начинающихся на pre» — в боре это поддерево, в map так не сделать без полного перебора ключей.
  2. Много общих префиксов — бор экономит память, не дублируя префиксы (важно при огромных словарях).

Бор с обратным индексом:

struct InvIndex {
    struct Node { array<int,26> next; vector<int> positions; Node(){ next.fill(-1);} };
    vector<Node> t{1};
    void add(const string& w, int pos){
        int v=0;
        for(char ch:w){ 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].positions.push_back(pos);     // позиции вхождений именно этого слова
    }
    const vector<int>* query(const string& w){
        int v=0;
        for(char ch:w){ int c=ch-'a'; if(t[v].next[c]==-1) return nullptr; v=t[v].next[c]; }
        return t[v].positions.empty()? nullptr : &t[v].positions;
    }
};

Построение — O(суммарная длина слов), запрос — O(|word|). Позиции можно держать отсортированными (если добавляете по возрастанию pos — они уже отсортированы), что позволяет пересекать списки для запросов из нескольких слов.

3

Если запросы — это «найти документы, где встречаются ОБА слова», обратный индекс + пересечение отсортированных списков позиций (merge за O(len1+len2)) — это ровно то, как работают настоящие поисковики. Бор тут не обязателен — суть в отсортированных posting-списках. Бор берите именно ради префиксных запросов и экономии на общих префиксах; иначе unordered_map проще и не медленнее.

Ваш ответ

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