Trie (от retrieval) — дерево поиска, в котором ключ не хранится в узле явно, а определяется путём от корня до узла. Каждый узел представляет один символ, а путь от корня до листа образует слово.
Придумано Эдвардом Фредкином в 1960 году.
| Свойство | Значение |
|---|---|
| Глубина дерева | длина самого длинного ключа |
| Число дочерних узлов | размер алфавита (напр. 26 для a–z) |
| Поиск | O(m), где m — длина ключа |
| Не зависит от | числа ключей n |
| Корень | всегда пустой (не содержит символа) |
┌──────────────────────────────────┐
│ children[0..A-1] │ ← A указателей (A = размер алфавита)
│ is_end: bool │ ← маркер конца слова
│ value: any (опционально) │ ← полезная нагрузка
└──────────────────────────────────┘
Вставлены слова: cat, car, card, care, bat, bad
✓ =
is_end = true— здесь заканчивается слово
Вставка "care":
root → c → a → r → e (is_end = true)
Если узел уже существует — просто идём дальше.
Если нет — создаём новый.
def insert(root, word):
node = root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end = True
Поиск "car":
root → c ✓ → a ✓ → r ✓ → is_end? → True ✓
Поиск "ca":
root → c ✓ → a ✓ → is_end? → False ✗ (есть как префикс, но не слово)
Поиск "cat":
root → c ✓ → a ✓ → t ✓ → is_end? → True ✓
def search(root, word):
node = root
for char in word:
if char not in node.children:
return False # символ не найден
node = node.children[char]
return node.is_end # True только если полное слово
def starts_with(root, prefix):
node = root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True # префикс существует (слова необязательно)
Рекурсивный обход: удаляем узел только если он не является предком другого слова.
Удаление "car" (но "card", "care" остаются):
→ узел r НЕ удаляем — у него есть дети (d, e)
→ просто сбрасываем is_end = false
| Операция | Сложность | Примечание |
|---|---|---|
| Вставка | O(m) | m — длина ключа |
| Поиск | O(m) | не зависит от n |
| Удаление | O(m) | |
| Поиск по префиксу | O(m + k) | k — число найденных слов |
| Память | O(A × N × m) | A — алфавит, N — число слов |
| ✅ Плюсы | ❌ Минусы |
|---|---|
| Поиск за O(m) независимо от n | Большой расход памяти |
| Префиксный поиск из коробки | Неэффективен для разреженных данных |
| Лексикографическая сортировка бесплатно | children[A] — много пустых указателей |
| Нет коллизий (в отличие от хэш-таблиц) | Медленнее хэш-таблицы для точного поиска |