Algoritmo de autómatas finitos para la búsqueda de patrones – Part 1

Dado un texto txt[0..n-1] y un patrón pat[0..m-1] , escriba una función search(char pat[], char txt[]) que imprima todas las apariciones de pat[] en txt [] . Puede suponer que n > m.
Ejemplos: 

Input:  txt[] = "THIS IS A TEST TEXT"
        pat[] = "TEST"
Output: Pattern found at index 10

Input:  txt[] =  "AABAACAADAABAABA"
        pat[] =  "AABA"
Output: Pattern found at index 0
        Pattern found at index 9
        Pattern found at index 12

Pattern

 

La búsqueda de patrones es un problema importante en informática. Cuando buscamos una string en el bloc de notas/archivo de Word, en el navegador o en la base de datos, se utilizan algoritmos de búsqueda de patrones para mostrar los resultados de la búsqueda. 
Hemos discutido los siguientes algoritmos en las publicaciones anteriores:
Algoritmo Naive Algoritmo 
KMP Algoritmo  
Rabin Karp
En esta publicación, discutiremos el algoritmo de búsqueda de patrones basado en Finite Automata (FA). En el algoritmo basado en FA, preprocesamos el patrón y construimos una array 2D que representa un autómata finito. La construcción de la FA es la principal parte complicada de este algoritmo. Una vez que se construye el FA, la búsqueda es simple. En la búsqueda, simplemente necesitamos comenzar desde el primer estado de los autómatas y el primer carácter del texto. En cada paso, consideramos el siguiente carácter del texto, buscamos el siguiente estado en el FA construido y pasamos a un nuevo estado. Si llegamos al estado final, entonces el patrón se encuentra en el texto. La complejidad temporal del proceso de búsqueda es O(n). 
Antes de discutir la construcción de FA, echemos un vistazo a la siguiente FA para el patrón ACACAGA. 
 

Finite Automata algorithm for Pattern Searching 1

Finite Automata algorithm for Pattern Searching 2

Los diagramas anteriores representan representaciones gráficas y tabulares del patrón ACACAGA.
El número de estados en FA será M+1 donde M es la longitud del patrón. Lo principal para construir FA es obtener el siguiente estado del estado actual para cada carácter posible. Dado un carácter x y un estado k, podemos obtener el siguiente estado considerando la string “pat[0..k-1]x” que es básicamente una concatenación de caracteres de patrón pat[0], pat[1] … pat[ k-1] y el carácter x. La idea es obtener la longitud del prefijo más largo del patrón dado, de modo que el prefijo también sea el sufijo de «pat[0..k-1]x». El valor de longitud nos da el siguiente estado. Por ejemplo, veamos cómo obtener el siguiente estado desde el estado actual 5 y el carácter ‘C’ en el diagrama anterior. Necesitamos considerar la string, “pat[0..4]C” que es “ACACAC”. La longitud del prefijo más largo del patrón tal que el prefijo es sufijo de “ACACAC” es 4 (“ACAC”). 
En el siguiente código, computeTF() construye el FA. La complejidad de tiempo de computeTF() es O(m^3*NO_OF_CHARS) donde m es la longitud del patrón y NO_OF_CHARS es el tamaño del alfabeto (número total de caracteres posibles en el patrón y el texto). La implementación prueba todos los prefijos posibles comenzando por el más largo posible que puede ser un sufijo de “pat[0..k-1]x”. Hay mejores implementaciones para construir FA en O(m*NO_OF_CHARS) (Sugerencia: podemos usar algo como la construcción de arrays lps en el algoritmo KMP ). Hemos cubierto la mejor implementación en nuestra próxima publicación sobre la búsqueda de patrones .
 

C

// C program for Finite Automata Pattern searching
// Algorithm
#include<stdio.h>
#include<string.h>
#define NO_OF_CHARS 256
 
