Введение

Алгоритм построения деревьев суффиксов
В информатике алгоритм Укконена — это алгоритм построения деревьев суффиксов за линейное время, работающий в режиме онлайн и предложенный Эско Укконеном в 1995 году. Алгоритм начинается с неявного дерева суффиксов, содержащего первый символ строки, и затем последовательно просматривает строку, добавляя символы до тех пор, пока дерево не будет построено полностью. Именно такой порядок добавления символов обеспечивает алгоритму Укконена свойство "онлайн" работы. Изначальный алгоритм, представленный Питером Вайнером, строил дерево, двигаясь от последнего символа к первому, от самого короткого к самому длинному суффиксу. Более простой алгоритм был найден Эдвардом М. МакКрейтом, который строил дерево, двигаясь от самого длинного к самому короткому суффиксу.

Дерево имплицитных суффиксов

При генерации суффиксного дерева с помощью алгоритма Укконена мы будем наблюдать имплицитное суффиксное дерево на промежуточных шагах, зависящих от символов в строке S. В имплицитных суффиксных деревьях не будет рёбер с меткой $ (или любого другого символа окончания) и внутренних узлов, из которых выходит только одно ребро.

Описание алгоритма Укконена на высоком уровне

Алгоритм Укконена строит имплицитное дерево суффиксов T для каждого префикса S[1 i] строки S (S – строка длины n). Сначала он строит T, используя 1 символ, затем T, используя 2 символ, затем T, используя 3 символ, и так далее, до T, используя n символ. В дереве суффиксов, построенном алгоритмом Укконена, можно выделить следующие характеристики: имплицитное дерево суффиксов T строится на основе предыдущего имплицитного дерева суффиксов T. В любой момент времени алгоритм Укконена строит дерево суффиксов для символов, которые были обработаны на данный момент, что обеспечивает свойство онлайн-обработки и позволяет алгоритму иметь время выполнения O(n). Алгоритм Укконена разделен на n фаз (по одной фазе для каждого символа в строке длиной n). Каждая фаза i+1 далее разделена на i+1 расширений, по одному для каждого из i+1 суффиксов S[1 i+1]. Расширение суффикса заключается в добавлении следующего символа в дерево суффиксов, построенное на данный момент. В расширении j фазы i+1 алгоритм находит конец строки S[j i] (которая уже присутствует в дереве благодаря предыдущей фазе i), а затем расширяет S[j i], чтобы гарантировать наличие суффикса S[j i+1] в дереве. Существует три правила расширения: если путь от корня, помеченный S[j i], заканчивается на листе (то есть S[i] является последним символом на листе), то символ S[i+1] просто добавляется в конец метки этого листа. Если путь от корня, помеченный S[j i], заканчивается на внутреннем узле (то есть после S[i] на пути есть другие символы) и следующий символ не равен S[i+1], то создается новый лист с меткой S[i+1] и номером j, начинающийся с символа S[i+1]. Новый внутренний узел также будет создан, если S[1 i] заканчивается внутри (между) символами внутреннего узла. Если путь от корня, помеченный S[j i], заканчивается на внутреннем узле (то есть после S[i] на пути есть другие символы) и следующий символ равен S[i+1] (уже присутствует в дереве), то ничего не делается. Важно отметить, что из данного узла (корня или внутреннего) исходит только одна ветвь, начинающаяся с определенного символа. Из любого узла не может исходить более одной ветви, начинающейся с одного и того же символа.

Время исполнения

Наивная реализация построения дерева суффиксов требует временной сложности O(n²) или даже O(n³) в нотации «большое O», где n — длина строки. Используя ряд алгоритмических приёмов, Укконен снизил эту сложность до O(n) (линейного) времени для алфавитов фиксированного размера и до O(n log n) в общем случае, что соответствует времени работы двух более ранних алгоритмов.

Пример алгоритма Укконена

Чтобы лучше проиллюстрировать, как строится дерево суффиксов с помощью алгоритма Укконена, рассмотрим строку S = xabxac. Начните с пустого корневого узла. Постройте структуру для S[1], добавив первый символ строки. Применяется правило 2, которое создает новый листовой узел. Постройте структуру для S[1 2], добавив суффиксы xa (xa и a). Применяется правило 1, которое расширяет метку пути в существующем ребре листа. Применяется правило 2, которое создает новый листовой узел. Постройте структуру для S[1 3], добавив суффиксы xab (xab, ab и b). Применяется правило 1, которое расширяет метку пути в существующем ребре листа. Применяется правило 2, которое создает новый листовой узел. Постройте структуру для S[1 4], добавив суффиксы xabx (xabx, abx, bx и x). Применяется правило 1, которое расширяет метку пути в существующем ребре листа. Правило 3 – ничего не делать. Постройте структуру для S[1 5], добавив суффиксы xabxa (xabxa, abxa, bxa, xa и a). Применяется правило 1, которое расширяет метку пути в существующем ребре листа. Правило 3 – ничего не делать. Постройте структуру для S[1 6], добавив суффиксы xabxac (xabxac, abxac, bxac, xac, ac и c). Применяется правило 1, которое расширяет метку пути в существующем ребре листа. Применяется правило 2, которое создает новый листовой узел (в этом случае создаются три новых листовых ребра и два новых внутренних узла).