Турбо - обращенние сегмента

     Этот алгоритм является улучшением 'алгоритма обращенного сегмента' уменьшающим наибольшее число сравнений до 2*n. В самом деле, достаточно запомнить префикс u (x), который совпал во время прошлой попытки. Тогда во время текущей попытки при достижении правого конца u, легко доказать, что достаточно прочитать заново не более, чем правую половину u. Это и заложено в алгоритме турбо-обращения сегмента.

     Пусть слово z - сегмент слова w.
     Oпределим смещение disp( z, w) - от англ. displacement как положительное целое число, такое что

w [ m - d - |z| - 1 , m - d ] = z.


     Типичная для TRF-алгоритма ( Turbo Reverse Factor - о чем мы говорим) ситуация возникает, когда префикс u был найден при прошлой попытке, а сейчас алгоритм пытается сравнить сегмент v длины m - |u| с текстом сразу справа за u. Точка между u и v называется 'точкой принятия решения'. Если v не является сегментом x, то сдвиг вычисляется, как в простом алгоритме обращенного сегмента.

     Если v - суффикс x, тогда мы нашли x, а если v - не суффикс, но сегмент x, то достаточно просмотреть заново min( per( u ) , |u| / 2 ) правых символов u. Если u - периодичное ( т.е per( u ) <= |u| / 2 ), то пусть z - суффикс u длины per( u ). По определению периода, z - непериодичное слово, а значит следующее наложение невозможно:

Иллюстрация 1


     Таким образом, z может появиться в u лишь на расстоянии, кратном per( u ), и следовательно, наименьший подходяший суффикс uv, являющийся префиксом x имеет длину |uv| - disp( zv , x ) = m - disp( zv , x ), значит, длину сдвига можно положить равной disp( zv , x ).

     Если u - не периодичное: per( u ) > |u| / 2, то очевидно, что x не может появиться второй раз в левой части u длины per( u ). А значит, достаточно будет просмотреть правую часть u длины |u| - per( u ) < |u| / 2, чтобы найти неопределенный переход автомата. Функция disp реализована непосредственно в автомате S( x ) без увеличения сложности его построения.

     Турбо алгоритм обращения сегмента производит в худшем случае 2*n сравнений и в среднем оптимален.

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


   struct Arrow {

   int target, shift;

};



struct State {

   int length, suf, pos;

   char terminal;

};



typedef struct Arrow ARROW;

typedef struct State STATE;



int state_counter;

int next[ XSIZE + 1 ];

/* Creates and returns a clone of state p. */

int COPY ( int p , STATE *states , ARROW trans[ XSIZE ][ ASIZE ])

{

 int r;

 

 r = state_counter++;

 memcpy( trans[ r ] , trans[ p ] , ASIZE * sizeof( ARROW ));

 states[ r ].suf = states[ p ].suf;

 states[ r ].pos = states[ p ].pos;

 return (r);

}



/* Creates the suffix automation for the reverse of the word x and */

/*  returns its initial state.      */

int SUFF( char *x, int m, STATE *states, ARROW trans[XSIZE][ASIZE])

{

 int i, art, init, last, p, q, r;

 char a;

 

 art = state_counter++;

 init = state_counter++;

 states[ init ].suf = art;

 last = init;

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

    a = x[ i ];

   p = last;

   q = state_counter++;

   states[ q ].length = states[ p ].length + 1;

   states[ q ].pos = states[ p ].pos + 1;

   while ( p != init && trans[ p ][ a ].target == 0 ) {

      trans[ p ][ a ].target = q;

      trans[ p ][ a ].shift = states[q].pos-states[p].pos-1;

      p = states[ p ].suf;

   }

   if ( trans[ p ][ a ].target == 0 ) {

      trans[ init ][ a ].target = q;

      trans[init][a].shift = states[q].pos-states[init].pos-1;

      states[ q ].suf = init;

   }

   else

    if ( states[p].length+1 == states[trans[p][a].target].length)

        states[ q ].suf = trans[ p ][ a ].target;

    else {

 r = COPY( trans[ p ][ a ].target , states, trans );

 states[ r ].length = states[ p ].length + 1;

 states[ trans[ p ][ a ].target ].suf = r;

 states[ q ].suf = r;

 while (p!=art && states[trans[p][a].target].length>=states[r].length)

  {

   trans[p][a].shift = states[trans[p][a].target].pos-states[p].pos-1;

   trans[ p ][ a ].target = r;

   p = states[ p ].suf;

 }

    }

   last = q;

 }

 states[ last ].terminal = 1;

 p = last;

 while ( p != init ) {

    p = states[ p ].suf;

   states[ p ].terminal = 1;

 }

 return ( init );

}



/* Computation of the Morris and Pratt next function */

int MP( char *x, int m, int mp_next[])

{

 int i, j;

 

 i = 1;

 j = 0;

 mp_next[ 0 ]= -1;

 while ( i < m )

    if ( j > -1 && x[ i ] != x[ j ])

      if ( j ) j = mp_next[ j-1 ] + 1;

      else j = -1;

   else mp_next[ i++ ] = j++;

 for ( i = 0; i < m; ++i ) mp_next[ i ] = i - mp_next[ i ];

 return 0;

}



/* Turbo Reverse Factor algorithm. */

void TRF( char *y, char *x, int n, int m)

{

 int period, i, j, shift, u, period_of_u;

 int disp, init, state, state_aux, mu;

 STATE states[ 2 * XSIZE + 2 ];

 ARROW trans[ XSIZE ][ ASIZE ];

 

 /* Preprocessing */

 memset( trans, 0, 2 * ( m + 2 ) * ASIZE * sizeof ( ARROW ) );

 memset( states, 0, 2 * ( m + 2 ) * sizeof( STATE ) );

 state_counter = 1;

 init = SUFF( x , m , states , trans );

 MP ( x, m, next );

 period = next [ m - 1 ];

 i = period_of_u = 0;

 shift = m;

 

 /* Searching */

 while ( i <= n - m ) {

    j = m - 1;

   state = init;

   u = m - 1 - shift;

   shift = m;

   disp = 0;

   while (j>u && (state_aux=trans[state][y[i+j]].target) !=0 )

   {

      disp += trans[ state ][ y[ i+j ] ].shift;

      state = state_aux;

      if ( states[ state ].terminal ) shift = j;

      j--;

   }

   if (j > u) period_of_u = (shift!=m ? next[m-1-shift] : 0 );

   else if ( !disp ) {

      OUTPUT (i);

      shift = period;

      period_of_u = ( shift != m ? next[ m-1-period ] : 0 );

   }

   else {

      mu = ( u + 1 ) / 2;

      if ( period_of_u <= mu ) {

         u -= period_of_u;

         while(j>u && (state_aux=trans[state][y[i+j]].target) != 0)

		 {

            disp += trans[ state ][ y[ i+j ] ].shift;

            state = state_aux;

            if ( states[ state ].terminal ) shift = j;

            j--;

         }

         if (j>u) period_of_u=(shift!=m ? next[m-1-shift] : 0 );

            else {

               shift = disp;

               period_of_u = next[ m - 1 - disp ];

            }

         }

         else {

            u -= mu;

            --u;

            while (j>u && (state_aux=trans[state][y[i+j]].target) !=0 )

			{

               disp += trans[ state ][ y[ i+j ] ].shift;

               state=state_aux;

               if ( states[ state ].terminal ) shift = j;

               j--;

            }

            period_of_u = ( shift != m ? next[ m - 1 - shift ] : 0 );

         }

      }

      i+=shift;

   }

}



   

   


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

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



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