1294
правки
Irina (обсуждение | вклад) Нет описания правки |
KVN (обсуждение | вклад) |
||
(не показано 11 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
== Ключевые слова и синонимы == | == Ключевые слова и синонимы == | ||
Построение суффиксного массива; построение B-дерева на основе строки; построение полнотекстового индекса | |||
'''Построение суффиксного дерева в иерархической памяти''' --- ''Suffix Tree Construction in Hierarchical Memory'' | |||
Построение суффиксного массива (''Suffix array construction''); построение B-дерева на основе строки (''String B-tree construction''); построение полнотекстового индекса (''Fulltext index construction'') | |||
Строка 10: | Строка 16: | ||
== Нотация == | == Нотация == | ||
Пусть S[1, n] – строка, составленная из символов алфавита <math>\ | Пусть S[1, n] – строка, составленная из символов алфавита <math>\Sigma \;</math>. Обозначим за <math>S_i \;</math> i-й [[суффикс]] строки S, за <math>lcp( \alpha, \beta) \;</math> – самый длинный общий префикс двух строк <math>\alpha \;</math> и <math>\beta \;</math>, а за lca(u, v) – [[наименьший общий предок|наименьшего общего предка]] двух вершин u и v в дереве. | ||
Суффиксное дерево S[1, n], которое далее будет обозначаться <math>\mathcal{T}_S \;</math>, представляет собой дерево, хранящее все суффиксы S# в компактной форме, где # | Суффиксное дерево S[1, n], которое далее будет обозначаться <math>\mathcal{T}_S \;</math>, представляет собой дерево, хранящее все суффиксы S# в компактной форме, где <math>\# \notin \Sigma \;</math> – специальный символ (см. рис. 1). <math>\mathcal{T}_S \;</math> содержит n листьев с номерами от 1 до n, и любой путь из корня до листа читается как суффикс S#. Маркер конца # гарантирует, что ни один суффикс не является префиксом другого суффикса в S#. Каждая внутренняя вершина имеет по меньшей мере двух потомков; каждое ребро помечено непустой подстрокой из S. Никакие два ребра, выходящие из одной вершины, не могут начинаться с одной и той же буквы; вершины-братья лексикографически упорядочены в соответствии с этими буквами. Метки ребер закодированы парами целых чисел; например, S[x, y] представлено парой hx;yi. В результате все <math>\Theta(n^2) \;</math> подстрок S можно представить в O(n)-оптимальном пространстве при помощи структуры <math>\mathcal{T}_S \;</math> и кодирования ребер. Кроме того, обход листьев суффиксного дерева справа налево дает упорядоченное множество суффиксов S, также известное как [[суффиксный массив]] [12]. Заметим, что случай большого набора строк <math>\Delta = \{ S^1, S^2, ..., S^k \} \;</math> сводится к случаю одной длинной строки <math>S = S^1 \#_1 S^2 \#_2 ...S^k \#_k \;</math>, где <math>\#_i \notin \Sigma \;</math> – специальные символы. | ||
[[Файл:STC_HM.png]] | |||
Рисунок 1. Слева – суффиксное дерево S = ACACACCG, справа – компактное кодирование его ребер. Маркер конца # не представлен. Вершина v читается как строка ACAC. Каждая внутренняя вершина хранит длину связанной с ней строки, а каждый лист – начальную позицию соответствующего суффикса | |||
Разработано множество алгоритмов оптимального построения суффиксного дерева в RAM-модели (см. [1] и ссылки в этой работе). Однако большинство из них выявляет отсутствие локальности ссылок и в результате обнаруживает многие операции ввода/вывода, у которых размер индексированной строки слишком велик для того, чтобы поместиться во внутреннюю память компьютера. Это серьезная проблема, поскольку низкая скорость работы этих алгоритмов не позволяет использовать суффиксные деревья даже в приложениях среднего масштаба. Далее будут рассмотрены алгоритмические решения, эффективно выполняющие построение суффиксного дерева над большими наборами строк, производя при этом оптимальное количество операций ввода/вывода. Поскольку предполагается, что ребра, выходящие из вершины <math>\mathcal{T}_S \;</math>, лексикографически упорядочены, очевидной нижней границей при построении суффиксных деревьев является сортировка (можно рассматривать суффиксное дерево как перестановку). Для представленных алгоритмов сортировка является самым узким местом; таким образом, сложности алгоритма сортировки и алгоритма построения суффиксного дерева совпадают. | |||
Алгоритм «Разделяй и властвуй» | Алгоритм «Разделяй и властвуй» | ||
(1) Построить строку | (1) Построить строку <math>S'[j] = ранг \langle S[2j], S[2j + 1] \rangle \;</math>, и рекурсивно вычислить <math>\mathcal{T}_{S'} \;</math>. | ||
(2) Вывести из <math>\mathcal{T}_{S'} \;</math> уплотненное префиксное дерево (trie-дерево) <math>\mathcal{T}_o \;</math> со всеми суффиксами S, начинающимися с нечетных позиций. | |||
(3) Вывести из <math>\mathcal{T}_o \;</math> уплотненное префиксное дерево <math>\mathcal{T}_e \;</math> со всеми суффиксами S, начинающимися с четных позиций. | |||
(4) Слить <math>\mathcal{T}_o \;</math> и <math>\mathcal{T}_e \;</math> в целое суффиксное дерево <math>\mathcal{T}_S \;</math> следующим образом: | |||
(4.1) Наложить <math>\mathcal{T}_o \;</math> и <math>\mathcal{T}_e \;</math> на дерево <math>\mathcal{T}_M \;</math>. | |||
(4.2) Частично отделить <math>\mathcal{T}_M \;</math>, чтобы получить <math>\mathcal{T}_S \;</math>. | |||
Рисунок 2. Алгоритм прямого построения суффиксного дерева | |||
Алгоритм прямого построения суффиксного дерева | |||
== Основные результаты == | == Основные результаты == | ||
Строка 47: | Строка 46: | ||
Первый алгоритм основан на подходе | Первый алгоритм основан на подходе «[[Разделяй и властвуй]]», позволяющем свести процесс построения к сортировке внешней памяти и нескольким низкоуровневым примитивам ввода/вывода. Он строит суффиксное дерево <math>\mathcal{T}_S \;</math> при помощи четырех макрошагов, представленных на рис. 2. Первые три шага несложно реализовать за <math>Sort(n) = O \Big( \frac{n}{B} \; log \; M/B \; \frac{n}{B} \Big) </math> операций ввода/вывода [16]. Последний шаг, слияние, является самым сложным, и именно объем операций ввода/вывода этого этапа определяет стоимость всего алгоритма. В работе [3] предложен элегантный способ слияния <math>\mathcal{T}_o \;</math> и <math>\mathcal{T}_e \;</math>: подшаг (4.1) временно ослабляет требование получения <math>\mathcal{T}_S \;</math> за один проход; он вслепую накладывает пути из <math>\mathcal{T}_o \;</math> и <math>\mathcal{T}_e \;</math>, сравнивая ребра только по их первым символам; затем подшаг (4.2) восстанавливает <math>\mathcal{T}_M \;</math>, определяя и отменяя чрезмерно наложенные пути эффективным с точки зрения количества операций ввода/вывода образом. Отметим, что сложность этого алгоритма, измеряемая по времени и по числу операций ввода/вывода, образует интересное рекурсивное соотношение: T(n) = T(n/2) + O(Sort(n)). | ||
Теорема 1 (Фарах-Колтон и др., 1999). Пусть дана произвольная строка S[1, n]; ее суффиксное дерево можно построить за O(Sort(n)) операций ввода/вывода и за время O( | '''Теорема 1 (Фарах-Колтон и др., 1999). Пусть дана произвольная строка S[1, n]; ее суффиксное дерево можно построить за O(Sort(n)) операций ввода/вывода и за время O(n log n), используя O(n/B) страниц дисковой памяти.''' | ||
Второй алгоритм кажется очень простым, элегантным и оптимальным по числу операций ввода/вывода; он успешно применяется для построения других индексированных структур данных – таких, как B-дерев на основе строки [5]. Основная идея заключается в выведении суффиксного дерева <math>\mathcal{T}_S \;</math> из суффиксного массива | Второй алгоритм кажется очень простым, элегантным и оптимальным по числу операций ввода/вывода; он успешно применяется для построения других индексированных структур данных – таких, как B-дерев на основе строки [5]. Основная идея заключается в выведении суффиксного дерева <math>\mathcal{T}_S \;</math> из суффиксного массива <math>\mathcal{A}_S \;</math> и массива lcp, который хранит длины самых длинных общих суффиксов для смежных суффиксов <math>\mathcal{A}_S \;</math>. Псевдокод алгоритма приведен на рис. 3. Заметим, что шаг (1) может задействовать любой алгоритм построения суффиксного массива с использованием внешней памяти. Здесь используется элегантный и оптимальный алгоритм перекоса Skew [9], требующий O(Sort(n)) операций ввода/вывода. Шаг 2 задействует в сумме O(n/B) операций ввода/вывода, используя стек, который хранит вершины текущего самого правого пути суффиксного дерева <math>\mathcal{T}_S \;</math> в обратном порядке, т.е. лист <math>\ell_i \;</math> находится наверху. Движение вверх, расщепление ребер или присоединение вершин в <math>\mathcal{T}_S \;</math> сводится к выталкиванию вершин из стека. В результате сложность этого алгоритма по времени и по числу операций ввода/вывода образует рекурсивное соотношение: T(n) = T(2n/3) + O(Sort(n)). | ||
Теорема 2 (Карккайнен и Сандерс, 2003). Пусть дана произвольная строка S[1, n]; ее суффиксное дерево можно построить за O(Sort(n)) операций ввода/вывода и за время O( | '''Теорема 2 (Карккайнен и Сандерс, 2003). Пусть дана произвольная строка S[1, n]; ее суффиксное дерево можно построить за O(Sort(n)) операций ввода/вывода и за время O(n log n), используя O(n/B) страниц дисковой памяти.''' | ||
(??? текст полностью совпадает) | (??? текст полностью совпадает с текстом теоремы 1) | ||
Строка 66: | Строка 65: | ||
Алгоритм на базе суффиксного массива | Алгоритм на базе суффиксного массива | ||
(1) Построить суффиксный массив | (1) Построить суффиксный массив <math>\mathcal{A}_S \;</math> и массив <math>lcp_S \;</math> для строки S. | ||
(2) Задать начальное значение <math>\mathcal{T}_S \;</math> в виде единственного ребра, соединяющего корень с листом, ссылающимся на суффикс <math>\mathcal{A}_S \;</math> [1]. | |||
(2) For i = 2, ..., n: | |||
(2.1) Создать новый лист <math>\ell_i \;</math>, ссылающийся на суффикс <math>\mathcal{A}_S [i] \;</math>. | |||
(2.2) Двигаться вверх от <math>\ell_{i - 1} \;</math> до тех пор, пока не встретится вершина <math>u_i \;</math> с длиной строки <math>x_i \le lcp_S[i] \;</math>. | |||
(2.3) Если <math>x_i = lcp_S[i] \;</math>, присоединить лист <math>\ell_i \;</math> к <math>u_i \;</math>. | |||
(2.4) Если <math>x_i < lcp_S[i] \;</math>, создать вершину <math>u'_i \;</math> с длиной строки <math>x_i \;</math>, присоединить ее к <math>u_i \;</math>, а лист <math>\ell_i \;</math> – к <math>u'_i \;</math>. | |||
Рисунок 3. Алгоритм построения суффиксного дерева обходом суффиксного массива | |||
Алгоритм построения суффиксного дерева обходом суффиксного массива | |||
== Применение == | == Применение == | ||
Строка 108: | Строка 98: | ||
Недавно удалось улучшить параметры объема памяти и эффективность буферизации [ ], что позволило построить суффиксное дерево на 3 Гб/с за 30 часов; в работе [ ] было улучшено поведение RAM-алгоритмов с точки зрения операций ввода/вывода для построения суффиксного дерева в режиме онлайн, за счет разработки новой политики буферизации с низким уровнем издержек. | Недавно удалось улучшить параметры объема памяти и эффективность буферизации [15], что позволило построить суффиксное дерево на 3 Гб/с за 30 часов; в работе [1] было улучшено поведение RAM-алгоритмов с точки зрения операций ввода/вывода для построения суффиксного дерева в режиме онлайн, за счет разработки новой политики буферизации с низким уровнем издержек. | ||
== См. также == | == См. также == | ||
Строка 150: | Строка 139: | ||
16. Vitter, J.: External memory algorithms and data structures: Dealing with MASSIVE DATA. ACM Comput. Surv. 33, 209-271 (2002) | 16. Vitter, J.: External memory algorithms and data structures: Dealing with MASSIVE DATA. ACM Comput. Surv. 33, 209-271 (2002) | ||
[[Категория: Совместное определение связанных терминов]] |