Алгоритм Shift-And

Материал из Викиконспекты
Версия от 21:04, 8 июня 2014; Shersh (обсуждение | вклад) (Корректность)
Перейти к: навигация, поиск

В 1990ые годы Рикардо Беза-Йетс (англ. Ricardo Baeza-Yates) и Гастон Гоннет (англ. Gaston Gonnet) изобрели простой битовый метод, эффективно решающий задачу точного поиска малых образцов (длиной в типичное английское слово). Они назвали его методом ShiftAnd. Также алгоритм известен как bitap алгоритм и алгоритм Беза-Йетса-Гоннета. Существует вариация данного алгоритма под названием Shift-Or, которая будет рассмотрена ниже.

Алгоритм

Пусть p — шаблон длины n, t — текст длины m.

Нам потребуется двоичный массив M размером n(m+1), в котором индекс i пробегает значения от 1 до n, а индекс j — от 0 до m.

M[i][j]=1, если первые i символов p точно совпадают с i символами t, кончаясь на позиции j; иначе M[i][j]=0.

M[i][j]={1,if p[1..i] = t[j - i + 1..j]0,otherwise

Например, пусть t=california, p=for. Тогда M[1][5]=M[2][6]=M[3][7]=1, остальные M[i][j]=0.

Получаем, что элементы, равные 1, в строчке i показывают все места в t, где заканчиватся копии p[1..i], а столбец j показывает все префиксы p, которые заканчиваются в позиции j строки t. M[n][j]=1 тогда, когда вхождение p заканчивается в позиции j строки t. То есть вычисление последней строки M решает задачу точного совпадения.

Построение массива M.

Создадим для каждого символа алфавита x двоичный вектор U(x) длины n. U(x) равно 1 в тех позициях p, где стоит символ x. Например, p=abacdeab, U(a)=10100010

Определим BitShift(M[j]) как вектор, полученный сдвигом вектора для столбца M[j] вниз на одну позицию и записью 1 в первой позиции. Старое значение в позиции n теряется. То есть BitShift(M[j]) состоит из 1, к которой приписаны первые n1 битов столбца M[j]. (0,0,0,1,0,1,1,0,1)(1,0,0,0,1,0,1,1,0)

Из определения, нулевой столбец M состоит из нулей. Элементы любого другого столбца M[j],j>0 получаются из столбца M[j1] и вектора U для символа t[j]. А именно, вектор для столбца j получается операцией побитового логического умножения and вектора BitShift(M[j1]) и вектора U(t[j]). M[j]=BitShift(M[j1]) and U(t[j])

Псевдокод

   string bitap_search(string text, string pattern)
       n = pattern.length
       m = text.length
       if n == 0
           return text
       M = new array [n] of bit // для поиска коротких слов достаточно одной переменной типа integer
       fill(M, 0)
       U = new array [|Σ|][n] of bit, initially all 0
       for i = 1..n // препроцессинг - вычисление вектора U
           U[pattern[i]][i] = 1
       for j = 1..m
           M = Bit-Shift(M) & U[text[j]]
           if M[n]
               return text[j - n + 1..j]
       return null

Корректность

Докажем, что метод ShiftAnd правильно вычисляет элементы массива M. Заметим, что для любого i>1 элемент M[i][j]=1 тогда и только тогда, когда p[1..i1] совпадает с t[ji+1j1], а символ p[i] совпадает с t[j]. Первое условие выполнено, когда элемент массива M[i1][j1]=1, а второе — когда i-ый бит вектора U для символа t[j] равен 1. После сдвига столбца j1 алгоритм логически умножает элемент M[i1][j1] столбца j1 на элемент i вектора U(t[j]). Следовательно, все элементы M вычисляются правильно и алгоритм находит все вхождения образца в текст.

Эффективность

Сложность алгоритма составляет O(nm), на препроцессинг — построение массива U требуется O(|Σ|n) операций и памяти. Если же n не превышает длину машинного слова, то сложность получается O(m) и O(n+|Σ|) соответсвенно.

Алгоритм Shift-Or

Аналогичен алгоритму ShiftAnd, но вместо массива M используется массив R, определяемый следующим образом:

R[i][j]={0,if p[1..i] = t[j - i + 1..j]1,otherwise

Следующий столбец R[j] получается операцией побитового логического сложения or вектора BitShift(R[j1]) и вектора W(t[j]). Здесь W(t[j])=not U(t[j]), а BitShift(R[j1]) - сдвиг вектора R[j1] на одну позицию вниз с записью 0 в первой позиции.

R[j]=BitShift(R[j1]) or W(t[j])

Очевидно, что алгоритм ShiftOr корректен, так как данная формула получается применением логического отрицания к аналогичной формуле для алгоритма ShiftAnd, корректность которого была доказана выше.