Professional Documents
Culture Documents
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.
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,
(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
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
1 2 3 4 5
W[i] A
B C D A B
T[i]
0 0 0 0 1
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'.
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