Алгоритм Колусси — различия между версиями
(→Алгоритм) |
Kabanov (обсуждение | вклад) м |
||
Строка 22: | Строка 22: | ||
{{Определение | {{Определение | ||
|definition= | |definition= | ||
− | Обозначим за <tex>\mathrm{K_{min}}(i) = \min\{k : \ x[0 \dots i-1-k]=x[d \dots i-1]\ and\ x[i-k] \neq x[i]\}</tex>. Функция <tex>\mathrm{K_{min}}</tex> для всех позиций <tex>i</tex>, у которых <tex>Kmp(i) \neq -1</tex>. | + | Обозначим за <tex>\mathrm{K_{min}}(i) = \min\{k : \ x[0 \dots i-1-k]=x[d \dots i-1]\ and\ x[i-k] \neq x[i]\}</tex>. Функция <tex>\mathrm{K_{min}}</tex> определена для всех позиций <tex>i</tex>, у которых <tex>Kmp(i) \neq -1</tex>. |
}} | }} | ||
− | Если <tex>\mathrm{ | + | Если <tex>\mathrm{K_{min}}(i) \neq 0</tex>, то периодичность шаблона <tex>x</tex> заканчивается в позиции <tex>i</tex>. |
Очевидно, что для <tex>0 < i < m</tex> позиция <tex>i</tex>: | Очевидно, что для <tex>0 < i < m</tex> позиция <tex>i</tex>: | ||
− | * насыщенная, если <tex>\mathrm{ | + | * насыщенная, если <tex>\mathrm{K_{min}}(i-1) \neq 0</tex> |
* ненасыщенная, иначе | * ненасыщенная, иначе | ||
Строка 39: | Строка 39: | ||
{{Определение | {{Определение | ||
|definition= | |definition= | ||
− | Обозначим за <tex>\mathrm{ | + | Обозначим за <tex>\mathrm{R_{min}}(i)</tex> наименьший период <tex>r</tex> шаблона <tex>x</tex> большего, чем <tex>i</tex>. Функция <tex>\mathrm{R_{min}}</tex> определена для всех позиций <tex>i</tex>, у которых <tex>Kmp(i) = -1</tex>. |
}} | }} | ||
{{Определение | {{Определение | ||
|definition= | |definition= | ||
− | Обозначим за <tex>\mathrm{ | + | Обозначим за <tex>\mathrm{first}(u)</tex> наименьший число <tex>v</tex> такое, что <tex>u \leqslant h[v]</tex>. |
}} | }} | ||
Строка 52: | Строка 52: | ||
Рассмотрим случай, когда <tex>x[h[k]]=y[j+h[k]]</tex> для <tex>0 \leqslant k < r < nd</tex> и <tex>x[h[r]] \neq y[j+h[r]]</tex>. | Рассмотрим случай, когда <tex>x[h[k]]=y[j+h[k]]</tex> для <tex>0 \leqslant k < r < nd</tex> и <tex>x[h[r]] \neq y[j+h[r]]</tex>. | ||
− | Пусть <tex>j' = j + \mathrm{ | + | Пусть <tex>j' = j + \mathrm{K_{min}}(h[r])</tex>. |
Тогда нет вхождений шаблона <tex>x</tex>, начиная с <tex>y[j \dots j']</tex> и <tex>x</tex> может быть сдвинут на <tex>\mathrm{K_{min}}(h[r])</tex> позиций вправо. | Тогда нет вхождений шаблона <tex>x</tex>, начиная с <tex>y[j \dots j']</tex> и <tex>x</tex> может быть сдвинут на <tex>\mathrm{K_{min}}(h[r])</tex> позиций вправо. | ||
Строка 108: | Строка 108: | ||
На каждой итерации цикла увеличивается либо переменная <tex>i</tex>, либо <tex>k</tex> (или переменная <tex>q</tex>, которая используется в конечном счете для обновления <tex>k</tex>). Поскольку <tex>i = 1</tex> и <tex>k = 1</tex> в начале и <tex>i < k = m + 1</tex> в конце алгоритма, количество итераций алгоритма не превосходит <tex>2 \cdot m</tex>. Следовательно функция требует <tex>O(m)</tex> времени и памяти. | На каждой итерации цикла увеличивается либо переменная <tex>i</tex>, либо <tex>k</tex> (или переменная <tex>q</tex>, которая используется в конечном счете для обновления <tex>k</tex>). Поскольку <tex>i = 1</tex> и <tex>k = 1</tex> в начале и <tex>i < k = m + 1</tex> в конце алгоритма, количество итераций алгоритма не превосходит <tex>2 \cdot m</tex>. Следовательно функция требует <tex>O(m)</tex> времени и памяти. | ||
− | Функция для построения массива <tex>\mathrm{ | + | Функция для построения массива <tex>\mathrm{K_{min}}</tex>. |
'''int'''[] buildKmin('''int'''[] hmax, '''int''' m) | '''int'''[] buildKmin('''int'''[] hmax, '''int''' m) | ||
'''int''' kmin[m] | '''int''' kmin[m] | ||
Строка 116: | Строка 116: | ||
'''return''' kmin | '''return''' kmin | ||
− | Функция для построения массива <tex>\mathrm{ | + | Функция для построения массива <tex>\mathrm{R_{min}}</tex>. |
'''int'''[] buildRmin('''int'''[] hmax, '''int'''[] kmin, '''int''' m) | '''int'''[] buildRmin('''int'''[] hmax, '''int'''[] kmin, '''int''' m) | ||
'''int''' rmin[m] | '''int''' rmin[m] |
Версия 15:11, 13 июня 2014
Содержание
Алгоритм
Отметим, что нумерация символов строк и элементов массива у нас начинается с
.Обозначим за префикс-функцию, но при этом она определена для и имеет значение по умолчанию.
—Множество всех позиций шаблона разделим на два непересекающихся множества. Тогда каждая попытка сравнения шаблона с исходной строкой состоит из двух фаз.
Определение: |
В первой фазе сравнения выполняются слева направо с символами текста, выровненными с шаблоном в позиции, для которой значение функции | строго больше . Такие позиции будем называть насыщенными (noholes).
Определение: |
Вторая фаза состоит в сравнении в оставшихся позициях справа налево. Такие позиции будем называть ненасыщенными (holes). |
Такая стратегия предоставляет, как минимум, 2 преимущества:
- когда несовпадение появляется во время первой фазы, после соответствующего сдвига уже нет необходимости делать проверки в насыщенных позициях, которые были проверены на предыдущем шаге.
- когда несовпадение появляется во время второй фазы, это означает, что суффикс шаблона совпал с периодом (factor) строки, после соответствующего сдвига префикс шаблона будет все ещё совпадать с периодом текста, поэтому нет необходимости в повторной проверке.
Определение: |
Обозначим за | . Функция определена для всех позиций , у которых .
Если , то периодичность шаблона заканчивается в позиции .
Очевидно, что для
позиция :- насыщенная, если
- ненасыщенная, иначе
Обозначим за
количество насыщенных позиций в шаблоне .Массив
содержит первыми элементами насыщенных позиций в возрастающем порядке и затем ненасыщенных в убывающем порядке, т.е.- для всех насыщенная позиция и для .
- для всех ненасыщенная и для .
Определение: |
Обозначим за | наименьший период шаблона большего, чем . Функция определена для всех позиций , у которых .
Определение: |
Обозначим за | наименьший число такое, что .
Допустим, что шаблон выровнен с .
Первая фаза
Рассмотрим случай, когда
для и .Пусть
.Тогда нет вхождений шаблона
, начиная с и может быть сдвинут на позиций вправо.Кроме того
для означает, что сравнения могут продолжены с и .Вторая фаза
Теперь рассмотрим ситуацию, когда
для и для .Пусть
позиций вправо.Тогда нет вхождений шаблона
, начиная с и может быть сдвинут на .Кроме того
означает, что сравнения могут продолжены с и .Предварительные вычисления
Для вычисления значений
будем использовать вспомогательную функцию .Определение: |
Обозначим за
| функцию, для которой выполняется:
Псевдокод
Наивный вариант
int[] buildHmax(char[] x, int m): int hmax[m + 1] for k = 1 .. m int i = k while x[i] == x[i - k] i++ hmax[k] = i return hmax
Явная реализация по определению, очевидно, работает за
и требует памяти.Улучшенный вариант
int[] buildHmax(char[] x, int m): int hmax[m + 1] int i = 1 int k = 1 while k <= m while x[i] == x[i - k] i++; hmax[k] = i int q = k + 1 while hmax[q - k] + k < i hmax[q] = hmax[q - k] + k q++ k = q if k == i + 1 i = k return hmax
На каждой итерации цикла увеличивается либо переменная
, либо (или переменная , которая используется в конечном счете для обновления ). Поскольку и в начале и в конце алгоритма, количество итераций алгоритма не превосходит . Следовательно функция требует времени и памяти.Функция для построения массива
.int[] buildKmin(int[] hmax, int m) int kmin[m] for i = m .. 1 if hmax[i] < m kmin[hmax[i]] = i return kmin
Функция для построения массива
.int[] buildRmin(int[] hmax, int[] kmin, int m) int rmin[m] int r = 0 for i = m - 1 .. 0 if hmax[i + 1] == m //— первое число большее, чем и такое, что шаблон имеет период r = i + 1 if kmin[i] == 0 rmin[i] = r else rmin[i] = 0 return rmin
Функция для построение массива
.int[] buildShift(int[] kmin, int[] rmin, int[] h, int nd, int m) int shift[m + 1] for i = 0 .. nd shift[i] = kmin[h[i]] for i = nd + 1 .. m - 1 shift[i] = rmin[h[i]] shift[m] = rmin[0] return shift
Функция для построения массива
.
Асимптотики
- partitions the set of pattern positions into two disjoint subsets; the positions in the first set are scanned from left to right and when no mismatch occurs the positions of the second subset are scanned from right to left;
- preprocessing phase in time and space complexity;
- searching phase in time complexity;
- performs text character comparisons in the worst case.
Сравнение с другими алгоритмами
Достоинства
- Поиск выполняется за алгоритма Кнута-Морриса-Пратта, поиск в котором занимается , что помогает уменьшить константу при . в отличие от
- Фаза предобработки выполняется за алгоритма Бойера-Мура, где в наилучшем случае можно получить время , что плохо при больших алфавитах. в отличие от
Недостатки
- Сложность реализации.
Источники
- COLUSSI L., 1991, Correctness and efficiency of the pattern matching algorithms, Information and Computation 95(2):225-251.
- Colussi algorithm
- Colussi.ppt