Алгоритм Боуера-Мура

     Ну вот мы и пришли к этому, одному из наиболее известных и, эффективных ( Это особенно касается его дальнейших улучшений ) для ОБЫЧНЫХ ПРИЛОЖЕНИЙ ( то есть редакторов текста, например ) алгоритму.

     Он совершает 3 * n сравнений в худшем случае при поиске первого совпадения с непериодничным образцом и O( n*m ) при поиске всех вхождений.

     Он производит сравнения справа налево, начиная с самого правого символа. В случае несовпадения ( или, наоборот, полного попадания ) используются две заранее вычисляемые функции: функция плохого символа и функция хорошего суффикса.

     Предположим, что несовпадение произошло между символом образца x[ j ] = b и символом текста y[ i + j ] = a на позиции i. Тогда y[ i + j + 1, i + m - 1 ] = x[ j + 1, m - 1 ] = u и y[ i + j ] =/= x[ j ]. Функция хорошего суффикса состоит в 'выравнивании' сегмента y[ i + j + 1, i + m - 1 ] = x[ j + 1, m - 1 ] = u по самому правому местонахождению в x символа, так чтобы перед u стоял символ, несовпадающий с x[ j ].


y:      ...------------------| a | ///////////// U ///////////// |---------------------...


x:      --x[0] -> |---------| b | ///////////// U ///////////// | <- x[m-1]  ------  - до сдвига


x:      ...-------------|----| с | ///////////// U ///////////// | ----- |   - после сдвига



Если такого сегмента нет, то выравниваем длиннейший суффикс v слова y[ i + j + 1, i + m - 1 ] c cовпадающим префиксом x.


y:      ...------------------| a | ///////////// U ///////////// |---------------------...


x:      --x[0] -> |---------| b | ///////////// U ///////////// | <- x[m-1]  ------   - до сдвига


x:                                                       | ////// V ////// | ---------------- |   - после сдвига



     Функция плохого символа выравнивает символ текста y[ i + j ] по его самому правому появлению в x[ 0 ... m - 2]. Если его там нет - сдвигаем на всю длину образца: левый конец теперь - y[ i + j + 1 ]

     Для сдвига образца мы берем минимум этих двух функций.

     Это приводит нас к следующему алгоритму:

сдвиг функции плохого символа хранится в таблице bc размера s, а сдвиг функции хорошего суффикса - в таблице gs размера m + 1.

     Для a из S:

bm_bc[ a ] = min{ j | 1 <= j < m и x[ m - 1 - j ] = a }, если a появляется в x и
bm_bc[ a ] = m в противоположном случае.

     Определим два условия:

cond 1 ( j , s ) : для каждого k, такого что j < k < m, s >= k или x[ k - s ] = x[ k ]
cond 2 ( j , s ) : если s < j то x[ j - s ] =/= x[ j ].

     Тогда для 0 <= i < m имеем:

bm_gs[ i + 1 ] = min{ s > 0 | cond 1 ( i , s ) AND cond 2 ( i , s ) hold}

     А bm_gs[ 0 ] - длина наименьшего периода x.

Реализация на Си


/* Preprocessing of the Bad Character function shift */

PRE_BC( char *x, int m, int bm_bc[] ) {

   int a, j; 

   

   for ( a=0; a < ASIZE; a++ ) bm_bc[ a ] = m; 

   for ( j=0; j < m-1;  j++ ) bm_bc[ x[ j ] ] = m - j - 1; 

  }

 

 /* Preprocessing of the Good Suffix function shift  */

 PRE_GS( char *x, int m,  int bm_gs[] ) {

   int i, j, p, f[XSIZE];

   

   memset( bm_gs, 0, ( m + 1 ) * sizeof( int ) );

   f[ m ] = j = m + 1; 

   for (i=m; i > 0; i-- ) {

      while ( j <= m && x[ i - 1 ] != x[ j - 1 ] ) {

        if ( bm_gs[ j ] == 0 ) bm_gs[ j ] = j - 1;

       j = f[ j ];

     }

     f[ i - 1 ] = --j; 

   }

   p=f[ 0 ]; 

   for ( j=0; j <= m; ++j ) {

      if ( bm_gs[ j ] == 0 ) bm_gs[ j ] = p; 

     if ( j == p ) p = f[ p ]; 

   }

}



/* Boyer-Moore string matching algorithm */

void BM( char *x, char *y, int n, int m ) {

  int i, j, bm_gs[XSIZE], bm_bc[ASIZE];

  

  /* Preprocessing */

  PRE_GS( x, m, bm_gs ); 

  PRE_BC( x, m, bm_bc );

  i=0; 

  while ( i <= n-m ) {

     for ( j=m-1; j >= 0 && x[j] == y[ i+j ];  --j ); 

    if ( j < 0 ) {

       OUTPUT(i); 

      i += bm_gs[ j+1 ]; 

    }

    else i += MAX(( bm_gs[ j+1 ]), ( bm_bc[ y[ i+j ] ] - m + j + 1 ) ); 

   }    

} 

   


Назад К началу странички

Вверх по каталогу
Вперед



Построение автомата Алгоритм грубой силы
Алгоритм Боуера-Мура Алгоритм Хорспула
Алгоритм Карпа-Рабина Алгоритм Кнута-Морриса-Пратта
Алгоритм Морриса-Пратта Не такой уж наивный алгоритм
Алгоритм Сдвига-Или