CT-234 Estruturs de Ddos, Análise de Algoritmos e Complexidde Estruturl Crlos Alberto Alonso Snches
CT-234 7) Busc de pdrões Knuth-Morris-Prtt, Boyer-Moore, Krp-Rbin
Pdrões e lfbetos Pdrões (ptterns ou strings) são sequêncis de crcteres. Exemplos: documentos, progrms, págins web, sequêncis de DNA, imgens digitlizds, etc. Um lfbeto Σ é um conjunto de possíveis crcteres pr um fmíli de pdrões. Exemplos: ASCII, Unicode, {A, C, G, T}, {0, 1}. Ddos os pdrões T e P, de tmnhos n e m, o problem d busc de pdrões (pttern mtching), tmbém chmdo de correspondênci de cdeis, consiste em encontrr subsequêncis de T iguis P. Sem perd de generlidde, vmos supor n > m.
Prefixos e sufixos Considerremos um pdrão P de tmnho m como um vetor P[0..m-1] de crcteres. Os prefixos de P são s subsequêncis P i = P[0..i], onde 0 i < m. Os sufixos de P são s subsequêncis S i = P[i..m-1], onde 0 i < m. Sej ε o crctere vzio. Por definição, P -1 = S m = ε. Se w é um pdrão, então εw = wε = w.
Solução por forç brut Há dois problems: encontrr tods s ocorrêncis de P em T ou pens primeir dels. Vmos bordr com detlhe pens esse último problem. O lgoritmo de busc de pdrões trvés d forç brut compr P com T pr cd possível deslocmento: té que primeir ocorrênci do pdrão P sej encontrd em T; ou té que todos os possíveis deslocmentos sejm testdos. No pior cso, (prticmente) todos os crcteres de P serão comprdos com todos os crcteres de T. Portnto, este lgoritmo gst tempo O(n.m).
Algoritmo forç brut BruteForceMtch() { for (i=0; i<=n-m; i++) { j = 0; while (j<m && T[i+j]==P[j]) j++; if (j == m) return i; // P encontrdo em T[i] } return -1; // P não foi encontrdo } Tempo: O((n-m).m) = O(n.m)
Busc trvés de utômto Um método mis eficiente é montr um máquin de estdos, chmd utômto finito. Ideis: A leitur de cd crctere de T provoc um mudnç no estdo desse utômto. Há um único estdo finl, que somente é tingido pós leitur de um subsequênci igul P. O utômto pode ser representdo por um mtriz AF de dus dimensões: considerndo que estej no estdo s e que o próximo crctere é x, AF[s,x] será o próximo estdo. A principl dificuldde não é o uso desse utômto, ms su construção.
Exemplo Σ = {, b, c} P = bbc b 0 1 b 2 3 b 4 5 c 6 7 b As trnsições não representds são retornos pr o estdo 0 T = bbbcb Estdo b c 0 1 0 0 1 1 2 0 2 3 0 0 3 1 4 0 4 5 0 0 5 1 4 6 6 7 0 0 7 1 2 0 Busc de P em T: i - 0 1 2 3 4 5 6 7 8 9 10 T[i] - b b b c b Estdo 0 1 2 3 4 5 4 5 6 7 2 3
Algoritmo Busc de P em T trvés de um utômto: AFMtch() { s = 0; // 0 é o estdo inicil for (i=0; i<n; i++) { s = AF[s,T[i]]; if (s == m) // último estdo foi tingido return i-m; // posição de P em T } return -1; // P não foi encontrdo } Tempo: O(n)
Construção do utômto Qundo o estdo m é tingido, os últimos m crcteres lidos correspondem P. O que crcteriz o estdo s, 0 s m, é que o prefixo P s-1 cbou de ser reconhecido. Fses d construção do utômto: ) Inicilmente, tod mtriz do utômto é zerd. b) As trnsições pr estdos miores correspondem à sequênci definid pelos crcteres de P. c) Ns trnsições pr estdos menores, desej-se voltr pr o mior prefixo que ind sej válido. Se o utômto está no estdo s (ou sej, P s-1 foi reconhecido) e, pós ler o crctere T[i], deve voltr um estdo nterior, então é preciso encontrr o mior estdo k < s tl que P k-1 sej sufixo de P s-1 T[i]. Isso pode ser feito trvés de um busc exustiv em P. P k-1 P k-1 T P i s P s-1
Algoritmo AFConstruct() { for (s=0; s<=m; s++) for x Σ AF[s,x] = 0; // mtriz AF é zerd for (s=0; s<m; s++) AF[s,P[s]] = s+1; // trnsições pr estdos miores for (s=0; s<=m; s++) for x Σ { k = min{s+2, m+1}; // primeiro estdo ser testdo repet k--; // testes em ordem decrescente until (P k-1 sej sufixo de P s-1 x); // tempo Θ(m) AF[s,x] = k; } } Tempo: O(m 3. Σ ) Pode ser melhordo pr Θ(m. Σ )
Knuth-Morris-Prtt (1970-1976) Idei: considerndo o lgoritmo forç brut, qundo ocorre um diferenç entre T[i] e P[j], não seri possível fzer um deslocmento mior de P pr direit, evitndo comprções redundntes? Exemplo: T P b b x i b b j P b b Ests comprções não precism ser refeits Deslocmento mior: recomeçr qui
Função de flh Pré-processmento em P: determin se seus prefixos precem como subsequêncis dele mesmo. A função de flh F(k) será definid como o tmnho do mior prefixo de P[0..k] que é sufixo de P[1..k]. Informlmente, é o tmnho do mior começo de P k que tmbém prece no seu fim, sem considerr ele mesmo. Exemplo: k 0 1 2 3 4 5 P[k] b b F(k) 0 0 1 1 2 3 b b x i b b j Se P[j] T[i], então j receberá o vlor F(j-1). T P P b b F(j-1)
Algoritmo KMP KMPMtch() { FilureFunction(); // Veremos que gst tempo Θ(m) i = 0; j = 0; while (i < n) if (T[i] == P[j]) if (j == m-1) return i-j; else { i++; j++; } else if (j!= 0) j = F[j-1]; else i++; return -1; } j é incrementdo n vezes no máximo Como é um decremento, será executdo té n vezes Tempo do lço while: O(n)
Exemplo b c b c c b c b b b 1 2 3 4 5 6 b c b 7 b c b j 0 1 2 3 4 5 P[j] b c b F(j) 0 0 1 0 1 2 8 9 10 11 12 b c b 13 b c b 14 15 16 17 18 19 b c b
Exemplo: cálculo d função de flh j 0 1 2 3 4 5 6 7 8 9 10 P[j] b b b b b F[j] 0 0 1 2 0 1 2 3 4 3 1 b b b b b b b b b b b b b b b b b b b b b Uso recursivo de F
Cálculo d função de flh Subsequêncis de P são procurds dentro dele mesmo: FilureFunction() { F[0] = 0; j = 0; // índice que percorre os prefixos i = 1; // índice que percorre os sufixos while (i < m) if (P[i] == P[j]) // já combinrm j+1 crcteres F[i++] = ++j; else if (j == 0) F[i++] = 0; else j = F[j-1]; // uso recursivo de F } j é incrementdo m-1 vezes no máximo Como é um decremento, será executdo té m-1 vezes Tempo: Θ(m)
Boyer-Moore (1976) Ideis do lgoritmo de Boyer-Moore: Bsei-se n lt probbilidde de encontrr diferençs em lfbetos grndes. Por isso, P é comprdo com T de trás pr frente. Qundo se encontr um diferenç em T[i], o pdrão P drá um slto à frente, considerndo-se s comprções já relizds. T x P i b = T[i] P[j] j Será preciso verigur 3 csos diferentes.
Cso 1 P não contém x T P d c x i b j T x P d c b i novo j novo Deslocr P pr direit, linhndo P[0] com T[i+1]
Cso 2 A últim ocorrênci de x em P está lgum índice menor do que j. T P x c x i b j T P x x c b i novo j novo Deslocr P pr direit, té que últim ocorrênci de x fique linhd com T[i].
Cso 3 A últim ocorrênci de x em P está em lgum índice mior do que j. T P x i b j x x T P x b x i novo x j novo Deslocr P pens um posição pr direit.
Exemplo p t t e r n m t c h i n g l g o r i t h m r i t h m r i t h m r i t h m r i t h m r i t h m r i t h m r i t h m
Outro exemplo b c b d c b c b b b 1 b c b 4 3 2 b c b 5 b c b 6 b c b 7 b c b 13 12 11 10 9 8 b c b
Função de últim ocorrênci Atrvés de um pré-processmento, o lgoritmo de Boyer-Moore clcul um função L: Σ I, onde L(x) é definid como: o mior índice i tl que P[i] = x; -1, cso este índice não exist. Exemplo: Σ = {, b, c, d} P b c b 0 1 2 3 4 5 x L(x) 4 b 5 c 3 d -1
Algoritmo BM BoyerMooreMtch() { for (k=0; k< Σ ; k++) L[k] = -1; for (k=0; k<m; k++) L[P[k]] = k; i = m-1; j = m-1; repet if (T[i] == P[j]) if (j == 0) return i; else { i--; j--; } else { x = L[T[i]]; i += m - min{j, 1+x}; j = m-1; } until (i > n-1); return -1; } Cso 1: i += m; pois x = -1 Cso 2 Cso 3
Análise de tempo Exemplo de pior cso: 6 5 4 3 2 1 b 12 11 b 18 10 17 9 16 8 15 7 14 13 b 24 23 22 21 20 19 b Tempo: Θ(n.m + Σ ) Os piores csos costumm ocorrer qundo o lfbeto é pequeno (DNA, imgens digitis, etc.), ms são pouco comuns em documentos. No entnto, qundo o lfbeto é grnde, o melhor cso é Ω(n/m)...
Krp-Rbin (1980) Se Σ = {0, 1} e m 8, busc de P em T poderi ser relizd trvés de comprções entre bytes, que é muito rápid. Se Σ = {0, 1, 2,..., 9}, P seri um número de m dígitos. Poderímos então plicr ess mesm idei, comprndo números inteiros? Se P eventulmente não couber em um vriável inteir, poderímos clculr lgum função de dispersão (hshing) pr cd subsequênci de T com tmnho m e comprá-l com o correspondente vlor dest função pr P: Se forem iguis, um lgoritmo de forç brut verificri se o pdrão foi mesmo encontrdo. Se forem diferentes, o lgoritmo continurá busc, clculndo mesm função pr próxim sequênci de m dígitos em T.
Vlor em P Σ = {0, 1, 2,..., 9} p: vlor do número representdo pelos m dígitos de P Atrvés d Fórmul de Horner, p pode ser clculdo em tempo Θ(m): p = (...(P[0].10 + P[1]).10 +... + P[m-3]).10 + P[m-2]).10 + P[m-1] Bst um comndo for com multiplicções e dições. Exemplo: P = 1569, m = 4 p = ((1.10 + 5)10 + 6)10 + 9 3 multiplicções e 3 dições
Vlores em T t s : vlor do número representdo pel subsequênci T[s..s+m-1], 0 s < n-m. T[s] t s+1 Exemplo: T = 64152, m = 4, s = 0, t s = 6415, T[s+m] = 2 t s+1 = 10(6415 1000.6) + 2 = 4152 t s T[s+m] t s+1 pode ser clculdo prtir de t s em tempo Θ(1): t s+1 = 10(t s 10 m-1 T[s]) + T[s+m] A subtrção de 10 m-1 T[s] remove o dígito de mis lt ordem T[s+m] será o novo dígito de mis bix ordem
Complexidde dos cálculos p e t 0 podem ser clculdos em tempo Θ(m). t s+1 pode ser clculdo prtir de t s em tempo Θ(1). t 1,..., t n-m podem ser clculdos tempo Θ(n-m). Portnto, tods s ocorrêncis de P em T podem ser encontrds em tempo Θ(n). No entnto, pr que s comprções entre p e cd t s sejm feits em tempo constnte, esses números devem estr limitdos o vlor máximo de um inteiro suportdo pelo sistem (depende d quntidde de bytes utilizdos). Como vimos, esse eventul problem pode ser resolvido com o uso de um função de dispersão (hshing).
Um solução Função de dispersão : todos os vlores (p, t 0, t 1,..., t n-m ) serão clculdos em módulo q, onde q é um número primo. Definindo d = Σ, q costum ser escolhido de tl modo que o vlor d.q poss ser rmzendo em um número inteiro. Os cálculos pssm ser: t s+1 = (d(t s T[s].h) + T[s+m]) mod q, onde h = d m-1 mod q. Evidentemente, t s p mod q não signific necessrimente que P = T[s..s+m]. Heurístic: Se t s p mod q, verificr por forç brut se P = T[s..s+m]. Cso contrário, continur busc.
Exemplo t s+1 = (d(t s T[s].h) + T[s+m]) mod q, onde h = d m-1 mod q. Sejm: d=10, T= 31526, n=5, P= 26, m=2, q=11. p = 26 mod 11 = 4 h = 10 1 mod 11 = 10 t 0 = 31 mod 11 = 9 t 1 = (10(9-3.10) + 5) mod 11 = -205 mod 11 = 4 Conferindo: t 1 = 15 mod 11 = 4 t 1 p mod 11, ms T[1..2] = 15 e P = 26 : P não foi encontrdo... t 2 = (10(4-1.10) + 2) mod 11 = -58 mod 11 = 8 Conferindo: t 2 = 52 mod 11 = 8 t 3 = (10(8-5.10) + 6) mod 11 = -414 mod 11 = 4 t 3 p mod 11, e P relmente é encontrdo em T
Algoritmo KR KrpRbinMtch() { d = Σ ; q = um primo mior que m; h = d m-1 mod q; p = 0; t 0 = 0; for (i=0; i<m; i++) { // cálculo de p e de t 0 p = (d.p + P[i]) mod q; t 0 = (d.t 0 + T[i]) mod q; } } for (s=0; s<=n-m; s++) { // cálculo de t 1,..., t n-m if (p == t s ) // fzer comprção forç brut if (P[1..m] == T[s..s+m]) return s; if (s < n-m) t s+1 = (d.(t s T[s].h)+T[s+m]) mod q; } return -1;
Comentários Os cálculos de p e t 0 gstm tempo Θ(m). Os cálculos de t 1,..., t n-m, mis eventul comprção por forç brut, gstm tempo O((n-m).m). Portnto, o tempo totl do lgoritmo de Rbin-Krp é O(n.m). N prátic, este lgoritmo tem bom desempenho. Importnte: ele é válido pr qulquer lfbeto! Bst interpretr cd crctere como um dígito...
Comprções Algoritmos Pré-processmento Tempo de busc Forç brut - O(n.m), Ω(n) Autômto finito Θ(m. Σ ) Θ(n) KMP Θ(m) Θ(n) Boyer-Moore Θ(m + Σ ) O(n.m), Ω(n/m) Krp-Rbin - O(n.m), Ω(n) A tbel cim present s complexiddes de tempo n busc de tods s ocorrêncis do pdrão. Teoricmente, KMP é o melhor. N prátic, Boyer-Moore é o mis usdo. Além disso, possui lgums vrições n litertur.