Revisdo 08Nov12 A busc de pdrões dentro de um conjunto de informções tem um grnde plicção em computção. São muits s vrições deste problem, desde procurr determinds plvrs ou sentençs em um texto té procurr um determindo objeto dentro de um sequênci de bits que representm um imgem. Todos eles se resumem procurr cert sequênci de bits ou bytes dentro de um sequênci mior de bits ou bytes. Vmos considerr versão de procurr um sequênci de bytes dentro de outr sequenci, ou ind, procurr um plvr dentro de um texto. Plvr deve ser entendid como um sequênci qulquer de crcteres. Assim, formulção do problem fic: Dd um sequênci de m>0 bytes ([1],..., [m] ou [1..m]) verificr qunts vezes el ocorre em um sequênci b de n elementos (b[1],..., b[n] ou b[1..n]). O lgoritmo trdicionl Nos lgoritmos bixo vmos considerr os índices começndo do 1 e não do 0. Os elementos [0] e b[0] serão ignordos. A solução mis trivil deste problem consiste então em comprr: [1] com b[1]; [2] com b[2];... [m] com b[m] [1] com b[2]; [2] com b[3];... [m] com b[m+1]... [1] com b[n-m+1]; [2] com b[n-m+2];... [m] com b[n] b 1 2 3 4 5 6 7 8 9 n-1 n............
Revisdo 08Nov12 N primeir comprção em que [i] diferente de b[j], pss-se pr o próximo psso. Exemplos: b - O linhmento do pensmento provoc csmento mento Ocorre 3 vezes n Ocorre 5 vezes cs Ocorre 1 vez ovo Ocorre 1 vez prov Ocorre 0 vezes b bbbb bb Ocorre 3 vezes bb Ocorre 3 vezes bbb Ocorre 2 vezes Abixo est primeir solução: int cspdro1(chr [], int m, chr b[], int n) { int i, j, k, cont=0; if (m<=0) return 0; for (k=1; k<=n-m+1; k++) { for (j=k, i=1; i<=m; j++, i++) if ([i]!= b[j]) brek; if (i>m) cont++; return cont; N solução cim, i e j cminhm d esquerd pr direit. Tmbém se desloc d esquerd pr direit cd nov tenttiv. b j i Podemos ter lgums vrições, tods equivlentes: Procurndo em b d direit pr esquerd:
Revisdo 08Nov12 b j i int cspdro2(chr [], int m, chr b[], int n) { int i, j, k, cont=0; if (m<=0) return 0; for (k=m; k<=n; k++) { for (j=k, i=m; i>0; j--, i--) if ([i]!= b[j]) brek; if (i==0) cont++; return cont; Vrrendo b d direit pr esquerd e procurndo em b d direit pr esquerd: b j i int cspdro3(chr [], int m, chr b[], int n) { int i, j, k, cont=0; if (m<=0) return 0; for (k=n; k>=m; k--) { for (j=k, i=m; i>0; j--, i--) if ([i]!= b[j]) brek; if (i==0) cont++; return cont; Exercícios: 1) Adpte o lgoritmo cim, vrrendo b d direit pr esquerd e procurndo em b d esquerd pr direit. 2) Qunts comprções são feits no mínimo e no máximo? Encontre sequêncis e b onde o mínimo e o máximo ocorrem. 3) Por que complexidde dos lgoritmos cim é O(n 2 )?
Revisdo 08Nov12 4) Explique porque s versões cim são tods equivlentes. 5) Adpte os lgoritmos cim, devolvendo o índice inicil em b d primeir ocorrênci de ou -1 se não encontrr. Algoritmo de Boyer-Moore versão 1 [1977] Esse lgoritmo tent fzer menos comprções usndo um crcterístic do pdrão ser procurdo. Qundo se compr [1..m] com b[i..k] (k=i+m-1 pr i=1,..., n-m+1), isto é, qundo se compr com um segmento qulquer dentro de b, próxim comprção não precis ser com b[i+1..k+1]. Pode ser com b[i+d..k+d] onde d é clculdo de form que b[k+1] coincid com últim ocorrênci de b[k+1] em. Assim, podemos deslocr comprção com o próximo segmento em mis de um elemento. Não import o resultdo d comprção nterior. Exemplo: Procurr bcd em bccbbcdcdbd Vej como podemos fzer busc vnçndo no modo proposto: b c c b b c d c d b d b c d b c d b c d b c d Outro exemplo Procurr b: b c c b b c d c d b d b b b b b b O problem então consiste em sber qul últim ocorrênci de b[k+1] em. Se soubermos todos os vlores possíveis de b[k+1], podemos clculr este vlor pr cd elemento de. Aqui está prticulridde do lgoritmo: é necessário conhecer o lfbeto. Como estmos lidndo com crcteres, o lfbeto são todos os crcteres de 0 255. Podemos então previmente clculr qul últim ocorrênci de cd um dos crcteres de.
Revisdo 08Nov12 Exemplo Qul últim ocorrênci de cd crctere n sequênci bixo e qul o deslocmento necessário? 1 2 3 4 5 6 7 8 9 b c b e c d Crctere Últim Ocorrênci Deslocmento 7 3 b 5 5 c 8 2 d 9 1 e 6 4 Todos os demis 0 10 Observe que: Deslocmento = Tmnho - Últim Ocorrênci + 1 Embor o objetivo sej encontrr o último [i] que coincid com b[k+1], o lgoritmo só depende de. No entnto, é necessário conhecer-se o lfbeto de. Vej bixo o lgoritmo. int boyermoore1(unsigned chr [], int m, unsigned chr b[], int n) { int ult[256]; int i, j, k, cont=0; if (m <= 0) return 0; /* verific últim ocorrênci de cd letr em */ for (i = 0; i < 256; i++) ult[i] = 0; for (i = 1; i <= m; i++) ult[[i]] = i; /* procur em b d direit pr esquerd */ for (k = m; k <= n; k = k + m - ult[b[k+1]] + 1) { for (j = k, i = m; i > 0; j--, i--) if ([i]!= b[j]) brek; if (i==0) cont++; /* pode ser que já tenh chegdo o fim de b e neste cso */ /* não dá pr usr [b[k+1]] como índice de ult[] */ if (k+1 > n) brek; return cont; Este lgoritmo é O(n.m). A fse de pré-processmento é O(m+K), onde K depende do lfbeto.
Revisdo 08Nov12 A fse de busc é O(n.m). Entretnto, no cso gerl se comport melhor que o lgoritmo trdicionl. Exercícios: 1) Porque declrção de e b tem que ser unsigned chr e não chr simplesmente? 2) Usndo mesm idei do lgoritmo cim, é possível vnçr comprção mis do que b[k+1]? E menos? 3) Adpte o lgoritmo cim pr fzer busc de em b d direit pr esquerd, isto é, comprndo com b[n-m+1..n], b[n-m-2..n-1],..., b[1..m]. 4) No lgoritmo cim é necessário conhecer o lfbeto, ou os vlores possíveis de b[k+1]. Se e b fossem do tipo int, como ficri o lgoritmo? 5) Qundo b[k+1] não coincide com nenhum de [1..m] já vimo que o deslocmento será de m+1. Um pequen vrição é procurr primeiro b[p] (p>k+1) tl que b[p]=[1]. Ou sej, vmos umentr o deslocmento. Algoritmo de Boyer-Moore versão 2 A versão 2 do lgoritmo é intuitiv, ms tem um implementção mis engenhos. Não é necessário conhecer-se o lfbeto de. Tmbém só depende de. Neste lgoritmo é necessário que comprção de com b, sej feit d direit pr esquerd: Pr i=m, m+1,..., n Comprr [m] com b[i]; [m-1] com b[i-1];...; [1] com b[i-m+1] A idei básic é seguinte: Suponh que num ds comprções já descobrimos que [h..m] é igul b[k-m+h..k], ou sej, descobrimos que existe um trecho (prcil ou totl) no meio de b que é igul um trecho corresponde dente de. Só hverá csmento se tiver um trecho igul em [1..m-1]. Se não houver tl trecho em, podemos deslocr de m elementos. Exemplos: : B A B b: A B A B C B A B C A B A B C B A B C B A B B A B
Revisdo 08Nov12 B A B B A B : b: B C A B A B C C A B A D D B C A B A B C C A B A D D B A B A B Portnto é necessário loclizr últim ocorrênci de [h..m] em [1..m-1]. Vmos chmr ess ocorrênci de lcnce[h] e vmos defini-l como o último índice onde houve coincidênci. Assim, se [h..m] = [p..q] (h,p >=1 e q<=m-1) e [p..q] é últim ocorrênci de [h..m] em [1..m-1], então lcnce[h] = q. Um cso prticulr ocorre qundo o início de coincide com o finl. Neste cso temos que considerr como se houvesse o csmento no restnte d cdei. Vej exemplos: h 1 2 3 4 5 C B A B A lcnce 0 0 0 3 3 h 1 2 3 4 5 lcnce 3 3 3 3 3 h 1 2 3 4 5 6 7 8 9 A B C A B B C A B lcnce 2 2 2 2 2 5 5 5 6
Revisdo 08Nov12 Vej bixo outros exemplos de deslocmento: b x x x x x x x x x x x x x x b b deslocmento b b b x x x x x x x b x x x x x x b b deslocmento b b b x x x x x x b x x x x x x b b deslocmento b b b x x x x x b b x x x x x x b b deslocmento b b b x x x x x x x x x x x x x x b deslocmento b b x x x x x x c x x x x x x x x b c deslocmento b c b x x x x x x x x x x x x x x deslocmento b x x x x x x b x x x x x x x deslocmento b x x x x x x x x x x x x x x deslocmento
Revisdo 08Nov12 b x x x x x x x x x x x x x deslocmento b x x x x x x x x x x x x deslocmento b x x x x x x x x x x x deslocmento D mesm form que o lgoritmo nterior temos que fzer um pré-processmento em pr determinr o lcnce[h]. Determindo lcnce[h], ele será usdo como deslocmento pr próxim tenttiv de fzer-se o csmento. A determinção de h é seguinte: for (h = m; h >= 1; h--) { mm = m-1; ii = mm; i = m; while (ii >= 1 && I >= h) if ([ii] == [i]) { --ii; --i; /* continu comprndo */ else { --mm; /* reduz o cndidto lcnce[h] */ ii = mm; i = m; /* reinici comprção */ lcnce[h] = mm; O lgoritmo completo com um versão mis otimizd d determinção de lcnce[h] está bixo: #define MAXm 100 /* mior vlor de m */ int boyermoore2(unsigned chr [], int m, unsigned chr b[], int n) { int lcnce[maxm]; int i, j, k, h, mm, ii, cont=0, d=0; if (m <= 0) return 0;
Revisdo 08Nov12 /* pré-processmento de - versão mis otimizd */ h = mm = m; do { ii = --mm; i = m; while (ii >= 1 && [ii] == [i]){ ii--; i--; while (h > i) lcnce[h--] = mm; while (ii >= 1); while (h >= 1) lcnce[h--] = mm; /* procur em b */ k = m; while (k <= n) { for (i = m, j = k; i >= 1; i--, j--) if ([i]!= b[j]) brek; if (i < 1) ++cont; if (i == m) k++; /* desloc pens 1 */ /* o último que coincidiu foi [i] */ else k = k + m - lcnce[i+1]; return cont; Este lgoritmo tmbém é O(n.m). Neste cso, tnto fse de pré-processmento qunto fse de busc são O(n.m). D mesm form que versão 1, no cso gerl se comport melhor que o lgoritmo trdicionl. Esse lgoritmo se comport melhor qundo há muit repetição de trechos em, o que pode ocorrer com mior frequênci se m é grnde. Entretnto qundo não há coincidênci o deslocmento é de pens 1 enqunto que n versão 1 o deslocmento é em gerl mior. Versão 1 versus Versão 2 Finlmente, reforçmos que n versão 1 é necessário conhecer o lfbeto enqunto que n versão 2 não é necessário. Ambs s versões só dependem de. Exercício versão híbrid Qundo o lfbeto é conhecido, é possível usr s dus versões o mesmo tempo. A cd repetição do lgoritmo, clcul-se o deslocmento referente cd versão e us-se o mior deles. Fic como exercício.
Revisdo 08Nov12 Outr versão (um pequen vrição) Um pequen vrição ds versões 1 e 2. Deslocndo-se pr o próximo crctere de diferente dquele que não houve coincidênci. Exemplo: b b c b b b b b Pr isso é necessário construir-se um tbel ult_dif[i] (i=1,2,..,m) tl que ult_dif[i]=k onde k é o mior índice menor que i e [k] é diferente de [i]. Exemplo: 1 2 3 4 5 6 7 b b c i ult_dif 7 5 6 5 5 3 4 3 3 2 2 2 1 1 Há 2 csos prticulres: 1) Qundo não há diferentes à esquerd. Neste cso o deslocmento deve ser igul o índice do elemento. 2) Qundo coincide totlmente. Neste cso o deslocmento deve ser 1 Outros lgoritmos Existem outros lgoritmos de complexidde mis bix que os nteriores. O mis conhecido é o lgoritmo de Knuth-Morris-Prtt [KNUTH D.E., MORRIS (Jr) J.H., PRATT V.R., 1977, Fst pttern mtching in strings, SIAM Journl on Computing 6(1):323-350].
Revisdo 08Nov12 Su complexidde é O(m) n fse de pré-processmento e de O(m+n) n fse de busc. Portnto um lgoritmo liner. Outrs referêncis pr este ssunto: No site http://www-igm.univ-mlv.fr/~lecroq/string/index.html há informções sobre vários lgoritmos de busc de plvrs em texto e tmbém um simulção do seu funcionmento.