Сжатое суффиксное дерево — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 1: Строка 1:
'''Суффиксное дерево''' (сжатое суффиксное дерево) <tex>T</tex> для строки <tex>s</tex> (где  <tex>|s| = n</tex>) {{---}} ориентированное дерево с корнем, имеющее ровно <tex>n</tex> листьев, занумерованных от <tex>1</tex> до <tex>n</tex>. Каждая внутренняя вершина, отличная от корня, имеет не меньше двух детей, а каждая дуга помечена непустой подстрокой строки <tex>s</tex>. Никакие две дуги, выходящие из одной и той же вершины, не могут иметь пометок, начинающихся с одного и того же символа. Суффиксное дерево содержит все суффиксы строки <tex>s</tex>: для каждого листа <tex>i</tex> конкатенация меток дуг на пути от корня к листу <tex>i</tex> в точности составляет суффикс, который начинается в позиции <tex>i</tex>, то есть <tex>s[i..n]</tex>.
+
[[Суффиксный бор|Суффиксный бор]] {{---}} удобная структура для поиска подстроки в строке, но занимающая много места в памяти. Рассмотрим все такие пути от <tex>u</tex> до  <tex>v</tex> в суффиксном боре, в которых каждая вершина имеет только одного сына. Такие пути можно сжать до одного ребра <tex>u v</tex>, пометив его всеми встречающимися на пути символами. Получившееся дерево носит название '''сжатое суффиксное дерево'''.
 +
 
 +
==Определение==
 +
'''Суффиксное дерево''' (сжатое суффиксное дерево) <tex>T</tex> для строки <tex>s</tex> (где  <tex>|s| = n</tex>) {{---}} ориентированное дерево, с ровно <tex>n</tex> листами, каждая внутренняя вершина которого, отличная от корня, имеет не меньше двух детей, а каждое ребро помечено непустой подстрокой строки <tex>s</tex> и символом, с которого начинается эта подстрока. Никакие два ребра, выходящие из одной и той же вершины, не могут иметь одинаковых символьных пометок. Суффиксное дерево содержит все суффиксы строки <tex>s</tex>: для каждого листа <tex>i</tex> конкатенация подстрок на ребрах пути от корня к листу <tex>i</tex> в точности составляет суффикс, который начинается в позиции <tex>i</tex>, то есть <tex>s[i..n]</tex>.
  
 
==Существование сжатого суффиксного дерева==
 
==Существование сжатого суффиксного дерева==
 