int getNextState(char *pat, int M, int state, int x)
{
    // If the character c is same as next character
    // in pattern,then simply increment state
    if (state < M && x == pat[state])
        return state+1;
 
    // ns stores the result which is next state
    int ns, i;
 
    // ns finally contains the longest prefix
    // which is also suffix in "pat[0..state-1]c"
 
    // Start from the largest possible value
    // and stop when you find a prefix which
    // is also suffix
    for (ns = state; ns > 0; ns--)
    {
        if (pat[ns-1] == x)
        {
            for (i = 0; i < ns-1; i++)
                if (pat[i] != pat[state-ns+1+i])
                    break;
            if (i == ns-1)
                return ns;
        }
    }
 
    return 0;
}
 
/* This function builds the TF table which represents4
    Finite Automata for a given pattern */
void computeTF(char *pat, int M, int TF[][NO_OF_CHARS])
{
    int state, x;
    for (state = 0; state <= M; ++state)
        for (x = 0; x < NO_OF_CHARS; ++x)
            TF[state][x] = getNextState(pat, M, state, x);
}
 
/* Prints all occurrences of pat in txt */
void search(char *pat, char *txt)
{
    int M = strlen(pat);
    int N = strlen(txt);
 
    int TF[M+1][NO_OF_CHARS];
 
    computeTF(pat, M, TF);
 
    // Process txt over FA.
    int i, state=0;
    for (i = 0; i < N; i++)
    {
        state = TF[state][txt[i]];
        if (state == M)
            printf ("\n Pattern found at index %d",
                                           i-M+1);
    }
}
 
// Driver program to test above function
int main()
{
    char *txt = "AABAACAADAABAAABAA";
    char *pat = "AABA";
    search(pat, txt);
    return 0;
}

CPP

// CPP program for Finite Automata Pattern searching
// Algorithm
#include <bits/stdc++.h>
using namespace std;
#define NO_OF_CHARS 256
 
int getNextState(string pat, int M, int state, int x)
{
    // If the character c is same as next character
    // in pattern,then simply increment state
    if (state < M && x == pat[state])
        return state+1;
 
    // ns stores the result which is next state
    int ns, i;
 
    // ns finally contains the longest prefix
    // which is also suffix in "pat[0..state-1]c"
 
    // Start from the largest possible value
    // and stop when you find a prefix which
    // is also suffix
    for (ns = state; ns > 0; ns--)
    {
        if (pat[ns-1] == x)
        {
            for (i = 0; i < ns-1; i++)
                if (pat[i] != pat[state-ns+1+i])
                    break;
            if (i == ns-1)
                return ns;
        }
    }
 
    return 0;
}
 
/* This function builds the TF table which represents4
    Finite Automata for a given pattern */
void computeTF(string pat, int M, int TF[][NO_OF_CHARS])
{
    int state, x;
    for (state = 0; state <= M; ++state)
        for (x = 0; x < NO_OF_CHARS; ++x)
            TF[state][x] = getNextState(pat, M, state, x);
}
 
/* Prints all occurrences of pat in txt */
void search(string pat, string txt)
{
    int M = pat.size();
    int N = txt.size();
 
    int TF[M+1][NO_OF_CHARS];
 
    computeTF(pat, M, TF);
 
    // Process txt over FA.
    int i, state=0;
    for (i = 0; i < N; i++)
    {
        state = TF[state][txt[i]];
        if (state == M)
            cout<<" Pattern found at index "<< i-M+1<<endl;
    }
}
 
// Driver program to test above function
int main()
{
    string txt = "AABAACAADAABAAABAA";
    string pat = "AABA";
    search(pat, txt);
    return 0;
}
 
//This code is contributed by rathbhupendra

Java

// Java program for Finite Automata Pattern
// searching Algorithm
class GFG {
     
    static int NO_OF_CHARS = 256;
    static int getNextState(char[] pat, int M, 
                             int state, int x)
    {
         
        // If the character c is same as next
        // character in pattern,then simply
        // increment state
        if(state < M && x == pat[state])
            return state + 1;
             
        // ns stores the result which is next state
        int ns, i;
 
        // ns finally contains the longest prefix
        // which is also suffix in "pat[0..state-1]c"
 
        // Start from the largest possible value
        // and stop when you find a prefix which
        // is also suffix
        for (ns = state; ns > 0; ns--)
        {
            if (pat[ns-1] == x)
            {
                for (i = 0; i < ns-1; i++)
                    if (pat[i] != pat[state-ns+1+i])
                        break;
                    if (i == ns-1)
                        return ns;
            }
        }
 
            return 0;
    }
 
    /* This function builds the TF table which
    represents Finite Automata for a given pattern */
    static void computeTF(char[] pat, int M, int TF[][])
    {
        int state, x;
        for (state = 0; state <= M; ++state)
            for (x = 0; x < NO_OF_CHARS; ++x)
                TF[state][x] = getNextState(pat, M, state, x);
    }
 
    /* Prints all occurrences of pat in txt */
    static void search(char[] pat, char[] txt)
    {
        int M = pat.length;
        int N = txt.length;
 
        int[][] TF = new int[M+1][NO_OF_CHARS];
 
        computeTF(pat, M, TF);
 
        // Process txt over FA.
        int i, state = 0;
        for (i = 0; i < N; i++)
        {
            state = TF[state][txt[i]];
            if (state == M)
                System.out.println("Pattern found "
                          + "at index " + (i-M+1));
        }
    }
 
    // Driver code
    public static void main(String[] args)
    {
        char[] pat = "AABAACAADAABAAABAA".toCharArray();
        char[] txt = "AABA".toCharArray();
        search(txt,pat);
    }
}
 
// This code is contributed by debjitdbb.

Python3

# Python program for Finite Automata
# Pattern searching Algorithm
 
NO_OF_CHARS = 256
 
def getNextState(pat, M, state, x):
    '''
    calculate the next state
    '''
 
    # If the character c is same as next character
      # in pattern, then simply increment state
 
    if state < M and x == ord(pat[state]):
        return state+1
 
    i=0
    # ns stores the result which is next state
 
    # ns finally contains the longest prefix
     # which is also suffix in "pat[0..state-1]c"
 
     # Start from the largest possible value and
      # stop when you find a prefix which is also suffix
    for ns in range(state,0,-1):
        if ord(pat[ns-1]) == x:
            while(i<ns-1):
                if pat[i] != pat[state-ns+1+i]:
                    break
                i+=1
            if i == ns-1:
                return ns
    return 0
 
def computeTF(pat, M):
    '''
    This function builds the TF table which
    represents Finite Automata for a given pattern
    '''
    global NO_OF_CHARS
 
    TF = [[0 for i in range(NO_OF_CHARS)]\
          for _ in range(M+1)]
 
    for state in range(M+1):
        for x in range(NO_OF_CHARS):
            z = getNextState(pat, M, state, x)
            TF[state][x] = z
 
    return TF
 
def search(pat, txt):
    '''
    Prints all occurrences of pat in txt
    '''
    global NO_OF_CHARS
    M = len(pat)
    N = len(txt)
    TF = computeTF(pat, M)   
 
    # Process txt over FA.
    state=0
    for i in range(N):
        state = TF[state][ord(txt[i])]
        if state == M:
            print("Pattern found at index: {}".\
                   format(i-M+1))
 
# Driver program to test above function           
def main():
    txt = "AABAACAADAABAAABAA"
    pat = "AABA"
    search(pat, txt)
 
if __name__ == '__main__':
    main()
 
# This code is contributed by Atul Kumar

C#

// C# program for Finite Automata Pattern
// searching Algorithm
using System;
 
class GFG
{
 
public static int NO_OF_CHARS = 256;
public static int getNextState(char[] pat, int M,
                               int state, int x)
{
 
    // If the character c is same as next
    // character in pattern,then simply
    // increment state
    if (state < M && (char)x == pat[state])
    {
        return state + 1;
    }
 
    // ns stores the result
    // which is next state
    int ns, i;
 
    // ns finally contains the longest
    // prefix which is also suffix in
    // "pat[0..state-1]c"
 
    // Start from the largest possible 
    // value and stop when you find a
    // prefix which is also suffix
    for (ns = state; ns > 0; ns--)
    {
        if (pat[ns - 1] == (char)x)
        {
            for (i = 0; i < ns - 1; i++)
            {
                if (pat[i] != pat[state - ns + 1 + i])
                {
                    break;
                }
            }
                if (i == ns - 1)
                {
                    return ns;
                }
        }
    }
 
        return 0;
}
 
/* This function builds the TF table which
represents Finite Automata for a given pattern */
public static void computeTF(char[] pat,
                             int M, int[][] TF)
{
    int state, x;
    for (state = 0; state <= M; ++state)
    {
        for (x = 0; x < NO_OF_CHARS; ++x)
        {
            TF[state][x] = getNextState(pat, M,
                                        state, x);
        }
    }
}
 
/* Prints all occurrences of
   pat in txt */
public static void search(char[] pat,
                          char[] txt)
{
    int M = pat.Length;
    int N = txt.Length;
 
 
    int[][] TF = RectangularArrays.ReturnRectangularIntArray(M + 1,
                                                      NO_OF_CHARS);
 
    computeTF(pat, M, TF);
 
    // Process txt over FA.
    int i, state = 0;
    for (i = 0; i < N; i++)
    {
        state = TF[state][txt[i]];
        if (state == M)
        {
            Console.WriteLine("Pattern found " +
                              "at index " + (i - M + 1));
        }
    }
}
 
public static class RectangularArrays
{
public static int[][] ReturnRectangularIntArray(int size1,
                                                int size2)
{
    int[][] newArray = new int[size1][];
    for (int array1 = 0; array1 < size1; array1++)
    {
        newArray[array1] = new int[size2];
    }
 
    return newArray;
}
}
 
 
// Driver code
public static void Main(string[] args)
{
    char[] pat = "AABAACAADAABAAABAA".ToCharArray();
    char[] txt = "AABA".ToCharArray();
    search(txt,pat);
}
}
 
// This code is contributed by Shrikant13

Javascript

<script>
// Javascript program for Finite Automata Pattern
// searching Algorithm
 
let NO_OF_CHARS = 256;
 
function getNextState(pat,M,state,x)
{   
    // If the character c is same as next
        // character in pattern,then simply
        // increment state
        if(state < M && x == pat[state].charCodeAt(0))
            return state + 1;
               
        // ns stores the result which is next state
        let ns, i;
   
        // ns finally contains the longest prefix
        // which is also suffix in "pat[0..state-1]c"
   
        // Start from the largest possible value
        // and stop when you find a prefix which
        // is also suffix
        for (ns = state; ns > 0; ns--)
        {
            if (pat[ns-1].charCodeAt(0) == x)
            {
                for (i = 0; i < ns-1; i++)
                    if (pat[i] != pat[state-ns+1+i])
                        break;
                    if (i == ns-1)
                        return ns;
            }
        }
   
            return 0;
}
 
/* This function builds the TF table which
    represents Finite Automata for a given pattern */
function computeTF(pat,M,TF)
{
    let state, x;
        for (state = 0; state <= M; ++state)
            for (x = 0; x < NO_OF_CHARS; ++x)
                TF[state][x] = getNextState(pat, M, state, x);   
}
 
/* Prints all occurrences of pat in txt */
function search(pat,txt)
{
    let M = pat.length;
        let N = txt.length;
   
        let TF = new Array(M+1);
        for(let i=0;i<M+1;i++)
        {
            TF[i]=new Array(NO_OF_CHARS);
            for(let j=0;j<NO_OF_CHARS;j++)
                TF[i][j]=0;
        }
   
        computeTF(pat, M, TF);
   
        // Process txt over FA.
        let i, state = 0;
        for (i = 0; i < N; i++)
        {
            state = TF[state][txt[i].charCodeAt(0)];
            if (state == M)
                document.write("Pattern found " + "at index " + (i-M+1)+"<br>");
        }
}
 
// Driver code
let pat = "AABAACAADAABAAABAA".split("");
let txt = "AABA".split("");
 
search(txt,pat);
 
 
// This code is contributed by avanitrachhadiya2155
</script>

Producción: 
 

  Pattern found at index 0
  Pattern found at index 9
  Pattern found at index 13

Complejidad del Tiempo: O(m 2 )

Espacio Auxiliar: O(m)

Referencias:  
Introducción a los algoritmos por Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *