4511
правок
Irina (обсуждение | вклад) |
Irina (обсуждение | вклад) |
||
Строка 39: | Строка 39: | ||
Отметим, что эта граница по памяти не является оптимальной, поскольку существуют \ | Отметим, что эта граница по памяти не является оптимальной, поскольку существуют <math> | \Sigma |^n\;</math> различных строк и, следовательно, суффиксных деревьев, тогда как n log n bits могут представлять n! различных объектов. | ||
Теорема 2. Суффиксные деревья могут быть построены за оптимальное время, в частности: | '''Теорема 2. Суффиксные деревья могут быть построены за оптимальное время, в частности:''' | ||
1. В случае алфавита константной длины суффиксное дерево T(S) для строки S длины n может быть построено за время O(n) [11, 12, 13]. В случае алфавита общего вида указанные алгоритмы требуют O(n log n) времени. | 1. В случае алфавита константной длины суффиксное дерево T(S) для строки S длины n может быть построено за время O(n) [11, 12, 13]. В случае алфавита общего вида указанные алгоритмы требуют O(n log n) времени. | ||
2. В случае целочисленного алфавита суффиксное дерево для строки S может быть построено за время O(n) [4, 9]. | 2. В случае целочисленного алфавита суффиксное дерево для строки S может быть построено за время O(n) [4, 9]. | ||
Строка 53: | Строка 54: | ||
Другой алгоритм в 1976 году предложил МакКрейт [11]. В этом алгоритме суффиксы вставляются в растущее дерево от самого длинного к самому короткому. Это упрощает процедуру обновления, а дополнительной структурой данных является только один вид ссылки: внутренняя вершина v с меткой пути P(v) = aw для некоторого символа a | Другой алгоритм в 1976 году предложил МакКрейт [11]. В этом алгоритме суффиксы вставляются в растущее дерево от самого длинного к самому короткому. Это упрощает процедуру обновления, а дополнительной структурой данных является только один вид ссылки: внутренняя вершина v с меткой пути P(v) = aw для некоторого символа <math>a \in \Sigma \;</math> и строка <math>w \in \Sigma^* \;</math> имеют суффиксную ссылку на вершину u с меткой пути P(u) = w. На рис. 1 суффиксные ссылки представлены пунктирными стрелками. Они часто соединяют вершины над точками вставки последовательно вставленных суффиксов, как в примере на рис. 1 для вершины с меткой пути «M» и корневой вершины при вставке суффиксов «MAMIA» и «AMIA». Это свойство позволяет перейти в следующую точку вставки без необходимости поиска ее от корня дерева, в силу чего обеспечивается амортизированное константное время вставки одного суффикса. Отметим, что поскольку алгоритм МакКрейта обрабатывает суффиксы от самого длинного к самому короткому, а промежуточные структуры не являются суффиксными деревьями, алгоритм не является онлайновым. | ||
Строка 63: | Строка 64: | ||
Первый алгоритм с линейным временем выполнения для построения суффиксного дерева на целочисленном алфавите предложили Фарах и Колтон [4]. Он использует так называемую четно-нечетную технику в три этапа: | Первый алгоритм с линейным временем выполнения для построения суффиксного дерева на целочисленном алфавите предложили Фарах и Колтон [4]. Он использует так называемую четно-нечетную технику в три этапа: | ||
1. Рекурсивно вычислить сокращенное trie-дерево всех суффиксов S, начинающихся с нечетных позиций; обозначим его <math>T_o \;</math>. | |||
2. Вывести из <math>T_o \;</math> сокращенное trie-дерево всех суффиксов S, начинающихся с четных позиций, обозначаемое <math>T_e \;</math>. | |||
3. Слить <math>T_o \;</math> и <math>T_e \;</math> в целое суффиксное дерево T(S). | |||
На третьем этапе два trie-дерева | |||
Основная идея первого этапа заключается в кодировании пар символов как единичных символов. Поскольку могут встретиться только n/2 таких различных символов, они могут быть поразрядно отсортированы с сокращением диапазона до алфавита размера n/2. Таким образом, строка S длины n над целочисленным алфавитом <math>\Sigma = \{ 1, ..., n \} \;</math> переводится за время O(n) в строку S' длины n/2 над целочисленным алфавитом <math>\Sigma' = \{ 1, ..., n/2 \} \;</math>. Рекурсивное применение этого алгоритма дает в итоге суффиксное дерево S'. После перевода меток ребер из подстрок S' обратно в подстроки S могут встречаться вершины с исходящими ребрами, метки которых начинаются с одного и того же символа, поскольку два различных символа из <math>\Sigma' \;</math> могут быть парами с одним и тем же первым символом из <math>\Sigma \;</math>. В таких случаях свойство trie-дерева может быть восстановлено при помощи локальных модификаций меток ребер или добавления дополнительных вершин, в результате чего будет получено требуемое дерево <math>T_o \;</math>. | |||
На втором этапе полученное «нечетное» дерево <math>T_o \;</math> используется для генерации лексикографически отсортированного списка суффиксов, начинающихся с нечетных позиций. Поразрядная сортировка этих суффиксов со значениями символов в предшествующих четных позициях в качестве ключей позволяет получить лексикографически отсортированный список четных суффиксов за линейное время. Наряду с самыми длинными общими префиксами последовательных позиций, которые могут быть вычислены из <math>T_o \;</math> за линейное время при помощи запросов по поводу самого низкого общего предка и равенства | |||
<math>lcp(l_{2i}, l_{2j}) = lcp(l_{2i + 1}, l_{2j + 1}) \;</math>, если S[2i] = S[2j], и 0 в противном случае | |||
это упорядочение позволяет реконструировать «четное» дерево <math>T_e \;</math> за линейное время. | |||
На третьем этапе два trie-дерева <math>T_o \;</math> и <math>T_e \;</math> сливаются в суффиксное дерево T(S). Концептуально эта процедура достаточно проста: выполняется параллельный обход двух trie-деревьев, и каждая часть, присутствующая в одном или обоих деревьях, включается в общую структуру. Однако эта процедура проста только в случае, если ребра обходятся символ за символом, таким образом, чтобы подобные общие и различающиеся фрагменты можно было наблюдать непосредственно. Такой обход потребует O(n2) времени в наихудшем случае, что существенно ухудшит общее линейное время выполнения. Поэтому Фарах и Колтон предлагают использовать оракула, который для ребра из To и ребра из Te сообщает длину их общего префикса. Однако предложенный оракул может переоценивать длину, в результате чего сгенерированное дерево иногда требует коррекции, называемой отделением. Полное описание оракула и процедуры отделения см. в [4]. | |||
Строка 84: | Строка 92: | ||
В некоторых приложениях используется так называемое обобщенное суффиксное дерево для нескольких строк; словарь получается путем построения суффиксного дерева для конкатенации соответствующих строк. Важный вопрос в контексте этого построения касается динамического обновления дерева по мере вставки и удаления строк из словаря. Точнее говоря, поскольку метки ребер хранятся в виде пар указателей на исходную строку, после удаления строки из словаря соответствующие указатели могут стать недействительными и будут требовать обновления. Алгоритм для решения этой задачи за амортизированное линейное время предложили Фиала и Грин [6], линейный алгоритм для наихудшего случая (и, следовательно, исполняемый в реальном времени) – Ферраджина и др. [5]. | В некоторых приложениях используется так называемое обобщенное суффиксное дерево для нескольких строк; словарь получается путем построения суффиксного дерева для конкатенации соответствующих строк. Важный вопрос в контексте этого построения касается динамического обновления дерева по мере вставки и удаления строк из словаря. Точнее говоря, поскольку метки ребер хранятся в виде пар указателей на исходную строку, после удаления строки из словаря соответствующие указатели могут стать недействительными и будут требовать обновления. Алгоритм для решения этой задачи за амортизированное линейное время предложили Фиала и Грин [6], линейный алгоритм для наихудшего случая (и, следовательно, исполняемый в реальном времени) – Ферраджина и др. [5]. | ||
== Применение == | == Применение == |
правок