Справочник от Автор24
Поделись лекцией за скидку на Автор24

Префиксные деревья (prefix tree, trie)

  • 👀 556 просмотров
  • 📌 533 загрузки
  • 🏢️ СибГУТИ
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Префиксные деревья (prefix tree, trie)» pdf
Лекция 4: Префиксные деревья (Prefix tree, trie) Курносов Михаил Георгиевич к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет телекоммуникаций и информатики http://www.mkurnosov.net Словарь со строковыми ключами  При анализе вычислительной сложности операций бинарных деревьев поиска, АВЛ-деревьев, красно-черных деревьев, Splay trees, списков с пропусками (Skip lists) мы полагали, что время выполнения операции сравнения двух ключей (=, <, >) выполняется за время O(1)  Если ключи – это длинные строки (char []), то время выполнения операции сравнения становится значимым и его следует учитывать! struct rbtree *rbtree_lookup(struct rbtree *tree, int key) { while (tree != NULL) { if (key == tree->key) return tree; else if (key < tree->key) tree = tree->left; else key1 = key2 tree = tree->right; key1 < key2 } return tree; key1 > key2 } O(1) 2 Префиксные деревья (Trie)  Префиксное дерево (Trie, prefix tree, digital tree, radix tree) – это структура данных для реализации словаря (ассоциативного массива), ключами в котором являются строки  Авторы: Briandais, 1959; Fredkin, 1960  Происхождение слова “trie” – retrieval (поиск, извлечение, выборка, возврат)  Альтернативные названия: o бор (Д. Кнут, Т. 3, 1978, выборка) o луч (Д. Кнут, Т. 3, 2000, получение) o нагруженное дерево (А. Ахо и др., 2000) 3 Префиксные деревья (Trie)  Префиксное дерево (Trie, prefix tree, digital tree, radix tree) – это структура данных для реализации словаря (ассоциативного массива), ключами в котором являются строки  Практические применения: o Предиктивный ввод текста (predictive text) – поиск возможных завершений слов o Автозавершение (Autocomplete) в текстовых редакторах и IDE o Проверка правописания (spellcheck) o Автоматическая расстановка переносов слов (hyphenation) o Squid Caching Proxy Server 4 Префиксные деревья (Trie) Б Т Словарь Ключ (Key) Значение (Value) ТИГР 180 ТАПИР 300 БАРИБАЛ 150 БАРСУК 15 И A Г П Р И $ Р А Р И С Б У А К Л $ 180 $ 300 Неупорядоченное дерево поиска (ребра одного узла не упорядочены по алфавиту) $ 150 15 5 Префиксные деревья (Trie)  Префиксное дерево (trie) содержит n ключей (строк) и ассоциированные с ними значения (values)  Ключ (key) – это набор символов (c1, c2, …, cm) из алфавита A = {a1, a2, …, ad}  Каждый узел содержит от 1 до d дочерних узлов И A Г П Р И $ Р  Символ $ – это маркер конца строки (ключа) А Р И С Б У А К Л $ 180 $  За каждым ребром закреплен символ алфавита Б Т 300 $ 150 15 6 Префиксные деревья (Trie)  Ключи не хранятся в узлах дерева!  Позиция листа в дереве определяется значением его ключа  Значения (values) хранятся в листьях Б Т И A Г П Р И $ Р А Р И С Б У А К Л $ 180 $ 300 $ 150 15 7 Префиксные деревья (Trie) Ключ Тигр Значение 180 Барибал 150 Тапир 300 Волк 60 Барсук 15 Бегемот 4000 Барс Т И A Г П Р И $ Р 55  Высота h = max(keyi), i = 1, 2, …, n Е А Р И Б С $ У О Г Л Е К М $ 60 180 $  Символ $ – это маркер конца строки В Б 300 А Л $ 150 55 К О $ Т 15 $ 4K 8 Узел префиксного дерева (Trie)  Ключ – это набор символов (c1, c2, …, cm) из алфавита A = {a1, a2, …, ad}  Каждый узел содержит от 1 до d указателей на дочерние узлы  Значения хранятся в листьях Value Т И A … cd А Г П Р Р И С $ Р $ 15 180 c1 c2 Б $ 300  Как хранить c1, c2, …, cd (массив, список, BST, hash table)? 9 Вставка элемента в префиксное дерево (Trie) 1. Инициализируем k = 1 root 2. В текущем узле (начиная с корня) отыскиваем символ ci, равный k-ому символу ключа key[k] Value 3. Если ci ≠ NULL, то делаем текущим узел, на который указывает ci; переходим к следующему символу ключа (k = k + 1) и пункту 2 c1 c2 … cd Value Value c1 c2 … cd c1 c2 … cd Value c1 c2 … cd 4. Если ci = NULL, создаем новый узел, делаем его текущим, переходим к следующему символу ключа и пункту 2 5. Если достигли конца строки ($) вставляем значение в текущий в узел 10 Вставка элемента в префиксное дерево (Trie)  Добавление элемента (Тигр, 180) Т И Г Р $ 180 11 Вставка элемента в префиксное дерево (Trie)  Добавление элемента (Тигр, 180)  Добавление (Тапир, 300) Т И A Г П Р И $ Р 180 $ 300 12 Вставка элемента в префиксное дерево (Trie)  Добавление элемента (Тигр, 180)  Добавление (Тапир, 300)  Добавление (Барибал, 150) Т И Б A Г П Р И $ Р А Р И Б 180 $ 300 А Л $ 150 13 Вставка элемента в префиксное дерево (Trie)  Добавление элемента (Тигр, 180)  Добавление (Тапир, 300)  Добавление (Барибал, 150)  Добавление (Барсук, 15) Т И Б A Г П Р И $ Р А Р И С Б У А К Л $ 180 $ 300 $ 150 15 14 Вставка элемента в префиксное дерево (Trie)  Добавление элемента (Тигр, 180)  Добавление (Тапир, 300)  Добавление (Барибал, 150)  Добавление (Барсук, 15)  Добавление (Барс, 55) Т И Б A Г П Р И $ Р А Р И Б 180 $ 300 А Л $ 150 С $ 55 У К $ 15 15 Вставка элемента в префиксное дерево (Trie) function TrieInsert(root, key, value) node = root for i = 1 to Length(key) do child = GetChild(node, key[i]) if child = NULL then child = TrieCreateNode() SetChild(node, key[i], child) end if node = child end for node.value = value end function  GetChild(node, c) – возвращает указатель на дочерний узел, соответствующий символу c  SetChild(node, c, child) – устанавливает указатель, соответствующий символу c, в значение child 16 Вставка элемента в префиксное дерево (Trie) function TrieInsert(root, key, value) node = root for i = 1 to Length(key) do child = GetChild(node, key[i]) if child = NULL then child = TrieCreateNode() SetChild(node, key[i], child) end if node = child end for node.value = value TInsert = O(m(TGetChild end function + TSetChild))  GetChild(node, c) – возвращает указатель на дочерний узел, соответствующий символу c  SetChild(node, c, child) – устанавливает указатель, соответствующий символу c, в значение child 17 Поиск элемента в префиксном дереве (Trie) function TrieLookup(root, key) node = root for i = 1 to Length(key) do child = GetChild(node, key[i]) if child = NULL then return NULL end if node = child end for return node end function  GetChild(node, c) – возвращает указатель на дочерний узел, соответствующий символу c  SetChild(node, c, child) – устанавливает указатель, соответствующий символу c, в значение child 18 Поиск элемента в префиксном дереве (Trie) function TrieLookup(root, key) node = root for i = 1 to Length(key) do child = GetChild(node, key[i]) if child = NULL then return NULL end if node = child end for return node TLookup end function = O(mTGetChild)  GetChild(node, c) – возвращает указатель на дочерний узел, соответствующий символу c  SetChild(node, c, child) – устанавливает указатель, соответствующий символу c, в значение child 19 Удаление элемента из префиксного дерева I. Отыскиваем лист, содержащий искомый ключ key Т II. Делаем текущим родительский узел найденного листа III. Поднимаемся вверх по дереву и удаляем узлы 1. Если текущий узел не имеет дочерних узлов, удаляем его 2. Делаем текущим родительский узел и переходим к пункту 2 И A Г П Р И $ Р 180 $ 300 20 Узел префиксного дерева (Trie) Как хранить указатели c1, c2, …, cd на дочерние узлы? Value c1 c2 … cd  Массив указателей (индекс – номер символа) struct trie *child[33]; node->child[char_index(‘Г’)] Сложность GetChild/SetChild O(1)  Связный список указателей на дочерние узлы struct trie *child; linkedlist_lookup(child, ‘Г’) Сложность GetChild/SetChild O(d) 21 Узел префиксного дерева (Trie) Как хранить указатели c1, c2, …, cd на дочерние узлы? Value c1 c2 … cd  Сбалансированное дерево поиска (Red black/AVL tree) struct rbtree *child; rbtree_lookup(child, ‘Г’) Сложность GetChild/SetChild O(logd) 22 Представление узла Trie struct trie { char *value; char ch; struct trie *sibling; struct trie *child; }; root value ch: К Сложность GetChild/SetChild: O(d) /* Sibling node */ /* First child node */ Неупорядоченное дерево поиска (unordered search tree) К И value value ch: И ch: О value value value ch: Т ch: Т ch: М Т О Т М 23 Создание пустого узла Trie struct trie *trie_create() { struct trie *node; if ( (node = malloc(sizeof(*node))) == NULL) return NULL; node->ch = '\0'; node->value = NULL; node->sibling = NULL; node->child = NULL; return node; } TCreate = O(1) 24 Поиск узла в Trie по ключу char *trie_lookup(struct trie *root, char *key) { struct trie *node, *list; for (list = root; *key != '\0'; key++) { for (node = list; node != NULL; node = node->sibling) { if (node->ch == *key) break; } if (node != NULL) list = node->child; else return NULL; } /* Check: Node must be a leaf node! */ return node->value; } TLookup = O(md) 25 Вставка узла в Trie struct trie *trie_insert(struct trie *root, char *key, char *value) { struct trie *node, *parent, *list; parent = NULL; list = root; for (; *key != '\0'; key++) { /* Lookup sibling node */ for (node = list; node != NULL; node = node->sibling) { if (node->ch == *key) break; } 26 Вставка узла в Trie if (node == NULL) { /* Node not found. Add new node */ node = trie_create(); node->ch = *key; node->sibling = list; if (parent != NULL) parent->child = node; else root = node; list = NULL; } else { /* Node found. Move to next level */ list = node->child; } parent = node; } /* Update value in leaf */ if (node->value != NULL) free(node->value); node->value = strdup(value); return root; } TInsert = O(md) 27 Удаление узла из Trie struct trie *trie_delete(struct trie *root, char *key) { int found; return trie_delete_dfs(root, NULL, key, &found); } 28 Удаление узла из Trie struct trie *trie_delete_dfs(struct trie *root, struct trie *parent, char *key, int *found) { struct trie *node, *prev = NULL; *found = (*key == '\0' && root == NULL) ? 1 : 0; if (root == NULL || *key == '\0') return root; for (node = root; node != NULL; node = node->sibling) { if (node->ch == *key) break; prev = node; } if (node == NULL) return root; 29 Удаление узла из Trie trie_delete_dfs(node->child, node, key + 1, found); if (*found > 0 && node->child == NULL) { /* Delete node */ if (prev != NULL) prev->sibling = node->sibling; else { if (parent != NULL) parent->child = node->sibling; else root = node->sibling; } free(node->value); free(node); } return root; } TDelete = TLookup + m = O(md + m) = O(md) 30 Вывод на экран элементов Trie void trie_print(struct trie *root, int level) { struct trie *node; int i; for (node = root; node != NULL; node = node->sibling) { for (i = 0; i < level; i++) printf(" "); if (node->value != NULL) printf("%c (%s)\n", node->ch, node->value); else printf("%c \n", node->ch); if (node->child != NULL) trie_print(node->child, level + 1); } } 31 Пример работы с Trie int main() { struct trie *root; root = trie_insert(NULL, root = trie_insert(root, root = trie_insert(root, root = trie_insert(root, root = trie_insert(root, trie_print(root, 0); "bars", "60"); "baribal", "100"); "kit", "3000"); "lev", "500"); "bars", "70"); printf("Lookup 'bars': %s\n", trie_lookup(root, "bars")); root = trie_delete(root, "bars"); trie_print(root, 0); return 0; } 32 Вычислительная сложность операций Trie Способ работы c указателями c1, c2, …, cd Операция Связный список Массив Self-balanced search tree (Red black/AVL tree) Lookup O(md) O(m) O(mlogd) Insert O(md) O(m) O(mlogd) Delete O(md) O(m) O(mlogd) Min O(hd) O(hd) O(hlogd) Max O(hd) O(hd) O(hlogd)  h – высота дерева (количество символов в самом длинном ключе) 33 Преимущества префиксных деревьев  Время поиска не зависит от количества n элементов в словаре (зависит от длины ключа)  Для хранения ключей на используется дополнительной памяти (ключи не хранятся в узлах)  В отличии от хеш-таблиц поддерживает обход в упорядоченном порядке (от меньших к большим и наоборот, реализует ordered map) – зависит от реализации SetChild/GetChild  В отличии от хеш-таблиц не возникает коллизий 34 Производительность строковых словарей Операция     Trie Self-balanced search tree (linked list) (Red black/AVL tree) Hash table Lookup O(md) O(mlogn) O(m + n) Insert O(md) O(mlogn) O(m) Delete O(md) O(mlogn) O(m + n) Min O(hd) O(logn) O(H + n) Max O(hd) O(logn) O(H + n) m – длина ключа d – количество символов в алфавите (константа) n – количество элементов в словаре H – размер хеш-таблицы 35 Bitwise tree  Bitwise trie – префиксное дерево (trie), в котором ключи рассматривается как последовательность битов  Bitwise trie – это бинарное дерево 36 Radix tree (patricia trie)  Radix tree (radix trie, patricia trie, compact prefix tree) – префиксное дерево (trie), в котором узел содержащий один дочерний элемент объединяется с ним для экономии памяти PATRICIA trie:  D. R. Morrison. PATRICIA – Practical Algorithm to Retrieve Information Coded in Alphanumeric. Jrnl. of the ACM, 15(4). pp. 514-534, Oct 1968.  Gwehenberger G. Anwendung einer binären Verweiskettenmethode beim Aufbau von Listen. Elektronische Rechenanlagen 10 (1968), pp. 223–226 37 Radix tree (patricia trie) http://en.wikipedia.org/wiki/Radix_tree 38 Suffix tree  Suffix tree (PAT tree, position tree) – префиксное дерево (trie), содержащее все суффиксы заданного текста (ключи) и их начальные позиции в тексте (values)  Суффиксное дерево для текста BANANA Суффиксы: A$, NA$, ANA$, NANA$, ANANA$, BANANA$  Применение: o o o o o  Поиск подстроки в строке O(m) Поиск наибольшей повторяющейся подстроки Поиск наибольшей общей подстроки Поиск наибольшей подстроки-палиндрома Алгоритм LZW сжатия информации Автор: Weiner P. Linear pattern matching algorithms // 14th Annual IEEE Symposium on Switching and Automata Theory, 1973, pp. 1-11 39 Литература  Ахо А.В., Хопкрофт Д., Ульман Д.Д. Структуры данных и алгоритмы. – М.: Вильямс, 2001. – 384 с.  Гасфилд Д. Строки, деревья и последовательности в алгоритмах. Информатика и вычислительная биология. – Санкт-Петербург: Невский Диалект, БХВ-Петербург, 2003. – 656 с.  Билл Смит. Методы и алгоритмы вычислений на строках. Теоретические основы регулярных вычислений. – М.: Вильямс, 2006. – 496 с. 40
«Префиксные деревья (prefix tree, trie)» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Найди решение своей задачи среди 1 000 000 ответов
Найти

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot