Редактирование: Алгоритм МакКрейта

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

Внимание! Вы не авторизовались на сайте. Ваш IP-адрес будет публично видимым, если вы будете вносить любые правки. Если вы войдёте или создадите учётную запись, правки вместо этого будут связаны с вашим именем пользователя, а также у вас появятся другие преимущества.

Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.
Текущая версия Ваш текст
Строка 2: Строка 2:
  
 
==Историческая справка==
 
==Историческая справка==
Первым оптимальным по времени был алгоритм, предложенный Вайнером в 1973 году. Идея алгоритма была в нахождении первых символов суффикса, которые находились в уже построенном дереве. Суффиксы просматривались от самого короткого к самому длинному, а для быстрого поиска использовались по два массива размера алфавита на каждую вершину, что затрудняло как понимание алгоритма, так и его реализацию и эффективность, особенно в плане занимаемой памяти. МакКрейт в 1976 году предложил свой алоритм<ref>[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.130.8022&rep=rep1&type=pdf Edward M. McCreight {{---}} A Space-Economical Suffix Tree Construction Algorithm]</ref>, в котором порядок добавления суффиксов заменен на обратный, а для быстрого вычисления места, откуда нужно продолжить построение нового суффикса, достаточно суффиксной ссылки в каждой вершине. В 1995 году Укконен представил свою версию алгоритма<ref>[http://www.cs.helsinki.fi/u/ukkonen/SuffixT1withFigs.pdf Esko Ukkonen {{---}} On-line construction of suffix trees]</ref>, которая считается наиболее простой для понимания, а также, в отличие от алгоритмов Вейнера и МакКрейта, является online алгоритмом, способным строить неявное суффиксное дерево по мере прочтения строки, а затем превратить его в настоящее.
+
Первым оптимальным по времени был алгоритм, предложенный Вайнером в 1973 году. Идея алгоритма была в нахождении первых символов суффикса, которые находились в уже построенном дереве. Суффиксы просматривались от самого короткого к самому длинному, а для быстрого поиска использовались по два массива размера алфавита на каждую вершину, что затрудняло как понимание алгоритма, так и его реализацию и эффективность, особенно в плане занимаемой памяти. МакКрейт в 1976 году предложил свой алоритм<ref>[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.130.8022&rep=rep1&type=pdf Edward M. McCreight {{---}} A Space-Economical Suffix Tree Construction Algorithm]</ref>, в котором порядок добавления суффиксов заменен на обратный, а для быстрого вычисления места, откуда нужно продолжить построение нового суффикса, достаточно суффиксной ссылки в каждой вершине. В 1995 году Укконен представил свою версию алгоритма<ref>[http://www.cs.helsinki.fi/u/ukkonen/SuffixT1withFigs.pdf Esko Ukkonen {{---}} On-line construction of suffix trees]</ref>, которая считается наиболее простой для понимания, а также, в отличие от алгоритмов Вейнера и МакКрейта, является online алгоритмом, способным строить неявное суффиксное дерево по мере прочтения строки, а затем превратить его в настоящее.
  
 
== Теоретическое обоснование ==
 
== Теоретическое обоснование ==
Строка 18: Строка 18:
 
}}
 
}}
  
Если нам известны суффиксные ссылки <tex>u.suf</tex> для каждой вершины <tex>u</tex>, мы можем быстро перейти от позиции <tex>head_i</tex> к её суффиксу и продолжить сравнение символов оттуда. Если бы новая позиция <tex>head_i</tex> всегда оказывалась существующей вершиной построенного дерева, этот алгоритм бы уже работал, но в реальности можно оказаться на середине ребра, для которой суффиксная ссылка неизвестна. Для нахождения её суффиксной ссылки на следующей итерации мы сначала перейдем к предку, пройдем по суффиксной ссылке, а уже затем будем продолжать сравнение.
+
Если нам известны суффиксные ссылки <tex>u.suf</tex> для каждой вершины <tex>u</tex>, мы можем быстро перейти от позиции <tex>head_i</tex> к ее суффиксу и продолжить сравнение символов оттуда. Если бы новая позиция <tex>head_i</tex> всегда оказывалась существующей вершиной построенного дерева, этот алгоритм бы уже работал, но в реальности можно оказаться на середине ребра, для которой суффиксная ссылка неизвестна. Для нахождения ее суффиксной ссылки на следующей итерации мы сначала перейдем к предку, пройдем по суффиксной ссылке, а уже затем будем продолжать сравнение.
  
 
== Алгоритм ==
 
== Алгоритм ==
Строка 31: Строка 31:
 
При добавлении каждого следующего суффикса будем выполнять следующие шаги:
 
При добавлении каждого следующего суффикса будем выполнять следующие шаги:
 
* Если суффиксная ссылка <tex>head_{i-1}</tex> не определена:
 