[[Файл:Suffix_tree_3.png|thumb|right|Суффиксное дерево для строки <tex>xabxa</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>s</tex>. Если один суффикс совпадает с префиксом другого суффикса, то построить суффиксное дерево, удовлетворяющее данному выше определению, невозможно, поскольку путь для первого суффикса не сможет закончиться в листе. Например, для строки <tex>xabxa</tex> суффикс <tex>xa</tex> является префиксом суффикса <tex>xabxa</tex>. Во избежание этого в конце строки <tex>s</tex> добавляется символ, не входящий в исходный алфавит. Такой символ называется '''''защитным'''''. Как правило, защитный символ обозначается <tex>\$</tex>. Любой суффикс строки с защитным символом заканчивается в листе, т.к. этот символ не встречается в строке нигде, кроме позиции последнего символа.
 +
 
 +
==Хранение суффиксного дерева==
 +
Как уже было отмечено выше, каждое ребро дерева помечается подстрокой исходной строки <tex>s</tex>. Значит, можно для каждого ребра хранить не саму подстроку, а индексы начала и конца подстроки в исходной строке {{---}} <tex>l, r</tex>. Итак, с каждым ребром дерева ассоциируются две инцидентные ей вершины, символ, с которого начинается подстрока на ребре и два числа <tex>l, r</tex>. Представим его как массив <tex>[|V|*|\Sigma|]</tex>, где <tex>|V|</tex> {{---}} количество вершин в дереве. Каждая <tex>[i][j]</tex> ячейка массива содержит информацию о том, в какую вершину ведет <tex>i-ое</tex> ребро по <tex>j-ому</tex> символу, в какую вершину оно ведет и индексы <tex>l, r</tex> подстроки на ребре.
  
==Связь с суффиксным бором==
+
==Количество вершин==
Пусть <tex>P</tex> {{---}} [[Суффиксный бор|суффиксный бор]] строки <tex>s</tex>. Тогда сжатое суффиксное дерево <tex>T</tex> может быть получено из <tex>P</tex> слиянием каждого пути из неветвящихся вершин в одну дугу.
+
В сжатом суффиксном дереве содержится <tex>n</tex> листьев, т.к. каждый суффикс строки <tex>s</tex> заканчивается в листе. Рассмотрим теперь количество внутренних вершин такого дерева.
  
==Количество внутренних вершин==
 
 
{{Лемма
 
{{Лемма
 
|statement=
 
|statement=
Строка 21: Строка 26:
 
'''Переход''' <tex>n \rightarrow n + 1</tex>
 
'''Переход''' <tex>n \rightarrow n + 1</tex>
  
Рассмотрим все вершины, у которых хотя бы один из детей - лист.
+
Рассмотрим все вершины в дереве для строки длины <tex>n + 1</tex>, у которых хотя бы один из детей - лист.
  
Если среди них есть вершина, у которой более двух детей, отрежем от нее лист. Получим дерево с <tex>n</tex> листьями, удовлетворяющее условию леммы, в котором количество внутренних вершин равно количеству внутренних вершин в исходном дереве. Тогда, по индукционному предположению, у полученного дерева менее <tex>n</tex> внутренних вершин, значит в исходном дереве количество внутренних вершин меньше количества листьев.
+
Если среди них есть вершина, у которой более двух детей, отрежем от нее лист. Получим дерево с <tex>n</tex> листьями, удовлетворяющее условию леммы по индукционному предположению, причем в нем количество внутренних вершин равно количеству внутренних вершин в исходном дереве. Тогда у полученного дерева менее <tex>n</tex> внутренних вершин, значит в исходном дереве количество внутренних вершин так же меньше количества листьев.
  
 
Иначе среди этих вершин есть вершина, у которой оба ребенка - листья. Отрежем оба этих листа, получим дерево с <tex>n</tex> листьями, удовлетворяющее условию леммы, количество внутренних вершин которого на <tex>1</tex> меньше количества внутренних вершин в исходном дереве. Тогда, по индукционному предположению, у полученного дерева менее <tex>n</tex> внутренних вершин, значит в исходном дереве количество внутренних вершин меньше <tex>n + 1</tex>.
 
Иначе среди этих вершин есть вершина, у которой оба ребенка - листья. Отрежем оба этих листа, получим дерево с <tex>n</tex> листьями, удовлетворяющее условию леммы, количество внутренних вершин которого на <tex>1</tex> меньше количества внутренних вершин в исходном дереве. Тогда, по индукционному предположению, у полученного дерева менее <tex>n</tex> внутренних вершин, значит в исходном дереве количество внутренних вершин меньше <tex>n + 1</tex>.
 
}}
 
}}
  
==Хранение в памяти==
+
==Занимаемая память==
Так как суффиксное дерево удовлетворяет условиям леммы, то количество внутренних вершин в нем меньше количества листьев, поэтому для его хранения требуется <tex>O(n|\Sigma|)</tex> памяти.
+
Очевидно, суффиксное дерево в виде массива занимает <tex>O(|V||\Sigma|)</tex> памяти. Так как любое суффиксное дерево удовлетворяет условиям леммы, то количество внутренних вершин в нем меньше количества листьев, равного <tex>n</tex>, поэтому для его хранения требуется <tex>O(n|\Sigma|)</tex> памяти.
 +
 
 +
==Построение суффиксного дерева==
 +
Рассмотрим наивный алгоритм построения суффиксного дерева.
 +
 
 +
Этот алгоритм работает за время<tex>O(n^2)</tex>, однако существует [[Алгоритм Укконена| алгоритм Укконена]], позволяющий построить дерево за время<tex>O(n)</tex>.
  
 
==Использование==
 
==Использование==
Строка 35: Строка 45:
 
* Количество различных подстрок данной строки
 
* Количество различных подстрок данной строки
 
* Наибольшую общую подстроку двух строк
 
* Наибольшую общую подстроку двух строк
* [[Суффиксный массив| Суффиксный массив]] и массив <tex>lcp</tex> (longest common prefix)
+
* [[Суффиксный массив| Суффиксный массив]] и массив <tex>lcp</tex> (longest common prefix) исходной строки
  
 
==Источники==
 
==Источники==
 
''Дэн Гасфилд'' — '''Строки, деревья и последовательности в алгоритмах: Информатика и вычислительная биология''' — СПб.: Невский Диалект; БХВ-Петербург, 2003. — 654 с: ил.
 
''Дэн Гасфилд'' — '''Строки, деревья и последовательности в алгоритмах: Информатика и вычислительная биология''' — СПб.: Невский Диалект; БХВ-Петербург, 2003. — 654 с: ил.

Версия 16:27, 22 апреля 2012

Суффиксный бор — удобная структура для поиска подстроки в строке, но занимающая много места в памяти. Рассмотрим все такие пути от [math]u[/math] до [math]v[/math] в суффиксном боре, в которых каждая вершина имеет только одного сына. Такие пути можно сжать до одного ребра [math]u v[/math], пометив его всеми встречающимися на пути символами. Получившееся дерево носит название сжатое суффиксное дерево.

Определение

Суффиксное дерево (сжатое суффиксное дерево) [math]T[/math] для строки [math]s[/math] (где [math]|s| = n[/math]) — ориентированное дерево, с ровно [math]n[/math] листами, каждая внутренняя вершина которого, отличная от корня, имеет не меньше двух детей, а каждое ребро помечено непустой подстрокой строки [math]s[/math] и символом, с которого начинается эта подстрока. Никакие два ребра, выходящие из одной и той же вершины, не могут иметь одинаковых символьных пометок. Суффиксное дерево содержит все суффиксы строки [math]s[/math]: для каждого листа [math]i[/math] конкатенация подстрок на ребрах пути от корня к листу [math]i[/math] в точности составляет суффикс, который начинается в позиции [math]i[/math], то есть [math]s[i..n][/math].

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

Суффиксное дерево для строки [math]xabxa[/math] с защитным символом

Определение суффиксного дерева не гарантирует, что такое дерево существует для любой строки [math]s[/math]. Если один суффикс совпадает с префиксом другого суффикса, то построить суффиксное дерево, удовлетворяющее данному выше определению, невозможно, поскольку путь для первого суффикса не сможет закончиться в листе. Например, для строки [math]xabxa[/math] суффикс [math]xa[/math] является префиксом суффикса [math]xabxa[/math]. Во избежание этого в конце строки [math]s[/math] добавляется символ, не входящий в исходный алфавит. Такой символ называется защитным. Как правило, защитный символ обозначается [math]\$[/math]. Любой суффикс строки с защитным символом заканчивается в листе, т.к. этот символ не встречается в строке нигде, кроме позиции последнего символа.

Хранение суффиксного дерева

Как уже было отмечено выше, каждое ребро дерева помечается подстрокой исходной строки [math]s[/math]. Значит, можно для каждого ребра хранить не саму подстроку, а индексы начала и конца подстроки в исходной строке — [math]l, r[/math]. Итак, с каждым ребром дерева ассоциируются две инцидентные ей вершины, символ, с которого начинается подстрока на ребре и два числа [math]l, r[/math]. Представим его как массив [math][|V|*|\Sigma|][/math], где [math]|V|[/math] — количество вершин в дереве. Каждая [math][i][j][/math] ячейка массива содержит информацию о том, в какую вершину ведет [math]i-ое[/math] ребро по [math]j-ому[/math] символу, в какую вершину оно ведет и индексы [math]l, r[/math] подстроки на ребре.

Количество вершин

В сжатом суффиксном дереве содержится [math]n[/math] листьев, т.к. каждый суффикс строки [math]s[/math] заканчивается в листе. Рассмотрим теперь количество внутренних вершин такого дерева.

Лемма:
Количество внутренних вершин дерева, каждая из которых имеет не менее двух детей, меньше количества листьев.
Доказательство:
[math]\triangleright[/math]

Докажем лемму индукцией по количеству листьев [math]n[/math].

База

При [math]n = 2[/math] в дереве одна внутренняя вершина - верно.

Переход [math]n \rightarrow n + 1[/math]

Рассмотрим все вершины в дереве для строки длины [math]n + 1[/math], у которых хотя бы один из детей - лист.

Если среди них есть вершина, у которой более двух детей, отрежем от нее лист. Получим дерево с [math]n[/math] листьями, удовлетворяющее условию леммы по индукционному предположению, причем в нем количество внутренних вершин равно количеству внутренних вершин в исходном дереве. Тогда у полученного дерева менее [math]n[/math] внутренних вершин, значит в исходном дереве количество внутренних вершин так же меньше количества листьев.

Иначе среди этих вершин есть вершина, у которой оба ребенка - листья. Отрежем оба этих листа, получим дерево с [math]n[/math] листьями, удовлетворяющее условию леммы, количество внутренних вершин которого на [math]1[/math] меньше количества внутренних вершин в исходном дереве. Тогда, по индукционному предположению, у полученного дерева менее [math]n[/math] внутренних вершин, значит в исходном дереве количество внутренних вершин меньше [math]n + 1[/math].
[math]\triangleleft[/math]

Занимаемая память

Очевидно, суффиксное дерево в виде массива занимает [math]O(|V||\Sigma|)[/math] памяти. Так как любое суффиксное дерево удовлетворяет условиям леммы, то количество внутренних вершин в нем меньше количества листьев, равного [math]n[/math], поэтому для его хранения требуется [math]O(n|\Sigma|)[/math] памяти.

Построение суффиксного дерева

Рассмотрим наивный алгоритм построения суффиксного дерева.

Этот алгоритм работает за время[math]O(n^2)[/math], однако существует алгоритм Укконена, позволяющий построить дерево за время[math]O(n)[/math].

Использование

Суффиксное дерево позволяет за линейное время найти:

  • Количество различных подстрок данной строки
  • Наибольшую общую подстроку двух строк
  • Суффиксный массив и массив [math]lcp[/math] (longest common prefix) исходной строки

Источники

Дэн ГасфилдСтроки, деревья и последовательности в алгоритмах: Информатика и вычислительная биология — СПб.: Невский Диалект; БХВ-Петербург, 2003. — 654 с: ил.