В информатике массив суффиксов — это отсортированный массив всех суффиксов строки . Это структура данных , используемая, среди прочего, в полнотекстовых индексах, алгоритмах сжатия данных и в области библиометрии .
Массивы суффиксов были введены Манбером и Майерсом (1990) как простая, экономящая место альтернатива деревьям суффиксов . Они были независимо открыты Гастоном Гонне в 1987 году под названием массив PAT (Гонне, Баеза-Йейтс и Снайдер, 1992).
Ли, Ли и Хуо (2016) предложили первый алгоритм построения массива суффиксов времени на месте , который является оптимальным как по времени, так и по пространству, где «на месте» означает, что алгоритму требуется только дополнительное пространство за пределами входной строки и выходного массива суффиксов.
Расширенные массивы суффиксов (ESA) — это массивы суффиксов с дополнительными таблицами, которые воспроизводят полную функциональность деревьев суффиксов, сохраняя при этом ту же сложность по времени и памяти. [1] Массив суффиксов для подмножества всех суффиксов строки называется разреженным массивом суффиксов. [2] Было разработано несколько вероятностных алгоритмов для минимизации дополнительного использования памяти, включая алгоритм оптимального времени и памяти. [3]
Пусть будет -строкой, а обозначим подстроку в диапазоне от до включительно.
Массив суффиксов теперь определяется как массив целых чисел, предоставляющий начальные позиции суффиксов в лексикографическом порядке . Это означает, что запись содержит начальную позицию -го наименьшего суффикса в и, таким образом, для всех : .
Каждый суффикс из появляется ровно один раз. Суффиксы — это простые строки. Эти строки сортируются (как в бумажном словаре), прежде чем их начальные позиции (целочисленные индексы) сохраняются в .
Рассмотрим текст = для индексации:banana$
Текст заканчивается специальной контрольной буквой $
, которая является уникальной и лексикографически меньше любого другого символа. Текст имеет следующие суффиксы:
Эти суффиксы можно отсортировать в порядке возрастания:
Массив суффиксов содержит начальные позиции этих отсортированных суффиксов:
Массив суффиксов, в котором суффиксы записаны вертикально снизу для ясности:
Так, например, содержит значение 4 и, следовательно, относится к суффиксу, начинающемуся с позиции 4 внутри , который является суффиксом .ana$
Массивы суффиксов тесно связаны с деревьями суффиксов :
Было показано, что каждый алгоритм суффиксного дерева может быть систематически заменен алгоритмом, который использует массив суффиксов, улучшенный дополнительной информацией (например, массив LCP ), и решает ту же проблему с той же временной сложностью. [1] Преимущества массивов суффиксов над деревьями суффиксов включают улучшенные требования к пространству, более простые алгоритмы линейного времени построения (например, по сравнению с алгоритмом Укконена ) и улучшенную локальность кэша. [4]
Массивы суффиксов были введены Манбером и Майерсом (1990) для улучшения требований к пространству деревьев суффиксов : Массивы суффиксов хранят целые числа. Если предположить, что целое число требует байтов, то массив суффиксов требует байтов в общей сложности. Это значительно меньше байтов , которые требуются при тщательной реализации дерева суффиксов. [5]
Однако в некоторых приложениях требования к пространству массивов суффиксов могут быть все еще непомерно высокими. Анализируемый в битах массив суффиксов требует пространства, тогда как исходный текст в алфавите размером требует только биты. Для человеческого генома с и массив суффиксов, следовательно, занял бы примерно в 16 раз больше памяти, чем сам геном.
Такие расхождения мотивировали тенденцию к сжатым массивам суффиксов и сжатым полнотекстовым индексам на основе BWT, таким как FM-индекс . Эти структуры данных требуют только пространства в пределах размера текста или даже меньше.
Дерево суффиксов может быть построено и преобразовано в массив суффиксов путем обхода дерева в глубину также в , поэтому существуют алгоритмы, которые могут построить массив суффиксов в .
Наивный подход к построению массива суффиксов заключается в использовании алгоритма сортировки на основе сравнения . Эти алгоритмы требуют сравнения суффиксов, но сравнение суффиксов выполняется во времени, поэтому общее время выполнения этого подхода составляет .
Более продвинутые алгоритмы используют тот факт, что суффиксы, которые нужно отсортировать, не являются произвольными строками, а связаны друг с другом. Эти алгоритмы стремятся достичь следующих целей: [6]
Одним из первых алгоритмов, достигших всех целей, является алгоритм SA-IS Нонга, Чжана и Чана (2009). Алгоритм также довольно прост (< 100 LOC ) и может быть улучшен для одновременного построения массива LCP . [7] Алгоритм SA-IS является одним из самых быстрых известных алгоритмов построения массива суффиксов. Тщательная реализация Юты Мори [8] превосходит большинство других линейных или суперлинейных подходов к построению.
Помимо требований по времени и пространству, алгоритмы построения массивов суффиксов также различаются по поддерживаемому алфавиту : константные алфавиты , где размер алфавита ограничен константой, целочисленные алфавиты , где символы являются целыми числами в диапазоне, зависящем от, и общие алфавиты , где разрешены только сравнения символов. [9]
Большинство алгоритмов построения массивов суффиксов основаны на одном из следующих подходов: [6]
Известным рекурсивным алгоритмом для целочисленных алфавитов является алгоритм DC3 / skew Карккяйнена и Сандерса (2003). Он работает за линейное время и успешно использовался в качестве основы для параллельных [10] и внешних алгоритмов построения массивов суффиксов памяти [11] .
Недавняя работа Сэлсона и др. (2010) предлагает алгоритм для обновления массива суффиксов текста, который был отредактирован, вместо перестройки нового массива суффиксов с нуля. Даже если теоретическая сложность в худшем случае составляет , на практике он, по-видимому, работает хорошо: экспериментальные результаты авторов показали, что их реализация динамических массивов суффиксов, как правило, более эффективна, чем перестройка, если рассматривать вставку разумного количества букв в исходный текст.
В практической работе с открытым исходным кодом обычно используемой процедурой для построения массива суффиксов была qsufsort, основанная на алгоритме Ларссона-Садакане 1999 года. [12] Эта процедура была заменена DivSufSort Юты Мори, «самым быстрым известным алгоритмом сортировки суффиксов в основной памяти» по состоянию на 2017 год. Ее также можно модифицировать для вычисления массива LCP. Она использует индуцированное копирование в сочетании с Ито-Танакой. [13] В 2021 году более быстрая реализация алгоритма была представлена Ильей Гребновым [14], которая в среднем показала 65%-ное улучшение производительности по сравнению с реализацией DivSufSort на Silesia Corpus. [15]
Концепция массива суффиксов может быть расширена до более чем одной строки. Это называется обобщенным массивом суффиксов (или GSA), массивом суффиксов, который содержит все суффиксы для набора строк (например, и лексикографически отсортирован со всеми суффиксами каждой строки. [16]
Массив суффиксов строки можно использовать в качестве индекса для быстрого поиска каждого вхождения шаблона подстроки в строке . Поиск каждого вхождения шаблона эквивалентен поиску каждого суффикса, который начинается с подстроки. Благодаря лексикографическому упорядочению эти суффиксы будут сгруппированы вместе в массиве суффиксов и могут быть эффективно найдены с помощью двух бинарных поисков . Первый поиск находит начальную позицию интервала, а второй определяет конечную позицию: [ необходима цитата ]
n = len ( S ) def search ( P : str ) -> Tuple [ int , int ]: """ Возвращает индексы (s, r) такие, что интервал A[s:r] (включая конечный индекс) представляет все суффиксы S, которые начинаются с шаблона P. """ # Находит начальную позицию интервала l = 0 # в Python массивы индексируются, начиная с 0 r = n while l < r : mid = ( l + r ) // 2 # деление с округлением вниз до ближайшего целого числа # suffixAt(A[i]) — i-й наименьший суффикс if P > suffixAt ( A [ mid ]): l = mid + 1 else : r = mid s = l # Найти конечную позицию интервала r = n while l < r : mid = ( l + r ) // 2 if suffixAt ( A [ mid ]) . startswith ( P ): l = mid + 1 else : r = mid return ( s , r )
Поиск шаблона подстроки длины в строке длины занимает время, учитывая, что для одного сравнения суффиксов необходимо сравнить символы. Манбер и Майерс (1990) описывают, как эту границу можно улучшить до времени с использованием информации LCP . Идея заключается в том, что сравнение шаблонов не требует повторного сравнения определенных символов, когда уже известно, что они являются частью самого длинного общего префикса шаблона и текущего интервала поиска. Абуэлхода, Курц и Олебуш (2004) еще больше улучшают границу и достигают времени поиска для постоянного размера алфавита, как известно из деревьев суффиксов .
Алгоритмы сортировки суффиксов могут использоваться для вычисления преобразования Барроуза–Уиллера (BWT) . BWT требует сортировки всех циклических перестановок строки. Если эта строка заканчивается специальным символом конца строки, который лексикографически меньше всех других символов (например, $), то порядок отсортированной повернутой матрицы BWT соответствует порядку суффиксов в массиве суффиксов. Поэтому BWT можно вычислить за линейное время, сначала построив массив суффиксов текста, а затем выведя строку BWT : .
Массивы суффиксов также можно использовать для поиска подстрок в машинном переводе на основе примеров , требуя гораздо меньше памяти, чем полная таблица фраз, используемая в статистическом машинном переводе .
Многие дополнительные приложения массива суффиксов требуют массив LCP . Некоторые из них подробно описаны в разделе приложений последнего.
Деревья суффиксов — это мощные структуры данных, которые широко применяются в областях сопоставления шаблонов и строк, индексирования и текстовой статистики. Однако они занимают значительное количество места и, таким образом, имеют недостаток во многих приложениях реального времени, которые требуют обработки значительного количества данных, таких как анализ генома. Чтобы преодолеть этот недостаток, были разработаны расширенные массивы суффиксов, которые представляют собой структуры данных, состоящие из массивов суффиксов и дополнительной таблицы, называемой дочерней таблицей, которая содержит информацию о родительско-дочерних отношениях между узлами в дереве суффиксов. Структура данных ветвления узлов для этого дерева представляет собой связанный список. Расширенные массивы суффиксов превосходны с точки зрения как эффективности использования пространства, так и временной сложности и просты в реализации. Более того, их можно применять к любому алгоритму, использующему дерево суффиксов, с помощью абстрактной концепции деревьев интервалов lcp. Временная сложность поиска шаблона в расширенном массиве суффиксов составляет O(m|Σ|).
Массив суффиксов строки — это массив из n целых чисел в диапазоне от 0 до n, представляющий n+1 суффиксов строки, включая специальный символ #.
Массив суффиксов состоит из двух массивов:
Для массива суффиксов S lcp-интервал, связанный с соответствующим узлом дерева суффиксов S, можно определить как:
Интервал [i,..j], 0 ≤ i ≤ j ≤ n является lcp-интервалом lcp-значения, если
1. lcptab[i] < l,
2. lcptab[k] ≥ l для всех i + 1 ≤ k ≤ j,
3. lcptab[k] = l для некоторых i + 1 ≤ k ≤ j, если i ≠ j и l = n − i + 1, если i = j,
4. lcptab[j + 1] < l.
Длина самого длинного общего префикса pos[i − 1] и pos[i] хранится в lcp[i], где 2 ≤ i ≤ n. Интервал lcp отображает те же родительско-дочерние отношения, что и среди связанных узлов в дереве суффиксов S. Это показывает, что если соответствующий узел [i..j] является дочерним узлом соответствующего узла [k..l], то интервал lcp [i..j] является дочерним интервалом другого интервала lcp [k..l]. Если [k..l] является дочерним интервалом [i..j], то интервал lcp [i..j] является родительским интервалом интервала lcp [k..l].
Дочерняя таблица cldtab состоит из трех массивов n, up , down и nextlIndex . Информация о ребрах соответствующего дерева суффиксов хранится и поддерживается массивами up и down . Массив nextlIndex хранит ссылки в связанном списке, используемом для ветвления узлов дерева суффиксов.
Массивы up , down и nextlIndex определяются следующим образом:
Выполняя обход снизу вверх lcp-интервала дерева, дочерняя таблица может быть построена за линейное время. Значения up/down и значения nextlIndex могут быть вычислены отдельно с использованием двух различных алгоритмов.
Суффиксные ссылки для расширенного массива суффиксов могут быть вычислены путем генерации интервала суффиксных ссылок [ 1,..,r ] для каждого интервала [i,..j] во время предварительной обработки. Левый и правый элементы l и r интервала сохраняются в первом индексе [i,..,j]. Таблица для этого интервала варьируется от 0 до n. Таблица суффиксных ссылок создается путем обхода дерева lcp-интервалов слева направо в ширину. Каждый раз, когда вычисляется l -интервал, он добавляется в список l-интервалов, который называется l-списком. Когда lcp-значение > 0, для каждого l -интервала[i,..,j] в списке вычисляется link[i]. Интервал [ l ,.., r ] вычисляется с помощью бинарного поиска в ( l -1)-списке, где l - наибольшая левая граница среди всех l -1 интервалов. Интервал суффиксной ссылки [i,..j] представлен этим интервалом [ l,..,r ]. Значения l и r в конечном итоге сохраняются в первом индексе [i,..,j].