Concordância de Modelos (Pattern Matching) Problema: Dada uma cadeia de carateres, detectar a occorrência de um modelo. Modelo: cadeia particular de carateres (Padrão). Aplicações: • processamento de texto • manipulação simbólica • tradução automática • ... Pattern Matching: solução trivial Deslocar o modelo ao longo da cadeia, uma posição de cada vez e comparar carater a carater. { C[1..n] ∧ P [1..m] ∧ m ≤ n } i := 0; achou := false; { achou ≡ (P [1..m] ∈ C[1..i]) ∧ i ≤ n } while not achou and (i < n) do begin j := i; i := i+1; k := 0; iguais := true; while iguais and (k < m) do begin k := k+1; j:= j+1; { iguais ≡ (C[i..j − 1] = P [1..k − 1]) } iguais := C[j]=P[k]; { iguais ≡ (C[i..j] = P [1..k]) } end; achou := iguais; end; { achou ≡ (∃i ∈ [1..n] : C[i..i + m − 1] = P [1..m]) } Note-se que: • o contador i não deve ultrapassar n − m + 1 • o contador j depende do valor de i: j = i + k − 1 procedure pattmatch(C, P :cadeiacar; m, n :indice; var achou :boolean; var indprim :indice); var i, k, fim : integer; iguais : boolean; begin achou := false; i := 0; fim := n-m+1 while not achou and (i < fim) do begin i := i+1; k := 0; iguais := false; while iguais and (k < m) do begin iguais := C[i+k]=P[k+1] k := k+1; end; achou := iguais; end ; { achou ≡ (∃i ∈ [1..n − m + 1] : C[i..i + m − 1] = P [1..m]) } if achou then indprim := i else indprim := 0; end; Exercı́cio: • Escrever uma versão para contar o número total de ocorrências do modelo na cadeia. • Fazer a verificação formal do algoritmo. Análise de Complexidade Operação básica: comparação entre carateres. Melhor dos casos: 1. Se m ≤ n2 , então m < n − m + 1, logo, BC (n, m) = m se P [1..m] = C[1..m] 2. Se m > n2 , então BC (n, m) = n − m + 1 se P [1] 6∈ C[1..n] Pior dos casos: para cada i, todos os carateres de p concordam menos o último, WC (n, m) = (n − m + 1) ∗ m Exemplo dum pior dos casos: 1 2 3 ... 4 a a a a a a a b a a a a ... n a a a a a b Casos ineficientes: concordâncias parciais Concordâncias parciais implicam repetições dentro do modelo =⇒ necessário um algoritmo que use conhecimento parcial! ... a b c a b c a b d a b c a b d a b c 1 3 ? 6 a b m ? Após C[i] = P [6] fazer a comparação C[i] = P [3] pois P [1] = P [4] e P [2] = P [5] c Algoritmo de Knuth-Morris-Pratt Precisamos de um registo de repetições P: a b c a b d a b c R: 0 0 0 1 2 0 1 2 3 • inicializar R[1..m] a zero; • inicializar k a 1; • para todo o i ∈ {2, . . . , m} fazer - se P [i] = P [k] - então R[i] ← k incrementar k - senão R[i] ← 0 k←1 { R[j] = l =⇒ P [l] = P [j]) } • Como usar o registo de repetições? C: a b c a b c a b d P: a b c a b d a b c 1 2 3 4 5 6 7 8 9 0 0 0 1 2 0 1 2 3 R: a b c Para voltar ao primeiro carater diferente no padrão anterior fazer k ← R[k − 1] + 1 e comparar ? C[i] = P [k] • Que fazer após uma concordância total? C: a b c a b c P: a b c a b c 1 2 3 4 5 6 0 0 0 1 2 3 R: a b d a b Avançar os contadores i e k; Como k = 7 > m = 6 faz-se k ← R[m] + 1 e ? compara-se C[i = 7] = P [k = 4] c function KMP(C, P :cadeiacar; m, n :indice) :integer; var i, k, numconc : integer; R : array[1..m] of integer; procedure construirR; var i, k : integer; begin for k:=1 to m do R[i] := 0; k := 1; for i:=2 to m do if P[i]=P[k] then begin R[i] := k; k := k+1; end else k := 1; end; begin { Programa principal do KMP } construirR; numconc := 0; i := 1; k := 1; while i < n do begin if C[i]=P[k] then begin i := i+1; k := k+1; if k > m then begin numconc := numconc+1; k :=R[k-1]+1; end end else if k = 1; then i := i+1 else k :=R[k-1]+1; end; end; Análise de Complexidade Pior dos casos: m + 1 + 2 n ⇒ WC (n, m) = O(m + n) Autómatos Finitos Um autómato finito A = (Q, Σ, g, I, F ) é um quintuplo onde: • Q é um conjunto finito de estados; • Σ é um alfabeto finito; • g : Σ × Q −→ Q diz-se relação de transição; • I ⊂ Q é um conjunto de estados iniciais; • F ⊂ Q é um conjunto de estados finais. Exemplo: Autómato reconhecedor da frase aabc Q = {0, 1, 2, 3, 4}; Σ = {a, b, c}; I = {0}; F = {4}; g 0 1 2 3 a 1 2 2 1 b 0 0 3 0 c 0 0 0 4 4