Изменения
→Асимптотика алгоритма с использованием суффиксных ссылок
|definition= '''Неявное суффиксное дерево''' (англ. ''implicit suffix tree, IST'') строки <tex>S</tex> {{---}} это суффиксное дерево, построенное для строки <tex>S</tex> без добавления <tex>\$</tex>.}}
[[Файл:ExampleUkkonen2.png|400px|thumb|right|Пример построения суффиксного дерева алгоритмом Укконена.]]
Алгоритм последовательно строит неявные суффиксные деревья для всех префиксов исходного текста <tex>S = s_{1}s_{2}...\ldots s_{n}</tex>. На <tex>i</tex>-ой итерации фазе неявное суффиксное дерево <tex>\tau_{i-1}</tex> для префикса <tex>s[1..\ldots i-1]</tex> достраивается до <tex>\tau_{i}</tex> для префикса <tex>s[1..\ldots i]</tex>. Будем спускаться от корня дерева до конца Достраивание происходит следующим образом: для каждого суффикса префикса подстроки <tex>s[1..\ldots i-1]</tex> необходимо спуститься от корня дерева до конца этого суффикса и дописывать к ним дописать символ <tex>s_{i}s_i</tex>. Не стоит забывать, что <tex>s_{i}</tex> является суффиксом <tex>s[1..i]</tex> , поэтому его тоже нужно добавить в дерево. <br>
== Продление суффиксов ==
Ниже приведены возможные случаи, которые могут возникнуть при добавлении символа <tex>s_{i}</tex> ко всем суффиксам префикса <tex>s[1..\ldots i-1]</tex>.{| border="1" cellpadding="53" cellspacing="0" style="text-align:center" width=75%
!style="background:#f2f2f2"|Случай
!style="background:#f2f2f2"|Правило
|-
|style="background:#ffffff"|''1. Продление листа''
|style="background:#ffffff"|Пусть суффикс <tex>s[k..\ldots i-1]</tex> заканчивается в листе. Добавим <tex>s_{i}</tex> в конец подстроки, которой помечено ребро, ведущее в этот лист.
|style="background:#ffffff"|[[Файл:ExampleUkkonen3.png|300px]]
|-
|style="background:#ffffff" rowspan="2"|''2.1 Создание листаОтветвление''|style="background:#ffffff"|а) Пусть суффикс <tex>s[k..\ldots i-1]</tex> заканчивается в вершине, не являющейся листом, из которой нет пути по символу <tex>s_{i}</tex>. Создадим новый лист, в который из текущей вершины ведет ведёт дуга с пометкой <tex>s_{i}</tex>.
|style="background:#ffffff"|[[Файл:ExampleUkkonen4.png|300px]]
|-
|style="background:#ffffff"|''2.2 Ответвление''|style="background:#ffffff"|б) Пусть суффикс <tex>s[k..\ldots i-1]</tex> заканчивается на ребре, с меткой <tex>ts[1..p-1l \ldots r]</tex> совпадает с концом в позиции <tex>s[k..ip-1](l \leqslant p \leqslant r)</tex> и <tex>t_s_{p}\ne s_{i}</tex>. Разобьем текущее ребро новой вершиной на <tex>ts[1..l \ldots p-1]</tex> и <tex>ts[p..l\ldots r]</tex>, где <tex>l</tex> {{---}} длина метки ребра, и подвесим к ней еще одного ребенка с дугой, помеченной <tex>s_{i}</tex>.
|style="background:#ffffff"|[[Файл:ExampleUkkonen5.png|300px]]
|-
|style="background:#ffffff"|''3 . Ничего не делать''|style="background:#ffffff"|Пусть суффикс <tex>s[k..\ldots i-1]</tex> заканчивается в вершине, из которой есть путь по <tex>s_{i}</tex>. Тогда ничего делать не надо.
|style="background:#ffffff"|[[Файл:ExampleUkkonen6.png|300px]]
|}
{{Определение
|definition= Пусть <tex>x\alpha</tex> обозначает произвольную строку, где <tex>x</tex> {{---}} ее её первый символ, а <tex>\alpha</tex> {{---}} оставшаяся подстрока (возможно пустая). Если для внутренней вершины <tex>v</tex> с путевой меткой <tex>x\alpha</tex> существует другая вершина <tex>s(v)</tex> с путевой меткой <tex>\alpha</tex>, то ссылка из <tex>v</tex> в <tex>s(v)</tex> называется '''суффиксной ссылкой''' (англ. ''suffix link'').}}
{{Лемма|id=l3
|about= Существование суффиксных ссылок
Для любой внутренней вершины <tex>v</tex> суффиксного дерева существует суффиксная ссылка, ведущая в некоторую внутреннюю вершину <tex>u</tex>.
|proof=
Рассмотрим внутренную внутреннюю вершину <tex>v</tex> с путевой меткой <tex>ts[j \ldots i..j]</tex>. Так как эта вершина внутренняя, ее её путевая метка ветвится справа в исходной строке. Тогда очевидно подстрока <tex>ts[ij+1..j\ldots i]</tex> тоже ветвится справа в исходной строке, и ей соответствует некоторая внутренняя вершина <tex>u</tex>. По определению суффиксная ссылка вершины <tex>v </tex> ведет ведёт в <tex> u</tex>.
}}
=== Использование суффиксных ссылок ===
[[Файл:ExampleUkkonen7.png|200px300px|thumb|right|Иллюстрация использования Использование суффиксных ссылок.]]Суффиксные ссылки используются для того, чтобы можно было быстро перейти от конца одного суффикса к концу другого, а не спускаться каждый раз от корняРассмотрим применение суффиксных ссылок. Пусть мы только что продлили был продлён суффикс <tex>s[j..\ldots i-1]</tex> до суффикса <tex>s[j..\ldots i]</tex> и стоим в вершине, в которую ведет ребро . Теперь с пометкой помощью построенных ссылок можно найти конец суффикса <tex>ts[kj+1..r\ldots i-1]</tex>в суффиксном дереве, содержащей конец текущего суффикса. Найдем с помощью построенных ссылок конец чтобы продлить его до суффикса <tex>s[j+1..\ldots i-1]</tex>. Пройдем Для этого надо пройти вверх по дереву до ближайшей внутренней вершины <tex>v</tex>, в которую ведет ребро с пометкой ведёт путь, помеченный <tex>ts[p..kj \ldots r]</tex>. У вершины <tex>v</tex> точно есть суффиксная ссылка(о том, так как ссылка для новой внутренней вершины строится внутри фазы ее созданиястроятся суффиксные ссылки, будет сказано позже, а пока можно просто поверить). Пусть Эта суффиксная ссылка ведет ведёт в вершину <tex>u</tex>, которой соответствует пометка путь, помеченный подстрокой <tex>ts[h..kj+1 \ldots r]</tex> (<tex>h</tex> и <tex>p</tex> могут быть не равны). Теперь пройдем от вершины <tex>u</tex> следует пройти вниз по дереву к концу суффикса <tex>s[j+1..\ldots i-1]</tex>, и сделаем продление продлить его до суффикса <tex>s[j+1\ldots i]</tex>. Можно заметить, что подстрока <tex>s[j+1 \ldots i-1]</tex> является суффиксом подстроки <tex>s[j \ldots i-1]</tex>.Следовательно, после перехода по суффиксной ссылке в вершину, помеченную путевой меткой <tex>s[j+1 \ldots r]</tex>, можно дойти до места, которому соответствует метка <tex>s[r+1 \ldots i-1]</tex>, сравнивая не символы на рёбрах, а лишь длину ребра по первому символу рассматриваемой части подстроки и длину самой этой подстроки. Таким образом можно спускаться вниз сразу на целое ребро.
=== Построение суффиксных ссылок ===
=== Оценка числа переходов ===
{{Определение
|definition= '''Глубиной вершины''' <tex>d(v)</tex> назовем число ребер рёбер на пути от корня до вершины <tex>v</tex>.}}
{{Лемма|id=l4
При переходе по суффиксной ссылке глубина уменьшается не более чем на <tex>1</tex>.
|proof=
}}
{{Лемма|id=l5
|about=о числе переходов внутри фазы
|statement=
Число переходов по ребрам рёбрам внутри фазы номер <tex>i</tex> не превышает равно <tex>4iO(i)</tex>.
|proof=
Оценим количество переходов по ребрам рёбрам при поиске конца суффикса. Переход до ближайшей внутренней вершины уменьшает высоту на <tex>1</tex>. Переход по суффиксной ссылке уменьшает высоту не более чем на <tex>1</tex> (по лемме, доказанной выше). Значит в течение одной фазы вверх А потом высота увеличивается, пока мы переходим по рёбрам вниз. Так как высота не более может увеличиваться больше глубины дерева, а на каждой <tex>2ij</tex> раз. Но внутри одной фазы начальная глубина -ой итерации мы уменьшаем высоту не меньше конечной (так как длины суффиксов убывают до более, чем на <tex>12 </tex>), поэтому вниз мы могли пройти то суммарно высота не более может увеличиться больше чем на <tex>2i</tex> ребер. Итого получаем оценку , число переходов по рёбрам за одну фазу в сумме составляет <tex>4iO(i)</tex>.
}}
=== Асимтотика Асимптотика алгоритма с использованием суффиксных ссылок ===
==Линейный алгоритм==
Чтобы улучшить время работы данного алгоритма до <tex>O(n)</tex>, нужно использовать линейное количество памяти, поэтому метка каждого ребра будет храниться как два числа {{---}} позиции ее её самого левого и самого правого символов в исходном тексте.
{{Лемма|id=l1
|about= Правило 3 заканчивает дело
|statement=
В любой фазе, если правило продления 3 применяется в продолжении суффикса, начинающего в позиции <tex>ij</tex>, оно же и будет реализовываться применяться во всех дальнейших продолжениях (от <tex>ij+1</tex> по <tex>j+1i</tex>) до конца фазы. <br>
|proof=
При использовании правила продолжения 3 путь, помеченный <tex>s[j \ldots i..j-1]</tex> в текущем дереве, должен продолжаться символом <tex>j+1i</tex>, и точно так же продолжается путь, помеченный <tex>s[j+1 \ldots i+-1..j]</tex>, поэтому правило 3 применяется в продолжениях <tex>ij+1, i\ j+2, ...\ldots, j+1i</tex>.
}}
Когда используется 3-е правило продления суффикса, никакой работы делать не нужно, так как требуемый суффикс уже в дереве есть. Поэтому можно заканчивать текущую итерацию после первого же использования этого правила. Так как лист навсегда останется листом, зададим можно задать метку ребра ведущего в этот лист как <tex>ts[i..nj \ldots x]</tex>, где <tex>nx</tex> {{---}} это длина исходного текстассылка на переменную, хранящую конец текущей подстроки. На следующих итерациях к этому ребру может применяться правило ответвления, но при этом будет меняться только левый(начальный) индекс <tex>ij</tex>. Таким образом мы сможем удлинять все суффиксы, заканчивающиеся в листах за <tex>O(1)</tex>. Следовательно, на каждой фазе <tex>i</tex> алгоритм реально работает с суффиксами в диапазоне от <tex>j^*</tex> до <tex>k,\ k \leqslant i</tex>, а не от <tex>1</tex> до <tex>i</tex>. Действительно, если суффикс <tex>s[j \ldots i-2]</tex> был продлён до суффикса <tex>s[j \ldots i-1]</tex> на прошлой фазе по правилу 1, то он и дальше будет продлеваться по правилу 1 (о чём говорит [[#l1 | лемма]]). Если он был продлён по правилу 2, то была создана новая листовая вершина, значит, на текущей фазе <tex> i </tex> этот суффикс будет продлён до суффикса <tex>s[j \ldots i]</tex> по листовой вершине. Поэтому после применения правила 3 на суффиксе <tex>s[k \ldots i]</tex> текущую фазу можно завершить, а следующую начать сразу с <tex>j^* = k</tex>.
=== Итоговая оценка времени работы ===
== Минусы алгоритма Укконена ==
# Константное время на одну итерацию {{---}} это амортизированная оценка, в худшем случае одна фаза может выполняться за <tex>O(n)</tex> времени. Например, алгоритм Дэни Бреслауера и Джузеппе Итальяно<ref>[https://books.google.ru/books?id=sGDXz53FwM4C&lpg=PP11&ots=utJ8jnql5h&dq=Dany%20Breslauer%2C%20Giuseppe%20F.%20Italiano%3A%20Near%20Real-Time%20Suffix%20Tree%20Construction%20via%20the%20Fringe%20Marked%20Ancestor%20Problem.&hl=ru&pg=PA156#v=onepage&q&f=false Dany Breslauer, Giuseppe F. Italiano {{---}} Near Real-Time Suffix Tree Construction via the Fringe Marked Ancestor Problem.]</ref>, хоть и строит дерево за <tex>O(n \log \log n)</tex>, но на одну итерацию в худшем случае тратит <tex>O(\log \log n)</tex> времени.
== См. также==
* [[Алгоритм МакКрейта]]
* [[Алгоритм Фарача| Алгоритм Фараx-Колтона]]* [[Суффиксный бор]]
==Примечания==