Введение
Алгоритм построения деревьев суффиксов
В информатике алгоритм Укконена — это алгоритм построения деревьев суффиксов за линейное время, работающий в режиме онлайн и предложенный Эско Укконеном в 1995 году. Алгоритм начинается с неявного дерева суффиксов, содержащего первый символ строки, и затем последовательно просматривает строку, добавляя символы до тех пор, пока дерево не будет построено полностью. Именно такой порядок добавления символов обеспечивает алгоритму Укконена свойство "онлайн" работы. Изначальный алгоритм, представленный Питером Вайнером, строил дерево, двигаясь от последнего символа к первому, от самого короткого к самому длинному суффиксу. Более простой алгоритм был найден Эдвардом М. МакКрейтом, который строил дерево, двигаясь от самого длинного к самому короткому суффиксу.
In computer science, Ukkonen's algorithm is a linear time, online algorithm for constructing suffix trees, proposed by Esko Ukkonen in 1995. The algorithm begins with an implicit suffix tree containing the first character of the string. Then it steps through the string, adding successive characters until the tree is complete. This order addition of characters gives Ukkonen's algorithm its "on line" property. The original algorithm presented by Peter Weiner proceeded backward from the last character to the first one from the shortest to the longest suffix. A simpler algorithm was found by Edward M. McCreight, going from the longest to the shortest suffix.
Дерево имплицитных суффиксов
При генерации суффиксного дерева с помощью алгоритма Укконена мы будем наблюдать имплицитное суффиксное дерево на промежуточных шагах, зависящих от символов в строке 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] (уже присутствует в дереве), то ничего не делается. Важно отметить, что из данного узла (корня или внутреннего) исходит только одна ветвь, начинающаяся с определенного символа. Из любого узла не может исходить более одной ветви, начинающейся с одного и того же символа.
Implicit suffix tree T is built on top of implicit suffix tree T At any given time, Ukkonen's algorithm builds the suffix tree for the characters seen so far and so it has on line property, allowing the algorithm to have an execution time of O(n). Ukkonen's algorithm is divided into n phases (one phase for each character in the string with length n). Each phase i+1 is further divided into i+1 extensions, one for each of the i+1 suffixes of S[1 i+1]. Suffix extension is all about adding the next character into the suffix tree built so far. In extension j of phase i+1, algorithm finds the end of S[j i] (which is already in the tree due to previous phase i) and then it extends S[j i] to be sure the suffix S[j i+1] is in the tree. There are three extension rules:
If the path from the root labelled S[j i] ends at a leaf edge (i. e., S[i] is last character on leaf edge), then character S[i+1] is just added to the end of the label on that leaf edge. if the path from the root labelled S[j i] ends at a non leaf edge (i. e., there are more characters after S[i] on path) and next character is not S[i+1], then a new leaf edge with label S[i+1] and number j is created starting from character S[i+1]. A new internal node will also be created if S[1 i] ends inside (in between) a non leaf edge. If the path from the root labelled S[j i] ends at a non leaf edge (i. e., there are more characters after S[i] on path) and next character is S[i+1] (already in tree), do nothing. One important point to note is that from a given node (root or internal), there will be one and only one edge starting from one character. There will not be more than one edge going out of any node starting with the same character.
Время исполнения
Наивная реализация построения дерева суффиксов требует временной сложности 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, которое создает новый листовой узел (в этом случае создаются три новых листовых ребра и два новых внутренних узла).