* Если суффиксная ссылка <tex>head_{i-1}</tex> не определена:
*# Поднимемся вверх к её предку;
+
*# Поднимемся вверх к ее предку;
 
*# Пройдем по суффиксной ссылке;
 
*# Пройдем по суффиксной ссылке;
 
*# Спустимся вниз на столько символов, сколько мы прошли вверх к предку (''fast scanning'').
 
*# Спустимся вниз на столько символов, сколько мы прошли вверх к предку (''fast scanning'').
Строка 57: Строка 57:
  
 
Конструктор будет иметь вид <code>Node(Node parent, '''int''' start, '''int''' end, '''int''' depth)</code>.
 
Конструктор будет иметь вид <code>Node(Node parent, '''int''' start, '''int''' end, '''int''' depth)</code>.
Пусть глобально известна строка <tex>s</tex> со специальным символом на конце, её длина <tex>n</tex> и используемый алфавит <tex>\Sigma</tex>.
+
Пусть глобально известна строка <tex>s</tex> со специальным символом на конце, ее длина <tex>n</tex> и используемый алфавит <tex>\Sigma</tex>.
  
 
<code>
 
<code>
Строка 102: Строка 102:
 
       child = curNode.children[s[curPos]] <font color=green> // Ребенок по символу суффикса </font>
 
       child = curNode.children[s[curPos]] <font color=green> // Ребенок по символу суффикса </font>
 
       edgePos = 0                        <font color=green> // Текущая позиция на ребре </font>
 
       edgePos = 0                        <font color=green> // Текущая позиция на ребре </font>
       '''while''' символы на ребре совпадают с суффиксом
+
       '''while''' символы на ребре совпадают с суффиксом  
 
           curPos++
 
           curPos++
 
           edgePos++
 
           edgePos++
Строка 117: Строка 117:
 
''Slow scanning'' делает <tex>\left\vert head_i \right\vert - \left\vert head_{i-1} \right\vert + 1</tex> операций, что суммарно дает <tex>\left\vert head_n \right\vert - \left\vert head_0 \right\vert + n = O(n)</tex> операций.
 
''Slow scanning'' делает <tex>\left\vert head_i \right\vert - \left\vert head_{i-1} \right\vert + 1</tex> операций, что суммарно дает <tex>\left\vert head_n \right\vert - \left\vert head_0 \right\vert + n = O(n)</tex> операций.
  
''Fast scanning'' работает с целыми рёбрами, поэтому будем использовать в качестве [[Амортизационный анализ#Метод потенциалов| потенциала]] глубину в вершинах. Из структуры [[Сжатое суффиксное дерево| суффиксного дерева]] мы знаем, что суффиксная ссылка может уменьшить глубину вершины не более, чем на <tex>1</tex>, так что мы на каждой итерации поднимаемся не более, чем на <tex>2</tex> {{---}} один раз к предку, а потом по суффиксной ссылке, что составляет <tex>O(n)</tex> за весь алгоритм. Соответственно, спустимся мы тоже суммарно <tex>O(n)</tex> раз, так как и максимальная глубина составляет <tex>O(n)</tex>.
+
''Fast scanning'' работает с целыми ребрами, поэтому будем использовать в качестве [[Амортизационный анализ#Метод потенциалов| потенциала]] глубину в вершинах. Из структуры [[Сжатое суффиксное дерево| суффиксного дерева]] мы знаем, что суффиксная ссылка может уменьшить глубину вершины не более, чем на <tex>1</tex>, так что мы на каждой итерации поднимаемся не более, чем на <tex>2</tex> {{---}} один раз к предку, а потом по суффиксной ссылке, что составляет <tex>O(n)</tex> за весь алгоритм. Соответственно, спустимся мы тоже суммарно <tex>O(n)</tex> раз, так как и максимальная глубина составляет <tex>O(n)</tex>.
  
 
Итоговая асимптотика алгоритма {{---}} <tex>O(n)</tex>.
 
Итоговая асимптотика алгоритма {{---}} <tex>O(n)</tex>.

Пожалуйста, учтите, что любой ваш вклад в проект «Викиконспекты» может быть отредактирован или удалён другими участниками. Если вы не хотите, чтобы кто-либо изменял ваши тексты, не помещайте их сюда.
Вы также подтверждаете, что являетесь автором вносимых дополнений, или скопировали их из источника, допускающего свободное распространение и изменение своего содержимого (см. Викиконспекты:Авторские права). НЕ РАЗМЕЩАЙТЕ БЕЗ РАЗРЕШЕНИЯ ОХРАНЯЕМЫЕ АВТОРСКИМ ПРАВОМ МАТЕРИАЛЫ!

Чтобы изменить эту страницу, пожалуйста, ответьте на приведённый ниже вопрос (подробнее):

Отменить | Справка по редактированию (в новом окне)

Шаблоны, используемые на этой странице: