Вы находитесь на странице: 1из 7

Descripcin del algoritmo KMP

El algoritmo KMP, trata de localizar la posicin de comienzo de una cadena, dentro de otra. Antes que nada con la cadena a localizar se precalcula una tabla de saltos (conocida como tabla de fallos) que despus al examinar entre si las cadenas se utiliza para hacer saltos cuando se localiza un fallo. Supongamos una tabla ya precalculada, y supongamos que la cadena a buscar est contenida en el array 'W()', y la cadena donde buscamos est contenida en un array 'S()'. Entonces ambas cadenas comienzan a compararse usando un puntero de avance para la cadena a buscar, si ocurre un fallo en vez de volver a la posicin siguiente a la primera coincidencia, se salta hacia donde sobre la tabla, indica el puntero actual de avance de la localizado en la tabla. El array 'S' utiliza un puntero de avance absoluto que considera donde se compara el primer carcter de ambas cadenas, y utiliza como un puntero relativo (sumado al absoluto) el que utiliza para su recorrido el array 'W'. Se dan 2 situaciones: Mientras existan coincidencias el puntero de avance de 'W', se va incrementando y si alcanza el final se devuelve la posicin actual del puntero del array 'S' Si se da un fallo, el puntero de avance de 'S' se actualiza sumndole el actual el puntero actual de 'W' menos el valor de la tabla 'T' apuntado por el mismo que 'W'. A continuacin se actualiza el puntero de 'W', bajo una de 2 circunstancias; Si el valor de T es mayor que -1 el puntero de 'W', toma el valor que indica la tabla de salto T: i=T(i), en caso contrario vuelve a recomenzar su valor en 0 (i=0). Se aconseja seguir el ejemplo al final del artculo, paso a paso para acabar de entender su funcionamiento.

Pseudocdigo del algoritmo


En el pseudocdigo no se incluye la verificacin de las cadenas vacas. Algoritmo BsquedaKMP: Entrada: un array de caracteres, S (el texto donde se busca) un array de caracteres, W (la palabra que se busca) Salida: un entero que expresa la posicin en S en la cual se encontr W. (nota: opcionalmente puede convenir devolver un entero con signo). Definicin de variables: un entero, m 0 (puntero de examen en S) un entero, i 0 (la posicin del caracter actual en W, y avance relativo respecto de m, para S) un array de enteros, T (la tabla, calculada a continuacin, o en otra parte) Si (tamao de S) >= (tamao de W) precalcular TablaKMP(W,T) mientras m <= ((longitud de S) - (longitud de W)) , hacer si W[i] = S[m + i] si i = (longitud de W) - 1 devolver m asignar m m + i - T[i] si i es mayor que 0 asignar i T[i] fin si sino asignar i i + 1 fin si sino asignar m m + i - T[i] si i es mayor que 0 asignar i T[i] fin si fin si repetir Fin si (si se alcanza este punto, se busc en todas las S sin xito) devolver longitud de S, si se usa una variable con signo, devolver -1

Descripcin de la tabla adicional (conocida como 'funcin de fallo')


El objetivo de la tabla (precalculada) es no permitir que cada carcter de S() sea examinado ms de 1 vez. El mtodo clave para lograr esto, consiste en haber comprobado algn trozo de la cadena donde se busca con algn trozo de la cadena que se busca, lo que nos proporciona en qu sitios potenciales puede existir una nueva coincidencia, sobre el sector analizado que indica fallo. Dicho de otro modo, partiendo del texto a buscar, elaboramos una lista con todas las posiciones, de salto atrs que sealen cuanto se retrocede desde la posicin actual del texto a buscar. Por ejemplo si el texto a

buscar es 'esconderse' y estamos examinando un texto como 'se esconden tras la mesa', cuando llegamos a la 2 'n' de 'esconden' (posicin 7 en el texto a buscar es una 'r'), falla, la pregunta lgica sera dnde se encuentra de nuevo (si existe) la primera letra en el texto 'esconderse'(antes del fallo), y hasta donde logra repetirse ?. La respuesta a esta pregunta ser el punto de salto, en el caso propuesto ('esconderse'). Dicho punto se encuentra en la posicin 6 (antes de la 'r'), luego para la tabla en la siguiente posicin debera de haber un 1. Por tanto esta tabla se confecciona con la distancia que existe desde un punto en la palabra a la ltima ocurrencia (de la 0 letra de la palabra) distinta de la primera vez que aparece, y mientras sigan coincidiendo, se marca la distancia, cuando haya una ruptura de coincidencia se marca 0 o un valor previo ya calculado anteriormente, y as sucesivamente hasta terminar con el texto. La tabla tiene sus 2 primeros valores fijados, de modo que la funcin de fallo empieza siempre examinando el 3 carcter del texto. La razn por la que dichos valores estn fijados es obvia: si para el 2 carcter se marcara 1, nunca se lograra un salto, pues siempre retornara a dicho punto. en cuanto al primero, por necesidad se marca -1, pues de ese modo le es imposible regresar ms atrs, sino siempre adelante,

Ejemplos de texto y su tabla de fallo


Primero un sencillo ejemplo donde slo hay una ocurrencia.
'01234567 'TANGENTE' -10000001'

La ltima e tiene a una distancia de 1 la ltima aparicin de T.

Ahora un ejemplo ms interesante


'0123456789012 'MAREMAGNUM EL' -1000012000100 Hay 2 ocurrencias consecutivas con 'MA' y ms adelante otra con 'M'

Y terminamos con un ejemplo de 2 coincidencias de 3 letras consecutivas.


'01234567890123456789012345 'PARTICIPARIA EN PARACAIDAS' -10000000123000000123000000 La P es la 0 letra, luego en la posicin 7 vuelve a aparecer, por tanto la 8, marca un 1, luego coinciden las 2 siguientes, luego se marcan su distancia, luego vuelve a fallar... las mismas ocurrencias vuelven a aparecer por 3 vez. 'PAR'

Pseudocdigo de la tabla (funcin de fallo)


Algoritmo TablaKMP: Entrada: un array de caracteres, W (el texto que va a ser analizada) un array de enteros, T (la tabla que ser rellenada) debe tener el mismo tamao que W Salida: nada, no devuelve valores( pero por referencia, devuelve la tabla rellenada) variables que se usan: un entero, pos 2 (la posicin actual donde se est calculando T) un entero, cnd 0 (el ndice en W del siguiente carcter del actual candidato en la subcadena)

(algunos valores se fijan con determinado valor, y por tanto no estn sujetos a lo que cabra esperar del algoritmo) asignar T[0] -1, T[1] 0 Hacer mientras pos sea menor o igual que el (tamao de W)-1: (primer caso: siguiente candidato coincidente en la cadena) Si W[pos - 1] = W[cnd] Asignar cnd cnd + 1, T[pos] cnd, pos pos + 1 (segundo caso: cuando empieza a fallar las coincidencias consecutivas, entonces asignamos un valor ya conocido la 1 vez) Sino si cnd > 0 Asignar cnd T[cnd] Fin si (tercer caso: no se hall candidatos coincidentes (otra vez)) Asignar T[pos] 0, pos pos + 1 Fin si Repetir

Eficiencia del algoritmo


Debido a que el algoritmo precisa de 2 partes donde se analiza una cadena en cada parte, la complejidad resultante es O(k) y O(n), cuya suma resulta ser O(n + k). La capacidad del algoritmo queda patente al apreciar como logra saltar varios caracteres a la vez cuando hay un fallo. Esto se aprecia mejor, mirando la tabla T, cuantos ms ceros existan tanto ms grande es el salto resultante. De modo que puede deducirse caso peores y ptimos. Los casos ptimos se denotan porque son todos ceros, o lo que es lo mismo, no se repiten caracteres desde el principio. Ejemplo W ="ABCDEFG". El peor caso se da cuando la cadena se compone de 1 nico carcter, por ejemplo: W= "AAAAAAAA", obsrvese la Tabla para dicho texto:

1 2 3 4 5 7

W[i] A

A A A A A A

T[i]

0 1 2 3 4 6

Ejemplo
Una forma de entender correctamente el funcionamiento del algoritmo es seguir paso a paso un ejemplo reseando en cada punto lo que hace o puede hacer el algoritmo en una situacin dada. Se considera tanto en los ejemplos como en el pseudocdigo que los array de caracteres se basan en ndice 0.

Sean 2 cadenas, que se entregan como arrays de caracteres a la funcin, donde S es el array de caracteres donde queremos buscar y W el array que se quiere hallar en S, usando m como puntero absoluto para los caracteres de S e i como puntero para los caracteres de W. Se usa tambin, una tabla (matriz) precalculada de la palabra a buscar T. A continuacin se ve una figura que representan las variables consideradas para el ejemplo.
m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T:-1000012

Se muestra la tabla T, precalculada para el ejemplo.

1 2 3 4 5

W[i] A

B C D A B

T[i]

0 0 0 0 1

m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T:-1000012

Comienza el clculo, los punteros 'm' e 'i' inicialmente valen 0. Si W(i) = S(m + i), se evala a continuacin si i = tamao de W en cuyo caso se habra encontrado la posicin de la cadena. En caso contrario, se incrementa 'i'. Esto sucede 3 veces, hasta que en la 4 ocasin, en W(3) tenemos 'D' y en W(m + i) tenemos ' '(un espacio), momento en que actualizamos 'm', m = m + i - T(i) (m = 3). A continuacin verificamos si T(i) > -1 (t(3) vale 0), como se da el caso hacemos para i = T(i). Es decir saltamos a la posicin sobre el array 'W' que seala 'T(i)', que en este caso es 0, por tanto al principio del array 'W', pero ahora el puntero del array 'S' est en 3 (m = 3). Por tanto en la siguiente figura avanzamos hasta la posicin absoluta de S actual, 3.
m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T: -1000012

Volvemos al principio del bucle (cada vez que se vuelve a este punto se comprueba si m alcanz el tamao de 'S' y de nuevo verificamos si W(i) = S(m + i). Vemos que en el punto actual en 'W' hay un espacio, por lo que, nuevamente se actualiza 'm', m = m + i - T(i) (m = 4), porque 'T(i) = -1'. Ahora entonces se hace i = 0 (aunque antes tambin era 0).

Como volvemos al inicio del bucle (se da por comprobado si el bucle finaliza), actualizamos la figura con el puntero en 'm', (m = 4)
m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T: -1000012

Ahora vemos que varias veces se cumple que W(i) = S(m + i), pero no tantas que se alcance el tamao de 'W', y con cada coincidencia 'i' se ha incrementado, por lo que ahora 'i=6', pero se ha incrementado justo despus de verificar si i = tamao W luego devolver m (si no habramos alcanzado la solucin). Al analizar de nuevo al inicio del bucle la posicin 6, falla ya que 'W(6) = D' y 'S(4 + 6) =' . en este punto toca actualizar 'm', y hacemos m = m + i - T(i) (m = 4 + 6 - T(6), en este punto T(6) vale 2, por lo que finalmente damos un salto 'm = 4 + 6 - 2 = 8'. Y actualizamos 'i', si t(6) > -1 luego i = t(i), es decir no solo alcanzamos el puntero de 'S', sino que adems avanzamos el puntero de 'W' a 2, porque precisamente en la posicin 8, hay una coincidencia 'AB' tal como comienza la cadena del array 'w'. es justo e este punto donde hemos visto el salto y la eficacia de la tabla T. Actualizamos la figura, damos por verificado la comprobacin del inicio del bucle.
m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T: -1000012

Una nueva vez volvemos comprobar si W(i) = S(m + i) (W(2) = S(8+2)), es decir 'C' = ' '), como falla toca actualizar el puntero de 'S'. m = m + i - T(i) (m=8 + 2 - 0 = 10), y actualizamos 'i', (si T(i) > -1 luego i = T(i)) 'i = 0'. Actualizamos a la siguiente figura (como cada vez que se actualiza 'm' el puntero absoluto de 'S').
m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T: -1000012

Con la siguiente comparacin tambin falla ya que 'A' <> ' ', y nuevamente debe actualizarse el puntero 'm', con su salto de tabla (si procede), m = m + i - T(i) (m = 10 + 0 - (-1) = 11), y tambin actualizamos 'i', como esta vez 'T(i)= -1', entonces volvemos al principio de 'W', es decir i = 0. Actualizamos la figura a la nueva posicin que apunta el puntero de 'S', (m = 11)
m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T: -1000012

En esta ocasin de nuevo varias veces se cumplir que W(i) = S(m +i), hasta que se llega a la posicin de 'i = 6, que sucede que 'W(6)=D' que es distinto de 'S(11 + 6)=C', por lo tanto es necesario una nueva bifurcacin hacia la actualizacin de 'm', m = m + 1 - T(i) (m = 11 + 6 - 2 = 15). De nuevo entra en juego el salto de la tabla, puesto que 'T(i) = 2', toca actualizar 'i', si T(i) > -1 luego i = T(i), por tanto 'i = 2. Actualizamos una vez ms la figura, hasta avanzar hasta 'm = 15'.

m: 01234567890123456789012 S: ABC ABCDAB ABCDABCDABDE W: ABCDABD i: 0123456 T: -1000012

Como 'i = 2' (porque conseguimos avanzar hasta el ndice 6 que en la tabla vale 2, porque antes de la 'D' final hay 2 posiciones coincidentes consecutivamente), entonces ahora volvemos a hacer las comprobaciones pero ahora en 15 + 2, que era: Si W(i) = S(m + i) luego... si i = tamao de w luego devolver m. Esta parte se cumple hasta finalmente encontrar por completo la cadena, antes de que 'i' pueda ser aumentado a 7 en la parte que sigue a la condicin anterior i = i + 1 . El algoritmo Knuth-Morris-Pratt realiza 26 comparaciones (y el ltimo carcter de la cadena buscada se halla en la posicin 21) en el ejemplo, hasta encontrar la solucin, en la posicin 15. Es necesario recordar solamente que al estar basado en array en ndice 0, la solucin es 15, aunque por otra parte, en las figuras se como los punteros de 'm' e 'i' empiezan en 0. Obtenido de http://es.wikipedia.org/wiki/Algoritmo_Knuth-Morris-Pratt