- •Элементарные алгоритмы для работы с графами
- •Работа алгоритма[править | править вики-текст]
- •Неформальное описание[править | править вики-текст]
- •Формальное описание[править | править вики-текст]
- •Алгоритм поиска в глубину[править | править вики-текст]
- •Нерекурсивные варианты[править | править вики-текст]
- •Общая идея
- •[Править]Пошаговое представление
- •[Править]Реализация
- •[Править]Время работы
- •[Править]Цвета вершин
- •Топологическая сортировка и сильно связные компоненты
- •↑ Пример ориентированного неотсортированного графа, к которому применима топологическая сортировка
- •Пример работы алгоритма[править | править вики-текст]
- •Алгоритмы[править | править вики-текст]
- •Минимальные остовные деревья (мst)
- •Введение
- •Постановка задачи
- •Кратчайшие пути
- •Давайте придумаем что-нибудь простое
- •А если я педант?
- •Задача о максимальном потоке
- •[Править]Определение потока
- •[Править]Пример
- •Увеличивающие пути. Теорема Бержа
- •Алгоритм Эдмондса. Сжатие цветков
- •Эффективная реализация
- •Оптимизация: предварительное построение паросочетания
- •Случай двудольного графа
- •Дальнейшая оптимизация
- •[Править]Реализация
- •[Править]Оценка производительности
- •[Править]Пример несходящегося алгоритма
- •[Править]Оценка быстродействия
- •[Править]Литература
- •Максимальные паросочетания[править | править вики-текст]
- •Описание алгоритма Необходимые определения
- •Теорема Бержа
- •Алгоритм Куна
- •Время работы
- •Реализация
- •Улучшенная реализация
- •[Править]Постановка задачи
- •[Править]Решение
- •[Править]Псевдокод
- •Префиксы и суффиксы строки
- •Прямые переходы
- •[Править]Суффиксные ссылки
- •Основные определения и описание структуры[править | править вики-текст]
- •Свойства суффиксных деревьев[править | править вики-текст]
- •Требования суффиксного дерева к памяти[править | править вики-текст]
- •[Править]Недостатки
- •Метод хеширования
- •[Править]Алгоритм
- •[Править]Псевдокод
- •[Править]Время работы
- •[Править]Надёжность
- •Автоматные модели в программировании
- •[Править]Переходы между состояниями [править]Прямые переходы
- •[Править]Суффиксные ссылки
- •[Править]Псевдокод
- •[Править]Пример использования
- •[Править]Псевдокод
- •[Править]Пример
- •[Править]Время работы
- •[Править]Эффективный алгоритм
- •[Править]Псевдокод
- •[Править]Время работы
- •[Править]Построение префикс-функции по z-функции [править]Постановка задачи
- •[Править]Описание алгоритма
- •Приближенные алгоритмы решения np-трудных задач
Свойства суффиксных деревьев[править | править вики-текст]
Лемма. Местоположение w явно в компактном суффиксном дереве тогда и только тогда, когда w является не вложенным суффиксом t или w — правое ветвление.
Доказательство.
.
Если
явно,
то это может быть либо лист, либо вершина
ветвления или корень (в этом случае
и w —
вложенный суффиксt).
Если
—
лист, тогда также является и суффиксом t.
Значит, это должен быть не вложенный
суффикс, так как иначе он появился бы
где-нибудь ещё в строке t:
v —
суффикс t такой,
что w —
префикс v.
Этот узел не может быть листом.
Если
—
узел ветвления, тогда должны существовать,
по меньшей мере, два выходящих ребра
из
с
различными метками. Это означает, что
существуют два различных суффикса u, v,
что w —
префикс u и w —
префикс v,
где v
= wxs, u =
, x
.
Следовательно, w —
правое ветвление.
.
Если w является
не вложенным суффиксом t,
это должен быть лист. Если w —
правое ветвление, то имеются два
суффикса u и v, u
= wxs, v =
,x
,
тогда w является
узлом ветвления. Лемма
доказана.
Теперь легко видеть, почему ответ на вопрос, входит ли слово w в строку t, может быть найден за время O(|w|): нужно только проверить, является ли wместоположением (явным или неявным) в cst(t).
Метки
рёбер должны представлять собой указатели
на положение в строке, чтобы суффиксное
дерево расходовало память размером O(n).
Метка (p, q) ребра означает подстроку
или
пустую строку, если p > q.
Укконен
вводит название открытые рёбра
для рёбер, заканчивающихся в листьях.
Пометки открытых рёбер записывают
как (p,
) вместо (p,
|t|),
где
—
длина, всегда большая, чем |t|.
Пусть T —
-дерево.
Пусть
—
узел T, v —
наидлиннейший суффикс w такой,
что
—
также узел T.
Непомеченное ребро от
до
называетсясуффиксным
звеном.
Если v
= w,
оно называется атомарным.
Утверждение. В
ast(t)
и cst(t$),
где $
t,
все суффиксные звенья являются атомарными.
Доказательство. Символ $ называется символом-стражем. Первая часть (для ast(t)) следует из определения, так как местоположения являются явными. Для доказательства второй (случай cst(t)) части мы должны показать, что для каждого узла также является узлом cst(t). Если — узел cst(t), то является либо листом, либо узлом ветвления. Если является листом, тогда aw — не вложенный суффикс t. Благодаря символу-стражу, из леммы следует, что все суффиксы (включая корень, пустой суффикс) являются явными, так как только корень — вложенный суффикс. Поэтому w является листом или корнем. Если — узел ветвления, тогда aw — правое ветвление, как и w. Следовательно, местоположение явно по лемме. Утверждение доказано.
Как следует из этого доказательства, символ-страж гарантирует существование листьев для всех суффиксов. С таким символом не может быть вложенных суффиксов, кроме пустого. Если мы опустим символ-страж, некоторые суффиксы могут стать вложенными, и их местоположения станут неявными.
Требования суффиксного дерева к памяти[править | править вики-текст]
Утверждение. Компактное суффиксное дерево может быть представлено в виде, требующем O(n) памяти.
Доказательство. Суффиксное дерево содержит не более одного листа на каждый суффикс (в точности один с символом-стражем). Каждый внутренний узел должен быть узлом ветвления, следовательно, внутренний узел имеет по меньшей мере двух потомков. Каждое ветвление увеличивает число листьев по меньшей мере на единицу, поэтому мы имеем не более n внутренних узлов и не более n листьев.
Для представления строк, являющихся метками рёбер, мы используем индексацию в исходной строке, как описано выше. Каждый узел имеет не более одного предка и, таким образом, общее число ребер не превышает 2n.
Аналогично, каждый узел имеет не более одного суффиксного звена, тогда общее число суффиксных звеньев также ограничено числом 2n. Утверждение доказано.
Как
пример суффиксного дерева с 2n-1 вершинами
можно рассмотреть дерево для слова
.
Размер атомарного суффиксного дерева
для строки tсоставляет O(
).
Простейший алгоритм
Дан
текст |
Определение: |
Будем
говорить, что паттерн
встречается
в тексте
со
сдвигом
,
если |
[править]Алгоритм
В
наивном алгоритме поиск всех допустимых
сдвигов производится с помощью цикла,
в котором проверяется условие
для
каждого из
возможных
значений
.
[править]Псевдокод
Приведем пример псевдокода, который находит все вхождения строки в и возвращает массив позиций, откуда начинаются вхождения.
vector<int> naiveStringMatcher(t : string, p : string):
int n = t.length
int m = p.length
vector<int> ans
for i = 0 to n - m
if t[i .. i + m - 1] == p
ans.push_back(i)
return ans
[править]Время работы
Алгоритм
работает за
.
В худшем случае
,
что даёт
.
Однако если
достаточно
мало по сравнению с
,
то тогда асимптотика получается близкой
к
,
поэтому этот алгоритм достаточно широко
применяется на практике.
[править]Сравнение с другими алгоритмами
[править]Преимущества
Требует памяти.
Приемлемое время работы на практике (см. выше). Благодаря этом алгоритм применяется, например, в браузерах и текстовых редакторах (при использовании Ctrl + F), потому что обычно паттерн, который нужно найти, очень короткий по сравнению с самим текстом. Также наивный алгоритм используется в стандартных библиотеках языков высокого уровня (C++, Java), потому что он не требует дополнительной памяти.
Простая и понятная реализация.
