strings (casamento de padrões) - ufjf.br · • uma cadeia é uma seqüência linear de ... •...
TRANSCRIPT
Strings(Casamento de padrões)
Estrutura de Dados IIJairo Francisco de Souza
2
Strings
• Tipo de dado importante para diversas aplicações.
• Abordaremos algumas questões relacionadas com Strings nos seguintes tópicos– Busca em Strings (String matching)– Codificação– Compressão
3
Busca em Cadeias de Caracteres
• Dados a ser processados nem sempre se decompõem logicamente em registros independentes com pequenas partes identificáveis
• Este tipo de dados é caracterizado apenas pelo fato de que pode ser escrito como uma cadeia
• Uma cadeia é uma seqüência linear de caracteres, tipicamente podendo ser muito longa
4
Busca em Cadeias de Caracteres
• Cadeias são centrais em sistemas de processamento de textos, recuperação de informação, estudo de sequências de DNA em biologia computacional, etc.
• Esses objetos podem ser bem grandes e algoritmos eficientes são necessários para manipulá-los
• T = “ABACAABACCABACABAABB”• P = “ABACAB”• “P” é uma substring de “T”, mais exatamente,
P = T[10...15].
5
Busca em Cadeias de Caracteres
• Outro tipo de cadeia é a cadeia binária• Cadeia binária é uma seqüência de apenas valores 0
e 1• Em certo sentido, isso é simplesmente um caso
especial de cadeia de caracteres• Mas vale a pena fazer distinção, porque algoritmos
diferentes são apropriados para cada caso• Além disso, cadeias binárias aparecem naturalmente
em muitas aplicações
– Por exemplo, alguns sistemas gráficos representam figuras como cadeias binárias
6
Busca em Cadeias de Caracteres
• Veremos que o tamanho do alfabeto a partir do qual os caracteres são tomados para formar uma cadeia é um fator importante no projeto de algoritmos de processamento de cadeias
• Uma operação fundamental sobre cadeias é o casamento de padrão:– Dado uma cadeia de comprimento N e um padrão de
comprimento M, encontrar uma ocorrência do padrão no texto
• Vamos usar o termo texto para referenciar tanto uma seqüência de valores 0 e 1 quanto qualquer outro tipo especial de cadeia
7
Busca em Cadeias de Caracteres
• A maioria dos algoritmos para o problema de casamento de padrão pode ser facilmente estendida para encontrar todas as ocorrências do padrão no texto
• O problema de casamento de padrão pode ser visto também como um problema de busca com o padrão sendo a chave
8
Um Breve Histórico
• O algoritmo mais óbvio de busca em cadeia, chamado algoritmo força-bruta ou algoritmo ingênuo, tem o pior caso de tempo de execução proporcional a MN
• Embora as cadeias que aparecem em muitas aplicações levam a um tempo de execução que é virtualmente proporcional a M + N
9
Um Breve Histórico
• Em 1970, S. A. Cook provou um resultado teórico sobre um tipo particular de autômato que implicava na existência de um algoritmo de casamento de padrão com tempo proporcional a M + N no pior caso
• D. E. Knuth e V. R. Pratt seguindo a construção que Cook usara na demonstração do seu teorema obtiveram um algoritmo relativamente simples e prático
10
Um Breve Histórico
• Ocorreu também que J. H. Morris descobriu praticamente o mesmo algoritmo como solução de um problema de edição de texto
• Os três cientistas, Knuth, Morris e Pratt, não se preocuparam em publicar o algoritmo até 1976
• Nesse meio tempo, R. S. Boyer e J. S. Moore (e, independentemente, R. W. Gosper) descobriram um algoritmo que é muito mais rápido em muitas aplicações
• Muitos editores de texto usam esse algoritmo para busca de cadeias
11
Um Breve Histórico
• Em 1980, M. O. Rabin e R. M. Karp desenvolveram um algoritmo tão simples quanto o de força bruta que roda virtualmente sempre em tempo proporcional a M + N
• Além disso, o algoritmo deles estende-se facilmente a padrões bidimensionais que o torna mais útil que os outros para processamento de figuras
12
Algoritmo Força-Bruta
• O método óbvio para casamento de padrão resume-se em testar, em cada posição do texto onde o padrão pode casar, se ele de fato casa
• O proceedimento forcaBruta a seguir busca dessa maneira a primeira ocorrência do padrão p no texto t
13
Algoritmo Força-Bruta
procedure ForcaBruta ( var T: TipoTexto ; var n : integer ; var P: TipoPadrao; var m : integer ) ;{−− Pesquisa P[ 1 . .m] em T[ 1 . .n] −−}var i , j , k : Integer ;begin for i := 1 to n − m + 1 do begin k := i ; j := 1; while T[ k ] = P[ j ] do begin j := j + 1; k := k + 1; end; if j > m then writeln ( ’Casamento na posicao ’ , i:3 ) ; end;end;
14
Algoritmo Força-Bruta
15
Algoritmo Força-Bruta
• Pior caso– O pior caso ocorre quando, por exemplo, o
padrão e o texto são os dois uma seqüência de zeros seguidos por um 1
– Por exemplo, 00001 e 000000000000000001– Ou seja, quando é preciso percorrer
praticamente todo P várias vezes a cada posição de T, estando P no fim da cadeia
– Complexidade: m*n
16
Algoritmo KMP
• A idéia básica do algoritmo desenvolvido por Knuth, Morris e Pratt é:– quando um descasamento é detectado, o
“falso começo” consiste em caracteres que já conhecemos de antemão (porque eles estão no padrão)
• De alguma forma, podemos levar vantagem desta informação ao invés de retroceder o índice j por todos os caracteres conhecidos
17
Algoritmo KMP
• Foi o primeiro algoritmo cujo pior caso tem complexidade de tempo linear no tamanho do texto: O(n)
• É um dos algoritmos mais famosos para resolver casamento de padrões
• Tem implementação complicada e na prática perde em eficiência para outros algoritmos, como o de Boyer.
18
Algoritmo KMP
• O algoritmo computa o sufixo mais longo no texto que é também o prefixo de P.
• Quando o comprimento do sufixo no texto é igual a |P|, ocorre um casamento.
• O pré-processamento de P permite que nenhum caractere seja reexaminado.
• O apontador para o texto nunca é decrementado.
19
Algoritmo KMP
20
Algoritmo KMP
• Porém, como saber quantas posições devem ser deslocadas?
• Para tal, utilizamos uma função chamada de Função Prefixo, denotada por π.– Por enquanto iremos considerar que essa
função é conhecida.
21
Função PrefixoTendo P = ababaca contra um texto T.• Em (a) sendo, q = 5, de caracteres que parearam com T.• Conhecendo estes q caracteres do texto é possível determinar que alguns deslocamentos s são inválidos (não precisam ser testados).• O deslocamento s’ = s + 1 é inválido, mas o deslocamento s’ = s + 2 é potencialmente válido pelo que conhecemos do texto.• Dado que q caracteres tiveram comparações com sucesso no deslocamento s, o próximo potencial deslocamento válido será:
s’ = s + (q – π[q])
22
Função Prefixo
• A função prefixo encapsula o conhecimento sobre quantas posições deve-se caminhar para continuar procedendo o casamento do padrão, evitando comparações inúteis.
• Para tal, a função analisa o padrão fornecido e cria uma “tabela” de deslocamentos.
• Idéia simples.
23
Função PrefixoValores da função prefixo para P:
a b a b a c a
1 2 3 4 5 6 7
0 0 1 2 3 0 1
Pq
π
5
b
6
c
7
b
8
a
9
e
10
b
11
c
12
b
1
b
2
c
3
b
4
a1 2 3 4 0 1 2 30 0 1 0
P
13
a4
q 14
b
15
c
16
b5 6 7
a8
0
Prefix
Outro exemplo:
24
Caso importante
• Considere o exemplo abaixo:
• Qual o valor para Prefix(10)?• Prefix(9)=4. Mas P(4)≠P(10).• Podemos concluir que Prefix(10)=0?• Não, não podemos.
5
a
6
g
7
c
8
g
9
c
10
g c
1 2
g
3
c
4
gP
i 0
c
0 0 1 2 3 4 ?0 1 20Prefix
25
Caso importante
• Existe um prefixo mais curto com tamanho 2 que é igual a um sufixo de P(0,9), e P(10)=P(2).
• Podemos concluir que Prefix(10)=2+1=3.
5
a
6
g
7
c
8
g
9
c
10
g c
1 2
g
3
c
4
gP
i 0
c
0 0 1 2 3 4 ?0 1 20Prefix
26
Exemplo
27
Algoritmo KMP
public static int KMPmatch(String text, String pattern) { int n = text.length(); int m = pattern.length(); int[] fail = prefixFunction(pattern); int i = 0; int j = 0; while (i < n) { if (pattern.charAt(j) == text.charAt(i)) { if (j == m - 1) return i - m + 1; // match i++; j++; } else if (j > 0) j = fail[j - 1]; else i++; } return -1; // no match }
public static int[] prefixFunction(String pattern) { int[] fail = new int[pattern.length()]; fail[0] = 0; int m = pattern.length(); int j = 0; int i = 1; while (i < m) { if (pattern.charAt(j) == pattern.charAt(i)) { fail[i] = j + 1; i++; j++; } else if (j > 0) // j follows a matching prefix j = fail[j - 1]; else { // no match fail[i] = 0; i++; } } return fail; }
28
Algoritmo KMP
• Como são evitadas comparações em P, o algoritmo é executado em tempo polinomial.
• É feito um pré-processamento em P– O(n)
• É feito um processamento em T– O(m)
• Processamento total: O(n + m)
29
Exercício
• Considere o texto abaixo:ABACAABACCABACABAABB
• Pesquise o padrão ABACAB utilizando o método KMP.
• Diga quantas comparações o método faz.
30
Algoritmo BMH
• Também chamado de Boyer-Moore-Horspool.
• Pela extrema simplicidade de implementação e comprovada eficiência, o BMH deve ser escolhido em aplicações de uso geral que necessitam realizar casamento exato de cadeias.
• A idéia é pesquisar no padrão no sentido da direita para a esquerda, o que torna o algoritmo muito rápido.
• Executado frequentemente em editores de texto para os comandos de “localizar" e "substituir".
• Veremos primeiro o algoritmo BM, o algoritmo original.
31
Algoritmo BM
• O algoritmo faz a varredura dos símbolos do padrão da direita para à esquerda (rightmost). O algoritmo utiliza duas funções pré-processadas para deslocar o padrão à direita.
• Estas funções dos deslocamentos são chamadas funções de ocorrência e de casamento.
32
Heurística de ocorrência
• Alinha a posição que causou a colisão no texto com o primeiro caractere no padrão que casa com este caractere;
• Ex.: P ={cacbac}, T ={aabcaccacbac}.1 2 3 4 5 6 7 8 9 0 1 2a a b c a c c a c b a cc a c b a c c a c b a c c a c b a c c a c b a c c a c b a c
33
Heurística de ocorrência
• A partir da posição 6, da direita para a esquerda, existe uma colisão na posição 4 de T, entre b do padrão e c do texto.
• Logo, o padrão deve ser deslocado para a direita até o primeiro caractere no padrão que casa com c.
• O processo é repetido até encontrar um casamento a partir da posição 7 de T.
34
Heurística do casamento
• Ao mover o padrão para a direita, faça-o casar com o pedaço do texto anteriormente casado.
• Ex.: P ={cacbac} no texto T ={aabcaccacbac}.1 2 3 4 5 6 7 8 9 0 1 2a a b c a c c a c b a cc a c b a c c a c b a c c a c b a c
35
Heurística do casamento
• Novamente, a partir da posição 6, da direita para a esquerda, existe uma colisão na posição 4 de T , entre o b do padrão e o c do texto.
• Neste caso, o padrão deve ser deslocado para a direita até casar com o pedaço do texto anteriormente casado, no caso ac, deslocando o padrão 3 posições à direita.
• O processo é repetido mais uma vez e o casamento entre P e T ocorre.
36
Escolha da heurística
• O algoritmo BM escolhe a heurística que provoca o maior deslocamento do padrão.
• Esta escolha implica em realizar uma comparação entre dois inteiros para cada caractere lido do texto, penalizando o desempenho do algoritmo com relação ao tempo de processamento.
• Várias propostas de simplificação ocorreram ao longo dos anos.
• As que produzem os melhores resultados são as que consideram apenas a heurística de ocorrência.
37
Algoritmo BMH
• A simplificação mais importante é devida a Horspool em 1980.
• Executa mais rápido do que o algoritmo BM original.
• Parte da observação de que qualquer caractere já lido do texto a partir do último deslocamento pode ser usado para endereçar a tabela de deslocamentos.
• Endereça a tabela com o caractere no texto correspondente ao último caractere do padrão.
38
Algoritmo BMH – Tabela de Deslocamentos
• Para pré-computar o padrão o valor inicial de todas as entradas na tabela de deslocamentos é feito igual a m.
• A seguir, apenas os m − 1 primeiros caracteres do padrão são usados para obter os outros valores da tabela.
• Formalmente, d[x] = min { j tal que j = m | (1 ≤ j < m & P [m − j] = x) }.
• Ex.:
– Para o padrão P ={teste}, os valores de d são d[t] = 1, d[e] = 3, d[s] = 2, e todos os outros valores são iguais ao valor de |P|, nesse caso m = 5.
– Para o padrão P={bola}, os valores de d são d[b] = 3, d[o] = 2, d[l] = 1, d[a] = 4.
39
Algoritmo BMH
40
Algoritmo BMH
[e]
41
Algoritmo BMH
{ G C A T C G C A G A G A G T A T A C A G T A C G }
42
Algoritmo BMH
achou!
43
Algoritmo BMH
44
Implementaçãoprocedure BMH ( var T: TipoTexto ; var n : integer ; var P: TipoPadrao ; var m: integer ) ;{−− Pesquisa P[ 1 .. m] em T[ 1 .. n] −−}var i , j , k : Integer ; d : array [ 0 ..MaxTamAlfabeto] of integer ;begin {−− Pre processamento do padrao−−} for j := 0 to MaxTamAlfabeto do d[ j ] : = m; for j := 0 to m-2 do d[ ord(P[ j ] ) ] : = m-j-1 ; i : = m; while i <= n do {−− Pesquisa−−} begin k := i ; j : = m; while (T[ k ] = P[ j ] ) and ( j >0) do begin k : = k−1; j : = j −1; end; if j = 0 then writeln ( ’ Casamento na posicao : ’ ,k+1:3); i : = i + d[ ord(T[ i ] ) ] ; end;end;
45
Exercício
• Considere o texto abaixo:ABACAABACCABACABAABB
• Pesquise o padrão ABACAB utilizando o método BMH.
• Diga quantas comparações o método faz.
46
Algoritmo BHMS
• Sunday (1990) apresentou outra simplificação importante para o algoritmo BM, ficando conhecida como BMHS.
• Variante do BMH: endereçar a tabela com o caractere no texto correspondente ao próximo caractere após o último caractere do padrão, em vez de deslocar o padrão usando o último caractere como no algoritmo BMH.
• Para pré-computar o padrão, o valor inicial de todas as entradas na tabela de deslocamentos é feito igual a m + 1.
• A seguir, os m primeiros caracteres do padrão são usados para obter os outros valores da tabela.
– Formalmente d[x] = min{j tal que j = m | (1 ≤ j ≤ m & P [m + 1 − j] = x)}.
• Exemplo:
– Para o padrão P = teste, os valores de d são d[t] = 2, d[e] = 1, d[s] = 3, e todos os outros valores são iguais ao valor de |P| + 1.
47
Implementação
procedure BMHS ( var T: TipoTexto ; var n : integer ; var P: TipoPadrao ; var m: integer ) ;var i , j , k : Integer ; d : array [ 0 .. MaxChar] of integer ;begin {−− Pre processamento do padrao−−} for j := 0 to MaxChar do d[ j ] : = m+1; for j := 0 to m-1 do d[ ord(P[ j ] ) ] : = m − j ; i : = m; while i <= n do {−− Pesquisa−−} begin k := i ; j : = m; while (T[ k ] = P[ j ] ) and ( j >0) do begin k : = k − 1; j : = j − 1; end; if j = 0 then writeln ( ’Casamento na posicao : ’ , k+1:3); i : = i + d[ ord(T[ i +1])]; end;end;
48
Implementação
• O pré-processamento do padrão ocorre nas duas primeiras linhas do código.
• A fase de pesquisa é constituída por um laço em que i varia de m até n, com incrementos d[ord(T[i+1])], o que equivale ao endereço na tabela d do caractere que está na i + 1-ésima posição no texto, a qual corresponde à posição do último caractere de P .
49
Exemplo
4 3 2 1
[e]
3 5 4 2 1 5 5 5
5 5 5 5 5 5 5 5
50
Exemplo
Shift para [c] = 4
Shift para [c] = 4
match!
51
Algoritmo BMHS
• Embora normalmente utiliza-se a comparação do padrão seguindo da direita, ao contrário dos algoritmos de BM e BMH, o algoritmo de Sunday pode comparar o padrão de forma arbitrária.
• Caso saiba-se qual o caracter menos comum no padrão, ele pode ser utilizado primeiro na comparação
52
Exercício
• Considere o texto abaixo:ABACAABACCABACABAABB
• Pesquise o padrão ABACAB utilizando o método BMHS.
• Diga quantas comparações o método faz.
53
BM - Análise
• Os dois tipos de deslocamento (ocorrência e casamento) podem ser pré-computados com base apenas no padrão e no alfabeto.
• Assim, a complexidade de tempo e de espaço para esta fase é O(m + c).
• O pior caso do algoritmo é O(n + rm), onde r é igual ao número total de casamentos, o que torna o algoritmo ineficente quando o número de casamentos é grande.
• O melhor caso e o caso médio para o algoritmo é O(n/m), um resultado excelente pois executa em tempo sublinear.
54
BMH - Análise
• O deslocamento de ocorrência também pode ser pré-computado com base apenas no padrão e no alfabeto.
• A complexidade de tempo e de espaço para essa fase é O(c).
• Para a fase de pesquisa, o pior caso do algoritmo é O(nm), o melhor caso é O(n/m) e o caso esperado é O(n/m), se c não é pequeno e m não é muito grande.
55
BMHS - Análise
• Na variante BMHS, seu comportamento assintótico é igual ao do algoritmo BMH.
• Entretanto, os deslocamentos são mais longos (podendo ser iguais a m + 1), levando a saltos relativamente maiores para padrões curtos.
• Por exemplo, para um padrão de tamanho m = 1, o deslocamento é igual a 2m quando não há casamento.
56
Análise
57
Método Robin-Karp• Princípio: tratar cada substring de tamanho M do texto como chave de
uma tabela de dispersão
– padrão é encontrado quando a chave da substring coincide com a do padrão
– como se procura chave específica, não é preciso guardar a tabela, mas apenas calcular as chaves
– com tabela virtual: tamanho elevado reduz probabilidade de falsas escolhas
• Para que o método seja eficaz
– cálculo da chave deve ser menos pesado que fazer as comparações
– função de dispersão: h(k) = k mod q q primo grande
– cálculo das chaves: chave da posição i usa a da posição i-1
• M caracteres transformam-se em número: empacotados na máquina como palavra, e esta interpretada como número
58
Pré-processamento do padrão
1 9 9 1P
∑ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} |∑| = 10
temos:
(P[1] * 10 + P[2]) = 19(19 * 10) + P[3] = 199(199 * 10) + P[4] = 1991
Generalizando:
P[m] + |∑| (P[m-1]+ |∑| (P[m-2] + ... + |∑| (P[2] + |∑| P[1]) ))
∑ = alfabeto
|∑| = tamanho de ∑
Dado um caractere, a representação numérica deste será sua posição no alfabeto ∑
Complexidade O(m)
59
Processamento do texto
1 8 8 7 1 9 9 1 2 0 0 0 5Texto TTexto T
1 9 9 1Padrão PPadrão P
1 8 8 7 = 1887 tempo O(m), para s = 0
s = 0, temos O(m)s > 0, temos O(1)s variando de 0 à n – mpara calcular |∑| m - 1 temos O(lg m)= O(m) + (n – m)O(1) + O(lg m)= O(n)
8 8 7 1 = 8871 não usaremos tempo O(m) para s > 0, pois temos que:
(1887 – |∑| m - 1 * P[1]) * |∑| + P[s+m] = 8871,onde|∑| m - 1 foi previamente calculado
Portanto temos tempo O(1), para cada deslocamento s > 0
60
Método Robin-Karp
• Aplicando a idéia para caracteres:– Atribuir números a cada letra (código ASCII,
por exemplo)– Aplicar hashing para a cadeia S[1,..,m] na
base b (número primo)– Por exemplo, considerando a base como 101
(a base pode ser o tamanho do alfabeto):• Palavra “hi”=104×1011 + 105×1010=10609
61
Método Robin-Karp
Os valores das transformações de Os valores das transformações de P P e das e das substrings de T são muito grandes, quando substrings de T são muito grandes, quando
m e |m e |∑| são muito longos ∑| são muito longos
Solução 1:Solução 1: reduzir esses valores a uma faixa controlada, reduzir esses valores a uma faixa controlada, utilizando módulo de um número utilizando módulo de um número qq, por exemplo., por exemplo.
Novo problema:Novo problema: um mesmo valor pode representar um mesmo valor pode representar substrings distintas.substrings distintas.
Solução 2:Solução 2: ocorrendo um provável casamento de ocorrendo um provável casamento de P P com com uma substring uma substring XX de de T, T, cada caractere de cada caractere de P P deve ser deve ser comparado a cada caractere de comparado a cada caractere de X, X, para verificar se o para verificar se o casamento realmente acontece.casamento realmente acontece.
62
Método Robin-Karp
• Implementação– Calcular hashing(PADRAO)– Calcular hashing(Substrings(TEXTO))
• Opção: Guardar em uma tabela
– Pesquisar hashing(PADRAO) na tabela• Se não encontrar, padrão não existe no texto• Se encontrar,
– Verificar se Substring(TEXTO) = PADRAO– Se for diferente, padrão não existe no texto
63
Método Robin-Karp
• Usado para descobrir casos de plágio
Análise:Análise:- custo para pré-processamento do padrão P é O(m)
- custo para processamento do texto T é O(n)
- número máximo de deslocamentos s válidos é n – m + 1
No pior caso:No pior caso:
- Todas as substrings X de T casam com P
Sabemos que o número de deslocamentos s válidos é n – m + 1, então temos s possíveis X, sabemos também que | X | = | P | = m, é possível concluir então que para cada s faremos m comparações, então: O((n-m+1)m).
64
Exercício
• Aplique o método de Robin-Karp para criar a tabela de hashing do texto abaixo, considerando um tamanho 3 de caracteres pro hashing e um alfabeto de tamanho 27, onde a letra A é denotada pelo número 1, B pela número 2, C como 3, D como 4, etc...
• Texto = “ABCAABAC”
• Como você procuraria a existência do padrão ABA no texto?