Изменения

Перейти к: навигация, поиск

Сжатое суффиксное дерево

44 байта убрано, 12:23, 8 мая 2012
Нет описания правки
[[Суффиксный бор|Суффиксный бор]] {{---}} удобная структура для поиска подстроки в строке, но занимающая много места в памяти. Рассмотрим все такие пути от <tex>u</tex> до <tex>v</tex> в суффиксном боре, в которых каждая вершина имеет только одного сына. Такие пути Такой путь можно сжать до одного ребра <tex>u v</tex>, пометив его всеми встречающимися на пути символами. Получившееся дерево носит название '''сжатое суффиксное дерево'''.
==Определение==
==Защитный символ==
[[Файл:Suffix_tree_3.png|thumb|right|Суффиксное дерево для строки <tex>xabxa</tex> с защитным символом]]
Определение суффиксного дерева не гарантирует, что такое дерево существует для любой строки <tex>s</tex>. Если один суффикс строки совпадает с префиксом другого, то построить суффиксное дерево, удовлетворяющее данному выше определению, невозможно. Например, для строки <tex>xabxa</tex> суффикс <tex>xa</tex> является префиксом суффикса <tex>xabxa.</tex> Во избежание этого в конце строки <tex>s</tex> добавляется символ, не входящий в исходный алфавит. Такой символ называется '''''защитным'''''. Как правило, это <tex>\$</tex>. Любой суффикс строки с защитным символом заканчивается в листе и только в листе, т.к. он не встречается в строке нигде, кроме позиции последнего символа.
Далее <tex>n</tex> - длина строки <tex>s</tex> с защитным символом.
==Хранение суффиксного дерева==
Каждое ребро суффиксного дерева помечается подстрокой исходной строки <tex>s</tex>. Но лучше для него хранить не саму подстроку, а индексы ее начала и конца в исходной строке {{---}} <tex>l, r</tex>. Итак, с каждым ребром дерева ассоциируются две инцидентные ей вершины, символ, с которого начинается подстрока на ребре и два числа <tex>l, r</tex>. Представим дерево как массив <tex>[|V|*|\Sigma|]</tex>, где <tex>|V|</tex> {{---}} количество вершин в дереве, <tex>|\Sigma|</tex> - мощность алфавита. Каждая <tex>[i][j]</tex> ячейка массива содержит информацию о том, в какую вершину ведет <tex>i-</tex>ое ребро по <tex>j-</tex>ому символу и индексы <tex>l, r</tex> подстроки на ребре. Очевидно, такое дерево занимает <tex>O(|V||\Sigma|)</tex> памяти.
==Количество вершин==
В сжатом суффиксном дереве содержится <tex>n</tex> листьев, т.к. каждый суффикс строки строка <tex>s</tex> заканчивается в листесодержит ровно <tex>n</tex> суффиксов. Рассмотрим теперь количество внутренних вершин такого дерева.
{{Лемма
Рассмотрим все вершины в дереве для строки длины <tex>n + 1</tex>, у которых хотя бы один из детей - лист.
Если среди них есть вершина, у которой более двух детей, отрежем от нее лист. Получим дерево с <tex>n</tex> листьями, удовлетворяющее условию леммы по индукционному предположению, причем в нем количество внутренних вершин равно количеству внутренних вершин в исходном дереве. Тогда у полученного дерева менее <tex>n</tex> внутренних вершин, значит в исходном дереве количество внутренних вершин так же меньше количества листьев.
Иначе среди этих вершин есть вершина, у которой оба ребенка - листья. Отрежем оба этих листа, получим дерево с <tex>n</tex> листьями, удовлетворяющее условию леммы, количество внутренних вершин которого на <tex>1</tex> меньше количества внутренних вершин в исходном дереве. Тогда, по индукционному предположению, у полученного дерева менее <tex>n</tex> внутренних вершин, значит в исходном дереве количество внутренних вершин меньше <tex>n + 1</tex>.
==Занимаемая память==
Очевидно, суффиксное дерево в виде массива занимает <tex>O(|V||\Sigma|)</tex> памяти. Так как любое суффиксное дерево удовлетворяет условиям леммы, и все его внутренние (у каждой вершины, по определению, имеют не менее двух детей), то количество внутренних вершин в нем меньше количества листьев, равного <tex>n</tex>. Значит, поэтому для его хранения требуется <tex>O(n|\Sigma|)</tex> памяти.
==Построение суффиксного дерева==
insert(<tex>i, n</tex>) //добавляем суффикс, начинающийся с него
insert(l,r) //процедура вставки
<tex> cur \leftarrow root </tex> //инициализируем текущую вершину корнем
'''while''' (<tex> i < r </tex>)
<tex>finish \leftarrow go[cur][s[i]].r </tex>
'''for''' <tex> j = start </tex> '''to''' <tex> finish </tex> //для каждого символа на ребре из текущей вершины
'''if''' <tex>s[i+j-start] <>s[j] </tex> //если нашли не совпадающий символ
'''разбить ребро'''
'''break'''
Этот алгоритм работает за время <tex>O(n^2)</tex>, однако существует [[Алгоритм Укконена| алгоритм Укконена]], позволяющий построить дерево за время <tex>O(n)</tex>.
==Использованиесжатого суффиксного дерева==
Суффиксное дерево позволяет за линейное время найти:
* Количество различных подстрок данной строки
80
правок

Навигация