Você está na página 1de 808

Introduo

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Charles Ornelas, Leonardo Rocha, Leonardo


Mata e Nivio Ziviani
Projeto de Algoritmos Cap.1 Introduo Seo 1.1 1

Algoritmos, Estruturas de Dados e


Programas

Os algoritmos fazem parte do dia-a-dia das


pessoas. Exemplos de algoritmos:
instrues para o uso de medicamentos,
indicaes de como montar um aparelho,
uma receita de culinria.

Seqncia de aes executveis para a


obteno de uma soluo para um
determinado tipo de problema.

Segundo Dijkstra, um algoritmo corresponde


a uma descrio de um padro de
comportamento, expresso em termos de um
conjunto finito de aes.
Executando a operao a + b percebemos
um padro de comportamento, mesmo
que a operao seja realizada para
valores diferentes de a e b.
Projeto de Algoritmos Cap.1 Introduo Seo 1.1 2

Estruturas de dados

Estruturas de dados e algoritmos esto


intimamente ligados:
no se pode estudar estruturas de dados
sem considerar os algoritmos associados
a elas,
assim como a escolha dos algoritmos em
geral depende da representao e da
estrutura dos dados.

Para resolver um problema necessrio


escolher uma abstrao da realidade, em
geral mediante a definio de um conjunto de
dados que representa a situao real.

A seguir, deve ser escolhida a forma de


representar esses dados.
Projeto de Algoritmos Cap.1 Introduo Seo 1.1 3

Escolha da Representao dos Dados

A escolha da representao dos dados


determinada, entre outras, pelas operaes a
serem realizadas sobre os dados.

Considere a operao de adio:


Para pequenos nmeros, uma boa
representao por meio de barras
verticais (caso em que a operao de
adio bastante simples).
J a representao por dgitos decimais
requer regras relativamente complicadas,
as quais devem ser memorizadas.
Entretanto, quando consideramos a adio
de grandes nmeros mais fcil a
representao por dgitos decimais
(devido ao princpio baseado no peso
relativo da posio de cada dgito).
Projeto de Algoritmos Cap.1 Introduo Seo 1.1 4

Programas
Programar basicamente estruturar dados e
construir algoritmos.
Programas so formulaes concretas de
algoritmos abstratos, baseados em
representaes e estruturas especficas de
dados.
Programas representam uma classe especial
de algoritmos capazes de serem seguidos por
computadores.
Um computador s capaz de seguir
programas em linguagem de mquina
(seqncia de instrues obscuras e
desconfortveis).
necessrio construir linguagens mais
adequadas, que facilitem a tarefa de
programar um computador.
Uma linguagem de programao uma
tcnica de notao para programar, com a
inteno de servir de veculo tanto para a
expresso do raciocnio algortmico quanto
para a execuo automtica de um algoritmo
por um computador.
Projeto de Algoritmos Cap.1 Introduo Seo 1.2 5

Tipos de Dados

Caracteriza o conjunto de valores a que uma


constante pertence, ou que podem ser
assumidos por uma varivel ou expresso, ou
que podem ser gerados por uma funo.

Tipos simples de dados so grupos de


valores indivisveis (como os tipos bsicos int,
boolean, char e float de Java).
Exemplo: uma varivel do tipo boolean
pode assumir o valor verdadeiro ou o valor
falso, e nenhum outro valor.

Os tipos estruturados em geral definem uma


coleo de valores simples, ou um agregado
de valores de tipos diferentes.
Projeto de Algoritmos Cap.1 Introduo Seo 1.2 6

Tipos Abstratos de Dados (TADs)


Modelo matemtico, acompanhado das
operaes definidas sobre o modelo.
Exemplo: o conjunto dos inteiros
acompanhado das operaes de adio,
subtrao e multiplicao.
TADs so utilizados extensivamente como
base para o projeto de algoritmos.
A implementao do algoritmo em uma
linguagem de programao especfica exige a
representao do TAD em termos dos tipos
de dados e dos operadores suportados.
A representao do modelo matemtico por
trs do tipo abstrato de dados realizada
mediante uma estrutura de dados.
Podemos considerar TADs como
generalizaes de tipos primitivos e
procedimentos como generalizaes de
operaes primitivas.
O TAD encapsula tipos de dados. A definio
do tipo e todas as operaes ficam
localizadas numa seo do programa.
Projeto de Algoritmos Cap.1 Introduo Seo 1.2 7

Implementao de TADs
Considere uma aplicao que utilize uma lista
de inteiros. Poderamos definir TAD Lista,
com as seguintes operaes:
1. faa a lista vazia;
2. obtenha o primeiro elemento da lista; se a lista
estiver vazia, ento retorne nulo;
3. insira um elemento na lista.

H vrias opes de estruturas de dados que


permitem uma implementao eficiente para
listas (por ex., o tipo estruturado arranjo).
Cada operao do tipo abstrato de dados
implementada como um procedimento na
linguagem de programao escolhida.
Qualquer alterao na implementao do
TAD fica restrita parte encapsulada, sem
causar impactos em outras partes do cdigo.
Cada conjunto diferente de operaes define
um TAD diferente, mesmo atuem sob um
mesmo modelo matemtico.
A escolha adequada de uma implementao
depende fortemente das operaes a serem
realizadas sobre o modelo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 8

Medida do Tempo de Execuo de um


Programa

O projeto de algoritmos fortemente


influenciado pelo estudo de seus
comportamentos.

Depois que um problema analisado e


decises de projeto so finalizadas,
necessrio estudar as vrias opes de
algoritmos a serem utilizados, considerando
os aspectos de tempo de execuo e espao
ocupado.

Muitos desses algoritmos so encontrados


em reas como pesquisa operacional,
otimizao, teoria dos grafos, estatstica,
probabilidades, entre outras.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 9

Tipos de Problemas na Anlise de


Algoritmos
Anlise de um algoritmo particular.
Qual o custo de usar um dado algoritmo
para resolver um problema especfico?
Caractersticas que devem ser
investigadas:
anlise do nmero de vezes que cada
parte do algoritmo deve ser executada,
estudo da quantidade de memria
necessria.
Anlise de uma classe de algoritmos.
Qual o algoritmo de menor custo
possvel para resolver um problema
particular?
Toda uma famlia de algoritmos
investigada.
Procura-se identificar um que seja o
melhor possvel.
Coloca-se limites para a complexidade
computacional dos algoritmos
pertencentes classe.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 10

Custo de um Algoritmo

Determinando o menor custo possvel para


resolver problemas de uma dada classe,
temos a medida da dificuldade inerente para
resolver o problema.

Quando o custo de um algoritmo igual ao


menor custo possvel, o algoritmo timo
para a medida de custo considerada.

Podem existir vrios algoritmos para resolver


o mesmo problema.

Se a mesma medida de custo aplicada a


diferentes algoritmos, ento possvel
compar-los e escolher o mais adequado.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 11

Medida do Custo pela Execuo do


Programa

Tais medidas so bastante inadequadas e os


resultados jamais devem ser generalizados:
os resultados so dependentes do
compilador que pode favorecer algumas
construes em detrimento de outras;
os resultados dependem do hardware;
quando grandes quantidades de memria
so utilizadas, as medidas de tempo
podem depender deste aspecto.

Apesar disso, h argumentos a favor de se


obterem medidas reais de tempo.
Ex.: quando h vrios algoritmos distintos
para resolver um mesmo tipo de problema,
todos com um custo de execuo dentro
de uma mesma ordem de grandeza.
Assim, so considerados tanto os custos
reais das operaes como os custos no
aparentes, tais como alocao de
memria, indexao, carga, dentre outros.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 12

Medida do Custo por meio de um


Modelo Matemtico

Usa um modelo matemtico baseado em um


computador idealizado.

Deve ser especificado o conjunto de


operaes e seus custos de execues.

mais usual ignorar o custo de algumas das


operaes e considerar apenas as operaes
mais significativas.

Ex.: algoritmos de ordenao. Consideramos


o nmero de comparaes entre os
elementos do conjunto a ser ordenado e
ignoramos as operaes aritmticas, de
atribuio e manipulaes de ndices, caso
existam.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 13

Funo de Complexidade

Para medir o custo de execuo de um


algoritmo comum definir uma funo de
custo ou funo de complexidade f .

f (n) a medida do tempo necessrio para


executar um algoritmo para um problema de
tamanho n.

Funo de complexidade de tempo: f (n)


mede o tempo necessrio para executar um
algoritmo em um problema de tamanho n.

Funo de complexidade de espao: f (n)


mede a memria necessria para executar
um algoritmo em um problema de tamanho n.

Utilizaremos f para denotar uma funo de


complexidade de tempo daqui para a frente.

A complexidade de tempo na realidade no


representa tempo diretamente, mas o nmero
de vezes que determinada operao
considerada relevante executada.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 14

Exemplo - Maior Elemento

Considere o algoritmo para encontrar o maior


elemento de um vetor de
inteirosv [0..n 1], n 1.

package cap1;
public class Max {
public static int max ( int v [ ] , int n) {
int max = v [ 0 ] ;
for ( int i = 1; i < n ; i ++)
i f (max < v [ i ] ) max = v [ i ] ;
return max;
}
}

Seja f uma funo de complexidade tal que


f (n) o nmero de comparaes entre os
elementos de v, se v contiver n elementos.

Logo f (n) = n 1, para n > 0.

Vamos provar que o algoritmo apresentado


no programa acima timo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 15

Exemplo - Maior Elemento

Teorema: Qualquer algoritmo para encontrar


o maior elemento de um conjunto com n
elementos, n 1, faz pelo menos n 1
comparaes.

Prova: Deve ser mostrado, por meio de


comparaes, que cada um dos n 1
elementos menor do que algum outro
elemento.

Logo n 1 comparaes so necessrias. 2

O teorema acima nos diz que, se o nmero


de comparaes for utilizado como medida de
custo, ento o mtodo max da classe Max
timo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 16

Tamanho da Entrada de Dados

A medida do custo de execuo de um


algoritmo depende principalmente do
tamanho da entrada dos dados.

comum considerar o tempo de execuo de


um programa como uma funo do tamanho
da entrada.

Para alguns algoritmos, o custo de execuo


uma funo da entrada particular dos
dados, no apenas do tamanho da entrada.

No caso do mtodo max do programa do


exemplo, o custo uniforme sobre todos os
problemas de tamanho n.

J para um algoritmo de ordenao isso no


ocorre: se os dados de entrada j estiverem
quase ordenados, ento o algoritmo pode ter
que trabalhar menos.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 17

Melhor Caso, Pior Caso e Caso Mdio


Melhor caso: menor tempo de execuo
sobre todas as entradas de tamanho n.
Pior caso: maior tempo de execuo sobre
todas as entradas de tamanho n.
Se f uma funo de complexidade baseada
na anlise de pior caso, o custo de aplicar o
algoritmo nunca maior do que f (n).
Caso mdio (ou caso esperado): mdia dos
tempos de execuo de todas as entradas de
tamanho n.
Na anlise do caso esperado, supe-se uma
distribuio de probabilidades sobre o
conjunto de entradas de tamanho n e o custo
mdio obtido com base nessa distribuio.
A anlise do caso mdio geralmente muito
mais difcil de obter do que as anlises do
melhor e do pior caso.
comum supor uma distribuio de
probabilidades em que todas as entradas
possveis so igualmente provveis.
Na prtica isso nem sempre verdade.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 18

Exemplo - Registros de um Arquivo

Considere o problema de acessar os


registros de um arquivo.

Cada registro contm uma chave nica que


utilizada para recuperar registros do arquivo.

O problema: dada uma chave qualquer,


localize o registro que contenha esta chave.

O algoritmo de pesquisa mais simples o


que faz a pesquisa seqencial.

Seja f uma funo de complexidade tal que


f (n) o nmero de registros consultados no
arquivo (nmero de vezes que a chave de
consulta comparada com a chave de cada
registro).
melhor caso: f (n) = 1 (registro procurado
o primeiro consultado);
pior caso: f (n) = n (registro procurado o
ltimo consultado ou no est presente no
arquivo);
caso mdio: f (n) = (n + 1)/2.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 19

Exemplo - Registros de um Arquivo

No estudo do caso mdio, vamos considerar


que toda pesquisa recupera um registro.

Se pi for a probabilidade de que o i-simo


registro seja procurado, e considerando que
para recuperar o i-simo registro so
necessrias i comparaes, ento
f (n) = 1 p1 + 2 p2 + 3 p3 + + n pn .

Para calcular f (n) basta conhecer a


distribuio de probabilidades pi .

Se cada registro tiver a mesma probabilidade


de ser acessado que todos os outros, ento
pi = 1/n, 0 i < n.

Neste caso  
n(n+1)
f (n) = n1 (1+2+3+ +n) = 1
n 2
= n+1
2

A anlise do caso esperado revela que uma


pesquisa com sucesso examina
aproximadamente metade dos registros.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 20

Exemplo - Maior e Menor Elemento (1)


Considere o problema de encontrar o maior e
o menor elemento de um vetor de inteiros
v [0..n 1], n 1.
Um algoritmo simples pode ser derivado do
algoritmo apresentado no programa para
achar o maior elemento.
O vetor maxMin definido localmente no
mtodo maxMin1 utilizado para retornar nas
posies 0 e 1 o maior e o menor elemento
do vetor v , respectivamente.

package cap1;
public class MaxMin1 {
public static int [ ] maxMin1 ( int v [ ] , int n) {
int max = v [ 0 ] , min = v [ 0 ] ;
for ( int i = 1; i < n ; i ++) {
i f ( v [ i ] > max) max = v [ i ] ;
i f ( v [ i ] < min) min = v [ i ] ;
}
int maxMin[ ] = new int [ 2 ] ;
maxMin[0] = max; maxMin[1] = min;
return maxMin;
}
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 21

Exemplo - Maior e Menor Elemento (1)

Seja f (n) o nmero de comparaes entre os


elementos de v, se v contiver n elementos.

Logo f (n) = 2(n 1), para n > 0, para o


melhor caso, pior caso e caso mdio.

MaxMin1 pode ser facilmente melhorado: a


comparao v [i] < min s necessria
quando a comparao v [i] > max falsa.

A seguir, apresentamos essa verso


melhorada.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 22

Exemplo - Maior e Menor Elemento (2)

package cap1;
public class MaxMin2 {
public static int [ ] maxMin2 ( int v [ ] , int n) {
int max = v [ 0 ] , min = v [ 0 ] ;
for ( int i = 1; i < n ; i ++) {
i f ( v [ i ] > max) max = v [ i ] ;
else i f ( v [ i ] < min) min = v [ i ] ;
}
int maxMin[ ] = new int [ 2 ] ;
maxMin[0] = max; maxMin[1] = min;
return maxMin;
}
}

Para a nova implementao temos:


melhor caso: f (n) = n 1 (quando os
elementos esto em ordem crescente);
pior caso: f (n) = 2(n 1) (quando os
elementos esto em ordem decrescente);
caso mdio: f (n) = 3n/2 3/2.
No caso mdio, v [i] maior do que max a
metade das vezes.
3n
Logo f (n) = n 1 + n1
2
= 2
32 , para n > 0.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 23

Exemplo - Maior e Menor Elemento (3)

Considerando o nmero de comparaes


realizadas, existe a possibilidade de obter um
algoritmo mais eficiente:
1. Compare os elementos de v aos pares,
separando-os em dois subconjuntos
(maiores em um e menores em outro), a
um custo de dn/2e comparaes.
2. O mximo obtido do subconjunto que
contm os maiores elementos, a um custo
de dn/2e 1 comparaes.
3. O mnimo obtido do subconjunto que
contm os menores elementos, a um
custo de dn/2e 1 comparaes.


d d d d
Contm o mximo



d d d d
Contm o mnimo

Projeto de Algoritmos Cap.1 Introduo Seo 1.3 24

Exemplo - Maior e Menor Elemento (3)

package cap1;
public class MaxMin3 {
public static int [ ] maxMin3 ( int v [ ] , int n) {
int max, min, FimDoAnel;
i f ( (n % 2) > 0) { v [n] = v [n1]; FimDoAnel = n ; }
else FimDoAnel = n1;
i f ( v[0] > v [ 1 ] ) { max = v [ 0 ] ; min = v [ 1 ] ; }
else { max = v [ 1 ] ; min = v [ 0 ] ; }
int i = 2;
while ( i < FimDoAnel) {
i f ( v [ i ] > v [ i +1]) {
i f ( v [ i ] > max) max = v [ i ] ;
i f ( v [ i +1] < min) min = v [ i +1];
}
else {
i f ( v [ i ] < min) min = v [ i ] ;
i f ( v [ i +1] > max) max = v [ i +1];
}
i = i + 2;
}
int maxMin[ ] = new int [ 2 ] ;
maxMin[0] = max; maxMin[1] = min;
return maxMin;
}
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 25

Exemplo - Maior e Menor Elemento (3)

Os elementos de v so comparados dois a


dois e os elementos maiores so comparados
com max e os elementos menores so
comparados com min.

Quando n mpar, o elemento que est na


posio v [n 1] duplicado na posio v [n]
para evitar um tratamento de exceo.

Para esta implementao,


3n
f (n) = n2 + n2
2
+ n2
2
= 2
2, para n > 0,
para o melhor caso, pior caso e caso mdio.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 26

Comparao entre os Algoritmos


MaxMin1, MaxMin2 e MaxMin3

A tabela apresenta uma comparao entre os


algoritmos dos programas MaxMin1, MaxMin2
e MaxMin3, considerando o nmero de
comparaes como medida de complexidade.

Os algoritmos MaxMin2 e MaxMin3 so


superiores ao algoritmo MaxMin1 de forma
geral.

O algoritmo MaxMin3 superior ao algoritmo


MaxMin2 com relao ao pior caso e bastante
prximo quanto ao caso mdio.

Os trs f (n)
algoritmos Melhor caso Pior caso Caso mdio

MaxMin1 2(n 1) 2(n 1) 2(n 1)


MaxMin2 n1 2(n 1) 3n/2 3/2
MaxMin3 3n/2 2 3n/2 2 3n/2 2
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 27

Limite Inferior - Uso de um Orculo

Existe possibilidade de obter um algoritmo


MaxMin mais eficiente?

Para responder temos de conhecer o limite


inferior para essa classe de algoritmos.

Tcnica muito utilizada: uso de um orculo.

Dado um modelo de computao que


expresse o comportamento do algoritmo, o
orculo informa o resultado de cada passo
possvel (no caso, o resultado de cada
comparao).

Para derivar o limite inferior, o orculo procura


sempre fazer com que o algoritmo trabalhe o
mximo, escolhendo como resultado da
prxima comparao aquele que cause o
maior trabalho possvel necessrio para
determinar a resposta final.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 28

Exemplo de Uso de um Orculo

Teorema: Qualquer algoritmo para encontrar


o maior e o menor elementos de um conjunto
com n elementos no ordenados, n 1, faz
pelo menos 3dn/2e 2 comparaes.

Prova: A tcnica utilizada define um orculo


que descreve o comportamento do algoritmo
por meio de um conjunto de ntuplas, mais
um conjunto de regras associadas que
mostram as tuplas possveis (estados) que
um algoritmo pode assumir a partir de uma
dada tupla e uma nica comparao.

Uma 4tupla, representada por (a, b, c, d),


onde os elementos de:
a nunca foram comparados;
b foram vencedores e nunca perderam
em comparaes realizadas;
c foram perdedores e nunca venceram
em comparaes realizadas;
d foram vencedores e perdedores em
comparaes realizadas.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 29

Exemplo de Uso de um Orculo


O algoritmo inicia no estado (n, 0, 0, 0) e
termina com (0, 1, 1, n 2).
Aps cada comparao a tupla (a, b, c, d)
consegue progredir apenas se ela assume
um dentre os seis estados possveis abaixo:
(a 2, b + 1, c + 1, d) se a 2 (dois
elementos de a so comparados)
(a 1, b + 1, c, d) ou (a 1, b, c + 1, d) ou
(a 1, b, c, d + 1) se a 1 (um elemento de
a comparado com um de b ou um de c)
(a, b 1, c, d + 1) se b 2 (dois elementos
de b so comparados)
(a, b, c 1, d + 1) se c 2 (dois elementos
de c so comparados)
O primeiro passo requer necessariamente
a manipulao do componente a.
O caminho mais rpido para levar a at
zero requer dn/2e mudanas de estado e
termina com a tupla (0, n/2, n/2, 0) (por
meio de comparao dos elementos de a
dois a dois).
Projeto de Algoritmos Cap.1 Introduo Seo 1.3 30

Exemplo de Uso de um Orculo

A seguir, para reduzir o componente b at um


so necessrias dn/2e 1 mudanas de
estado (mnimo de comparaes necessrias
para obter o maior elemento de b).

Idem para c, com dn/2e 1 mudanas de


estado.

Logo, para obter o estado (0, 1, 1, n 2) a


partir do estado (n, 0, 0, 0) so necessrias

dn/2e + dn/2e 1 + dn/2e 1 = d3n/2e 2

comparaes. 2

O teorema nos diz que se o nmero de


comparaes entre os elementos de um vetor
for utilizado como medida de custo, ento o
algoritmo MaxMin3 timo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 31

Comportamento Assinttico de
Funes

O parmetro n fornece uma medida da


dificuldade para se resolver o problema.

Para valores suficientemente pequenos de n,


qualquer algoritmo custa pouco para ser
executado, mesmo os ineficientes.

A escolha do algoritmo no um problema


crtico para problemas de tamanho pequeno.

Logo, a anlise de algoritmos realizada para


valores grandes de n.

Estuda-se o comportamento assinttico das


funes de custo (comportamento de suas
funes de custo para valores grandes de n)

O comportamento assinttico de f (n)


representa o limite do comportamento do
custo quando n cresce.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 32

Dominao assinttica
A anlise de um algoritmo geralmente conta
com apenas algumas operaes elementares.
A medida de custo ou medida de
complexidade relata o crescimento assinttico
da operao considerada.
Definio: Uma funo f (n) domina
assintoticamente outra funo g(n) se
existem duas constantes positivas c e m tais
que, para n m, temos |g(n)| c |f (n)|.
f,g
c f (n)
g(n)

n
m

Exemplo:
Sejam g(n) = (n + 1)2 e f (n) = n2 .
As funes g(n) e f (n) dominam
assintoticamente uma a outra, desde que
|(n + 1)2 | 4|n2 | para n 1 e |n2 | |(n + 1)2 |
para n 0.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 33

Notao O
Escrevemos g(n) = O(f (n)) para expressar
que f (n) domina assintoticamente g(n). L-se
g(n) da ordem no mximo f (n).
Exemplo: quando dizemos que o tempo de
execuo T (n) de um programa O(n2 ),
significa que existem constantes c e m tais
que, para valores de n m, T (n) cn2 .
Exemplo grfico de dominao assinttica
que ilustra a notao O.
f,g
c f (n)
g(n)

n
m
O valor da constante m mostrado o menor
valor possvel, mas qualquer valor maior
tambm vlido.
Definio: Uma funo g(n) O(f (n)) se
existem duas constantes positivas c e m tais
que g(n) cf (n), para todo n m.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 34

Exemplos de Notao O

Exemplo: g(n) = (n + 1)2 .


Logo g(n) O(n2 ), quando m = 1 e c = 4.
Isso porque (n + 1)2 4n2 para n 1.

Exemplo: g(n) = n e f (n) = n2 .


Sabemos que g(n) O(n2 ), pois para
n 0, n n2 .
Entretanto f (n) no O(n).
Suponha que existam constantes c e m
tais que para todo n m, n2 cn.
Logo c n para qualquer n m, e no
existe uma constante c que possa ser
maior ou igual a n para todo n.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 35

Exemplos de Notao O

Exemplo: g(n) = 3n3 + 2n2 + n O(n3 ).


Basta mostrar que 3n3 + 2n2 + n 6n3 ,
para n 0.
A funo g(n) = 3n3 + 2n2 + n tambm
O(n4 ), entretanto esta afirmao mais
fraca do que dizer que g(n) O(n3 ).

Exemplo: g(n) = log5 n O(log n).


O logb n difere do logc n por uma constante
que no caso logb c.
Como n = clogc n , tomando o logaritmo
base b em ambos os lados da igualdade,
temos que
logb n = logb clogc n = logc n logb c.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 36

Operaes com a Notao O

f (n) = O(f (n))


c O(f (n)) = O(f (n)) c = constante
O(f (n)) + O(f (n)) = O(f (n))
O(O(f (n)) = O(f (n))
O(f (n)) + O(g(n)) = O(max(f (n), g(n)))
O(f (n))O(g(n)) = O(f (n)g(n))
f (n)O(g(n)) = O(f (n)g(n))

Exemplo: regra da soma O(f (n)) + O(g(n)).

Suponha trs trechos cujos tempos de


execuo so O(n), O(n2 ) e O(n log n).

O tempo de execuo dos dois primeiros


trechos O(max(n, n2 )), que O(n2 ).

O tempo de execuo de todos os trs


trechos ento O(max(n2 , n log n)), que
O(n2 ).

Exemplo: O produto de [log n + k + O(1/n)] por



[n + O( n)] n log n + kn + O( n log n).
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 37

Notao
Especifica um limite inferior para g(n).
Definio: Uma funo g(n) (f (n)) se
existirem duas constantes c e m tais que
g(n) cf (n), para todo n m.
Exemplo: Para mostrar que g(n) = 3n3 + 2n2
(n3 ) basta fazer c = 1, e ento
3n3 + 2n2 n3 para n 0.
Exemplo: Seja g(n) = n para n mpar (n 1)
e g(n) = n2 /10 para n par (n 0).
Neste caso g(n) (n2 ), bastando
considerar c = 1/10 e n = 0, 2, 4, 6, . . .
Exemplo grfico para a notao
f,g
g(n)

c f (n)

n
m

Para todos os valores direita de m, o valor


de g(n) est sobre ou acima do valor de cf (n).
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 38

Notao

Definio: Uma funo g(n) (f (n)) se


existirem constantes positivas c1 , c2 e m tais
que 0 c1 f (n) g(n) c2 f (n), para todo
n m.

Exemplo grfico para a notao


f,g
c2 f ( n )

g(n)
c1 f ( n )

n
m

Dizemos que g(n) = (f (n)) se existirem


constantes c1 , c2 e m tais que, para todo
n m, o valor de g(n) est sobre ou acima de
c1 f (n) e sobre ou abaixo de c2 f (n).

Isto , para todo n m, a funo g(n) igual


a f (n) a menos de uma constante.

Neste caso, f (n) um limite assinttico


firme.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 39

Exemplo de Notao

Seja g(n) = n2 /3 2n.

Vamos mostrar que g(n) = (n2 ).

Temos de obter constantes c1 , c2 e m tais que


c1 n2 31 n2 2n c2 n2 para todo n m.
1 2
Dividindo por n2 leva a c1 3
n
c2 .

O lado direito da desigualdade ser sempre


vlido para qualquer valor de n 1 quando
escolhemos c2 1/3.

Escolhendo c1 1/21, o lado esquerdo da


desigualdade ser vlido para qualquer valor
de n 7.

Logo, escolhendo c1 = 1/21, c2 = 1/3 e m = 7,


verifica-se que n2 /3 2n = (n2 ).

Outras constantes podem existir, mas o


importante que existe alguma escolha para
as trs constantes.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 40

Notao o

Usada para definir um limite superior que no


assintoticamente firme.

Definio: Uma funo g(n) o(f (n)) se,


para qualquer constante c > 0, ento
0 g(n) < cf (n) para todo n m.

Exemplo: 2n = o(n2 ), mas 2n2 6= o(n2 ).

Em g(n) = O(f (n)), a expresso


0 g(n) cf (n) vlida para alguma
constante c > 0, mas em g(n) = o(f (n)), a
expresso 0 g(n) < cf (n) vlida para
todas as constantes c > 0.

Na notao o, a funo g(n) tem um


crescimento muito menor que f (n) quando n
tende para infinito.
g(n)
Alguns autores usam limn f (n)
= 0 para a
definio da notao o.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1 41

Notao

Por analogia, a notao est relacionada


com a notao da mesma forma que a
notao o est relacionada com a notao O.

Definio: Uma funo g(n) (f (n)) se,


para qualquer constante c > 0, ento
0 cf (n) < g(n) para todo n m.
n2 n2
Exemplo: 2
= (n), mas 2
6= (n2 ).

A relao g(n) = (f (n)) implica


limn fg(n)
(n)
= , se o limite existir.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 42

Classes de Comportamento
Assinttico
Se f uma funo de complexidade para
um algoritmo F , ento O(f ) considerada a
complexidade assinttica ou o
comportamento assinttico do algoritmo F .
A relao de dominao assinttica permite
comparar funes de complexidade.
Entretanto, se as funes f e g dominam
assintoticamente uma a outra, ento os
algoritmos associados so equivalentes.
Nestes casos, o comportamento assinttico
no serve para comparar os algoritmos.
Por exemplo, considere dois algoritmos F e G
aplicados mesma classe de problemas,
sendo que F leva trs vezes o tempo de G ao
serem executados, isto , f (n) = 3g(n), sendo
que O(f (n)) = O(g(n)).
Logo, o comportamento assinttico no serve
para comparar os algoritmos F e G, porque
eles diferem apenas por uma constante.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 43

Comparao de Programas

Podemos avaliar programas comparando as


funes de complexidade, negligenciando as
constantes de proporcionalidade.

Um programa com tempo de execuo O(n)


melhor que outro com tempo O(n2 ).

Porm, as constantes de proporcionalidade


podem alterar esta considerao.

Exemplo: um programa leva 100n unidades


de tempo para ser executado e outro leva 2n2 .
Qual dos dois programas melhor?
depende do tamanho do problema.
Para n < 50, o programa com tempo 2n2
melhor do que o que possi tempo 100n.
Para problemas com entrada de dados
pequena prefervel usar o programa cujo
tempo de execuo O(n2 ).
Entretanto, quando n cresce, o programa
com tempo de execuo O(n2 ) leva muito
mais tempo que o programa O(n).
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 44

Principais Classes de Problemas


f (n) = O(1).
Algoritmos de complexidade O(1) so
ditos de complexidade constante.
Uso do algoritmo independe de n.
As instrues do algoritmo so executadas
um nmero fixo de vezes.
f (n) = O(log n).
Um algoritmo de complexidade O(log n)
dito de complexidade logartmica.
Tpico em algoritmos que transformam um
problema em outros menores.
Pode-se considerar o tempo de execuo
como menor que uma constante grande.
Quando n mil, log2 n 10, quando n 1
milho, log2 n 20.
Para dobrar o valor de log n temos de
considerar o quadrado de n.
A base do logaritmo muda pouco estes
valores: quando n 1 milho, o log2 n 20
e o log10 n 6.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 45

Principais Classes de Problemas

f (n) = O(n).
Um algoritmo de complexidade O(n) dito
de complexidade linear.
Em geral, um pequeno trabalho
realizado sobre cada elemento de entrada.
a melhor situao possvel para um
algoritmo que tem de processar/produzir n
elementos de entrada/sada.
Cada vez que n dobra de tamanho, o
tempo de execuo tambm dobra.

f (n) = O(n log n).


Tpico em algoritmos que quebram um
problema em outros menores, resolvem
cada um deles independentemente e
juntando as solues depois.
Quando n 1 milho, nlog2 n cerca de 20
milhes.
Quando n 2 milhes, nlog2 n cerca de
42 milhes, pouco mais do que o dobro.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 46

Principais Classes de Problemas


f (n) = O(n2 ).
Um algoritmo de complexidade O(n2 )
dito de complexidade quadrtica.
Ocorrem quando os itens de dados so
processados aos pares, muitas vezes em
um anel dentro de outro.
Quando n mil, o nmero de operaes
da ordem de 1 milho.
Sempre que n dobra, o tempo de
execuo multiplicado por 4.
teis para resolver problemas de
tamanhos relativamente pequenos.
f (n) = O(n3 ).
Um algoritmo de complexidade O(n3 )
dito de complexidade cbica.
teis apenas para resolver pequenos
problemas.
Quando n 100, o nmero de operaes
da ordem de 1 milho.
Sempre que n dobra, o tempo de
execuo fica multiplicado por 8.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 47

Principais Classes de Problemas


f (n) = O(2n ).
Um algoritmo de complexidade O(2n )
dito de complexidade exponencial.
Geralmente no so teis sob o ponto de
vista prtico.
Ocorrem na soluo de problemas quando
se usa fora bruta para resolv-los.
Quando n 20, o tempo de execuo
cerca de 1 milho. Quando n dobra, o
tempo fica elevado ao quadrado.
f (n) = O(n!).
Um algoritmo de complexidade O(n!)
dito de complexidade exponencial, apesar
de O(n!) ter comportamento muito pior do
que O(2n ).
Geralmente ocorrem quando se usa fora
bruta para na soluo do problema.
n = 20 20! = 2432902008176640000, um
nmero com 19 dgitos.
n = 40 um nmero com 48 dgitos.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 48

Comparao de Funes de
Complexidade
Funo Tamanho n
de custo 10 20 30 40 50 60

n 0,00001 0,00002 0,00003 0,00004 0,00005 0,00006


s s s s s s

n2 0,0001 0,0004 0,0009 0,0016 0,0.35 0,0036


s s s s s s

n3 0,001 0,008 0,027 0,64 0,125 0.316


s s s s s s

n5 0,1 3,2 24,3 1,7 5,2 13


s s s min min min

2n 0,001 1 17,9 12,7 35,7 366


s s min dias anos sc.

3n 0,059 58 6,5 3855 108 1013


s min anos sc. sc. sc.

Funo de Computador Computador Computador


custo atual 100 vezes 1.000 vezes
de tempo mais rpido mais rpido
n t1 100 t1 1000 t1
n2 t2 10 t2 31, 6 t2
n3 t3 4, 6 t3 10 t3
2n t4 t4 + 6, 6 t4 + 10
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 49

Algoritmos Polinomiais
Algoritmo exponencial no tempo de
execuo tem funo de complexidade
O(cn ), c > 1.
Algoritmo polinomial no tempo de execuo
tem funo de complexidade O(p(n)), onde
p(n) um polinmio.
A distino entre estes dois tipos de
algoritmos torna-se significativa quando o
tamanho do problema a ser resolvido cresce.
Por isso, os algoritmos polinomiais so muito
mais teis na prtica do que os exponenciais.
Algoritmos exponenciais so geralmente
simples variaes de pesquisa exaustiva.
Algoritmos polinomiais so geralmente
obtidos mediante entendimento mais
profundo da estrutura do problema.
Um problema considerado:
intratvel: se no existe um algoritmo
polinomial para resolv-lo.
bem resolvido: quando existe um
algoritmo polinomial para resolv-lo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 50

Algoritmos Polinomiais Algoritmos


Exponenciais

A distino entre algoritmos polinomiais


eficientes e algoritmos exponenciais
ineficientes possui vrias excees.

Exemplo: um algoritmo com funo de


complexidade f (n) = 2n mais rpido que
um algoritmo g(n) = n5 para valores de n
menores ou iguais a 20.

Tambm existem algoritmos exponenciais que


so muito teis na prtica.

Exemplo: o algoritmo Simplex para


programao linear possui complexidade de
tempo exponencial para o pior caso mas
executa muito rpido na prtica.

Tais exemplos no ocorrem com freqncia


na prtica, e muitos algoritmos exponenciais
conhecidos no so muito teis.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 51

Exemplo de Algoritmo Exponencial

Um caixeiro viajante deseja visitar n cidades


de tal forma que sua viagem inicie e termine
em uma mesma cidade, e cada cidade deve
ser visitada uma nica vez.

Supondo que sempre h uma estrada entre


duas cidades quaisquer, o problema
encontrar a menor rota para a viagem.

A figura ilustra o exemplo para quatro cidades


c1 , c2 , c3 , c4 , em que os nmeros nos arcos
indicam a distncia entre duas cidades.
c1

9 4 8
5 c3 3

c2 c4
8

O percurso < c1 , c3 , c4 , c2 , c1 > uma soluo


para o problema, cujo percurso total tem
distncia 24.
Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2 52

Exemplo de Algoritmo Exponencial

Um algoritmo simples seria verificar todas as


rotas e escolher a menor delas.

H (n 1)! rotas possveis e a distncia total


percorrida em cada rota envolve n adies,
logo o nmero total de adies n!.

No exemplo anterior teramos 24 adies.

Suponha agora 50 cidades: o nmero de


adies seria 50! 1064 .

Em um computador que executa 109 adies


por segundo, o tempo total para resolver o
problema com 50 cidades seria maior do que
1045 sculos s para executar as adies.

O problema do caixeiro viajante aparece com


freqncia em problemas relacionados com
transporte, mas tambm aplicaes
importantes relacionadas com otimizao de
caminho percorrido.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 53

Tcnicas de Anlise de Algoritmos

Determinar o tempo de execuo de um


programa pode ser um problema matemtico
complexo;

Determinar a ordem do tempo de execuo,


sem preocupao com o valor da constante
envolvida, pode ser uma tarefa mais simples.

A anlise utiliza tcnicas de matemtica


discreta, envolvendo contagem ou
enumerao dos elementos de um conjunto:
manipulao de somas,
produtos,
permutaes,
fatoriais,
coeficientes binomiais,
soluo de equaes de recorrncia.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 54

Anlise do Tempo de Execuo


Comando de atribuio, de leitura ou de
escrita: O(1).
Seqncia de comandos: determinado pelo
maior tempo de execuo de qualquer
comando da seqncia.
Comando de deciso: tempo dos comandos
dentro do comando condicional, mais tempo
para avaliar a condio, que O(1).
Anel: soma do tempo de execuo do corpo
do anel mais o tempo de avaliar a condio
para terminao (geralmente O(1)),
multiplicado pelo nmero de iteraes.
Procedimentos no recursivos: cada um
deve ser computado separadamente um a
um, iniciando com os que no chamam outros
procedimentos. Avalia-se ento os que so
chamam os j avaliados (utilizando os tempos
desses). O processo repetido at chegar no
programa principal.
Procedimentos recursivos: associada uma
funo de complexidade f (n) desconhecida,
onde n mede o tamanho dos argumentos.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 55

Procedimento no Recursivo
Algoritmo para ordenar os n elementos de um
conjunto A em ordem ascendente.

package cap1;
public class Ordenacao {
public static void ordena ( int v [ ] , int n) {
(1) for ( int i = 0; i < n 1; i ++) {
(2) int min = i ;
(3) for ( int j = i + 1; j < n ; j ++)
(4) i f ( v [ j ] < v [min] )
(5) min = j ;
/ Troca v[min] e v[i] /
(6) int x = v [min ] ;
(7) v [min] = v [ i ] ;
(8) v[ i ] = x;
}
}
}

Seleciona o menor elemento do conjunto.


Troca este com o primeiro elemento v [0].
Repita as duas operaes acima com os
n 1 elementos restantes, depois com os
n 2, at que reste apenas um.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 56

Anlise do Procedimento no
Recursivo

Anel Interno

Contm um comando de deciso, com um


comando apenas de atribuio. Ambos levam
tempo constante para serem executados.

Quanto ao corpo do comando de deciso,


devemos considerar o pior caso, assumindo
que serSS sempre executado.

O tempo para incrementar o ndice do anel e


avaliar sua condio de terminao O(1).

O tempo combinado para executar uma vez o


anel O(max(1, 1, 1)) = O(1), conforme regra
da soma para a notao O.

Como o nmero de iteraes n i, o tempo


gasto no anel O((n i) 1) = O(n i),
conforme regra do produto para a notao O.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 57

Anlise do Procedimento no
Recursivo

Anel Externo

Contm, alm do anel interno, quatro


comandos de atribuio.
O(max(1, (n i), 1, 1, 1)) = O(n i).

A linha (1) executada n 1 vezes, e o


tempo total para executar o programa est
limitado ao produto de uma constante pelo
somatrio de (n i):
Pn1 n(n1) n2 n 2
1 (n i) = 2
= 2
2
= O(n )

Considerarmos o nmero de comparaes


como a medida de custo relevante, o
programa faz (n2 )/2 n/2 comparaes para
ordenar n elementos.

Considerarmos o nmero de trocas, o


programa realiza exatamente n 1 trocas.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 58

Procedimento Recursivo

void pesquisa(n) {
(1) i f (n <= 1)
(2) inspecione elemento e termine
else {
(3) para cada um dos n elementos inspecione elemento ;
(4) pesquisa(n/ 3 ) ;
}
}

Para cada procedimento recursivo


associada uma funo de complexidade f (n)
desconhecida, onde n mede o tamanho dos
argumentos para o procedimento.

Obtemos uma equao de recorrncia para


f (n).

Equao de recorrncia: maneira de definir


uma funo por uma expresso envolvendo a
mesma funo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 59

Anlise do Procedimento Recursivo

Seja T (n) uma funo de complexidade que


represente o nmero de inspees nos n
elementos do conjunto.

O custo de execuo das linhas (1) e (2)


O(1) e o da linha (3) exatamente n.

Usa-se uma equao de recorrncia para


determinar o no de chamadas recursivas.

O termo T (n) especificado em funo dos


termos anteriores T (1), T (2), . . ., T (n 1).

T (n) = n + T (n/3), T (1) = 1 (para n = 1


fazemos uma inspeo)

Por exemplo, T (3) = T (3/3) + 3 = 4,


T (9) = T (9/3) + 9 = 13, e assim por diante.

Para calcular o valor da funo seguindo a


definio so necessrios k 1 passos para
computar o valor de T (3k ).
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 60

Exemplo de Resoluo de Equao de


Recorrncia

Sustitui-se os termos T (k), k < n, at que


todos os termos T (k), k > 1, tenham sido
substitudos por frmulas contendo apenas
T (1).

T (n) = n + T (n/3)
T (n/3) = n/3 + T (n/3/3)
T (n/3/3) = n/3/3 + T (n/3/3/3)
.. ..
. .
T (n/3/3 /3) = n/3/3 /3 + T (n/3 /3)

Adicionando lado a lado, temos


T (n) = n + n (1/3) + n (1/32 ) + n (1/33 ) +
+ (n/3/3 /3) que representa a soma de
uma srie geomtrica de razo 1/3,
multiplicada por n, e adicionada de
T (n/3/3 /3), que menor ou igual a 1.
Projeto de Algoritmos Cap.1 Introduo Seo 1.4 61

Exemplo de Resoluo de Equao de


Recorrncia

T (n) = n + n (1/3) + n (1/32 ) + n (1/33 ) + +


+ (n/3/3 /3)

Se desprezarmos o termo T (n/3/3 /3),


quando n tende para infinito,
 ento

i 1 3n
T (n) = n i=0 (1/3) =n =
P
1 31 2

Se considerarmos o termo T (n/3/3/3 /3) e


denominarmos x o nmero de subdivises
por 3 do tamanho do problema, ento
n/3x = 1, e n = 3x . Logo x = log3 n.

Lembrando que T (1) = 1 temos


Px1 n n Px1
T (n) = i=0 3i + T ( 3x ) = n i=0 (1/3)i + 1 =
n(1( 31 )x ) 3n
(1 13 )
+1= 2
12

Logo, o programa do exemplo O(n).


Projeto de Algoritmos Cap.1 Introduo Seo 1.5 62

A Linguagem de Programao Java

Programao orientada a objetos: nasceu


porque algumas linguagens procedimentais
se mostraram inadequadas para a construo
de programas de grande porte.

Existem dois tipos de problemas:


1. Falta de correspondncia entre o
programa e o mundo real: Os
procedimentos implementam tarefas e
estruturas de dados armazenam
informao, mas a maioria dos objetos do
mundo real contm as duas coisas.
2. Organizao interna dos programas:
No existe uma maneira flexvel para dizer
que determinados procedimentos
poderiam acessar uma varivel enquanto
outros no.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 63

A Linguagem de Programao Java


Programao orientada a objetos: permite
que objetos do mundo real que compartilham
propriedades e comportamentos comuns
sejam agrupados em classes.
Estilo de programao diretamente suportado
pelo conceito de classe em Java.
Pode-se tambm impor restries de
visibilidade aos dados de um programa.
Classes e objetos so os conceitos
fundamentais nas linguagens orientadas a
objeto.
A linguagem Java possui um grau de
orientao a objetos maior do que a
linguagem C++.
Java no totalmente orientada a objetos
como a linguagem Smalltalk.
Java no totalmente orientada a objetos
porque, por questes de eficincia, foram
mantidos alguns tipos primitivos e suas
operaes.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 64

Principais Componentes de um
Programa Java

Em Java, as funes e os procedimentos so


chamados de mtodos.

Um objeto contm mtodos e variveis que


representam seus campos de dados
(atributos).
Ex: um objeto painelDeControle deveria
conter no somente os mtodos ligaForno
e desligaForno, mas tambm as variveis
temperaturaCorrente e
temperaturaDese-jada.

O conceito de objeto resolve bem os


problemas apontados anteriormente.
Os mtodos ligaForno e desligaForno
podem acessar as variveis
temperaturaCorrente e
temperaturaDesejada, mas elas ficam
escondidas de outros mtodos que no
fazem parte do objeto painelDeControle.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 65

Principais Componentes de um
Programa Java
O conceito de classe nasceu da necessidade
de se criar diversos objetos de um mesmo
tipo.
Dizemos que um objeto pertence a uma
classe ou, mais comumente, que uma
instncia

package cap1;
class PainelDeControle {
private float temperaturaCorrente ;
private float temperaturaDesejada;

public void ligaForno ( ) {


/ / cdigo do mtodo
}
public void desligaForno ( ) {
/ / cdigo do mtodo
}
}

A palavra chave class introduz a classe


PainelDeControle.
A palavra chave void utilizada para indicar
que os mtodos no retornam nenhum valor.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 66

Principais Componentes de um
Programa Java

Um objeto em Java criado usando a palavra


chave new

necessrio armazenar uma referncia para


ele em uma varivel do mesmo tipo da classe,
como abaixo:
PainelDeControle painel1, painel2;

Posteriormente, cria-se os objetos, como a


seguir:
painel1 = new PainelDeControle ();
painel2 = new PainelDeControle ();

Outras partes do programa interagem com os


mtodos dos objetos por meio do operador
(.), o qual associa um objeto com um de seus
mtodos, como a seguir:
painel1.ligaForno ();
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 67

Herana e Polimorfismo

Herana: criao de uma classe a partir de


uma outra classe.

A classe estendida a partir da classe base


usando a palavra chave extends.

A classe estendida (subclasse) tem todas as


caractersticas da classe base (superclasse)
mais alguma caracterstica adicional.

Polimorfismo: tratamento de objetos de


classes diferentes de uma mesma forma.

As classes diferentes devem ser derivadas da


mesma classe base.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 68

Herana e Polimorfismo

package cap1;
class Empregado {
protected float salario ;
public float salarioMensal ( ) { return salario ; }
public void imprime ( ) { System. out . println ( "Empregado" ) ; }
}
class Secretaria extends Empregado {
private int velocidadeDeDigitacao ;
public void imprime ( ) { System. out . println ( "Secretaria" ) ; }
}
class Gerente extends Empregado {
private float bonus;
public float salarioMensal ( ) { return salario + bonus; }
public void imprime ( ) { System. out . println ( "Gerente" ) ; }
}
public class Polimorfismo {
public static void main ( String [ ] args ) {
Empregado empregado = new Empregado ( ) ;
Empregado secretaria = new Secretaria ( ) ;
Empregado gerente = new Gerente ( ) ;
empregado.imprime ( ) ; secretaria .imprime ( ) ;
gerente .imprime ( ) ;
}
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 69

Objetos e Tipos Genricos

Uma estrutura de dados genrica quando o


tipo dos dados armazenados na estrutura
definido na aplicao que a utiliza (objetos
genricos).

Um objeto genrico pode armazenar uma


referncia para um objeto de qualquer classe
(classe Object em Java).

Os mecanismos de herana e polimorfismo


que permitem a implementao de estruturas
de dados genricas.

package cap1. objetogenerico ;


public class Lista {
private static class Celula {
Object item ; Celula prox ;
}
private Celula primeiro , ultimo ;
}

O objeto item definido como um objeto


genrico, assim Lista pode ter objetos de
classes distintas em cada item
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 70

Objetos e Tipos Genricos


Para evitar que se declare o tipo de cada
objeto a ser inserido ou retirado da lista, a
Verso 5 da linguagem Java introduziu um
mecanismo de definio de um tipo genrico.
Tipo genrico: definio de um parmetro
de tipo que deve ser especificado na
aplicao que utiliza a estrutura de dados:

package cap1. tipogenerico ;


public class Lista<T> {
private static class Celula<T> {
T item ;
Celula<T> prox ;
}
private Celula<T> primeiro , ultimo ;
}

O objeto item tem de ser uma instncia de um


tipo genrico T que ser fornecido quando
um objeto da classe Lista for instanciado.
Para instanciar uma lista de inteiros basta
declarar o comando Lista<Integer> lista =
new Lista<Integer>();.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 71

Sobrecarga

A sobrecarga acontece quando determinado


objeto se comporta de diferentes formas.

um tipo de polimorfismo ad hoc, no qual um


identificador representa vrios mtodos com
computaes distintas.

public float salarioMensal ( float desconto ) {


return salario + bonus desconto;
}

O programa acima apresenta um exemplo de


sobrecarga do mtodo salarioMensal da
classe Gerente mostrada em um programa
anterior, em que um desconto subtrado de
salario + bonus.

Note que o mtodo salarioMensal do


programa acima possui uma assinatura
diferente da assinatura apresentada no
programa anterior.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 72

Sobrescrita

A ocultao de um mtodo de uma classe


mais genrica em uma classe mais especfica
chamada de sobrescrita

Por exemplo, o mtodo imprime da classe


Empregado apresentada nas parte de
Herana e Polimorfismo, foi sobrescrito nas
classes Gerente e Secretaria.

Para sobrescrever um mtodo em uma


subclasse preciso que ele tenha a mesma
assinatura na superclasse.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 73

Programa Principal

package cap1;
class ContaBancaria {
private double saldo ;
public ContaBancaria (double saldoInicial ) {
saldo = saldoInicial ;
}
public void deposito (double valor ) {
saldo = saldo + valor ;
}
public void saque (double valor ) {
saldo = saldo valor ;
}
public void imprime ( ) {
System. out . println ( "saldo=" + saldo ) ;
}
}
public class AplicacaoBancaria {
public static void main ( String [ ] args ) {
ContaBancaria conta1 = new ContaBancaria (200.00);
System. out . print ( "Antes da movimentacao, " ) ;
conta1.imprime ( ) ;
conta1. deposito (50.00); conta1.saque (70.00);
System. out . print ( "Depois da movimentacao, " ) ;
conta1.imprime ( ) ;
}
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 74

Programa Principal

Programa anterior modela uma conta


bancria tpica com as operaes: cria uma
conta com um saldo inicial; imprime o saldo;
realiza um depsito; realiza um saque e
imprime o novo saldo;

A classe Contabancaria tem um campo de


dados chamado saldo e trs mtodos
chamados deposito, saque e imprime.

Para compilar o Programa acima a partir de


uma linha de comando em MS-DOS ou Linux,
fazemos:
javac -d ./ AplicacaoBancaria.java
e para execut-lo, fazemos:
java cap1 .AplicacaoBancaria

A classe ContaBancaria tem um mtodo


especial denominado construtor, que
chamado automaticamente sempre que um
novo objeto criado com o comando new e
tem sempre o mesmo nome da classe.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 75

Modificadores de Acesso
Modificadores de acesso: determinam
quais outros mtodos podem acessar um
campo de dados ou um mtodo.
Um campo de dados ou um mtodo que seja
precedido pelo modificador private pode ser
acessado somente por mtodos que fazem
parte da mesma classe.
Um campo de dados ou um mtodo que seja
precedido pelo modificador public pode ser
acessado por mtodos de outras classes.
Classe modificada com o modificador
public indica que a classe visvel
externamente ao pacote em que ela foi
definida (classe AplicacaoBancaria,
package cap1).
Em cada arquivo de um programa Java s
pode existir uma classe modificada por
public, e o nome do arquivo deve ser o
mesmo dado classe.
Os campos de dados de uma classe so
geralmente feitos private e os mtodos so
tornados public.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 76

Modificadores de Acesso

Modificador protected: utilizado para permitir


que somente subclasses de uma classe mais
genrica possam acessar os campos de
dados precedidos com protected.

Um campo de dados ou um mtodo de uma


classe declarado como static pertence
classe e no s suas instncias, ou seja,
somente um campo de dados ou um mtodo
ser criado pelo compilador para todas as
instncias.

Os mtodos de uma classe que foram


declarados static operam somente sobre os
campos da classe que tambm foram
declarados static.

Se alm de static o mtodo for declarado


public ser possvel acess-lo com o nome
da classe e o operador (.).
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 77

Modificadores de Acesso

package cap1;
class A {
public static int total ;
public int media;
}
public class B {
public static void main ( String [ ] args ) {
A a = new A( ) ; a. total = 5; a.media = 5;
A b = new A( ) ; b. total = 7; b.media = 7;
}
}

No exemplo acima, o campo de dados total


pertence somente classe A, enquanto o
campo de dados media pertence a todas as
instncias da classe A.

Ao final da execuo do mtodo main, os


valores de a.total e b.total so iguais a 7,
enquanto os valores de a.media e b.media so
iguais a 5 e 7, respectivamente.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 78

Interfaces
Uma interface em Java uma classe
abstrata que no pode ser instanciada, cujos
os mtodos devem ser public e somente suas
assinaturas so definidas
Uma interface sempre implementada por
outras classes.
Utilizada para prover a especificao de um
comportamento que seja comum a um
conjunto de objetos.

package cap1;
import java . io . ;
public class Max {
public static Item max ( Item v [ ] , int n) {
Item max = v [ 0 ] ;
for ( int i = 1; i < n ; i ++)
i f (max.compara ( v [ i ] ) < 0 ) max = v [ i ] ;
return max;
}
}

O programa acima apresenta uma verso


generalizada do programa para obter o
mximo de um conjunto de inteiros.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 79

Interfaces
Para permitir a generalizao do tipo de
dados da chave necessrio criar a interface
Item que apresenta a assinatura do mtodo
abstrato compara.

package cap1;
public interface Item {
public int compara ( Item i t ) ;
}

A classe MeuItem, o tipo de dados da chave


definido e o mtodo compara implementado.

package cap1;
import java . io . ;
public class MeuItem implements Item {
public int chave;
/ / outros componentes do registro

public MeuItem ( int chave ) { this .chave = chave ; }


public int compara ( Item i t ) {
MeuItem item = (MeuItem) i t ;
i f ( this .chave < item .chave) return 1;
else i f ( this .chave > item .chave) return 1;
return 0;
}
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 80

Interfaces

package cap1;
public class EncontraMax {
public static void main ( String [ ] args ) {
MeuItem v [ ] = new MeuItem[ 2 ] ;
v[0] = new MeuItem ( 3 ) ; v[1] = new MeuItem (10);
MeuItem max = (MeuItem) Max.max ( v , 2 ) ;
System. out . println ( "Maior chave : " + max.chave) ;
}
}

O programa acima ilustra a utilizao do


mtodo compara apresentado.

Note que para atribuir a um objeto da classe


MeuItem o valor mximo retornado pelo
mtodo max necessrio fazer uma
converso do tipo Item para o tipo MeuItem,
conforme ilustra a penltima linha do mtodo
main.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 81

Pacotes
A linguagem Java permite agrupar as classes
e as interfaces em pacotes(do ingls,
package.
Convenientes para organizar e separar as
classes de um conjunto de programas de
outras bibliotecas de classes, evitando
colises entre nomes de classes
desenvolvidas por uma equipe composta por
muitos programadores.
Deve ser realizada sempre na primeira linha
do arquivo fonte, da seguinte forma por
exemplo:
package cap1;
possvel definir subpacotes separados por
".", por exemplo, para definir o subpacote
arranjo do pacote cap3 fazemos:
package cap3.arranjo;
A utilizao de uma classe definida em outro
pacote realizada atravs da palavra chave
import. O comando abaixo possibilita a
utilizao de todas as classes de um pacote:
import cap3.arranjo.*;
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 82

Pacotes

possvel utilizar determinada classe de um


pacote sem import-la, para isso basta
prefixar o nome da classe com o nome do
pacote durante a declarao de uma varivel.
Exemplo:
cap3.arranjo.Lista lista;

Para que uma classe possa ser importada em


um pacote diferente do que ela foi definida
preciso declar-la como pblica por meio do
modificador public.

Se o comando package no colocado no


cdigo fonte, ento Java adiciona as classes
daquele cdigo fonte no que chamado de
pacote default

Quando o modificador de um campo ou


mtodo no estabelecido, diz-se que o
campo ou mtodo possui visibilidade default,
ou seja, qualquer objeto de uma classe do
pacote pode acessar diretamente aquele
campo (ou mtodo).
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 83

Classes Internas
Java permite realizar aninhamento de classes
como abaixo:

package cap1;
public class Lista {
/ / Cdigo da classe Lista
private class Celula {
/ / Cdigo da classe Celula
}
}

Classes internas so muito teis para evitar


conflitos de nomes.
Os campos e mtodos declarados na classe
externa podem ser diretamente acessados
dentro da classe interna, mesmo os
declarados como protected ou private, mas
o contrrio no verdadeiro.
As classes externas s podem ser declaradas
como pblicas ou com visibilidade default.
As classes internas podem tambm ser
qualificadas com os modificadores private,
protected e static e o efeito mesmo obtido
sobre qualquer atributo da classe externa.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 84

O Objeto this

Toda instncia de uma classe possui uma


varivel especial chamada this, que contm
uma referncia para a prpria instncia.

Em algumas situaes resolve questes de


ambigidade.

package cap1;
public class Conta {
private double saldo ;
public void alteraSaldo (double saldo ) {
this . saldo = saldo ;
}
}

No exemplo acima, o parmetro saldo do


mtodo alteraSaldo possui o mesmo nome do
campo de instncia saldo da classe Conta.

Para diferenci-los necessrio qualificar o


campo da instncia com o objeto this.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 85

Excees
As excees so erros ou anomalias que
podem ocorrer durante a execuo de um
programa.
Deve ser obrigatoriamente representada por
um objeto de uma subclasse da classe
Throwable, que possui duas subclasses
diretas: (i) Exception e (ii) Error
Uma abordagem simples para tratar uma
exceo exibir uma mensagem relatando o
erro ocorrido e retornar para quem chamou
ou finalizar o programa, como no exemplo
abaixo:

int divisao ( int a, int b) {


try {
i f (b == 0) throw new Exception ( "Divisao por zero" ) ;
return (a/b) ;
}
catch ( Exception objeto ) {
System. out . println ( "Erro : " + objeto .getMessage( ) ) ;
return ( 0 ) ;
}
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 86

Excees

O comando try trata uma exceo que tenha


sido disparada em seu interior por um
comando throw

O comando throw instancia o objeto que


representa a exceo e o envia para ser
capturado pelo trecho de cdigo que vai tratar
a exceo.

O comando catch captura a exceo e


fornece o tratamento adequado.

Uma abordagem mais elaborada para tratar


uma exceo separar o local onde a
exceo tratada do local onde ela ocorreu.

Importante pelo fato de que um trecho de


cdigo em um nvel mais alto pode possuir
mais informao para decidir como melhor
tratar a exceo.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 87

Excees

No exemplo abaixo a exceo no tratada


no local onde ela ocorreu, e esse fato
explicitamente indicado pelo comando throws

int divisao ( int a, int b) throws {


i f (b == 0) throw new Exception ( "Divisao por zero" ) ;
return (a/b) ;
}

Considerando que o mtodo divisao est


inserido em uma classe chamada Divisao, o
trecho de cdigo abaixo ilustra como capturar
o objeto exceo que pode ser criado no
mtodo:
Divisao d = new Divisao ();
try {
d.divisao (3, 0);
}
catch(Exception objeto) {
System.out.println("Erro:"+objeto.getMessage());
}
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 88

Sada de Dados

Os tipos primitivos e objetos do tipo String


podem ser impressos com os comandos
System.out.print (var);
System.out.println (var);

O mtodo print deixa o cursor na mesma


linha e o mtodo println move o cursor para a
prxima linha de sada.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 89

Entrada de Dados
Todo programa em Java que tenha leitura de
dados tem de incluir o comando no incio do
programa
import java.io.*;
Mtodo para ler do teclado uma cadeia de
caracteres terminada com a tecla Enter:
public static String getString () throws
IOException {
InputStreamReader inputString = new
InputStreamReader (System.in);
BufferedReader buffer = new BufferedReader
(inputString);
String s = buffer.readLine (); return s;
}
Mtodo para realizar a entrada de um
caractere a partir do teclado:
public static char getChar () throws IOException {
String s = getString ();
return s.charAt (0);
}
Se o que est sendo lido de outro tipo,
ento necessrio realizar uma converso.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 90

Diferenas entre Java e C++

A maior diferena entre Java e C++ a


ausncia de apontadores em Java(no utiliza
apontadores explicitamente).

Java trata tipos de dados primitivos, tais como


int, double e float, de forma diferente do
tramento dado a objetos.

Em Java, uma referncia pode ser vista como


um apontador com a sintaxe de uma varivel.

A linguagem C++ tem variveis referncia,


mas elas tm de ser especificadas de forma
explcita com o smbolo &.

Outra diferena significativa est relacionada


com o operador de atribuio (=):
C++: aps a execuo de um comando
com operador (=), passam a existir dois
objetos com os mesmos dados estticos.
Java: aps a execuo de um comando
com operador (=), passam a existir duas
variveis que se referem ao mesmo objeto.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 91

Diferenas entre Java e C++

Em Java e em C++ os objetos so criados


utilizando o operador new, entretanto, em
Java o valor retornado uma referncia ao
objeto criado, enquanto em C++ o valor
retornado um apontador para o objeto
criado.

A eliminao de apontadores em Java tem


por objetivo tornar o software mais seguro,
uma vez que no possvel manipular o
endereo de conta1 , evitando que algum
possa acidentalmente corromper o endereo.

Em C++, a memria alocada pelo operador


new tem de ser liberada pelo programador
quando no mais necessria, utilizando o
operador delete.

Em Java, a liberao de memria realizada


pelo sistema de forma transparente para o
programador (coleta de lixo, do ingls
garbage collection).
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 92

Diferenas entre Java e C++


Em Java, os objetos so passados para
mtodos como referncias aos objetos
criados, entretanto, os tipos primitivos de
dados em Java so sempre passados por
valor
Em C++ uma passagem por referncia deve
ser especificada utilizando-se o &, caso
contrrio, temos uma passagem por valor.
No caso de tipos primitivos de dados, tanto
em Java quanto em C++ o operador de
igualdade (==) diz se duas variveis so
iguais.
No caso de objetos, em C++ o operador diz
se dois objetos contm o mesmo valor e em
Java o operador de igualdade diz se duas
referncias so iguais, isto , se apontam
para o mesmo objeto.
Em Java, para verificar se dois objetos
diferentes contm o mesmo valor
necessrio utilizar o mtodo equals da classe
Object (O programador deve realizar a
sobrescrita desse mtodo para estabelecer a
relao de igualdade).
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 93

Diferenas entre Java e C++

Em C++ possvel redefinir operadores


como +, , , =, de tal forma que eles se
comportem de maneira diferente para os
objetos de uma classe particular, mas em
Java, no existe sobrecarga de operadores.

Por questes de eficincia foram mantidos


diversos tipos primitivos de dados, assim
variveis declaradas como um tipo primitivo
em Java permitem acesso direto ao seu valor,
exatamente como ocorre em C++.

Em Java, o tipo boolean pode assumir os


valores false ou true enquanto em C++ os
valores inteiros 0 e 1

O tipo byteno existe em C++.

O tipo char em Java sem sinal e usa dois


bytes para acomodar a representao

O tipo Unicode de caracteres acomoda


caracteres internacionais de linguas tais
como chins e japons.
Projeto de Algoritmos Cap.1 Introduo Seo 1.5 94

Diferenas entre Java e C++

O tipo short tem tratamento parecido em


Java e C++.

Em Java, o tipo int tem sempre 32 bits,


enquanto em C++ de tamanho, dependendo
de cada arquitetura do computador onde vai
ser executado.

Em Java, o tipo float usa o sufixo F (por


exemplo, 2.357F) enquanto o tipo double no
necessita de sufixo.

Em Java, o tipo long usa o sufixo L (por


exemplo, 33L); quaisquer outros tipos inteiros
no necessitam de sufixo.
Paradigmas de Projeto
de Algoritmos

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Charles Ornelas, Leonardo Rocha, Leonardo


Mata e Nivio Ziviani
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos 1

Paradigmas de Projeto de Algoritmos

induo,

recursividade,

algoritmos tentativa e erro,

diviso e conquista,

balanceamento,

programao dinmica,

algoritmos gulosos,

algoritmos aproximados.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.1 2

Induo Matemtica
til para provar asseres sobre a correo
e a eficincia de algoritmos.
Consiste em inferir uma lei geral a partir de
instncias particulares.
Seja T um teorema que que tenha como
parmetro um nmero natural n. Para provar
que T vlido para todos os valores de n,
basta provarmos que:
1. T vlido para n = 1;
2. Para todo n > 1, se T vlido para n 1,
ento T vlido para n.
A condio 1 chamada de passo base.
Provar a condio 2 geralmente mais fcil
que provar o teorema diretamente, uma vez
que podemos usar a assero de que T
vlido para n 1.
Esta afirmativa chamada de hiptese de
induo ou passo indutivo
As condies 1 e 2 implicam T vlido para
n = 2, o que junto com a condio 2 implica T
tambm vlido para n = 3, e assim por diante.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.1 3

Exemplo de Induo Matemtica

S(n) = 1 + 2 + + n = n(n + 1)/2

Para n = 1 a assero verdadeira, pois


S(1) = 1 = 1 (1 + 1)/2 (passo base).

Assumimos que a soma dos primeiros n


nmeros naturais S(n) n(n + 1)/2 (hiptese
de induo).

Pela definio de S(n) sabemos que


S(n + 1) = S(n) + n + 1.

Usando a hiptese de induo,


S(n + 1) = n(n + 1)/2 + n + 1 = (n + 1)(n + 2)/2,
que exatamente o que queremos provar.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.1 4

Limite Superior de Equaes de


Recorrncia

A soluo de uma equao de recorrncia


pode ser difcil de ser obtida.

Nesses casos, pode ser mais fcil tentar


adivinhar a soluo ou chegar a um limite
superior para a ordem de complexidade.

Adivinhar a soluo funciona bem quando


estamos interessados apenas em um limite
superior, ao invs da soluo exata.

Mostrar que um limite existe mais fcil do


que obter o limite.

Ex.: T (2n) 2T (n) + 2n 1, T (2) = 1,


definida para valores de n que so potncias
de 2.
O objetivo encontrar um limite superior
na notao O, onde o lado direito da
desigualdade representa o pior caso.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.1 5

Induo Matemtica para Resolver


Equao de Recorrncia

T (2n) 2T (n) + 2n 1, T (2) = 1, definida para


valores de n que so potncias de 2.

Procuramos f (n) tal que T (n) = O(f (n)), mas


fazendo com que f (n) seja o mais prximo
possvel da soluo real para T (n).

Vamos considerar o palpite f (n) = n2 .

Queremos provar que T (n) = O(f (n))


utilizando induo matemtica em n.

Passo base: T (2) = 1 f (2) = 4.

Passo de induo: provar que T (n) f (n)


implica T (2n) f (2n).

T (2n) 2T (n) + 2n 1, (def. da recorrncia)


2n2 + 2n 1, (hiptese de induo)
< (2n)2 ,

que exatamente o que queremos provar.


Logo, T (n) = O(n2 ).
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.1 6

Induo Matemtica para Resolver


Equao de Recorrncia

Vamos tentar um palpite menor, f (n) = cn,


para alguma constante c.

Queremos provar que T (n) cn implica em


T (2n) c2n. Assim:

T (2n) 2T (n) + 2n 1, (def. da recorrncia)


2cn + 2n 1, (hiptese de induo)
> c2n.

cn cresce mais lentamente que T (n), pois


c2n = 2cn e no existe espao para o valor
2n 1.

Logo, T (n) est entre cn e n2 .


Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.1 7

Induo Matemtica para Resolver


Equao de Recorrncia

Vamos ento tentar f (n) = n log n.

Passo base: T (2) < 2 log 2.

Passo de induo: vamos assumir que


T (n) n log n.

Queremos mostrar que T (2n) 2n log 2n.


Assim:

T (2n) 2T (n) + 2n 1, (def. da recorrncia)


2n log n + 2n 1, (hiptese de induo)
< 2n log 2n,

A diferena entre as frmulas agora de


apenas 1.

De fato, T (n) = n log n n + 1 a soluo


exata de T (n) = 2T (n/2) + n 1, T (1) = 0,
que descreve o comportamento do algoritmo
de ordenao Mergesort.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2 8

Recursividade
Um mtodo que chama a si mesmo, direta ou
indiretamente, dito recursivo.
Recursividade permite descrever algoritmos
de forma mais clara e concisa, especialmente
problemas recursivos por natureza ou que
utilizam estruturas recursivas.
Ex.: rvore binria de pesquisa:
Todos os registros com chaves menores
esto na subrvore esquerda;
Todos os registros com chaves maiores
esto na subrvore direita.
5

3 7

2 4 6

package cap2;
public class ArvoreBinaria {
private static class No {
Object reg ;
No esq, dir ;
}
private No raiz ;
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2 9

Recursividade

Algoritmo para percorrer todos os registros


em ordem de caminhamento central:
1. caminha na subrvore esquerda na ordem
central;
2. visita a raiz;
3. caminha na subrvore direita na ordem
central.

No caminhamento central, os ns so
visitados em ordem lexicogrfica das chaves.

private void central (No p) {


i f (p ! = null ) {
central (p.esq) ;
System. out . println (p. reg . toString ( ) ) ;
central (p. dir ) ;
}
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.1 10

Implementao de Recursividade

Usa-se uma pilha para armazenar os dados


usados em cada chamada de um
procedimento que ainda no terminou.

Todos os dados no globais vo para a pilha,


registrando o estado corrente da computao.

Quando uma ativao anterior prossegue, os


dados da pilha so recuperados.

No caso do caminhamento central:


para cada chamada recursiva, o valor de p
e o endereo de retorno da chamada
recursiva so armazenados na pilha.
Quando encontra p=null o procedimento
retorna para quem chamou utilizando o
endereo de retorno que est no topo da
pilha.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.1 11

Problema de Terminao em
Procedimentos Recursivos

Procedimentos recursivos introduzem a


possibilidade de iteraes que podem no
terminar: existe a necessidade de considerar
o problema de terminao.

fundamental que a chamada recursiva a um


procedimento P esteja sujeita a uma
condio B, a qual se torna no-satisfeita em
algum momento da computao.

Esquema para procedimentos recursivos:


composio C de comandos Si e P .
P if B then C[Si , P ]

Para demonstrar que uma repetio termina,


define-se uma funo f (x), sendo x o
conjunto de variveis do programa, tal que:
1. f (x) 0 implica na condio de
terminao;
2. f (x) decrementada a cada iterao.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.1 12

Problema de Terminao em
Procedimentos Recursivos

Uma forma simples de garantir terminao


associar um parmetro n para P (no caso por
valor) e chamar P recursivamente com n 1.

A substituio da condio B por n > 0


garante terminao.
P if n > 0 then P[Si , P (n 1)]

necessrio mostrar que o nvel mais


profundo de recurso finito, e tambm
possa ser mantido pequeno, pois cada
ativao recursiva usa uma parcela de
memria para acomodar as variveis.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.2 13

Quando No Usar Recursividade

Nem todo problema de natureza recursiva


deve ser resolvido com um algoritmo
recursivo.

Estes podem ser caracterizados pelo


esquema P if B then (S, P )

Tais programas so facilmente transformveis


em uma verso no recursiva
P (x := x0 ; while B do S)
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.2 14

Exemplo de Quando No Usar


Recursividade
Clculo dos nmeros de Fibonacci
f0 = 0, f1 = 1,
fn = fn1 + fn2 paran 2
Soluo: fn = 15 [n ()n ], onde

= (1 + 5)/2 1, 618 a razo de ouro.
O procedimento recursivo obtido diretamente
da equao o seguinte:

package cap2;
public class Fibonacci {
public static int fibRec ( int n) {
i f (n < 2) return n;
else return ( fibRec ( n1) + fibRec ( n2));
}
}

O programa extremamente ineficiente


porque recalcula o mesmo valor vrias vezes.
Neste caso, a complexidade de espao para
calcular fn O(n ).
Considerando que a complexidade de tempo
f (n) o nmero de adies, f (n) = O(n ).
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.2 15

Verso iterativa do Clculo de


Fibonacci

package cap2;
public class Fibonacci {
public static int f i b I t e r ( int n) {
int i = 1 , f = 0;
for ( int k = 1; k <= n ; k++) {
f = i + f;
i = f i;
}
return f ;
}
}

O programa tem complexidade de tempo


O(n) e complexidade de espao O(1).
Devemos evitar uso de recursividade quando
existe uma soluo bvia por iterao.
Comparao verses recursiva e iterativa:
n 10 20 30 50 100
fibRec 8 ms 1s 2 min 21 dias 109 anos
fibIter 1/6 ms 1/3 ms 1/2 ms 3/4 ms 1,5 ms
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3 16

Algoritmos Tentativa e Erro


(Backtracking)
Tentativa e erro: decompor o processo em
um nmero finito de subtarefas parciais que
devem ser exploradas exaustivamente.
O processo de tentativa gradualmente
constri e percorre uma rvore de subtarefas.

Algoritmos tentativa e erro no seguem regra


fixa de computao:
Passos em direo soluo final so
tentados e registrados;
Caso esses passos tomados no levem
soluo final, eles podem ser retirados e
apagados do registro.
Quando a pesquisa na rvore de solues
cresce rapidamente necessrio usar
algoritmos aproximados ou heursticas que
no garantem a soluo tima mas so
rpidos.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3 17

Backtracking: Passeio do Cavalo

Tabuleiro com n n posies: cavalo


movimenta-se segundo as regras do xadrez.

Problema: a partir de (x0 , y0 ), encontrar, se


existir, um passeio do cavalo que visita todos
os pontos do tabuleiro uma nica vez.

Tenta um prximo movimento:

void tenta ( ) {
inicializa seleo de movimentos ;
do {
seleciona prximo candidato ao movimento ;
i f ( aceitvel ) {
registra movimento ;
i f ( tabuleiro no est cheio ) {
tenta novo movimento ; / / Chamada recursiva
para tenta
i f ( no sucedido ) apaga registro anterior ;
}
}
} while ( movimento no sucedido e no acabaram can-
didatos a movimento ) ;
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3 18

Exemplo de Backtracking - Passeio do


Cavalo

O tabuleiro pode ser representado por uma


matriz n n.

A situao de cada posio pode ser


representada por um inteiro para recordar o
histrico das ocupaes:
t[x,y] = 0, campo < x, y > no visitado,
t[x,y] = i, campo < x, y > visitado no
i-simo movimento, 1 i n2 .

Regras do xadrez para os movimentos do


cavalo:
3 2

4 1

5 8

6 7
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3 19

Implementao do Passeio do Cavalo

package cap2;
public class PasseioCavalo {
private int n ; / / Tamanho do lado do tabuleiro
private int a [ ] , b [ ] , t [ ] [ ] ;

public PasseioCavalo ( int n) {


this .n = n;
this . t = new int [n ] [ n ] ; this .a = new int [n ] ;
this .b = new int [n ] ;
a[ 0 ] = 2 ; a[ 1 ] = 1 ; a[2] =1; a[3] =2;
b[ 0 ] = 1 ; b[ 1 ] = 2 ; b[ 2 ] = 2 ; b[3] = 1;
a[4] = 2; a[5] = 1; a[ 6 ] = 1 ; a[7] = 2;
b[4] = 1; b[5] = 2; b[6] =2; b[7] = 1;
for ( int i = 0; i < n ; i ++)
for ( int j = 0; j < n ; j ++) t [ i ] [ j ] = 0;
t [ 0 ] [ 0 ] = 1 ; / / escolhemos uma casa do tabuleiro
}
/ / { Entra aqui os mtodos tenta, imprimePasseio e main mos-
trados a seguir }
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3 20

Implementao do Passeio do Cavalo

public boolean tenta ( int i , int x , int y ) {


int u, v , k ; boolean q;
k = 1; / / inicializa seleo de movimentos
do {
k = k + 1; q = false ;
u = x + a[ k ] ; v = y + b[ k ] ;
/ Teste para verificar se os limites do tabuleiro
sero respeitados. /
i f ( (u >= 0) && (u <= 7) && (v >= 0) && (v <= 7))
i f ( t [u ] [ v] == 0) {
t [u ] [ v ] = i ;
i f ( i < n n ) { / / tabuleiro no est cheio
q = tenta ( i +1, u, v ) ; / / tenta novo movimento
i f ( ! q) t [u ] [ v ] = 0 ; / / no sucedido apaga reg.
anterior
}
else q = true ;
}
} while ( ! q && (k ! = 7 ) ) ; / / no h casas a visitar a par-
tir de x,y
return q;
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3 21

Implementao do Passeio do Cavalo

public void imprimePasseio ( ) {


for ( int i = 0; i < n ; i ++) {
for ( int j = 0; j < n ; j ++)
System. out . print ( " \ t " +this . t [ i ] [ j ] ) ;
System. out . println ( ) ;
}
}
public static void main ( String [ ] args ) {
PasseioCavalo passeioCavalo = new PasseioCavalo ( 8 ) ;
boolean q = passeioCavalo. tenta (2 , 0 , 0);
i f (q) passeioCavalo.imprimePasseio ( ) ;
else System. out . println ( "Sem solucao" ) ;
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 22

Diviso e Conquista

Consiste em dividir o problema em partes


menores, encontrar solues para as partes,
e combin-las em uma soluo global.

Exemplo: encontrar o maior e o menor


elemento de um vetor de inteiros, v [0..n 1],
n 1,. Algoritmo na prxima pgina.

Cada chamada de maxMin4 atribui


maxMin[0] e maxMin[1] o maior e o menor
elemento em v [linf ], v [linf + 1], . . . , v [lsup],
respectivamente.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 23

Diviso e Conquista

package cap2;
public class MaxMin4 {
public static int [ ] maxMin4( int v [ ] , int l i n f , int lsup ) {
int maxMin[ ] = new int [ 2 ] ;
i f ( lsup l i n f <= 1) {
i f ( v [ l i n f ] < v [ lsup ] ) {
maxMin[0] = v [ lsup ] ; maxMin[1] = v [ l i n f ] ;
}
else {
maxMin[0] = v [ l i n f ] ; maxMin[1] = v [ lsup ] ;
}
}
else {
int meio = ( l i n f + lsup ) / 2 ;
maxMin = maxMin4 ( v , l i n f , meio) ;
int max1 = maxMin[ 0 ] , min1 = maxMin[ 1 ] ;
maxMin = maxMin4 ( v , meio + 1 , lsup ) ;
int max2 = maxMin[ 0 ] , min2 = maxMin[ 1 ] ;
i f (max1 > max2) maxMin[0] = max1;
else maxMin[0] = max2;
i f (min1 < min2) maxMin[1] = min1;
else maxMin[1] = min2;
}
return maxMin;
}
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 24

Diviso e Conquista - Anlise do


Exemplo
Seja T (n) uma funo de complexidade tal
que T (n) o nmero de comparaes entre
os elementos de v , se v contiver n elementos.

T (n) = 1, para n 2,
T (n) = T (bn/2c) + T (dn/2e) + 2, para n > 2.

Quando n = 2i para algum inteiro positivo i:

T (n) = 2T (n/2) + 2
2T (n/2) = 4T (n/4) + 2 2
4T (n/4) = 8T (n/8) + 2 2 2
.. ..
. .
2i2 T (n/2i2 ) = 2i1 T (n/2i1 ) + 2i1

Adicionando lado a lado, obtemos:


Pi1
T (n) = 2i1 T (n/2i1 ) + k=1 2k
=
3n
= 2i1 T (2) + 2i 2 = 2i1 + 2i 2 = 2
2.

Logo, T (n) = 3n/2 2 para o melhor caso, o


pior caso e o caso mdio.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 25

Diviso e Conquista - Anlise do


Exemplo

Conforme o Teorema da pgina 10 do livro, o


algoritmo anterior timo.

Entretanto, ele pode ser pior do que os


apresentados no Captulo 1, pois, a cada
chamada do mtodo salva os valores de linf ,
lsup, maxMin[0] e maxMin[1], alm do
endereo de retorno dessa chamada.

Alm disso, uma comparao adicional


necessria a cada chamada recursiva para
verificar se lsup linf 1.

n deve ser menor do que a metade do maior


inteiro que pode ser representado pelo
compilador, para no provocar overflow na
operao linf + lsup.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 26

Diviso e Conquista - Teorema Mestre


Teorema Mestre: Sejam a 1 e b > 1
constantes, f (n) uma funo
assintoticamente positiva e T (n) uma medida
de complexidade definida sobre os inteiros. A
soluo da equao de recorrncia:

T (n) = aT (n/b) + f (n),

para b uma potncia de n :


1. T (n) = (nlogb a ), se f (n) = O(nlogb a )
para alguma constante  > 0,
2. T (n) = (nlogb a log n), se f (n) = (nlogb a ),
3. T (n) = (f (n)), se f (n) = (nlogb a+ ) para
alguma constante  > 0, e se
af (n/b) cf (n) para alguma constante
c < 1 e todo n a partir de um valor
suficientemente grande.
O problema dividido em a subproblemas de
tamanho n/b cada um sendo resolvidos
recursivamente em tempo T (n/b) cada.
A funo f (n) descreve o custo de dividir o
problema em subproblemas e de combinar os
resultados de cada subproblema.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 27

Diviso e Conquista - Teorema Mestre


A prova desse teorema no precisa ser
entendida para ele ser aplicado.
Em cada um dos trs casos a funo f (n)
comparada com a funo nlogb a e a soluo
de T (n) determinada pela maior dessas
duas funes.
No caso 1, f (n) tem de ser
polinomialmente menor do que nlogb a .
No caso 2, se as duas funes so iguais,
ento
T (n) = (nlogb a log n) = (f (n) log n).
No caso 3, f (n) tem de ser
polinomialmente maior do que nlogb a e,
alm disso, satisfazer a condio de que
af (n/b) cf (n).
Ele no pode ser aplicado nas aplicaes que
ficam entre os casos 1 e 2 (quando f (n)
menor do que nlogb a , mas no
polinomialmente menor), entre os casos 2 e 3
(quando f (n) maior do que nlogb a , mas no
polinomialmente maior) ou quando a
condio af (n/b) cf (n) no satisfeita.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4 28

Diviso e Conquista - Exemplo do Uso


do Teorema Mestre

Considere a equao de recorrncia:

T (n) = 4T (n/2) + n,

onde a = 4, b = 2, f (n) = n e
nlogb a = nlog2 4 = (n2 ).

O caso 1 se aplica porque


f (n) = O(nlogb a ) = O(n), onde  = 1, e a
soluo T (n) = (n2 ).
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.5 29

Balanceamento

No projeto de algoritmos, importante


procurar sempre manter o balanceamento
na subdiviso de um problema em partes
menores.

Diviso e conquista no a nica tcnica em


que balanceamento til.

Vamos considerar um exemplo de ordenao

Seleciona o menor elemento do conjunto


v [0..n 1] e ento troca este elemento com o
primeiro elemento v [0].

Repete o processo com os n 1 elementos,


resultando no segundo maior elemento, o
qual trocado com o segundo elemento v [1].

Repetindo para n 2, n 3, . . ., 2 ordena a


seqncia.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.5 30

Balanceamento - Anlise do Exemplo


O algoritmo leva equao de recorrncia:
T (n) = T (n 1) + n 1, T (1) = 0, para o
nmero de comparaes entre elementos.
Substituindo:

T (n) = T (n 1) + n 1
T (n 1) = T (n 2) + n 2
.. ..
. .
T (2) = T (1) + 1

Adicionando lado a lado, obtemos:


n(n1)
T (n) = T (1) + 1 + 2 + + n 1 = 2

Logo, o algorimo O(n2 ).
Embora o algoritmo possa ser visto como
uma aplicao recursiva de diviso e
conquista, ele no eficiente para valores
grandes de n.
Para obter eficincia assinttica necessrio
balanceamento: dividir em dois
subproblemas de tamanhos
aproximadamente iguais, ao invs de um de
tamanho 1 e o outro de tamanho n 1.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.5 31

Exemplo de Balanceamento -
Mergesort

Intercalao: unir dois arquivos ordenados


gerando um terceiro ordenado (merge).
Colocar no terceiro arquivo o menor elemento
entre os menores dos dois arquivos iniciais,
desconsiderando este mesmo elemento nos
passos posteriores.
Este processo deve ser repetido at que
todos os elementos dos arquivos de entrada
sejam escolhidos.
Algoritmo de ordenao (Mergesort):
dividir recursivamente o vetor a ser
ordenado em dois, at obter n vetores de 1
nico elemento.
Aplicar a intercalao tendo como entrada
2 vetores de um elemento, formando um
vetor ordenado de dois elementos.
Repetir este processo formando vetores
ordenados cada vez maiores at que todo
o vetor esteja ordenado.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.5 32

Exemplo de Balanceamento -
Implementao do Mergesort

package cap2;
public class Ordenacao {
public static void mergeSort ( int v [ ] , int i , int j ) {
if ( i < j ) {
int m = ( i + j ) / 2 ;
mergeSort ( v , i , m) ; mergeSort ( v , m + 1 , j ) ;
merge ( v , i , m, j ) ; / / Intercala v[i..m] e v[m+1..j] em
v[i..j]
}
}
}

Considere n como sendo uma potncia de 2.


merge(v, i, m, j), recebe duas seqncias
ordenadas v [i..m] e v [m + 1..j] e produz uma
outra seqncia ordenada dos elementos de
v [i..m] e v [m + 1..j].
Como v [i..m] e v [m + 1..j] esto ordenados,
merge requer no mximo n 1 comparaes.
merge seleciona repetidamente o menor
dentre os menores elementos restantes em
v [i..m] e v [m + 1..j]. Caso empate, retira de
qualquer uma delas.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.5 33

Anlise do Mergesort
Na contagem de comparaes, o
comportamento do Mergesort pode ser
representado por:
T (n) = 2T (n/2) + n 1, T (1) = 0
No caso da equao acima temos:

T (n) = 2T (n/2) + n 1
n
2T (n/2) = 22 T (n/22 ) + 2 2 1
2
.. ..
. .
i1 i1 i i i1 n i1
2 T (n/2 ) = 2 T (n/2 ) + 2 2
2i1
Adicionando lado a lado:
i1 i1
T (n) = 2i T (n/2i ) + 2k
X X
n
k=0 k=0
2i1+1 1
= in
21
= n log n n + 1.

Logo, o algoritmo O(n log n).


Para valores grandes de n, o balanceamento
levou a um resultado muito superior, samos
de O(n2 ) para O(n log n).
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 34

Programao Dinmica

Quando a soma dos tamanhos dos


subproblemas O(n) ento provvel que o
algoritmo recursivo tenha complexidade
polinomial.

Quando a diviso de um problema de


tamanho n resulta em n subproblemas de
tamanho n 1 ento provvel que o
algoritmo recursivo tenha complexidade
exponencial.

Nesse caso, a tcnica de programao


dinmica pode levar a um algoritmo mais
eficiente.

A programao dinmica calcula a soluo


para todos os subproblemas, partindo dos
subproblemas menores para os maiores,
armazenando os resultados em uma tabela.

A vantagem que uma vez que um


subproblema resolvido, a resposta
armazenada em uma tabela e nunca mais
recalculado.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 35

Programao Dinmica - Exemplo

Produto de n matrizes

M = M1 M2 Mn , onde cada Mi
uma matriz com di1 linhas e di colunas.

A ordem da multiplicao pode ter um efeito


enorme no nmero total de operaes de
adio e multiplicao necessrias para obter
M.

Considere o produto de uma matriz p q por


outra matriz q r cujo algoritmo requer
O(pqr) operaes.

Considere o produto M =
M1 [10, 20] M2 [20, 50] M3 [50, 1] M4 [1, 100],
onde as dimenses de cada matriz est
mostrada entre colchetes.

A avaliao de M na ordem
M = M1 (M2 (M3 M4 )) requer 125.000
operaes, enquanto na ordem
M = (M1 (M2 M3 )) M4 requer apenas
2.200.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 36

Programao Dinmica - Exemplo


Tentar todas as ordens possveis para
minimizar o nmero de operaes f (n)
exponencial em n, onde f (n) 2n2 .
Usando programao dinmica possvel
obter um algoritmo O(n3 ).
Seja mij menor custo para computar
Mi Mi+1 Mj , para 1 i j n.
Neste caso,

0,

se i = j,
mij =
Minik<j (mik + mk+1,j + di1 dk dj ), se j > i.

mik representa o custo mnimo para calcular


M 0 = Mi Mi+1 Mk
mk+1,j representa o custo mnimo para
calcular M 00 = Mk+1 Mk+2 Mj .
di1 dk dj representa o custo de multiplicar
M 0 [di1 , dk ] por M 00 [dk , dj ].
mij , j > i representa o custo mnimo de
todos os valores possveis de k entre i e
j 1, da soma dos trs termos.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 37

Programao Dinmica - Exemplo

O enfoque programao dinmica calcula os


valores de mij na ordem crescente das
diferenas nos subscritos.

O calculo inicia com mii para todo i, depois


mi,i+1 para todo i, depois mi,i+2 , e assim
sucessivamente.

Desta forma, os valores mik e mk+1,j estaro


disponveis no momento de calcular mij .

Isto acontece porque j i tem que ser


estritamente maior do que ambos os valores
de k i e j (k + 1) se k estiver no intervalo
i k < j.

Programa para computar a ordem de


multiplicao de n matrizes,
M1 M2 Mn , de forma a obter o
menor nmero possvel de operaes.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 38

Programao Dinmica -
Implementao

package cap2;
import java . io . ;
public class AvaliaMultMatrizes {
public static void main( String [ ] args)throws IOException {
int n, maxn = Integer . parseInt ( args [ 0 ] ) ;
int d[ ] = new int [maxn + 1];
int m[ ] [ ] = new int [maxn] [maxn] ;
BufferedReader in = new BufferedReader (
new InputStreamReader (System. in ) ) ;
System. out . print ( "Numero de matrizes n: " ) ;
n = Integer . parseInt ( in . readLine ( ) ) ;
System. out . println ( "Dimensoes das matrizes : " ) ;
for ( int i = 0; i <= n ; i ++) {
System. out . print ( " d[ "+i+" ] = " ) ;
d[ i ] = Integer . parseInt ( in . readLine ( ) ) ;
}
/ / Continua na prxima transparncia...
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 39

Programao Dinmica - Continuao


da Implementao

for ( int i = 0; i < n ; i ++) m[ i ] [ i ] = 0;


for ( int h = 1; h < n ; h++) {
for ( int i = 1; i <= n h ; i ++) {
int j = i + h;
m[ i 1][ j 1] = Integer .MAX_VALUE;
for ( int k = i ; k < j ; k++) {
int temp = m[ i 1][k1] + m[ k ] [ j 1] +
+ d[ i 1] d[ k ] d[ j ] ;
i f (temp < m[ i 1][ j 1]) m[ i 1][ j 1] = temp;
}
System. out . print ( " m[ " + i+" ] [ "+j+" ]= " + m[ i 1][ j 1]);
}
System. out . println ( ) ;
}
}
}
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 40

Programao Dinmica -
Implementao

A execuo do programa obtm o custo


mnimo para multiplicar as n matrizes,
assumindo que so necessrias pqr
operaes para multiplicar uma matriz p q
por outra matriz q r.

A execuo do programa para as quatro


matrizes onde d0 , d1 , d2 , d3 , d4 so 10, 20, 50,
1, 100, resulta:

m11 = 0 m22 = 0 m33 = 0 m44 = 0


m12 = 10.000 m23 = 1.000 m34 = 5.000
m13 = 1.200 m24 = 3.000
m14 = 2.200
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 41

Programao Dinmica - Princpio da


Otimalidade

A ordem de multiplicao pode ser obtida


registrando o valor de k para cada entrada da
tabela que resultou no mnimo.

Essa soluo eficiente est baseada no


princpio da otimalidade:
em uma seqncia tima de escolhas ou
de decises cada subseqncia deve
tambm ser tima.

Cada subseqncia representa o custo


mnimo, assim como mij , j > i.

Assim, todos os valores da tabela


representam escolhas timas.

O princpio da otimalidade no pode ser


aplicado indiscriminadamente.

Quando o princpio no se aplica provvel


que no se possa resolver o problema com
sucesso por meio de programao dinmica.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 42

Aplicao do Princpio da Otimalidade

Por exemplo, quando o problema utiliza


recursos limitados, quando o total de recursos
usados nas subinstncias maior do que os
recursos disponveis.

Se o caminho mais curto entre Belo Horizonte


e Curitiba passa por Campinas:
o caminho entre Belo Horizonte e
Campinas tambm o mais curto possvel
assim como o caminho entre Campinas e
Curitiba.
Logo, o princpio da otimalidade se aplica.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6 43

No Aplicao do Princpio da
Otimalidade

No problema de encontrar o caminho mais


longo entre duas cidades:
Um caminho simples nunca visita uma
mesma cidade duas vezes.
Se o caminho mais longo entre Belo
Horizonte e Curitiba passa por Campinas,
isso no significa que o caminho possa ser
obtido tomando o caminho simples mais
longo entre Belo Horizonte e Campinas e
depois o caminho simples mais longo
entre Campinas e Curitiba.
Quando os dois caminhos simples so
ajuntados pouco provvel que o caminho
resultante tambm seja simples.
Logo, o princpio da otimalidade no se
aplica.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.7 44

Algoritmos Gulosos

Resolve problemas de otimizao.

Exemplo: algoritmo para encontrar o caminho


mais curto entre dois vrtices de um grafo.
Escolhe a aresta que parece mais
promissora em qualquer instante;
Independente do que possa acontecer
mais tarde, nunca reconsidera a deciso.

No necessita avaliar alternativas, ou usar


procedimentos sofisticados para desfazer
decises tomadas previamente.

Problema geral: dado um conjunto C,


determine um subconjunto S C tal que:
S satisfaz uma dada propriedade P , e
S mnimo (ou mximo) em relao a
algum critrio .

O algoritmo guloso para resolver o problema


geral consiste em um processo iterativo em
que S construdo adicionando-se ao mesmo
elementos de C um a um.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.7 45

Caractersticas dos Algoritmos


Gulosos

Para construir a soluo tima existe um


conjunto ou lista de candidatos.

So acumulados um conjunto de candidatos


considerados e escolhidos, e o outro de
candidatos considerados e rejeitados.

Existe funo que verifica se um conjunto


particular de candidatos produz uma soluo
(sem considerar otimalidade no momento).

Outra funo verifica se um conjunto de


candidatos vivel (tambm sem preocupar
com a otimalidade).

Uma funo de seleo indica a qualquer


momento quais dos candidatos restantes o
mais promissor.

Uma funo objetivo fornece o valor da


soluo encontrada, como o comprimento do
caminho construdo (no aparece de forma
explicita no algoritmo guloso).
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.7 46

Pseudo Cdigo de Algoritmo Guloso

Conjunto guloso ( Conjunto C) { / C: conjunto de candidatos /


S = ; / S contm conjunto soluo /
while ( (C 6= ) && not soluo(S) ) {
x = seleciona (C) ;
C = C x;
i f ( vivel (S + x ) ) S = S + x ;
}
i f ( soluo (S) )
return S else return ( "No existe soluo" ) ;
}

Inicialmente, o conjunto S de candidatos


escolhidos est vazio.
A cada passo, o melhor candidato restante
ainda no tentado considerado. O critrio
de escolha ditado pela funo de seleo.
Se o conjunto aumentado de candidatos se
torna invivel, o candidato rejeitado. Seno,
o candidato adicionado ao conjunto S de
candidatos escolhidos.
A cada aumento de S verificamos se S
constitui uma soluo tima.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.7 47

Caractersticas da Implementao de
Algoritmos Gulosos

Quando funciona corretamente, a primeira


soluo encontrada sempre tima.

A funo de seleo geralmente


relacionada com a funo objetivo.

Se o objetivo :
maximizar provavelmente escolher o
candidato restante que proporcione o
maior ganho individual.
minimizar ento ser escolhido o
candidato restante de menor custo.

O algoritmo nunca muda de idia:


Uma vez que um candidato escolhido e
adicionado soluo ele l permanece
para sempre.
Uma vez que um candidato excludo do
conjunto soluo, ele nunca mais
reconsiderado.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.8 48

Algoritmos Aproximados

Problemas que somente possuem algoritmos


exponenciais para resolv-los so
considerados difceis.

Problemas considerados intratveis ou


difceis so muito comuns.

Exemplo: problema do caixeiro viajante


cuja complexidade de tempo O(n!).

Diante de um problema difcil comum


remover a exigncia de que o algoritmo tenha
sempre que obter a soluo tima.

Neste caso procuramos por algoritmos


eficientes que no garantem obter a soluo
tima, mas uma que seja a mais prxima
possvel da soluo tima.
Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.8 49

Tipos de Algoritmos Aproximados

Heurstica: um algoritmo que pode produzir


um bom resultado, ou at mesmo obter a
soluo tima, mas pode tambm no
produzir soluo alguma ou uma soluo que
est distante da soluo tima.

Algoritmo aproximado: um algoritmo que


gera solues aproximadas dentro de um
limite para a razo entre a soluo tima e a
produzida pelo algoritmo aproximado
(comportamento monitorado sob o ponto de
vista da qualidade dos resultados).
Estruturas de Dados
Bsicas

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Charles Ornelas, Leonardo Rocha, Leonardo


Mata e Nivio Ziviani
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1 1

Listas Lineares

Uma das formas mais simples de interligar os


elementos de um conjunto.

Estrutura em que as operaes inserir, retirar


e localizar so definidas.

Podem crescer ou diminuir de tamanho


durante a execuo de um programa, de
acordo com a demanda.

Itens podem ser acessados, inseridos ou


retirados de uma lista.

Duas listas podem ser concatenadas para


formar uma lista nica, ou uma pode ser
partida em duas ou mais listas.

Adequadas quando no possvel prever a


demanda por memria, permitindo a
manipulao de quantidades imprevisveis de
dados, de formato tambm imprevisvel.

So teis em aplicaes tais como


manipulao simblica, gerncia de memria,
simulao e compiladores.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1 2

Definio de Listas Lineares

Seqncia de zero ou mais itens


x1 , x2 , , xn , na qual xi de um determinado
tipo e n representa o tamanho da lista linear.

Sua principal propriedade estrutural envolve


as posies relativas dos itens em uma
dimenso.
Assumindo n 1, x1 o primeiro item da
lista e xn o ltimo item da lista.
xi precede xi+1 para i = 1, 2, , n 1
xi sucede xi1 para i = 2, 3, , n
o elemento xi dito estar na i-sima
posio da lista.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1 3

TAD Listas Lineares


O conjunto de operaes a ser definido
depende de cada aplicao.
Um conjunto de operaes necessrio a uma
maioria de aplicaes :
1. Criar uma lista linear vazia.
2. Inserir um novo item imediatamente aps
o i-simo item.
3. Retirar o i-simo item.
4. Localizar o i-simo item para examinar
e/ou alterar o contedo de seus
componentes.
5. Combinar duas ou mais listas lineares em
uma lista nica.
6. Partir uma lista linear em duas ou mais
listas.
7. Fazer uma cpia da lista linear.
8. Ordenar os itens da lista em ordem
ascendente ou descendente, de acordo
com alguns de seus componentes.
9. Pesquisar a ocorrncia de um item com
um valor particular em algum componente.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1 4

Implementaes de Listas Lineares

Vrias estruturas de dados podem ser usadas


para representar listas lineares, cada uma
com vantagens e desvantagens particulares.

As duas representaes mais utilizadas so


as implementaes por meio de arranjos e de
estruturas auto-referenciadas.

Exemplo de Conjunto de Operaes:


1. Lista(maxTam). Cria uma lista vazia.
2. insere(x). Insere x aps o ltimo item da
lista.
3. retira(x). Retorna o item x que est na
posio p da lista, retirando-o da lista e
deslocando os itens a partir da posio
p+1 para as posies anteriores.
4. vazia(). Esta funo retorna true se lista
vazia; seno retorna false.
5. imprime(). Imprime os itens da lista na
ordem de ocorrncia.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.1 5

Implementao de Listas por meio de


Arranjos
Os itens da lista so armazenados em
posies contguas de memria.
A lista pode ser percorrida em qualquer
direo.
A insero de um novo item pode ser
realizada aps o ltimo item com custo
constante.
A insero de um novo item no meio da lista
requer um deslocamento de todos os itens
localizados aps o ponto de insero.
Retirar um item do incio da lista requer um
deslocamento de itens para preencher o
espao deixado vazio.
Itens
primeiro = 0 x1
1 x2
..
.
ltimo 1 xn
..
.
maxTam 1
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.1 6

Estrutura da Lista Usando Arranjo

Os itens so armazenados em um arranjo de


tamanho suficiente para armazenar a lista.

O campo ltimo referencia para a posio


seguinte a do ltimo elemento da lista.

O i-simo item da lista est armazenado na


i-sima posio do arranjo, 1 i <ltimo.

A constante MaxTam define o tamanho


mximo permitido para a lista.

package cap3. arranjo ;


public class Lista {
private Object item [ ] ;
private int primeiro , ultimo , pos;
/ / Operaes
public Lista ( int maxTam) { / / Cria uma Lista vazia
this . item = new Object [maxTam] ; this .pos = 1;
this . primeiro = 0; this . ultimo = this . primeiro ;
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.1 7

Operaes sobre Lista Usando Arranjo

public Object pesquisa ( Object chave) {


i f ( this . vazia ( ) | | chave == null ) return null ;
for ( int p = 0; p < this . ultimo ; p++)
i f ( this . item [p ] . equals (chave) ) return this . item [p ] ;
return null ;
}
public void insere ( Object x ) throws Exception {
i f ( this . ultimo >= this . item . length )
throw new Exception ( "Erro : A l i s t a esta cheia" ) ;
else { this . item [ this . ultimo ] = x ;
this . ultimo = this . ultimo + 1 ; }
}
public Object retira ( Object chave) throws Exception {
i f ( this . vazia ( ) | | chave == null )
throw new Exception ( "Erro : A l i s t a esta vazia" ) ;
int p = 0;
while(p < this . ultimo && !this . item [p ] . equals(chave) )p++;
i f (p >= this . ultimo ) return null ; / / Chave no en-
contrada
Object item = this . item [p ] ;
this . ultimo = this . ultimo 1;
for ( int aux = p ; aux < this . ultimo ; aux++)
this . item [aux] = this . item [aux + 1];
return item ;
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.1 8

Operaes sobre Lista Usando Arranjo

public Object retiraPrimeiro ( ) throws Exception {


i f ( this . vazia ( ) ) throw new Exception
( "Erro : A l i s t a esta vazia" ) ;
Object item = this . item [ 0 ] ;
this . ultimo = this . ultimo 1;
for ( int aux = 0; aux < this . ultimo ; aux++)
this . item [aux] = this . item [aux + 1];
return item ;
}
public Object primeiro ( ) {
this .pos = 1; return this .proximo ( ) ; }
public Object proximo ( ) {
this .pos++;
i f ( this .pos >= this . ultimo ) return null ;
else return this . item [ this .pos ] ;
}
public boolean vazia ( ) {
return ( this . primeiro == this . ultimo ) ; }
public void imprime ( ) {
for ( int aux = this . primeiro ; aux < this . ultimo ; aux++)
System. out . println ( this . item [aux ] . toString ( ) ) ;
}
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.1 9

Lista Usando Arranjo - Vantagens e


Desvantagens

Vantagem: economia de memria (os


apontadores so implcitos nesta estrutura).

Desvantagens:
custo para inserir ou retirar itens da lista,
que pode causar um deslocamento de
todos os itens, no pior caso;
em aplicaes em que no existe previso
sobre o crescimento da lista, a utilizao
de arranjos exigir a realocao de
memria.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 10

Implementao de Listas por meio de


Estruturas Auto-Referenciadas

Cada item da lista contm a informao que


necessria para alcanar o prximo item.

Permite utilizar posies no contguas de


memria.

possvel inserir e retirar elementos sem


necessidade de deslocar os itens seguintes
da lista.

H uma clula cabea para simplificar as


operaes sobre a lista.

Lista x1 ... xn nil


Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 11

Implementao de Listas por meio de


Estruturas Auto-Referenciadas

A lista constituda de clulas.

Cada clula contm um item da lista e uma


referncia para a clula seguinte.

A classe Lista contm uma referncia para a


clula cabea, uma referncia para a ltima
clula da lista e uma referncia para
armazenar a posio corrente na lista.

package cap3. autoreferencia ;


public class Lista {
private static class Celula { Object item ; Celula prox ; }
private Celula primeiro , ultimo , pos;
/ / Operaes
public Lista ( ) { / / Cria uma Lista vazia
this . primeiro = new Celula ( ) ; this .pos = this . primeiro ;
this . ultimo = this . primeiro ; this . primeiro . prox = null ;
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 12

Lista Usando Estruturas


Auto-Referenciadas

public Object pesquisa ( Object chave) {


i f ( this . vazia ( ) | | chave == null ) return null ;
Celula aux = this . primeiro ;
while (aux. prox ! = null ) {
i f (aux. prox . item . equals (chave) ) return aux. prox . item ;
aux = aux. prox ;
} return null ;
}
public void insere ( Object x ) {
this . ultimo . prox = new Celula ( ) ;
this . ultimo = this . ultimo . prox ;
this . ultimo . item = x ; this . ultimo . prox = null ;
}
public Object retira ( Object chave) throws Exception {
i f ( this . vazia ( ) | | ( chave == null ) )
throw new Exception
( "Erro : Lista vazia ou chave invalida " ) ;
Celula aux = this . primeiro ;
while (aux. prox!=null && !aux. prox . item . equals(chave) )
aux=aux. prox ;
i f (aux. prox == null ) return null ; / / no encontrada
Celula q = aux. prox ;
Object item = q. item ; aux. prox = q. prox ;
i f (aux. prox == null ) this . ultimo = aux ; return item ;
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 13

Lista Usando Estruturas


Auto-Referenciadas

public Object retiraPrimeiro ( ) throws Exception {


i f ( this . vazia ( ) ) throw new Exception
( "Erro : Lista vazia" ) ;
Celula aux = this . primeiro ; Celula q = aux. prox ;
Object item = q. item ; aux. prox = q. prox ;
i f (aux. prox == null ) this . ultimo = aux ; return item ;
}
public Object primeiro ( ) {
this .pos = primeiro ; return proximo ( ) ; }
public Object proximo ( ) {
this .pos = this .pos. prox ;
i f ( this .pos == null ) return null ;
else return this .pos. item ;
}
public boolean vazia ( ) {
return ( this . primeiro == this . ultimo ) ; }
public void imprime ( ) {
Celula aux = this . primeiro . prox ;
while (aux ! = null ) {
System. out . println (aux. item . toString ( ) ) ;
aux = aux. prox ; }
}
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 14

Lista Usando Estruturas


Auto-Referenciadas - Vantagens e
Desvantagens

Vantagens:
Permite inserir ou retirar itens do meio da
lista a um custo constante (importante
quando a lista tem de ser mantida em
ordem).
Bom para aplicaes em que no existe
previso sobre o crescimento da lista (o
tamanho mximo da lista no precisa ser
definido a priori).

Desvantagem: utilizao de memria extra


para armazenar as referncias.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 15

Exemplo de Uso Listas - Vestibular

Num vestibular, cada candidato tem direito a


trs opes para tentar uma vaga em um dos
sete cursos oferecidos.

Para cada candidato lido um registro:


chave: nmero de inscrio do candidato.
notaFinal : mdia das notas do candidato.
opcao: vetor contendo a primeira, a
segunda e a terceira opes de curso do
candidato.

short chave ; / / assume valores de 1 a 999.


byte notaFinal ; / / assume valores de 0 a 10.
byte opcao [ ] ; / / arranjo de 3 posies ;

Problema: distribuir os candidatos entre os


cursos, segundo a nota final e as opes
apresentadas por candidato.

Em caso de empate, os candidatos sero


atendidos na ordem de inscrio para os
exames.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 16

Vestibular - Possvel Soluo


ordenar registros pelo campo notaFinal ,
respeitando a ordem de inscrio;
percorrer cada conjunto de registros com
mesma notaFinal , comeando pelo conjunto
de notaFinal , 10, seguido pelo de notaFinal 9,
e assim por diante.
Para um conjunto de mesma notaFinal
tenta-se encaixar cada registro desse
conjunto em um dos cursos, na primeira
das trs opes em que houver vaga (se
houver).
Primeiro refinamento:

void Vestibular {
ordena os registros pelo campo notaFinal ;
for ( nota = 10; nota >= 0; nota)
while ( houver registro com mesma nota)
i f ( existe vaga em um dos cursos
de opo do candidato)
insere registro no conjunto de aprovados
else insere registro no conjunto de reprovados;
imprime aprovados por curso ;
imprime reprovados;
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 17

Vestibular - Classificao dos Alunos

Uma boa maneira de representar um conjunto


de registros com o uso de listas.

Ao serem lidos, os registros so


armazenados em listas para cada nota.

Aps a leitura do ltimo registro os candidatos


esto automaticamente ordenados por
notaFinal .

Dentro de cada lista, os registros esto


ordenados por ordem de inscrio, desde que
os registros sejam lidos na ordem de inscrio
de cada candidato e inseridos nesta ordem.
NotaFinal
0
...

7
8 ...
9 Registro nil
10 Registro Registro nil
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 18

Vestibular - Classificao dos Alunos

As listas de registros so percorridas,


iniciando-se pela de notaFinal 10, seguida
pela de notaFinal 9, e assim sucessivamente.

Cada registro retirado e colocado em uma


das listas da abaixo, na primeira das trs
opes em que houver vaga.
Cursos
1 Registro Registro ...
2 Registro ...
3 ...
4
5
6
7

Se no houver vaga, o registro colocado em


uma lista de reprovados.

Ao final a estrutura acima conter a relao


de candidatos aprovados em cada curso.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 19

Vestibular - Segundo Refinamento

void Vestibular {
l nmero de vagas para cada curso;
inicializa listas de classificao, de aprovados e de reprovados;
l registro; // vide formato do registro na transparncia 15
while (chave 6= 0) {
insere registro nas listas de classificao, conforme notaFinal;
l registro;
}
for (nota = 10; nota >= 0; nota)
while (houver prximo registro com mesma notaFinal) {
retira registro da lista;
if (existe vaga em um dos cursos de opo do candidato) {
insere registro na lista de aprovados;
decrementa o nmero de vagas para aquele curso;
}
else insere registro na lista de reprovados;
obtm prximo registro;
}
imprime aprovados por curso;
imprime reprovados;
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 20

Vestibular - Refinamento Final

Observe que o programa completamente


independente da implementao do tipo
abstrato de dados Lista.

package cap3;
import java . io . ;
import cap3. autoreferencia . Lista ; / / vide programa da trans-
parncia 11
public class Vestibular {
private class Definicoes {
public static final int nOpcoes = 3;
public static final int nCursos = 7;
}
private static class Registro {
short chave ; byte notaFinal ;
byte opcao[ ] = new byte[ Definicoes .nOpcoes] ;
public String toString ( ) {
return new String ( " " + this .chave ) ; }
}
private static BufferedReader in =
new BufferedReader(new InputStreamReader(System. in ) ) ;
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 21

Vestibular - Refinamento Final

static Registro leRegistro ( ) throws IOException {


/ / os valores lidos devem estar separados por brancos
Registro registro = new Registro ( ) ;
String str = in . readLine ( ) ;
registro .chave = Short . parseShort ( str . substring (0 ,
str . indexOf ( " " ) ) ) ;
registro . notaFinal = Byte.parseByte ( str . substring (
str . indexOf ( " " ) + 1 ) ) ;
for ( int i = 0; i < Definicoes .nOpcoes; i ++)
registro .opcao[ i ] = Byte.parseByte ( in . readLine ( ) ) ;
return registro ;
}
public static void main ( String [ ] args ) {
Registro registro = null ;
Lista classificacao [ ] = new Lista [11];
Lista aprovados [ ] = new Lista [ Definicoes .nCursos ] ;
Lista reprovados = new Lista ( ) ;
long vagas[ ] = new long[ Definicoes .nCursos ] ;
boolean passou;
int i ;
try {
for ( i = 0; i < Definicoes .nCursos ; i ++)
vagas[ i ] = Long.parseLong ( in . readLine ( ) ) ;
for ( i = 0; i < 11; i ++)classificacao [ i ] = new Lista ( ) ;
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 22

Vestibular - Refinamento Final (Cont.)

for ( i = 0; i < Definicoes .nCursos ; i ++)


aprovados[ i ] = new Lista ( ) ;
registro = leRegistro ( ) ;
while ( registro .chave ! = 0 ) {
classificacao [ registro . notaFinal ] . insere ( registro ) ;
registro = leRegistro ( ) ;
}
for ( int Nota = 10; Nota >= 0; Nota) {
while ( ! classificacao [Nota ] . vazia ( ) ) {
registro =
( Registro ) classificacao [Nota ] . retiraPrimeiro ( ) ;
i = 0; passou = false ;
while ( i < Definicoes .nOpcoes && !passou) {
i f (vagas[ registro .opcao[ i ] 1] > 0) {
aprovados[ registro .opcao[ i ]1].insere ( registro ) ;
vagas[ registro .opcao[ i ]1]; passou = true ;
}
i ++;
}
i f ( ! passou) reprovados. insere ( registro ) ;
}
}
} catch ( Exception e) {
System. out . println (e.getMessage ( ) ) ; }
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.2 23

Vestibular - Refinamento Final (Cont.)

for ( i = 0; i < Definicoes .nCursos ; i ++) {


System. out . println ( "Relacao dos aprovados no Curso" +
( i + 1));
aprovados[ i ] . imprime ( ) ;
}
System. out . println ( "Relacao dos reprovados" ) ;
reprovados.imprime ( ) ;
}
}

O exemplo mostra a importncia de utilizar


tipos abstratos de dados para escrever
programas, em vez de utilizar detalhes
particulares de implementao.

Altera-se a implementao rapidamente. No


necessrio procurar as referncias diretas
s estruturas de dados por todo o cdigo.

Este aspecto particularmente importante


em programas de grande porte.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2 24

Pilha

uma lista linear em que todas as inseres,


retiradas e, geralmente, todos os acessos so
feitos em apenas um extremo da lista.

Os itens so colocados um sobre o outro. O


item inserido mais recentemente est no topo
e o inserido menos recentemente no fundo.

O modelo intuitivo o de um monte de pratos


em uma prateleira, sendo conveniente retirar
ou adicionar pratos na parte superior.

Esta imagem est freqentemente associada


com a teoria de autmato, na qual o topo de
uma pilha considerado como o receptculo
de uma cabea de leitura/gravao que pode
empilhar e desempilhar itens da pilha.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2 25

Propriedade e Aplicaes das Pilhas


Propriedade: o ltimo item inserido o
primeiro item que pode ser retirado da lista.
So chamadas listas lifo (last-in, first-out).
Existe uma ordem linear para pilhas, do mais
recente para o menos recente.
ideal para processamento de estruturas
aninhadas de profundidade imprevisvel.
Uma pilha contm uma seqncia de
obrigaes adiadas. A ordem de remoo
garante que as estruturas mais internas sero
processadas antes das mais externas.
Aplicaes em estruturas aninhadas:
Quando necessrio caminhar em um
conjunto de dados e guardar uma lista de
coisas a fazer posteriormente.
O controle de seqncias de chamadas de
subprogramas.
A sintaxe de expresses aritmticas.
As pilhas ocorrem em estruturas de natureza
recursiva (como rvores). Elas so utilizadas
para implementar a recursividade.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2 26

TAD Pilhas

Conjunto de operaes:
1. Cria uma pilha Vazia.
2. Verifica se a lista est vazia. Retorna true
se a pilha est vazia; caso contrrio,
retorna false.
3. Empilhar o item x no topo da pilha.
4. Desempilhar o item x no topo da pilha,
retirando-o da pilha.
5. Verificar o tamanho atual da pilha.

Existem vrias opes de estruturas de


dados que podem ser usadas para
representar pilhas.

As duas representaes mais utilizadas so


as implementaes por meio de arranjos e de
estruturas auto-referenciadas.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.1 27

Implementao de Pilhas por meio de


Arranjos

Os itens da pilha so armazenados em


posies contguas de memria.

Como as inseres e as retiradas ocorrem no


topo da pilha, um cursor chamado Topo
utilizado para controlar a posio do item no
topo da pilha.
Itens
primeiro = 0 x1
1 x2
..
.
topo 1 xn
..
.
maxTam 1
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.1 28

Estrutura e Operaes sobre Pilhas


Usando Arranjos

Os itens so armazenados em um arranjo de


tamanho suficiente para conter a pilha.
O outro campo do mesmo registro contm
uma referncia para o item no topo da pilha.
A constante maxTam define o tamanho
mximo permitido para a pilha.

package cap3. arranjo ;


public class Pilha {
private Object item [ ] ;
private int topo ;
/ / Operaes
public Pilha ( int maxTam) { / / Cria uma Pilha vazia
this . item = new Object [maxTam] ; this . topo = 0;
}
public void empilha ( Object x ) throws Exception {
i f ( this . topo == this . item . length )
throw new Exception ( "Erro : A pilha esta cheia" ) ;
else this . item [ this . topo++] = x ;
}
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.1 29

Estrutura e Operaes sobre Pilhas


Usando Arranjos

public Object desempilha ( ) throws Exception {


i f ( this . vazia ( ) )
throw new Exception ( "Erro : A pilha esta vazia" ) ;
return this . item[this . topo ] ;
}
public boolean vazia ( ) {
return ( this . topo == 0);
}
public int tamanho ( ) {
return this . topo ;
}
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 30

Implementao de Pilhas por meio de


Estruturas Auto-Referenciadas
Ao contrrio da implementao de listas
lineares por meio e estruturas
auto-referenciadas no h necessidade de
manter uma clula cabea no topo da pilha.
Para desempilhar um item, basta desligar a
clula que contm xn e a clula que contm
xn1 passa a ser a clula de topo.
Para empilhar um novo item, basta fazer a
operao contrria, criando uma nova clula
para receber o novo item.

nil
6
x1

6
..
.
6
xn1

topo - xn
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 31

Estrutura e operaes sobre Pilhas


Usando Estruturas
Auto-Referenciadas
O campo tam evita a contagem do nmero de
itens no mtodo tamanho.
Cada clula de uma pilha contm um item da
pilha e uma referncia para outra clula.
A classe Pilha contm uma referncia para o
topo da pilha.

package cap3. autoreferencia ;


public class Pilha {
private static class Celula {
Object item ;
Celula prox ;
}
private Celula topo ;
private int tam;
/ / Operaes
public Pilha ( ) { / / Cria uma Pilha vazia
this . topo = null ; this .tam = 0;
}
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 32

Estrutura e operaes sobre Pilhas


Usando Estruturas
Auto-Referenciadas

public void empilha ( Object x ) {


Celula aux = this . topo ;
this . topo = new Celula ( ) ;
this . topo . item = x ;
this . topo . prox = aux;
this .tam++;
}
public Object desempilha ( ) throws Exception {
i f ( this . vazia ( ) )
throw new Exception ( "Erro : A pilha esta vazia" ) ;
Object item = this . topo . item ;
this . topo = this . topo . prox ;
this .tam;
return item ;
}
public boolean vazia ( ) {
return ( this . topo == null ) ;
}
public int tamanho ( ) {
return this .tam;
}
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 33

Exemplo de Uso Pilhas - Editor de


Textos (ET)
#: cancelar caractere anterior na linha sendo
editada. Ex.: UEM##FMB#G UFMG.
\: cancela todos os caracteres anteriores na
linha sendo editada.
*: salta a linha. Imprime os caracteres que
pertencem linha sendo editada, iniciando
uma nova linha de impresso a partir do
caractere imediatamente seguinte ao
caractere salta-linha. Ex: DCC*UFMG.*
DCC
UFMG.
Vamos escrever um Editor de Texto (ET ) que
aceite os trs comandos descritos acima.
O ET dever ler um caractere de cada vez do
texto de entrada e produzir a impresso linha
a linha, cada linha contendo no mximo 70
caracteres de impresso.
O ET dever utilizar o tipo abstrato de
dados Pilha definido anteriormente,
implementado por meio de arranjo.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 34

Sugesto de Texto para Testar o ET


Este et# um teste para o ET, o extraterrestre em

JAVA.*Acabamos de testar a capacidade de o ET


saltar de linha,

utilizando seus poderes extras (cuidado, pois agora


vamos estourar

a capacidade mxima da linha de impresso, que de


70

caracteres.)*O k#cut#rso dh#e Estruturas de Dados


et# h#um

cuu#rsh#o #x# x?*!#?!#+.* Como et# bom

n#nt#ao### r#ess#tt#ar mb#aa#triz#cull#ado


nn#x#ele!\ Sera

que este funciona\\\? O sinal? no### deve ficar! ~


Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 35

ET - Implementao
Este programa utiliza um tipo abstrato de
dados sem conhecer detalhes de sua
implementao.
A implementao do TAD Pilha que utiliza
arranjo pode ser substituda pela
implementao que utiliza estruturas
auto-referenciadas sem causar impacto no
programa.

package cap3;
import cap3. arranjo . Pilha ; / / vide programa da transparn-
cia 11

public class ET {
private class Definicoes {
public static final int maxTam = 70;
public static final char cancelaCarater = # ;
public static final char cancelaLinha = \\ ;
public static f i n a l char saltaLinha = ;
public static f i n a l char marcaEof = ~ ;
}
private static void imprime( Pilha pilha )throws Exception {
Pilha pilhaAux = new Pilha ( Definicoes .maxTam) ;
Character x ;
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 36

ET - Implementao

while ( ! pilha . vazia ( ) ) {


x = (Character ) pilha .desempilha ( ) ;
pilhaAux .empilha ( x ) ;
}
while ( ! pilhaAux . vazia ( ) ) {
x = (Character ) pilhaAux .desempilha ( ) ;
System. out . print ( x ) ;
}
System. out . print ( \n ) ;
}
public static void main ( String [ ] args ) {
Pilha pilha = new Pilha ( Definicoes .maxTam) ;
try {
char c = (char) System. in .read ( ) ;
Character x = new Character ( c ) ;
i f ( x .charValue () == \n ) x =
new Character ( ) ;
while ( x .charValue ( ) ! = Definicoes .marcaEof) {
i f ( x .charValue () == Definicoes . cancelaCarater ) {
i f ( ! pilha . vazia ( ) ) x =
(Character ) pilha .desempilha ( ) ;
}
else i f ( x .charValue () == Definicoes . cancelaLinha)
pilha = new Pilha ( Definicoes .maxTam) ;
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.2 37

ET - Implementao

else i f ( x .charValue () == Definicoes . saltaLinha )


imprime ( pilha ) ;
else {
i f ( pilha .tamanho () == Definicoes .maxTam)
imprime ( pilha ) ;
pilha .empilha ( x ) ;
}
c = (char) System. in .read ( ) ;
x = new Character ( c ) ;
i f ( x .charValue () == \n ) x = new Character ( ) ;
}
i f ( ! pilha . vazia ( ) ) imprime ( pilha ) ;
} catch ( Exception e) {
System. out . println (e.getMessage ( ) ) ; }
}
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3 38

Filas

uma lista linear em que todas as inseres


so realizadas em um extremo da lista, e
todas as retiradas e, geralmente, os acessos
so realizados no outro extremo da lista.

O modelo intuitivo de uma fila o de uma fila


de espera em que as pessoas no incio da fila
so servidas primeiro e as pessoas que
chegam entram no fim da fila.

So chamadas listas fifo (first-in, first-out).

Existe uma ordem linear para filas que a


ordem de chegada.

So utilizadas quando desejamos processar


itens de acordo com a ordem
primeiro-que-chega, primeiro-atendido.

Sistemas operacionais utilizam filas para


regular a ordem na qual tarefas devem
receber processamento e recursos devem ser
alocados a processos.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3 39

TAD Filas

Conjunto de operaes:
1. Criar uma fila vazia.
2. Enfileirar o item x no final da fila.
3. Desenfileirar. Essa funo retorna o item x
no incio da fila e o retira da fila.
4. Verificar se a fila est vazia. Essa funo
retorna true se a fila est vazia; do
contrrio, retorna false.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1 40

Implementao de Filas por meio de


Arranjos
Os itens so armazenados em posies
contguas de memria.
A operao enfileira faz a parte de trs da fila
expandir-se.
A operao desenfileira faz a parte da frente
da fila contrair-se.
A fila tende a caminhar pela memria do
computador, ocupando espao na parte de
trs e descartando espao na parte da frente.
Com poucas inseres e retiradas, a fila vai
ao encontro do limite do espao da memria
alocado para ela.
Soluo: imaginar o arranjo como um crculo.
A primeira posio segue a ltima.
n 1
2 Frente
3
...

4
Tras
8 5
7 6
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1 41

Implementao de Filas por meio de


Arranjos
n 1
2 Frente
3

...
4
Tras
8 5
7 6

A fila se encontra em posies contguas de


memria, em alguma posio do crculo,
delimitada pelos apontadores frente e trs.

Para enfileirar, basta mover o apontador trs


uma posio no sentido horrio.

Para desenfileirar, basta mover o apontador


frente uma posio no sentido horrio.
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1 42

Estrutura da Fila Usando Arranjo


O tamanho mximo do arranjo circular
definido pela constante maxTam.
Os outros campos da classe Fila contm
referncias para a parte da frente e de trs da
fila.
Nos casos de fila cheia e fila vazia, os
apontadores frente e trs apontam para a
mesma posio do crculo.
Uma sada para distinguir as duas situaes
deixar uma posio vazia no arranjo.
Neste caso, a fila est cheia quando trs+1
for igual a frente.
A implementao utiliza aritmtica modular
nos procedimentos enfileira e desenfileira (%
do Java).

package cap3. arranjo ;


public class Fila {
private Object item [ ] ;
private int frente , tras ;
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1 43

Estrutura e operaes sobre Filas


Usando arranjo

/ / Operaes
public Fila ( int maxTam) { / / Cria uma Fila vazia
this . item = new Object [maxTam] ;
this . frente = 0;
this . tras = this . frente ;
}
public void enfileira ( Object x ) throws Exception {
i f ( ( this . tras + 1) % this . item . length == this . frente )
throw new Exception ( "Erro : A f i l a esta cheia" ) ;
this . item [ this . tras ] = x ;
this . tras = ( this . tras + 1) % this . item . length ;
}
public Object desenfileira ( ) throws Exception {
i f ( this . vazia ( ) )
throw new Exception ( "Erro : A f i l a esta vazia" ) ;
Object item = this . item [ this . frente ] ;
this . frente = ( this . frente + 1) % this . item . length ;
return item ;
}
public boolean vazia ( ) {
return ( this . frente == this . tras ) ;
}
}
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.2 44

Implementao de Filas por meio de


Estruturas Auto-Referenciadas

H uma clula cabea para facilitar a


implementao das operaes enfileira e
desenfileira quando a fila est vazia.

Quando a fila est vazia, os apontadores


frente e trs referenciam para a clula cabea.

Para enfileirar um novo item, basta criar uma


clula nova, lig-la aps a clula que contm
xn e colocar nela o novo item.

Para desenfileirar o item x1 , basta desligar a


clula cabea da lista e a clula que contm
x1 passa a ser a clula cabea.
- x1 - - xn - nil

6 6
frente trs
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.2 45

Estrutura da Fila Usando Estruturas


Auto-Referenciadas

A fila implementada por meio de clulas.

Cada clula contm um item da fila e uma


referncia para outra clula.

A classe Fila contm uma referncia para a


frente da fila (clula cabea) e uma referncia
para a parte de trs da fila.

package cap3. autoreferencia ;


public class Fila {
private static class Celula { Object item ; Celula prox ; }
private Celula frente ;
private Celula tras ;
/ / Operaes
public Fila ( ) { / / Cria uma Fila vazia
this . frente = new Celula ( ) ;
this . tras = this . frente ;
this . frente . prox = null ;
}
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.2 46

Estrutura Operaes da fila usando


estruturas auto-referenciadas

public void enfileira ( Object x ) {


this . tras . prox = new Celula ( ) ;
this . tras = this . tras . prox ;
this . tras . item = x ;
this . tras . prox = null ;
}
public Object desenfileira ( ) throws Exception {
Object item = null ;
i f ( this . vazia ( ) )
throw new Exception ( "Erro : A f i l a esta vazia" ) ;
this . frente = this . frente . prox ;
item = this . frente . item ;
return item ;
}

public boolean vazia ( ) {


return ( this . frente == this . tras ) ;
}
}
Ordenao

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Fabiano C. Botelho, Leonardo Rocha, Leo-


nardo Mata e Nivio Ziviani
Projeto de Algoritmos Cap.4 Ordenao 1

Ordenao
Introduo - Conceitos Bsicos
Ordenao Interna
Ordenao por Seleo
Ordenao por Insero
Shellsort
Quicksort
Heapsort
Ordenao Parcial
Seleo Parcial
Insero Parcial
Heapsort Parcial
Quicksort Parcial
Ordenao Externa
Intercalao Balanceada de Vrios
Caminhos
Implementao por meio de Seleo por
Substituio
Consideraes Prticas
Intercalao Polifsica
Quicksort Externo
Projeto de Algoritmos Cap.4 Ordenao 2

Introduo - Conceitos Bsicos

Ordenar: processo de rearranjar um conjunto


de objetos em uma ordem ascendente ou
descendente.

A ordenao visa facilitar a recuperao


posterior de itens do conjunto ordenado.
Dificuldade de se utilizar um catlogo
telefnico se os nomes das pessoas no
estivessem listados em ordem alfabtica.

A maioria dos mtodos de ordenao


baseada em comparaes das chaves.

Existem mtodos de ordenao que utilizam


o princpio da distribuio.
Projeto de Algoritmos Cap.4 Ordenao 3

Introduo - Conceitos Bsicos

Exemplo de ordenao por distribuio:


considere o
problema de ordenar um baralho com 52
cartas na ordem:
A < 2 < 3 < < 10 < J < Q < K

e
< < < .

Algoritmo:
1. Distribuir as cartas abertas em treze
montes: ases, dois, trs, . . ., reis.
2. Colete os montes na ordem especificada.
3. Distribua novamente as cartas abertas em
quatro montes: paus, ouros, copas e
espadas.
4. Colete os montes na ordem especificada.
Projeto de Algoritmos Cap.4 Ordenao 4

Introduo - Conceitos Bsicos


Mtodos como o ilustrado so tambm
conhecidos como ordenao digital,
radixsort ou bucketsort.
O mtodo no utiliza comparao entre
chaves.
Uma das dificuldades de implementar este
mtodo est relacionada com o problema de
lidar com cada monte.
Se para cada monte ns reservarmos uma
rea, ento a demanda por memria extra
pode tornar-se proibitiva.
O custo para ordenar um arquivo com n
elementos da ordem de O(n).
Notao utilizada nos algoritmos:
Os algoritmos trabalham sobre os
registros de um arquivo.
Cada registro possui uma chave utilizada
para controlar a ordenao.
Podem existir outros componentes em um
registro.
Projeto de Algoritmos Cap.4 Ordenao 5

Introduo - Conceitos Bsicos

Qualquer tipo de chave sobre o qual exista


uma regra de ordenao bem-definida pode
ser utilizado.

Em Java pode-se criar um tipo de registro


genrico chamado iterface

Uma interface uma classe que no pode


ser instanciada e deve ser implementada por
outra classe.

A iterface para a chave de ordenao


chama-se Item inclui os mtodos compara,
alteraChave e recuperaChave.

package cap4;
public interface Item {
public int compara ( Item i t ) ;
public void alteraChave ( Object chave) ;
public Object recuperaChave ( ) ;
}
Projeto de Algoritmos Cap.4 Ordenao 6

Introduo - Conceitos Bsicos

A classe MeuItem define o tipo de dados int


para a chave e implementa os mtodos
compara, alteraChave e recuperaChave.

O mtodo compara retorna um valor menor do


que zero se a < b, um valor maior do que zero
se a > b, e um valor igual a zero se a = b.

package cap4;
import java . io . ;
public class MeuItem implements Item {
private int chave;
/ / outros componentes do registro

public MeuItem ( int chave ) { this .chave = chave ; }

public int compara ( Item i t ) {


MeuItem item = (MeuItem) i t ;
i f ( this .chave < item .chave) return 1;
else i f ( this .chave > item .chave) return 1;
return 0;
}
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.4 Ordenao 7

Introduo - Conceitos Bsicos

public void alteraChave ( Object chave) {


Integer ch = ( Integer ) chave;
this .chave = ch. intValue ( ) ;
}
public Object recuperaChave ( ) {
return new Integer ( this .chave ) ; }
}

Deve-se ampliar a interface Item sempre que


houver necessidade de manipular a chave de
um registro.

O mtodo compara sobrescrito para


determinar como so comparados dois
objetos da classe MeuItem.

Os mtodos alteraChave e recuperaChave so


sobrescritos para determinar como alterar e
como recuperar o valor da chave de um
objeto da classe MeuItem.
Projeto de Algoritmos Cap.4 Ordenao 8

Introduo - Conceitos Bsicos

Um mtodo de ordenao estvel se a


ordem relativa dos itens com chaves iguais
no se altera durante a ordenao.

Alguns dos mtodos de ordenao mais


eficientes no so estveis.

A estabilidade pode ser forada quando o


mtodo no-estvel.

Sedgewick (1988) sugere agregar um


pequeno ndice a cada chave antes de
ordenar, ou ento aumentar a chave de
alguma outra forma.
Projeto de Algoritmos Cap.4 Ordenao 9

Introduo - Conceitos Bsicos

Classificao dos mtodos de ordenao:


Ordenao interna: arquivo a ser
ordenado cabe todo na memria principal.
Ordenao externa: arquivo a ser
ordenado no cabe na memria principal.

Diferenas entre os mtodos:


Em um mtodo de ordenao interna,
qualquer registro pode ser imediatamente
acessado.
Em um mtodo de ordenao externa, os
registros so acessados seqencialmente
ou em grandes blocos.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1 10

Ordenao Interna

Na escolha de um algoritmo de ordenao


interna deve ser considerado o tempo gasto
pela ordenao.

Sendo n o nmero registros no arquivo, as


medidas de complexidade relevantes so:
Nmero de comparaes C(n) entre
chaves.
Nmero de movimentaes M (n) de itens
do arquivo.

O uso econmico da memria disponvel


um requisito primordial na ordenao interna.

Mtodos de ordenao in situ so os


preferidos.

Mtodos que utilizam listas encadeadas no


so muito utilizados.

Mtodos que fazem cpias dos itens a serem


ordenados possuem menor importncia.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1 11

Ordenao Interna

Classificao dos mtodos de ordenao


interna:
Mtodos simples:
Adequados para pequenos arquivos.
Requerem O(n2 ) comparaes.
Produzem programas pequenos.
Mtodos eficientes:
Adequados para arquivos maiores.
Requerem O(n log n) comparaes.
Usam menos comparaes.
As comparaes so mais complexas
nos detalhes.
Mtodos simples so mais eficientes
para pequenos arquivos.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1 12

Ordenao Interna

A classe mostrada a seguir apresenta os


mtodos de ordenao interna que sero
estudados.

Utilizaremos um vetor v de registros do tipo


Item e uma varivel inteira n com o tamanho
de v .

O vetor contm registros nas posies de 1


at n, e a 0 utilizada para sentinelas.

package cap4. ordenacaointerna ;


import cap4. Item ; / / vide transparncia 6

public class Ordenacao {


public static void selecao ( Item v [ ] , int n)
public static void insercao ( Item v [ ] , int n)
public static void shellsort ( Item v [ ] , int n)
public static void quicksort ( Item v [ ] , int n)
public static void heapsort ( Item v [ ] , int n)
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.1 13

Ordenao por Seleo


Um dos algoritmos mais simples de
ordenao.
Algoritmo:
Selecione o menor item do vetor.
Troque-o com o item da primeira posio
do vetor.
Repita essas duas operaes com os
n 1 itens restantes, depois com os n 2
itens, at que reste apenas um elemento.
O mtodo ilustrado abaixo:
1 2 3 4 5 6

Chaves iniciais: O R D E N A
i=1 A R D E N O
i=2 A D R E N O
i=3 A D E R N O
i=4 A D E N R O
i=5 A D E N O R

As chaves em negrito sofreram uma troca


entre si.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.1 14

Ordenao por Seleo

public static void selecao ( Item v [ ] , int n) {


for ( int i = 1; i <= n 1; i ++) {
int min = i ;
for ( int j = i + 1; j <= n ; j ++)
i f ( v [ j ] .compara ( v [min] ) < 0 ) min = j ;
Item x = v [min ] ; v [min] = v [ i ] ; v [ i ] = x ;
}
}

Anlise

Comparaes entre chaves e movimentaes


de registros:

n2 n
C(n) = 2
2

M (n) = 3(n 1)

A atribuio min = j executada em mdia


n log n vezes, Knuth (1973).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.1 15

Ordenao por Seleo

Vantagens:

Custo linear no tamanho da entrada para o


nmero de movimentos de registros.

o algoritmo a ser utilizado para arquivos


com registros muito grandes.

muito interessante para arquivos pequenos.

Desvantagens:

O fato de o arquivo j estar ordenado no


ajuda em nada, pois o custo continua
quadrtico.

O algoritmo no estvel.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2 16

Ordenao por Insero

Mtodo preferido dos jogadores de cartas.

Algoritmo:
Em cada passo a partir de i=2 faa:
Selecione o i-simo item da seqncia
fonte.
Coloque-o no lugar apropriado na
seqncia destino de acordo com o
critrio de ordenao.

O mtodo ilustrado abaixo:


1 2 3 4 5 6

Chaves iniciais: O R D E N A
i=2 O R D E N A
i=3 D O R E N A
i=4 D E O R N A
i=5 D E N O R A
i=6 A D E N O R

As chaves em negrito representam a


seqncia destino.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2 17

Ordenao por Insero

public static void insercao ( Item v [ ] , int n) {


int j ;
for ( int i = 2; i <= n ; i ++) {
Item x = v [ i ] ;
j = i 1;
v[0] = x ; / / sentinela
while ( x .compara ( v [ j ] ) < 0 ) {
v [ j + 1] = v [ j ] ; j ;
}
v [ j + 1] = x ;
}
}

A colocao do item no seu lugar apropriado


na seqncia destino realizada movendo-se
itens com chaves maiores para a direita e
ento inserindo o item na posio deixada
vazia.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2 18

Ordenao por Insero


Consideraes sobre o algoritmo:

O processo de ordenao pode ser terminado


pelas condies:
Um item com chave menor que o item em
considerao encontrado.
O final da seqncia destino atingido
esquerda.

Soluo:
Utilizar um registro sentinela na posio
zero do vetor.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2 19

Ordenao por Insero


Anlise

Seja C(n) a funo que conta o nmero de


comparaes.

No anel mais interno, na i-sima iterao, o


valor de Ci :

melhor caso : Ci (n) = 1


pior caso : Ci (n) = i
caso medio : Ci (n) = 1i (1 + 2 + + i) = i+1
2

Assumindo que todas as permutaes de n


so igualmente provveis no caso mdio,
temos:

melhor caso : C(n) = (1 + 1 + + 1) = n 1


n2
pior caso : C(n) = (2 + 3 + + n) = 2
+
n
2
1
1
caso medio : C(n) = 2
(3 + 4 + + n + 1) =
n2 3n
4
+ 4
1
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2 20

Ordenao por Insero


Anlise

Seja M (n) a funo que conta o nmero de


movimentaes de registros.

O nmero de movimentaes na i-sima


iterao :

Mi (n) = Ci (n) 1 + 3 = Ci (n) + 2

Logo, o nmero de movimentos :

melhor caso : M (n) = (3 + 3 + + 3) =


3(n 1)
pior caso : M (n) = (4 + 5 + + n + 2) =
n2 5n
2
+ 2
3
1
caso medio : M (n) = 2
(5 + 6 + + n + 3) =
n2 11n
4
+ 4
3
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2 21

Ordenao por Insero

O nmero mnimo de comparaes e


movimentos ocorre quando os itens esto
originalmente em ordem.

O nmero mximo ocorre quando os itens


esto originalmente na ordem reversa.

o mtodo a ser utilizado quando o arquivo


est quase ordenado.

um bom mtodo quando se deseja


adicionar uns poucos itens a um arquivo
ordenado, pois o custo linear.

O algoritmo de ordenao por insero


estvel.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3 22

Shellsort

Proposto por Shell em 1959.

uma extenso do algoritmo de ordenao


por insero.

Problema com o algoritmo de ordenao por


insero:
Troca itens adjacentes para determinar o
ponto de insero.
So efetuadas n 1 comparaes e
movimentaes quando o menor item est
na posio mais direita no vetor.

O mtodo de Shell contorna este problema


permitindo trocas de registros distantes um
do outro.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3 23

Shellsort

Os itens separados de h posies so


rearranjados.

Todo h-simo item leva a uma seqncia


ordenada.

Tal seqncia dita estar h-ordenada.

Exemplo de utilizao:

1 2 3 4 5 6

Chaves iniciais: O R D E N A
h=4 N A D E O R
h=2 D A N E O R
h=1 A D E N O R

Quando h = 1 Shellsort corresponde ao


algoritmo de insero.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3 24

Shellsort

Como escolher o valor de h:


Seqncia para h:

h(s) = 3h(s 1) + 1, para s > 1

h(s) = 1, para s = 1.

Knuth (1973, p. 95) mostrou


experimentalmente que esta seqncia
difcil de ser batida por mais de 20% em
eficincia.
A seqncia para h corresponde a 1, 4,
13, 40, 121, 364, 1.093, 3.280, . . .
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3 25

Shellsort

public static void shellsort ( Item v [ ] , int n) {


int h = 1;
do h = h 3 + 1; while (h < n) ;
do {
h /= 3;
for ( int i = h + 1; i <= n ; i ++) {
Item x = v [ i ] ; int j = i ;
while ( v [ j h ] .compara ( x) > 0) {
v [ j ] = v [ j h ] ; j = h;
i f ( j <= h) break;
}
v[ j ] = x;
}
} while (h ! = 1 ) ;
}

A implementao do Shellsort no utiliza


registros sentinelas.

Seriam necessrios h registros sentinelas,


uma para cada h-ordenao.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3 26

Shellsort
Anlise

A razo da eficincia do algoritmo ainda no


conhecida.

Ningum ainda foi capaz de analisar o


algoritmo.

A sua anlise contm alguns problemas


matemticos muito difceis.

A comear pela prpria seqncia de


incrementos.

O que se sabe que cada incremento no


deve ser mltiplo do anterior.

Conjecturas referente ao nmero de


comparaes para a seqncia de Knuth:

Conjetura 1 : C(n) = O(n1,25 )

Conjetura 2 : C(n) = O(n(ln n)2 )


Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3 27

Shellsort

Vantagens:
Shellsort uma tima opo para arquivos
de tamanho moderado.
Sua implementao simples e requer
uma quantidade de cdigo pequena.

Desvantagens:
O tempo de execuo do algoritmo
sensvel ordem inicial do arquivo.
O mtodo no estvel,
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 28

Quicksort

Proposto por Hoare em 1960 e publiccado em


1962.

o algoritmo de ordenao interna mais


rpido que se conhece para uma ampla
variedade de situaes.

Provavelmente o mais utilizado.

A idia bsica dividir o problema de ordenar


um conjunto com n itens em dois problemas
menores.

Os problemas menores so ordenados


independentemente.

Os resultados so combinados para produzir


a soluo final.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 29

Quicksort

A parte mais delicada do mtodo relativa ao


mtodo particao.

O vetor v [esq..dir ] rearranjado por meio da


escolha arbitrria de um piv x.

O vetor v particionado em duas partes:


A parte esquerda com chaves menores ou
iguais a x.
A parte direita com chaves maiores ou
iguais a x.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 30

Quicksort

Algoritmo para o particionamento:


1. Escolha arbitrariamente um piv x.
2. Percorra o vetor a partir da esquerda at
que v [i] x.
3. Percorra o vetor a partir da direita at que
v [j] x.
4. Troque v [i] com v [j].
5. Continue este processo at os
apontadores i e j se cruzarem.

Ao final, o vetor v [esq..dir ] est particionado


de tal forma que:
Os itens em v [esq], v [esq + 1], . . . , v [j] so
menores ou iguais a x.
Os itens em v [i], v [i + 1], . . . , v [dir ] so
maiores ou iguais a x.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 31

Quicksort

Ilustrao do processo de partio:

1 2 3 4 5 6

O R D E N A
A R D E N O
A D R E N O

O piv x escolhido como sendo v [(i + j) / 2].

Como inicialmente i = 1 e j = 6, ento


x = v [3] = D.

Ao final do processo de partio i e j se


cruzam em i = 3 e j = 2.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 32

Quicksort
Mtodo Partio:

private static class LimiteParticoes { int i ; int j ; }


private static LimiteParticoes particao
(Item v [ ] , int esq, int dir ) {
LimiteParticoes p = new LimiteParticoes ( ) ;
p. i = esq ; p. j = dir ;
Item x = v [ (p. i + p. j ) / 2 ] ; / / obtm o pivo x
do {
while ( x .compara ( v [p. i ] ) > 0 ) p. i ++;
while ( x .compara ( v [p. j ] ) < 0 ) p. j ;
i f (p. i <= p. j ) {
Item w = v [p. i ] ; v [p. i ] = v [p. j ] ; v [p. j ] = w;
p. i ++; p. j ;
}
} while (p. i <= p. j ) ;
return p;
}

O modificador private nessa classe


encapsula os mtodos para serem utilizados
somente dentro da classe Ordenacao.
O anel interno do procedimento Particao
extremamente simples.
Razo pela qual o algoritmo Quicksort to
rpido.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 33

Quicksort
Mtodo ordena e algoritmo Quicksort:

private static void ordena ( Item v [ ] , int esq, int dir ) {


LimiteParticoes p = particao ( v , esq, dir ) ;
i f (esq < p. j ) ordena ( v , esq, p. j ) ;
i f (p. i < dir ) ordena ( v , p. i , dir ) ;
}

public static void quicksort ( Item v [ ] , int n) {


ordena ( v , 1 , n) ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 34

Quicksort

Exemplo do estado do vetor em cada


chamada recursiva do procedimento Ordena:

Chaves iniciais: O R D E N A
1 A D R E N O
2 A D
3 E R N O
4 N R O
5 O R
A D E N O R

O piv mostrado em negrito.


Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 35

Quicksort
Anlise

Seja C(n) a funo que conta o nmero de


comparaes.

Pior caso:
C(n) = O(n2 )

O pior caso ocorre quando, sistematicamente,


o piv escolhido como sendo um dos
extremos de um arquivo j ordenado.

Isto faz com que o procedimento Ordena seja


chamado recursivamente n vezes, eliminando
apenas um item em cada chamada.

O pior caso pode ser evitado empregando


pequenas modificaes no algoritmo.

Para isso basta escolher trs itens quaisquer


do vetor e usar a mediana dos trs como
piv.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 36

Quicksort
Anlise

Melhor caso:

C(n) = 2C(n/2) + n = n log n n + 1

Esta situao ocorre quando cada partio


divide o arquivo em duas partes iguais.

Caso mdio de acordo com Sedgewick e


Flajolet (1996, p. 17):

C(n) 1, 386n log n 0, 846n,

Isso significa que em mdia o tempo de


execuo do Quicksort O(n log n).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4 37

Quicksort

Vantagens:
extremamente eficiente para ordenar
arquivos de dados.
Necessita de apenas uma pequena pilha
como memria auxiliar.
Requer cerca de n log n comparaes em
mdia para ordenar n itens.

Desvantagens:
Tem um pior caso O(n2 ) comparaes.
Sua implementao muito delicada e
difcil:
Um pequeno engano pode levar a
efeitos inesperados para algumas
entradas de dados.
O mtodo no estvel.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 38

Heapsort

Possui o mesmo princpio de funcionamento


da ordenao por seleo.

Algoritmo:
1. Selecione o menor item do vetor.
2. Troque-o com o item da primeira posio
do vetor.
3. Repita estas operaes com os n 1 itens
restantes, depois com os n 2 itens, e
assim sucessivamente.

O custo para encontrar o menor (ou o maior)


item entre n itens n 1 comparaes.

Isso pode ser reduzido utilizando uma fila de


prioridades.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 39

Heapsort
Filas de Prioridades

uma estrutura de dados onde a chave de


cada item reflete sua habilidade relativa de
abandonar o conjunto de itens rapidamente.

Aplicaes:
SOs usam filas de prioridades, nas quais
as chaves representam o tempo em que
eventos devem ocorrer.
Mtodos numricos iterativos so
baseados na seleo repetida de um item
com maior (menor) valor.
Sistemas de gerncia de memria usam a
tcnica de substituir a pgina menos
utilizada na memria principal por uma
nova pgina.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 40

Heapsort
Filas de Prioridades - Tipo Abstrato de Dados

Operaes:
1. Constri uma fila de prioridades a partir de
um conjunto com n itens.
2. Informa qual o maior item do conjunto.
3. Retira o item com maior chave.
4. Insere um novo item.
5. Aumenta o valor da chave do item i para
um novo valor que maior que o valor
atual da chave.
6. Substitui o maior item por um novo item, a
no ser que o novo item seja maior.
7. Altera a prioridade de um item.
8. Remove um item qualquer.
9. Ajunta duas filas de prioridades em uma
nica.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 41

Heapsort
Filas de Prioridades - Representao

Representao atravs de uma lista linear


ordenada:
Neste caso, Constri leva tempo
O(n log n).
Insere O(n).
Retira O(1).
Ajunta O(n).

Representao atravs de uma lista linear


no ordenada:
Neste caso, Constri tem custo linear.
Insere O(1).
Retira O(n).
Ajunta O(1) para apontadores e O(n)
para arranjos.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 42

Heapsort
Filas de Prioridades - Representao

A melhor representao atravs de uma


estruturas de dados chamada heap:
Neste caso, Constri O(n).
Insere, Retira, Substitui e Altera so
O(log n).

Observao:
Para implementar a operao Ajunta de forma
eficiente e ainda preservar um custo
logartmico para as operaes Insere, Retira,
Substitui e Altera necessrio utilizar
estruturas de dados mais sofisticadas, tais
como rvores binomiais (Vuillemin, 1978).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 43

Heapsort
Filas de Prioridades - Algoritmos de
Ordenao

As operaes das filas de prioridades podem


ser utilizadas para implementar algoritmos de
ordenao.

Basta utilizar repetidamente a operao


Insere para construir a fila de prioridades.

Em seguida, utilizar repetidamente a


operao Retira para receber os itens na
ordem reversa.

O uso de listas lineares no ordenadas


corresponde ao mtodo da seleo.

O uso de listas lineares ordenadas


corresponde ao mtodo da insero.

O uso de heaps corresponde ao mtodo


Heapsort.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 44

Heapsort
Heaps
uma seqncia de itens com chaves
c[1], c[2], . . . , c[n], tal que:

c[i] c[2i],
c[i] c[2i + 1],

para todo i = 1, 2, . . . , n/2.


A definio pode ser facilmente visualizada
em uma rvore binria completa:

1 S

2 R O 3

4 E 5 N A 6 D 7

rvore binria completa:


Os ns so numerados de 1 a n.
O primeiro n chamado raiz.
O n bk/2c o pai do n k, para 1 < k n.
Os ns 2k e 2k + 1 so os filhos
esquerda e direita do n k, para
1 k bk/2c.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 45

Heapsort
Heaps

As chaves na rvore satisfazem a condio


do heap.

As chaves em cada n s ao maiores do que


as chaves em seus filhos.

A chave no n raiz a maior chave do


conjunto.

Uma rvore binria completa pode ser


representada por um arranjo:

1 2 3 4 5 6 7
S R O E N A D

A representao extremamente compacta.

Permite caminhar pelos ns da rvore


facilmente.

Os filhos de um n i esto nas posies 2i e


2i + 1.

O pai de um n i est na posio i / 2.


Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 46

Heapsort
Heaps

Na representao do heap em um arranjo, a


maior chave est sempre na posio 1 do
vetor.

Os algoritmos para implementar as


operaes sobre o heap operam ao longo de
um dos caminhos da rvore.

Um algoritmo elegante para construir o heap


foi proposto por Floyd em 1964.

O algoritmo no necessita de nenhuma


memria auxiliar.

Dado um vetor v [1], v [2], . . . , v [n].

Os itens v [n/2 + 1], v [n/2 + 2], . . . , v [n]


formam um heap:
Neste intervalo no existem dois ndices i
e j tais que j = 2i ou j = 2i + 1.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 47

Heapsort
Estrutura de dados fila de prioridades
implementada utilizando um heap

package cap4. ordenacaointerna ;


import cap4. Item ; / / vide transparncia 6
public class FPHeapMax {
private Item v [ ] ;
private int n;
public FPHeapMax ( Item v [ ] ) {
this . v = v ; this .n = this . v . length 1;
}
public void refaz ( int esq, int dir )
public void constroi ( )
public Item max ( )
public Item retiraMax ( ) throws Exception
public void aumentaChave ( int i , Object chaveNova)
throws Exception
public void insere ( Item x ) throws Exception
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 48

Heapsort
Heaps
Algoritmo:
1 2 3 4 5 6 7

Chaves iniciais: O R D E N A S
Esq = 3 O R S E N A D
Esq = 2 O R S E N A D
Esq = 1 S R O E N A D

Os itens de v [4] a v [7] formam um heap.


O heap estendido para a esquerda
(esq = 3), englobando o item v [3], pai dos
itens v [6] e v [7].
A condio de heap violada:
O heap refeito trocando os itens D e S.
O item R incluindo no heap (esq = 2), o que
no viola a condio de heap.
O item O incluindo no heap (esq = 1).
A Condio de heap violada:
O heap refeito trocando os itens O e S,
encerrando o processo.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 49

Heapsort
Heaps

O Programa que implementa a operao que


informa o item com maior chave:

public Item max ( ) {


return this . v [ 1 ] ;
}

Mtodo para refazer o heap:

public void refaz ( int esq, int dir ) {


int j = esq 2 ; Item x = this . v [esq ] ;
while ( j <= dir ) {
i f ( ( j < dir ) && (this . v [ j ] .compara ( this . v [ j + 1]) < 0))
j ++;
i f ( x .compara ( this . v [ j ]) >= 0) break;
this . v [esq] = this . v [ j ] ;
esq = j ; j = esq 2;
}
this . v [esq] = x ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 50

Heapsort
Heaps

Mtodo para construir o heap:

/ / Usa o mtodo refaz da transparncia 49


public void constroi ( ) {
int esq = n / 2 + 1 ;
while (esq > 1) {
esq;
this . refaz (esq, this .n) ;
}
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 51

Heapsort
Heaps

Programa que implementa a operao de retirar o


item com maior chave:

/ / Usa o mtodo refaz da transparncia 49


public Item retiraMax ( ) throws Exception {
Item maximo;
i f ( this .n < 1) throw new Exception ( "Erro : heap vazio" ) ;
else {
maximo = this . v [ 1 ] ;
this . v[1] = this . v [ this .n];
refaz ( 1 , this .n) ;
}
return maximo;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 52

Heapsort
Heaps

Programa que implementa a operao de


aumentar o valor da chave do item i:

public void aumentaChave ( int i , Object chaveNova)


throws Exception {
Item x = this . v [ i ] ;
i f (chaveNova == null )
throw new Exception ( "Erro : chaveNova com valor null " ) ;
x . alteraChave (chaveNova) ;
while ( ( i > 1) && (x .compara ( this . v [ i / 2 ] ) > = 0 ) ) {
this . v [ i ] = this . v [ i / 2 ] ; i /= 2;
}
this . v [ i ] = x ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 53

Heapsort
Heaps

Exemplo da operao de aumentar o valor da


chave do item na posio i:

(a) S (b) S

R O R O

i i
E N A D E N U D

(c) S (d) U i

i
R U R S

E N O D E N O D

O tempo de execuo do procedimento


AumentaChave em um item do heap
O(log n).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 54

Heapsort
Heaps

Programa que implementa a operao de inserir


um novo item no heap:

/ / Usa o mtodo aumentaChave da tranparncia 52


public void insere ( Item x ) throws Exception {
this .n++;
i f ( this .n == this . v . length ) throw new Exception
( "Erro : heap cheio" ) ;
Object chaveNova = x .recuperaChave ( ) ;
this . v [ this .n] = x ;
this . v [ this .n ] . alteraChave (new Integer
( Integer . MIN_VALUE ) ) ; / /
this .aumentaChave ( this .n, chaveNova) ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 55

Heapsort

Algoritmo:
1. Construir o heap.
2. Troque o item na posio 1 do vetor (raiz
do heap) com o item da posio n.
3. Use o procedimento Refaz para
reconstituir o heap para os itens v [1],
v [2], . . . , v [n 1].
4. Repita os passos 2 e 3 com os n 1 itens
restantes, depois com os n 2, at que
reste apenas um item.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 56

Heapsort

Exemplo de aplicao do Heapsort:

1 2 3 4 5 6 7

S R O E N A D
R N O E D A S
O N A E D R
N E A D O
E D A N
D A E
A D

O caminho seguido pelo procedimento Refaz


para reconstituir a condio do heap est em
negrito.

Por exemplo, aps a troca dos itens S e D na


segunda linha da Figura, o item D volta para a
posio 5, aps passar pelas posies 1 e 2.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 57

Heapsort
Programa que mostra a implementao do
Heapsort para um conjunto de n itens
implementado como um vetor do tipo Item:

public static void heapsort ( Item v [ ] , int n) {


/ / Usa a classe FPHeapMax da transparncia 47
FPHeapMax fpHeap = new FPHeapMax ( v ) ;
int dir = n;
fpHeap. constroi ( ) ; / / constroi o heap
while ( dir > 1 ) { / / ordena o vetor
Item x = v [ 1 ] ;
v[1] = v [ dir ] ;
v [ dir ] = x ;
dir;
fpHeap. refaz ( 1 , dir ) ;
}
}

Anlise
O procedimento Refaz gasta cerca de log n
operaes, no pior caso.
Logo, Heapsort gasta um tempo de execuo
proporcional a n log n, no pior caso.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5 58

Heapsort

Vantagens:
O comportamento do Heapsort sempre
O(n log n), qualquer que seja a entrada.

Desvantagens:
O anel interno do algoritmo bastante
complexo se comparado com o do
Quicksort.
O Heapsort no estvel.

Recomendado:
Para aplicaes que no podem tolerar
eventualmente um caso desfavorvel.
No recomendado para arquivos com
poucos registros, por causa do tempo
necessrio para construir o heap.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 59

Comparao entre os Mtodos


Complexidade:

Complexidade
Insero O(n2 )
Seleo O(n2 )
Shellsort O(n log n)
Quicksort O(n log n)
Heapsort O(n log n)

Apesar de no se conhecer analiticamente o


comportamento do Shellsort, ele
considerado um mtodo eficiente.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 60

Comparao entre os Mtodos


Tempo de execuo:
Oservao: O mtodo que levou menos
tempo real para executar recebeu o valor 1 e
os outros receberam valores relativos a ele.
Registros na ordem aleatria:
5.00 5.000 10.000 30.000
Insero 11,3 87 161
Seleo 16,2 124 228
Shellsort 1,2 1,6 1,7 2
Quicksort 1 1 1 1
Heapsort 1,5 1,6 1,6 1,6

Registros na ordem ascendente:


500 5.000 10.000 30.000
Insero 1 1 1 1
Seleo 128 1.524 3.066
Shellsort 3,9 6,8 7,3 8,1
Quicksort 4,1 6,3 6,8 7,1
Heapsort 12,2 20,8 22,4 24,6
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 61

Comparao entre os Mtodos


Tempo de execuo:

Registros na ordem descendente:

500 5.000 10.000 30.000


Insero 40,3 305 575
Seleo 29,3 221 417
Shellsort 1,5 1,5 1,6 1,6
Quicksort 1 1 1 1
Heapsort 2,5 2,7 2,7 2,9
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 62

Comparao entre os Mtodos


Observaes sobre os mtodos:
1. Shellsort, Quicksort e Heapsort tm a mesma
ordem de grandeza.
2. O Quicksort o mais rpido para todos os
tamanhos aleatrios experimentados.
3. A relao Heapsort/Quicksort se mantm
constante para todos os tamanhos, sendo o
Heapsort mais lento.
4. A relao Shellsort/Quicksort aumenta
medida que o nmero de elementos aumenta;
para arquivos pequenos (500 elementos), o
Shellsort mais rpido que o Heapsort;
porm, quando o tamanho da entrada cresce,
essa relao se inverte.
5. O mtodo da Insero o mais rpido para
qualquer tamanho se os elementos esto
ordenados; Ele o mais lento para qualquer
tamanho se os elementos esto em ordem
descendente;
6. Entre os algoritmos de custo O(n2 ), o
Insero melhor para todos os tamanhos
aleatrios experimentados.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 63

Comparao entre os Mtodos


Influncia da ordem inicial do registros:
Shellsort Quicksort Heapsort
5.000 10.000 30.000 5.000 10.000 30.000 5.000 10.000 30.000
Asc 1 1 1 1 1 1 1,1 1,1 1,1
Des 1,5 1,6 1,5 1,1 1,1 1,1 1 1 1
Ale 2,9 3,1 3,7 1,9 2,0 2,0 1,1 1 1

1. O Shellsort bastante sensvel ordenao


ascendente ou descendente da entrada;

2. Em arquivos do mesmo tamanho, o Shellsort


executa mais rpido para arquivos ordenados.

3. O Quicksort sensvel ordenao


ascendente ou descendente da entrada.

4. Em arquivos do mesmo tamanho, o Quicksort


executa mais rpido para arquivos ordenados.

5. O Quicksort o mais rpido para qualquer


tamanho para arquivos na ordem ascendente.

6. O Heapsort praticamente no sensvel


ordenao da entrada.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 64

Comparao entre os Mtodos


Mtodo da Insero:

o mais interessante para arquivos com


menos do que 20 elementos.

O mtodo estvel.

Possui comportamento melhor do que o


mtodo da bolha (Bubblesort) que tambm
estvel.

Sua implementao to simples quanto as


implementaes do Bubblesort e Seleo.

Para arquivos j ordenados, o mtodo O(n).

O custo linear para adicionar alguns


elementos a um arquivo j ordenado.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 65

Comparao entre os Mtodos


Mtodo da Seleo:

vantajoso quanto ao nmero de


movimentos de registros, que O(n).

Deve ser usado para arquivos com registros


muito grandes, desde que o tamanho do
arquivo no exceda 1.000 elementos.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 66

Comparao entre os Mtodos


Shellsort:

o mtodo a ser escolhido para a maioria


das aplicaes por ser muito eficiente para
arquivos de tamanho moderado.

Mesmo para arquivos grandes, o mtodo


cerca de apenas duas vezes mais lento do
que o Quicksort.

Sua implementao simples e geralmente


resulta em um programa pequeno.

No possui um pior caso ruim e quando


encontra um arquivo parcialmente ordenado
trabalha menos.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 67

Comparao entre os Mtodos


Quicksort:

o algoritmo mais eficiente que existe para


uma grande variedade de situaes.

um mtodo bastante frgil no sentido de


que qualquer erro de implementao pode
ser difcil de ser detectado.

O algoritmo recursivo, o que demanda uma


pequena quantidade de memria adicional.

Seu desempenho da ordem de O(n2 )


operaes no pior caso.

O principal cuidado a ser tomado com


relao escolha do piv.

A escolha do elemento do meio do arranjo


melhora muito o desempenho quando o
arquivo est total ou parcialmente ordenado.

O pior caso tem uma probabilidade muito


remota de ocorrer quando os elementos
forem aleatrios.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 68

Comparao entre os Mtodos


Quicksort:

Geralmente se usa a mediana de uma


amostra de trs elementos para evitar o pior
caso.

Esta soluo melhora o caso mdio


ligeiramente.

Outra importante melhoria para o


desempenho do Quicksort evitar chamadas
recursivas para pequenos subarquivos.

Para isto, basta chamar um mtodo de


ordenao simples nos arquivos pequenos.

A melhoria no desempenho significativa,


podendo chegar a 20% para a maioria das
aplicaes (Sedgewick, 1988).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 69

Comparao entre os Mtodos


Heapsort:

um mtodo de ordenao elegante e


eficiente.

Apesar de ser cerca de duas vezes mais lento


do que o Quicksort, no necessita de
nenhuma memria adicional.

Executa sempre em tempo proporcional a


n log n,

Aplicaes que no podem tolerar eventuais


variaes no tempo esperado de execuo
devem usar o Heapsort.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6 70

Comparao entre os Mtodos


Consideraes finais:

Para registros muito grandes desejvel que


o mtodo de ordenao realize apenas n
movimentos dos registros.

Com o uso de uma ordenao indireta


possvel se conseguir isso.

Suponha que o arquivo A contenha os


seguintes registros: v [1], v [2], . . . , v [n].

Seja p um arranjo p[1], p[2], . . . , p[n] de


apontadores.

Os registros somente so acessados para


fins de comparaes e toda movimentao
realizada sobre os apontadores.

Ao final, p[1] contm o ndice do menor


elemento de v , p[2] o ndice do segundo
menor e assim sucessivamente.

Essa estratgia pode ser utilizada para


qualquer dos mtodos de ordenao interna.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 71

Ordenao Parcial

Consiste em obter os k primeiros elementos


de um vetor ordenado com n elementos.

Quando k = 1, o problema se reduz a


encontrar o mnimo (ou o mximo) de um
conjunto de elementos.

Quando k = n camos no problema clssico


de ordenao.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 72

Ordenao Parcial
Aplicaes:

Facilitar a busca de informao na Web com


as mquinas de busca:
comum uma consulta na Web retornar
centenas de milhares de documentos
relacionados com a consulta.
O usurio est interessado apenas nos k
documentos mais relevantes.
Em geral k menor do que 200
documentos.
Normalmente so consultados apenas os
dez primeiros.
Assim, so necessrios algoritmos
eficientes de ordenao parcial.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 73

Ordenao Parcial
Algoritmos considerados:

Seleo parcial.

Insero parcial.

Heapsort parcial.

Quicksort parcial.

A classe OrdenacaoParcial mostrada a


seguir.

package cap4. ordenacaointerna ;


import cap4. Item ; / / vide transparncia 5

public class OrdenacaoParcial {


public static void selecaoParcial(Item v [ ] , int n, int k)
public static void insercaoParcial (Item v [ ] , int n, int k)
public static void insercaoParcial2(Item V[ ] , int n, int k)
public static void quicksortParcial (Item v [ ] , int n, int k)
public static void heapsortParcial (Item v [ ] , int n, int k)
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 74

Seleo Parcial

Um dos algoritmos mais simples.

Princpio de funcionamento:
Selecione o menor item do vetor.
Troque-o com o item que est na primeira
posio do vetor.
Repita estas duas operaes com os itens
n 1, n 2 . . . n k.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 75

Seleo Parcial

public static void selecaoParcial ( Item v [ ] , int n, int k) {


for ( int i = 1; i <= k ; i ++) {
int min = i ;
for ( int j = i + 1; j <= n ; j ++)
i f ( v [ j ] .compara ( v [min] ) < 0 ) min = j ;
Item x = v [min ] ; v [min] = v [ i ] ; v [ i ] = x ;
}
}

Anlise:

Comparaes entre chaves e movimentaes


de registros:

k2 k
C(n) = kn 2
2

M (n) = 3k
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 76

Seleo Parcial

muito simples de ser obtido a partir da


implementao do algoritmo de ordenao
por seleo.

Possui um comportamento espetacular


quanto ao nmero de movimentos de
registros:
Tempo de execuo linear no tamanho
de k.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 77

Insero Parcial

Pode ser obtido a partir do algoritmo de


ordenao por Insero por meio de uma
modificao simples:
Tendo sido ordenados os primeiros k itens,
o item da k-sima posio funciona como
um piv.
Quando um item entre os restantes
menor do que o piv, ele inserido na
posio correta entre os k itens de acordo
com o algoritmo original.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 78

Insero Parcial

public static void insercaoParcial ( Item v [ ] , int n, int k) {


int j ;
for ( int i = 2; i <= n ; i ++) {
Item x = v [ i ] ;
i f ( i > k ) j = k ; else j = i 1;
v[0] = x ; / / sentinela
while ( x .compara ( v [ j ] ) < 0 ) {
v [ j + 1] = v [ j ] ; j ;
}
v [ j + 1] = x ;
}
}

Obs:

1. A modificao realizada verifica o momento


em que i se torna maior do que k e ento
passa a considerar o valor de j igual a k a
partir deste ponto.

2. O algoritmo no preserva o restante do vetor.


Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 79

Insero Parcial
Algoritmo de Insero Parcial que preserva o
restante do vetor:

public static void insercaoParcial2 ( Item v [ ] , int n, int k) {


int j ;
for ( int i = 2; i <= n ; i ++) {
Item x = v [ i ] ;
if ( i > k) {
j = k;
i f ( x .compara ( v [ k] ) < 0 ) v [ i ] = v [ k ] ;
}
else j = i 1;
v[0] = x ; / / sentinela
while ( x .compara ( v [ j ] ) < 0 ) {
i f ( j < k ) v [ j + 1] = v [ j ] ;
j ;
}
i f ( j < k ) v [ j + 1] = x ;
}
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 80

Insero Parcial
Anlise:
No anel mais interno, na i-sima iterao o
valor de Ci :
melhor caso : Ci (n) = 1
pior caso : Ci (n) = i
1 i+1
caso medio : Ci (n) = i
(1 + 2 + + i) = 2

Assumindo que todas as permutaes de n


so igualmente provveis, o nmero de
comparaes :

melhor caso : C(n) = (1 + 1 + + 1) = n 1


pior caso : C(n) = (2 + 3 + + k + (k + 1)(n k))
k2 k
= kn + n 2
2
1
1
caso medio : C(n) = 2
(3 + 4 + + k + 1 + (k + 1)(n k))
kn k2
= 2
+n 2
4
+ k
4
1
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 81

Insero Parcial
Anlise:
O nmero de movimentaes na i-sima
iterao :
Mi (n) = Ci (n) 1 + 3 = Ci (n) + 2

Logo, o nmero de movimentos :

melhor caso : M (n) = (3 + 3 + + 3) = 3(n 1)


pior caso : M (n) = (4 + 5 + + k + 2 + (k + 1)(n k))
k2 3k
= kn + n 2
+ 2
3
1
caso medio : M (n) = 2
(5 + 6 + + k + 3 + (k + 1)(n k))
kn k2
= 2
+n 2
4
+ 5k
4
2

O nmero mnimo de comparaes e


movimentos ocorre quando os itens esto
originalmente em ordem.

O nmero mximo ocorre quando os itens


esto originalmente na ordem reversa.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 82

Heapsort Parcial

Utiliza um tipo abstrato de dados heap para


informar o menor item do conjunto.

Na primeira iterao, o menor item que est


em v [1]
(raiz do heap) trocado com o item que est
em v [n].

Em seguida o heap refeito.

Novamente, o menor est em A[1], troque-o


com A[n-1].

Repita as duas ltimas operaes at que o


k-simo menor seja trocado com v [n k].

Ao final, os k menores esto nas k ltimas


posies do vetor v .
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 83

Heapsort Parcial

public static void heapsortParcial ( Item v [ ] , int n, int k) {


/ / Coloca menor em v[n], segundo em v[n-1],...,k-esimo em v[n-k]
FPHeapMin fpHeap = new FPHeapMin ( v ) ;
int dir = n, aux = 0;
fpHeap. constroi ( ) ; / / constroi o heap
while (aux < k ) { / / ordena o vetor
Item x = v [ 1 ] ; v[1] = v [ dir ] ; v [ dir ] = x ;
dir ; aux++;
fpHeap. refaz ( 1 , dir ) ;
}
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 84

Heapsort Parcial
Anlise:

O Heapsort Parcial deve construir um heap a


um custo O(n).

O mtodo refaz tem custo O(log n).

O mtodo heapsortParcial chama o mtodo


refaz k vezes.

Logo, o algoritmo apresenta a complexidade:



O(n) n

se k log n
O(n + k log n) =
O(k log n) se k >
n
log n
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 85

Quicksort Parcial

Assim como o Quicksort, o Quicksort Parcial


o algoritmo de ordenao parcial mais
rpido em vrias situaes.

A alterao no algoritmo para que ele ordene


apenas os k primeiros itens dentre n itens
muito simples.

Basta abandonar a partio direita toda vez


que a partio esquerda contiver k ou mais
itens.

Assim, a nica alterao necessria no


Quicksort evitar a chamada recursiva
ordena(i, dir ).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 86

Quicksort Parcial

Chaves iniciais: O R D E N A
1 A D R E N O
2 A D
3 E R N O
4 N R O
5 O R
A D E N O R

Considere k = 3 e D o piv para gerar as


linhas 2 e 3.
A partio esquerda contm dois itens e a
partio direita contm quatro itens.
A partio esquerda contm menos do que
k itens.
Logo, a partio direita no pode ser
abandonada.
Considere E o piv na linha 3.
A partio esquerda contm trs itens e a
partio direita tambm.
Assim, a partio direita pode ser
abandonada.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 87

Quicksort Parcial

private static void ordena(Item v [ ] , int esq, int dir , int k) {


LimiteParticoes p = particao ( v , esq, dir ) ;
i f (p. j esq >= k 1) {
i f (esq < p. j ) ordena ( v , esq, p. j , k ) ;
return ;
}
i f (esq < p. j ) ordena ( v , esq, p. j , k ) ;
i f (p. i < dir ) ordena ( v , p. i , dir , k ) ;
}
public static void quicksortParcial (Item v [ ] , int n, int k) {
ordena ( v , 1 , n, k ) ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 88

Quicksort Parcial
Anlise:

A anlise do Quicksort difcil.

O comportamento muito sensvel escolha


do piv.

Podendo cair no melhor caso O(k log k).

Ou em algum valor entre o melhor caso e


O(n log n).
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 89

Comparao entre os Mtodos de


Ordenao Parcial
n, k Seleo Quicksort Insero Insero2 Heapsort
1 0
n : 10 k : 10 1 2,5 1 1,2 1,7
1 1
n : 10 k : 10 1,2 2,8 1 1,1 2,8
n : 102 k : 100 1 3 1,1 1,4 4,5
2 1
n : 10 k : 10 1,9 2,4 1 1,2 3
2 2
n : 10 k : 10 3 1,7 1 1,1 2,3
n : 103 k : 100 1 3,7 1,4 1,6 9,1
3 1
n : 10 k : 10 4,6 2,9 1 1,2 6,4
3 2
n : 10 k : 10 11,2 1,3 1 1,4 1,9
3 3
n : 10 k : 10 15,1 1 3,9 4,2 1,6
5 0
n : 10 k : 10 1 2,4 1,1 1,1 5,3
5 1
n : 10 k : 10 5,9 2,2 1 1 4,9
5 2
n : 10 k : 10 67 2,1 1 1,1 4,8
n : 105 k : 103 304 1 1,1 1,3 2,3
5 4
n : 10 k : 10 1445 1 33,1 43,3 1,7
5 5
n : 10 k : 10 1 1,9
n : 106 k : 100 1 3,9 1,2 1,3 8,1
6 1
n : 10 k : 10 6,6 2,7 1 1 7,3
6 2
n : 10 k : 10 83,1 3,2 1 1,1 6,6
6 3
n : 10 k : 10 690 2,2 1 1,1 5,7
6 4
n : 10 k : 10 1 5 6,4 1,9
6 5
n : 10 k : 10 1 1,7
6 6
n : 10 k : 10 1 1,8
n : 107 k : 100 1 3,4 1,1 1,1 7,4
7 1
n : 10 k : 10 8,6 2,6 1 1,1 6,7
7 2
n : 10 k : 10 82,1 2,6 1 1,1 6,8
7 3
n : 10 k : 10 3,1 1 1,1 6,6
7 4
n : 10 k : 10 1,1 1 1,2 2,6
7 5
n : 10 k : 10 1 2,2
7 6
n : 10 k : 10 1 1,2
n : 107 k : 107 1 1,7
Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7 90

Comparao entre os Mtodos de


Ordenao Parcial

1. Para valores de k at 1.000, o mtodo da


InseroParcial imbatvel.

2. O Quicksort Parcial nunca ficar muito longe


da InseroParcial.

3. Na medida em que o k cresce,o Quicksort


Parcial a melhor opo.

4. Para valores grandes de k, o mtodo da


InseroParcial se torna ruim.

5. Um mtodo indicado para qualquer situao


o QuicksortParcial.

6. O Heapsort Parcial tem comportamento


parecido com o do Quicksort Parcial.

7. No entano, o Heapsort Parcial mais lento.


Projeto de Algoritmos Cap.4 Ordenao Seo 4.2 91

Ordenao Externa

A ordenao externa consiste em ordenar


arquivos de tamanho maior que a memria
interna disponvel.

Os mtodos de ordenao externa so muito


diferentes dos de ordenao interna.

Na ordenao externa os algoritmos devem


diminuir o nmero de acesso as unidades de
memria externa.

Nas memrias externas, os dados so


armazenados como um arquivo seqencial.

Apenas um registro pode ser acessado em


um dado momento.

Esta uma restrio forte se comparada com


as possibilidades de acesso em um vetor.

Logo, os mtodos de ordenao interna so


inadequados para ordenao externa.

Tcnicas de ordenao completamente


diferentes devem ser utilizadas.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2 92

Ordenao Externa
Fatores que determinam as diferenas das
tcnicas de ordenao externa:

1. Custo para acessar um item algumas


ordens de grandeza maior.

2. O custo principal na ordenao externa


relacionado a transferncia de dados entre a
memria interna e externa.

3. Existem restries severas de acesso aos


dados.

4. O desenvolvimento de mtodos de ordenao


externa muito dependente do estado atual
da tecnologia.

5. A variedade de tipos de unidades de memria


externa torna os mtodos dependentes de
vrios parmetros.

6. Assim, apenas mtodos gerais sero


apresentados.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2 93

Ordenao Externa

O mtodo mais importante o de ordenao


por intercalao.

Intercalar significa combinar dois ou mais


blocos ordenados em um nico bloco
ordenado.

A intercalao utilizada como uma


operao auxiliar na ordenao.

Estratgia geral dos mtodos de ordenao


externa:
1. Quebre o arquivo em blocos do tamanho
da memria interna disponvel.
2. Ordene cada bloco na memria interna.
3. Intercale os blocos ordenados, fazendo
vrias passadas sobre o arquivo.
4. A cada passada so criados blocos
ordenados cada vez maiores, at que todo
o arquivo esteja ordenado.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2 94

Ordenao Externa

Os algoritmos para ordenao externa devem


reduzir o nmero de passadas sobre o
arquivo.

Uma boa medida de complexidade de um


algoritmo de ordenao por intercalao o
nmero de vezes que um item lido ou
escrito na memria auxiliar.

Os bons mtodos de ordenao geralmente


envolvem no total menos do que dez
passadas sobre o arquivo.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1 95

Intercalao Balanceada de Vrios


Caminhos

Considere um arquivo armazenado em uma


fita de entrada:
INTERCALACAOBALANCEADA

Objetivo:
Ordenar os 22 registros e coloc-los em
uma fita de sada.

Os registros so lidos um aps o outro.

Considere uma memria interna com


capacidade para para trs registros.

Considere que esteja disponvel seis


unidades de fita magntica.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1 96

Intercalao Balanceada de Vrios


Caminhos

Fase de criao dos blocos ordenados:

fita 1: INT ACO ADE


fita 2: CER ABL A
fita 3: AAL ACN
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1 97

Intercalao Balanceada de Vrios


Caminhos
Fase de intercalao - Primeira passada:
1. O primeiro registro de cada fita lido.
2. Retire o registro contendo a menor chave.
3. Armazene-o em uma fita de sada.
4. Leia um novo registro da fita de onde o
registro retirado proveniente.
5. Ao ler o terceiro registro de um dos blocos,
sua fita fica inativa.
6. A fita reativada quando o terceiro
registro das outras fitas forem lidos.
7. Neste instante um bloco de nove registros
ordenados foi formado na fita de sada.
8. Repita o processo para os blocos
restantes.
Resultado da primeira passada da segunda
etapa:
fita 4: AACEILNRT
fita 5: AAABCCLNO
fita 6: AADE
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1 98

Intercalao Balanceada de Vrios


Caminhos

Quantas passadas so necessrias para


ordenar um arquivo de tamanho arbitrrio?
Seja n, o nmero de registros do arquivo.
Suponha que cada registro ocupa m
palavras na memria interna.
A primeira etapa produz n/m blocos
ordenados.
Seja P (n) o nmero de passadas para a
fase de intercalao.
Seja f o nmero de fitas utilizadas em
cada passada.
Assim:
n
.
P (n) = logf
m
No exemplo acima, n=22, m=3 e f=3
temos:
22
P (n) = log3 = 2.
3
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1 99

Intercalao Balanceada de Vrios


Caminhos

No exemplo foram utilizadas 2f fitas para uma


intercalao-de-f -caminhos.

possvel usar apenas f + 1 fitas:


Encaminhe todos os blocos para uma
nica fita.
Redistribuia estes blocos entre as fitas de
onde eles foram lidos.
O custo envolvido uma passada a mais
em cada intercalao.

No caso do exemplo de 22 registros, apenas


quatro fitas seriam suficientes:
A intercalao dos blocos a partir das fitas
1, 2 e 3 seria toda dirigida para a fita 4.
Ao final, o segundo e o terceiro blocos
ordenados de nove registros seriam
transferidos de volta para as fitas 1 e 2.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2 100

Implementao por meio de Seleo


por Substituio

A implementao do mtodo de intercalao


balanceada pode ser realizada utilizando filas
de prioridades.

As duas fases do mtodo podem ser


implementadas de forma eficiente e elegante.

Operaes bsicas para formar blocos


ordenados:
Obter o menor dentre os registros
presentes na memria interna.
Substitu-lo pelo prximo registro da fita de
entrada.

Estrutura ideal para implementar as


operaes: heap.

Operao de substituio:
Retirar o menor item da fila de prioridades.
Colocar um novo item no seu lugar.
Reconstituir a propriedade do heap.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2 101

Implementao por meio de Seleo


por Substituio
Algoritmo:

1. Inserir m elementos do arquivo na fila de


prioridades.

2. Substituir o menor item da fila de prioridades


pelo prximo item do arquivo.

3. Se o prximo item menor do que o que saiu,


ento:
Considere-o membro do prximo bloco.
Trate-o como sendo maior do que todos os
itens do bloco corrente.

4. Se um item marcado vai para o topo da fila de


prioridades ento:
O bloco corrente encerrado.
Um novo bloco ordenado iniciado.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2 102

Implementao por meio de Seleo


por Substituio
Primeira passada sobre o arquivo exemplo:
Entra 1 2 3

E I N T
R N E* T
C R E* T
A T E* C*
L A* E* C*
A C* E* L*
C E* A L*
A L* A C
O A A C
B A O C
A B O C
L C O A*
A L O A*
N O A* A*
C A* N* A*
E A* N* C*
A C* N* E*
D E* N* A
A N* D A
A D A
A D
D

Os asteriscos indicam quais chaves pertencem a


blocos diferentes.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2 103

Implementao por meio de Seleo


por Substituio
Tamanho dos blocos produzidas para chaves
randmicas:
Os blocos ordenados so cerca de duas
vezes o tamanho dos blocos criados pela
ordenao interna.
Isso pode salvar uma passada na fase de
intercalao.
Se houver alguma ordem nas chaves, os
blocos ordenados podem ser ainda maiores.
Se nenhuma chave possui mais do que m
chaves maiores do que ela, o arquivo
ordenado em um passo.
Exemplo para as chaves RAPAZ:
Entra 1 2 3

A A R P
Z A R P
P R Z
R Z
Z
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2 104

Implementao por meio de Seleo


por Substituio

Fase de intercalao dos blocos ordenados


obtidos na primeira fase:
Operao bsica: obter o menor item
dentre os ainda no retirados dos f blocos
a serem intercalados.

Algoritmo:

Monte uma fila de prioridades de tamanho f .

A partir de cada uma das f entradas:


Substitua o item no topo da fila de
prioridades pelo prximo item do mesmo
bloco do item que est sendo substitudo.
Imprima em outra fita o elemento
substitudo.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2 105

Implementao por meio de Seleo


por Substituio
Exemplo:
Entra 1 2 3

A A C I
L A C I
E C L I
R E L I
N I L R
L N R
T N R
R T
T

Para f pequeno no vantajoso utilizar


seleo por substituio para intercalar
blocos:
Obtm-se o menor item fazendo f 1
comparaes.
Quando f 8 ou mais, o mtodo adequado:
Obtm-se o menor item fazendo log2 f
comparaes.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3 106

Consideraes Prticas

As operaes de entrada e sada de dados


devem ser implementadas eficientemente.

Deve-se procurar realizar a leitura, a escrita e


o processamento interno dos dados de forma
simultnea.

Os computadores de maior porte possuem


uma ou mais unidades independentes para
processamento de entrada e sada.

Assim, pode-se realizar processamento e


operaes de E/S simultaneamente.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3 107

Consideraes Prticas

Tcnica para obter superposio de E/S e


processamento interno:
Utilize 2f reas de entrada e 2f de sada.
Para cada unidade de entrada ou sada,
utiliza-se duas reas de armazenamento:
1. Uma para uso do processador central
2. Outra para uso do processador de
entrada ou sada.
Para entrada, o processador central usa
uma das duas reas enquanto a unidade
de entrada est preenchendo a outra rea.
Depois a utilizao das reas invertida
entre o processador de entrada e o
processador central.
Para sada, a mesma tcnica utilizada.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3 108

Consideraes Prticas

Problemas com a tcnica:


Apenas metade da memria disponvel
utilizada.
Isso pode levar a uma ineficincia se o
nmero de reas for grande.
Ex: Intercalao-de-f -caminhos para f
grande.
Todas as f reas de entrada em uma
intercalao-de-f -caminhos se esvaziando
aproximadamente ao mesmo tempo.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3 109

Consideraes Prticas

Soluo para os problemas:


Tcnica de previso:
Requer a utilizao de uma nica rea
extra de armazenamento durante a
intercalao.
Superpe a entrada da prxima rea
que precisa ser preenchida com a parte
de processamento interno do algoritmo.
fcil saber qual rea ficar vazia
primeiro.
Basta olhar para o ltimo registro de
cada rea.
A rea cujo ltimo registro o menor,
ser a primeira a se esvaziar.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3 110

Consideraes Prticas

Escolha da ordem de intercalao f :


Para fitas magnticas:
f deve ser igual ao nmero de unidades
de fita disponveis menos um.
A fase de intercalao usa f fitas de
entrada e uma fita de sada.
O nmero de fitas de entrada deve ser
no mnimo dois.
Para discos magnticos:
O mesmo raciocnio acima vlido.
O acesso seqencial mais eficiente.
Sedegwick (1988) sugere considerar f
grande o suficiente para completar a
ordenao em poucos passos.
Porm, a melhor escolha para f depende
de vrios parmetros relacionados com o
sistema de computao disponvel.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4 111

Intercalao Polifsica

Problema com a intercalao balanceada de


vrios caminhos:
Necessita de um grande nmero de fitas.
Faz vrias leituras e escritas entre as fitas
envolvidas.
Para uma intercalao balanceada de f
caminhos so necessrias 2f fitas.
Alternativamente, pode-se copiar o arquivo
quase todo de uma nica fita de sada
para f fitas de entrada.
Isso reduz o nmero de fitas para f + 1.
Porm, h um custo de uma cpia
adicional do arquivo.

Soluo:
Intercalao polifsica.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4 112

Intercalao Polifsica

Os blocos ordenados so distribudos de


forma desigual entre as fitas disponveis.

Uma fita deixada livre.

Em seguida, a intercalao de blocos


ordenados executada at que uma das fitas
esvazie.

Neste ponto, uma das fitas de sada troca de


papel com a fita de entrada.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4 113

Intercalao Polifsica

Exemplo:
Blocos ordenados obtidos por meio de
seleo por substituio:

fita 1: INRT ACEL AABCLO


fita 2: AACEN AAD
fita 3:

Configurao aps uma


intercalao-de-2-caminhos das fitas 1 e 2
para a fita 3:

fita 1: AABCLO
fita 2:
fita 3: AACEINNRT AAACDEL
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4 114

Intercalao Polifsica

Exemplo:
Depois da intercalao-de-2-caminhos das
fitas 1 e 3 para a fita 2:

fita 1:
fita 2: AAAABCCEILNNORT
fita 3: AAACDEL

Finalmente:
fita 1: AAAAAAABCCCDEEILLNNORT
fita 2:
fita 3:

A intercalao realizada em muitas


fases.
As fases no envolvem todos os blocos.
Nenhuma cpia direta entre fitas
realizada.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4 115

Intercalao Polifsica

A implementao da intercalao polifsica


simples.

A parte mais delicada est na distribuio


inicial dos blocos ordenados entre as fitas.

Distribuio dos blocos nas diversas etapas


do exemplo:

fita 1 fita 2 fita 3 Total


3 2 0 5
1 0 2 3
0 1 1 2
1 0 0 1
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4 116

Intercalao Polifsica
Anlise:

A anlise da intercalao polifsica


complicada.

O que se sabe que ela ligeiramente


melhor do que a intercalao balanceada
para valores pequenos de f .

Para valores de f > 8, a intercalao


balanceada pode ser mais rpida.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 117

Quicksort Externo

Foi proposto por Monard em 1980.

Utiliza o paradigma de diviso e conquista.

O algoritmo ordena in situ um arquivo


A = {R1 , . . . , Rn } de n registros.

Os registros esto armazenados


consecutivamente em memria secundria de
acesso randmico.

O algoritmo utiliza somente O(log n) unidades


de memria interna e no necessria
nenhuma memria externa adicional.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 118

Quicksort Externo

So necessrios quatro mtodos adicionais


para a classe MeuItem (transparncia 6).

O mtodo toString especifica como o objeto


formatado.

Os mtodos leArq e gravaArq so utilizados


para ler e gravar um objeto da classe
MeuItem em um arquivo de acesso aleatrio.

O mtodo tamanho retorna o tamanho em


bytes de um objeto da classe MeuItem.

public String toString ( ) { return " " + this .chave ; }

public void gravaArq (RandomAccessFile arq)


throws IOException {
arq . writeInt ( this .chave) ;
}
public void leArq (RandomAccessFile arq)
throws IOException {
this .chave = arq . readInt ( ) ;
}
public static int tamanho ( ) { return 4 ; / 4 bytes / }
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 119

Quicksort Externo

Seja Ri , 1 i n, o registro que se encontra


na i-sima posio de A.

Algoritmo:
1. Particionar A da seguinte forma:
{R1 , . . . , Ri } Ri+1 Ri+2 . . . Rj2
Rj1 {Rj , . . . , Rn },
2. chamar recursivamente o algoritmo em
cada um dos subarquivos
A1 = {R1 , . . . , Ri } e A2 = {Rj , . . . , Rn }.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 120

Quicksort Externo

Para o partionamento utilizanda uma rea


de armazenamento na memria interna.

Tamanho da rea: TamArea = j i 1, com


TamArea 3.

Nas chamadas recusivas deve-se considerar


que:
Primeiro deve ser ordenado o subarquivo
de menor tamanho.
Condio para que, na mdia, O(log n)
subarquivos tenham o processamento
adiado.
Subarquivos vazios ou com um nico
registro so ignorados.
Caso o arquivo de entrada A possua no
mximo TamArea registros, ele ordenado
em um nico passo.
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 121

Quicksort Externo

i Li Ls j i Li Ls j
rea Linf Lsup rea Linf Lsup
a) 5 3 10 6 1 7 4 b) 5 3 10 6 1 7 4 4

Ei Es Ei Es
i Li Ls j i Li Ls j

c) 5 3 10 6 1 7 4 4 5 d) 5 3 10 6 1 7 4 4 5 7

Ei Es Ei Es
i Li Ls j i Li Ls j

e) 5 3 10 6 1 7 7 4 5 7 f) 5 3 10 6 1 7 7 3 4 5 7

Ei Es Ei Es
i Li Ls j i Li Ls j

g) 3 3 10 6 1 7 7 4 5 3 7 h) 3 3 10 6 1 7 7 4 5 3 7

Ei Es Ei Es
Li
i Li Ls j i Ls j

i) 3 1 10 6 1 7 7 4 5 3 7 j) 3 1 10 6 1 7 7 4 5 3 7

Ei Es Ei Es
Li
i Ls j i Ls Li j

k) 3 1 10 6 1 10 7 4 5 3 7 l) 3 1 10 6 1 10 7 4 5 6 3 7

Ei Es Ei Es
i Ls Li j i Ls Li j

m) 3 1 10 6 6 10 7 4 5 3 7 n) 3 1 4 5 6 10 7 3 7

Ei Es Es Ei
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 122

Quicksort Externo
O programa a seguir apresenta a classe
QuicksortExterno, na qual so definidos as
estruturas de dados e os mtodos utilizados
pelo algoritmo Quicksort Externo.

package cap4.ordenacaoexterna;
import cap3. arranjo .Area;
import cap4.MeuItem;
import java . io . ;
public class QuicksortExterno {
private static class LimiteParticoes { int i ; int j ; }
private RandomAccessFile arqLi ;
private RandomAccessFile arqEi ;
private RandomAccessFile arqLEs;
private boolean ondeLer;
private MeuItem ultLido ;
private Area area;
private int tamArea;
/ / Mtodos utilizados pelo mtodo particao do quicksort ex-
terno
private int leSup ( int ls ) throws IOException
private int leInf ( int l i ) throws IOException
private int inserirArea ( ) throws Exception

/ / Continua na prxima transparncia


Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 123

Quicksort Externo

private int escreveMax ( int es) throws Exception


private int escreveMin ( int ei ) throws IOException
private int retiraMax ( ) throws Exception
private int retiraMin ( ) throws Exception
private LimiteParticoes particao
( int esq, int dir ) throws Exception
public QuicksortExterno ( String nomeArq, int tamArea)
throws FileNotFoundException {
this . arqLi = new RandomAccessFile (nomeArq, "rws" ) ;
this . arqEi = new RandomAccessFile (nomeArq, "rws" ) ;
this .arqLEs = new RandomAccessFile (nomeArq, "rws" ) ;
this .tamArea = tamArea;
}
public void quicksortExterno
( int esq, int dir ) throws Exception
public void fechaArquivos ( ) throws Exception {
this . arqEi . close ( ) ;
this . arqLi . close ( ) ;
this .arqLEs. close ( ) ;
}
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 124

Quicksort Externo

public void quicksortExterno ( int esq, int dir )


throws Exception {
i f ( dir esq < 1) return ;
LimiteParticoes p = particao (esq, dir ) ;
i f (p. i esq < dir p. j ) { / / ordene primeiro o subar-
quivo menor
quicksortExterno (esq, p. i ) ;
quicksortExterno (p. j , dir ) ;
}
else {
quicksortExterno (p. j , dir ) ;
quicksortExterno (esq, p. i ) ;
}
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 125

Quicksort Externo
Mtodos auxiliares utilizados pelo mtodo
particao:

private int leSup ( int ls ) throws IOException {


this . ultLido = new MeuItem ( 0 ) ;
arqLEs.seek ( ( ls 1) MeuItem.tamanho ( ) ) ;
this . ultLido . leArq (arqLEs ) ; ondeLer = false ;
return ls ;
}
private int leInf ( int l i ) throws IOException {
this . ultLido = new MeuItem ( 0 ) ;
this . ultLido . leArq ( arqLi ) ; ondeLer = true ;
return ++ l i ;
}
private int inserirArea ( ) throws Exception {
area. insereItem ( this . ultLido ) ;
return area.obterNumCelOcupadas ( ) ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 126

Quicksort Externo
Mtodos auxiliares utilizados pelo mtodo
particao:

private int escreveMax ( int es) throws Exception {


arqLEs.seek ( ( es 1) MeuItem.tamanho ( ) ) ;
this . ultLido .gravaArq (arqLEs) ;
return es;
}
private int escreveMin ( int ei ) throws IOException {
this . ultLido .gravaArq ( arqEi ) ;
return ++ei ;
}
private int retiraMax ( ) throws Exception {
this . ultLido = (MeuItem) area. retiraUltimo ( ) ;
return area.obterNumCelOcupadas ( ) ;
}
private int retiraMin ( ) throws Exception {
this . ultLido = (MeuItem) area. retiraPrimeiro ( ) ;
return area.obterNumCelOcupadas ( ) ;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 127

Quicksort Externo
Mtodo Partio:

private LimiteParticoes particao ( int esq, int dir )


throws Exception {
int ls = dir , es = dir , l i = esq, ei = esq, nrArea = 0;
MeuItem l i n f = new MeuItem ( Integer .MIN_VALUE) ; / /
MeuItem lsup = new MeuItem ( Integer .MAX_VALUE) ; / /
this .ondeLer = true ;
LimiteParticoes p = new LimiteParticoes ( ) ;
this .area = new Area ( this .tamArea) ;
arqLi .seek ( ( l i 1) MeuItem.tamanho ( ) ) ;
arqEi .seek ( ( ei 1) MeuItem.tamanho ( ) ) ;
p. i = esq 1; p. j = dir + 1;
while ( ls >= l i ) {
i f ( nrArea < this .tamArea 1) {
i f (ondeLer) ls = this .leSup ( ls ) ;
else l i = leInf ( l i ) ;
nrArea = inserirArea ( ) ;
}
else {
i f ( ls == es) ls = leSup ( ls ) ;
else i f ( l i == ei ) l i = leInf ( l i ) ;
else i f (ondeLer) ls = leSup ( ls ) ;
else l i = leInf ( l i ) ;
/ / Continua na prxima transparncia
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 128

Quicksort Externo
Mtodo Partio:

i f ( ultLido .compara ( lsup ) > 0) {


p. j = es ; es = escreveMax (es) ;
}
else i f ( ultLido .compara ( l i n f ) < 0) {
p. i = ei ; ei = escreveMin ( ei ) ;
}
else {
nrArea = inserirArea ( ) ;
i f ( ei esq < dir es ) {
nrArea = retiraMin ( ) ;
l i n f = this . ultLido ; ei=escreveMin ( ei ) ;
}
else {
nrArea = retiraMax ( ) ;
lsup = this . ultLido ; es=escreveMax (es) ;
}
}
}
}
while ( ei <= es ) {
nrArea = retiraMin ( ) ; ei = escreveMin ( ei ) ;
}
return p;
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 129

Quicksort Externo
Programa teste:
package cap4;
import java . io .RandomAccessFile;
import cap4.ordenacaoexterna. QuicksortExterno ; / / vide transparncia 122
public class TestaQuicksortExterno {
public static void main ( String [ ] args ) {
try {
RandomAccessFile arq = new RandomAccessFile ( "qe. dat" , "rwd" ) ;
MeuItem item = new MeuItem ( 5 ) ; item .gravaArq ( arq ) ;
item = new MeuItem ( 3 ) ; item .gravaArq ( arq ) ;
item = new MeuItem ( 1 0 ) ; item .gravaArq ( arq ) ;
item = new MeuItem ( 6 ) ; item .gravaArq ( arq ) ;
item = new MeuItem ( 1 ) ; item .gravaArq ( arq ) ;
item = new MeuItem ( 7 ) ; item .gravaArq ( arq ) ;
item = new MeuItem ( 4 ) ; item .gravaArq ( arq ) ;
arq . close ( ) ;
QuicksortExterno quicksortExterno=new QuicksortExterno( "qe. dat" ,3);
quicksortExterno . quicksortExterno ( 1 , 7 ) ;
quicksortExterno . fechaArquivos ( ) ;
arq = new RandomAccessFile ( "qe. dat" , " r " ) ;
item . leArq ( arq ) ;
while ( arq . getFilePointer ( ) < arq . length ( ) ) {
System. out . println ( "Registro=" + item . toString ( ) ) ;
item . leArq ( arq ) ;
}
System. out . println ( "Registro=" + item . toString ( ) ) ; arq . close ( ) ;
} catch ( Exception e ) { System. out . println (e.getMessage ( ) ) ; }
}
}
Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5 130

Quicksort Externo
Anlise:

Seja n o nmero de registros a serem


ordenados.

Seja e b o tamanho do bloco de leitura ou


gravao do Sistema operacional.

Melhor caso: O( nb )
Por exemplo, ocorre quando o arquivo de
entrada j est ordenado.
n2
Pior caso: O( TamArea )
ocorre quando um dos arquivos retornados
pelo procedimento Particao tem o maior
tamanho possvel e o outro vazio.
A medida que n cresce, a probabilidade de
ocorrncia do pior caso tende a zero.
n
Caso Mdio: O( nb log( TamArea ))
o que tem amaior probabilidade de
ocorrer.
Pesquisa em Memria
Primria

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Fabiano C. Botelho, Leonardo Rocha, Leo-


nardo Mata e Nivio Ziviani
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria 1

Pesquisa em Memria Primria


Introduo - Conceitos Bsicos
Pesquisa Seqencial
Pesquisa Binria
rvores de Pesquisa
rvores Binrias de Pesquisa sem
Balanceamento
rvores Binrias de Pesquisa com
Balanceamento
rvores SBB
Transformaes para Manuteno da
Propriedade SBB
Pesquisa Digital
Trie
Patricia
Transformao de Chave (Hashing)
Funes de Transformao
Listas Encadeadas
Endereamento Aberto
Hashing Perfeito
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria 2

Introduo - Conceitos Bsicos

Estudo de como recuperar informao a partir


de uma grande massa de informao
previamente armazenada.

A informao dividida em registros.

Cada registro possui uma chave para ser


usada na pesquisa.

Objetivo da pesquisa:
Encontrar uma ou mais ocorrncias de
registros com chaves iguais chave de
pesquisa.

Pesquisa com sucesso X Pesquisa sem


sucesso.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria 3

Introduo - Conceitos Bsicos


Tabelas

Conjunto de registros ou arquivos


TABELAS

Tabela:
Associada a entidades de vida curta, criadas
na memria interna durante a execuo de
um programa.

Arquivo:
Geralmente associado a entidades de vida
mais longa, armazenadas em memria
externa.

Distino no rgida:
tabela: arquivo de ndices
arquivo: tabela de valores de funes.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria 4

Escolha do Mtodo de Pesquisa mais


Adequado a uma Determinada
Aplicao

Depende principalmente:
1. Quantidade dos dados envolvidos.
2. Arquivo estar sujeito a inseres e
retiradas freqentes.

se contedo do arquivo estvel


importante minimizar o tempo de
pesquisa, sem preocupao com o tempo
necessrio para estruturar o arquivo
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria 5

Algoritmos de Pesquisa Tipos


Abstratos de Dados

importante considerar os algoritmos de


pesquisa como tipos abstratos de dados,
com um conjunto de operaes associado a
uma estrutura de dados, de tal forma que haja
uma independncia de implementao para
as operaes.

Operaes mais comuns:


1. Inicializar a estrutura de dados.
2. Pesquisar um ou mais registros com
determinada chave.
3. Inserir um novo registro.
4. Retirar um registro especfico.
5. Ordenar um arquivo para obter todos os
registros em ordem de acordo com a
chave.
6. Ajuntar dois arquivos para formar um
arquivo maior.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria 6

Dicionrio

Nome comumente utilizado para descrever


uma estrutura de dados para pesquisa.

Dicionrio um tipo abstrato de dados


com as operaes:
1. Inicializa
2. Pesquisa
3. Insere
4. Retira

Analogia com um dicionrio da lngua


portuguesa:
Chaves palavras
Registros entradas associadas com
cada palavra:
pronncia
definio
sinnimos
outras informaes
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.1 7

Pesquisa Seqencial

Mtodo de pesquisa mais simples: a partir


do primeiro registro, pesquise
seqencialmente at encontrar a chave
procurada; ento pare.

Armazenamento de um conjunto de registros


por meio do tipo estruturado arranjo.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.1 8

Pesquisa Seqencial

package cap5;
import cap4. Item ; / / vide programa do captulo 4
public class Tabela {
private Item registros [ ] ;
private int n;

public Tabela ( int maxN) {


this . registros = new Item [maxN+1];
this .n = 0;
}
public int pesquisa ( Item reg ) {
this . registros [0] = reg ; / / sentinela
int i = this .n;
while ( this . registros [ i ] .compara ( reg ) ! = 0 ) i ;
return i ;
}
public void insere ( Item reg ) throws Exception {
i f ( this .n == ( this . registros . length 1))
throw new Exception ( "Erro : A tabela esta cheia" ) ;
this . registros[++this .n] = reg ;
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.1 9

Pesquisa Seqencial

Cada registro contm um campo chave que


identifica o registro.

A Interface Item definida no captulo 4 foi


utilizada por permitir a criao de mtodos
genricos.

Alm da chave, podem existir outros


componentes em um registro, os quais no
tm influncia nos algoritmos.

O mtodo pesquisa retorna o ndice do registro


que contm a chave passada como
parmetro no registro reg; caso no esteja
presente, o valor retornado zero.

Essa implementao no suporta mais de um


registro com a mesma chave.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.1 10

Pesquisa Seqencial

Utilizao de um registro sentinela na


posio zero do array:
1. Garante que a pesquisa sempre termina:
se o ndice retornado por Pesquisa for
zero, a pesquisa foi sem sucesso.
2. No necessrio testar se i > 0, devido a
isto:
o anel interno da funo Pesquisa
extremamente simples: o ndice i
decrementado e a chave de pesquisa
comparada com a chave que est no
registro.
isto faz com que esta tcnica seja
conhecida como pesquisa seqencial
rpida.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.1 11

Pesquisa Seqencial
Anlise

Pesquisa com sucesso:

melhor caso : C(n) = 1


pior caso : C(n) = n
caso medio : C(n) = (n + 1)/2

Pesquisa sem sucesso:

C 0 (n) = n + 1.

O algoritmo de pesquisa seqencial a


melhor escolha para o problema de
pesquisa em tabelas com at 25 registros.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.2 12

Pesquisa Binria

Pesquisa em tabela pode ser mais


eficiente Se registros forem mantidos
em ordem

Para saber se uma chave est presente na


tabela
1. Compare a chave com o registro que est
na posio do meio da tabela.
2. Se a chave menor ento o registro
procurado est na primeira metade da
tabela
3. Se a chave maior ento o registro
procurado est na segunda metade da
tabela.
4. Repita o processo at que a chave seja
encontrada, ou fique apenas um registro
cuja chave diferente da procurada,
significando uma pesquisa sem sucesso.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.2 13

Exemplo de Pesquisa Binria para a


Chave G
1 2 3 4 5 6 7 8

Chaves iniciais: A B C D E F G H
A B C D E F G H
E F G H
G H
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.2 14

Algoritmo de Pesquisa binria

O algoritmo foi feito com um mtodo da


classe Tabela apresentada anteriormente.

public int binaria ( Item chave) {


i f ( this .n == 0) return 0;
int esq = 1 , dir = this .n, i ;
do {
i = (esq + dir ) / 2 ;
i f (chave.compara ( this . registros [ i ] ) > 0 ) esq = i + 1;
else dir = i 1;
} while ( (chave.compara ( this . registros [ i ] ) ! = 0 )
&& (esq <= dir ) ) ;
i f (chave.compara ( this . registros [ i ]) == 0) return i ;
else return 0;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.2 15

Pesquisa Binria
Anlise

A cada iterao do algoritmo, o tamanho da


tabela dividido ao meio.

Logo: o nmero de vezes que o tamanho da


tabela dividido ao meio cerca de log n.

Ressalva: o custo para manter a tabela


ordenada alto:
a cada insero na posio p da tabela
implica no deslocamento dos registros a partir
da posio p para as posies seguintes.

Conseqentemente, a pesquisa binria no


deve ser usada em aplicaes muito
dinmicas.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3 16

rvores de Pesquisa

A rvore de pesquisa uma estrutura de


dados muito eficiente para armazenar
informao.

Particularmente adequada quando existe


necessidade de considerar todos ou alguma
combinao de:
1. Acesso direto e seqencial eficientes.
2. Facilidade de insero e retirada de
registros.
3. Boa taxa de utilizao de memria.
4. Utilizao de memria primria e
secundria.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 17

rvores Binrias de Pesquisa sem


Balanceamento

Para qualquer n que contenha um registro

E D

Temos a relao invariante

R D
E

1. Todos os registros com chaves menores


esto na subrvore esquerda.
2. Todos os registros com chaves maiores
esto na subrvore direita.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 18

rvores Binrias de Pesquisa sem


Balanceamento
Exemplo

3 7

2 4 6

O nvel do n raiz 0.

Se um n est no nvel i ento a raiz de suas


subrvores esto no nvel i + 1.

A altura de um n o comprimento do
caminho mais longo deste n at um n folha.

A altura de uma rvore a altura do n raiz.


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 19

Implementao do Tipo Abstrato de


Dados Dicionrio usando a Estrutura
de Dados rvore Binria de Pesquisa
Estrutura de dados:

Contm as operaes inicializa, pesquisa,


insere e retira.

A operao inicializa implementada pelo


construtor da classe ArvoreBinaria.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 20

Implementao do Tipo Abstrato de


Dados Dicionrio usando a Estrutura
de Dados rvore Binria de Pesquisa

package cap5;
import cap4. Item ; / / vide programa do captulo 4
public class ArvoreBinaria {
private static class No {
Item reg ;
No esq, dir ;
}
private No raiz ;
/ / Entram aqui os mtodos privados das transparncias 21, 22 e
26
public ArvoreBinaria ( ) {
this . raiz = null ;
}
public Item pesquisa ( Item reg ) {
return this .pesquisa ( reg , this . raiz ) ;
}
public void insere ( Item reg ) {
this . raiz = this . insere ( reg , this . raiz ) ;
}
public void retira ( Item reg ) {
this . raiz = this . retira ( reg , this . raiz ) ;
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 21

Mtodo para Pesquisar na rvore


Para encontrar um registro com uma chave
reg:

Compare-a com a chave que est na raiz .

Se menor, v para a subrvore esquerda.

Se maior, v para a subrvore direita.

Repita o processo recursivamente, at que a


chave procurada seja encontrada ou um n
folha atingido.

Se a pesquisa tiver sucesso ento o registro


contendo a chave passada em reg
retornado.

private Item pesquisa ( Item reg , No p) {


i f (p == null ) return null ; / / Registro no encontrado
else i f ( reg .compara (p. reg) < 0)
return pesquisa ( reg , p.esq) ;
else i f ( reg .compara (p. reg) > 0)
return pesquisa ( reg , p. dir ) ;
else return p. reg ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 22

Procedimento para Inserir na rvore

Atingir uma referncia null em um processo


de pesquisa significa uma pesquisa sem
sucesso.

Caso se queira inseri-lo na rvore, a


referncia null atingida justamente o ponto
de insero.

private No insere ( Item reg , No p) {


i f (p == null ) {
p = new No ( ) ; p. reg = reg ;
p.esq = null ; p. dir = null ;
}
else i f ( reg .compara (p. reg) < 0)
p.esq = insere ( reg , p.esq) ;
else i f ( reg .compara (p. reg) > 0)
p. dir = insere ( reg , p. dir ) ;
else System. out . println ( "Erro : Registro ja existente " ) ;
return p;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 23

Programa para Criar a rvore

package cap5;
import java . io . ;
import cap4.MeuItem; / / vide programa do captulo 4
public class CriaArvore {
public static void main ( String [ ] args ) throws Exception {
ArvoreBinaria dicionario = new ArvoreBinaria ( ) ;
BufferedReader in = new BufferedReader (
new InputStreamReader (System. in ) ) ;
int chave = Integer . parseInt ( in . readLine ( ) ) ;
while (chave > 0) {
MeuItem item = new MeuItem (chave) ;
dicionario . insere ( item ) ;
chave = Integer . parseInt ( in . readLine ( ) ) ;
}
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 24

Procedimento para Retirar x da rvore

Alguns comentrios:
1. A retirada de um registro no to simples
quanto a insero.
2. Se o n que contm o registro a ser
retirado possui no mximo um
descendente a operao simples.
3. No caso do n conter dois descendentes o
registro a ser retirado deve ser primeiro:
substitudo pelo registro mais direita
na subrvore esquerda;
ou pelo registro mais esquerda na
subrvore direita.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 25

Exemplo da Retirada de um Registro


da rvore

3 7

2 4 6

Assim: para retirar o registro com chave 5 na


rvore basta troc-lo pelo registro com chave 4 ou
pelo registro com chave 6, e ento retirar o n
que recebeu o registro com chave 5.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 26

Mtodo para retirar reg da rvore

private No antecessor (No q, No r ) {


i f ( r . dir ! = null ) r . dir = antecessor ( q, r . dir ) ;
else { q. reg = r . reg ; r = r .esq ; }
return r ;
}
private No retira ( Item reg , No p) {
i f (p == null )
System. out . println ( "Erro : Registro nao encontrado" ) ;
else i f ( reg .compara (p. reg) < 0)
p.esq = retira ( reg , p.esq) ;
else i f ( reg .compara (p. reg) > 0)
p. dir = retira ( reg , p. dir ) ;
else {
i f (p. dir == null ) p = p.esq;
else i f (p.esq == null ) p = p. dir ;
else p.esq = antecessor ( p, p.esq) ;
}
return p;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 27

Outro Exemplo de Retirada de N

bye

and easy

be to

bye

and to

be

be be

and to
and to
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 28

Caminhamento Central

Aps construda a rvore, pode ser


necessrio percorrer todos os registros que
compem a tabela ou arquivo.

Existe mais de uma ordem de caminhamento


em rvores, mas a mais til a chamada
ordem de caminhamento central.

O caminhamento central mais bem


expresso em termos recursivos:
1. caminha na subrvore esquerda na ordem
central;
2. visita a raiz;
3. caminha na subrvore direita na ordem
central.

Uma caracterstica importante do


caminhamento central que os ns so
visitados de forma ordenada.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 29

Caminhamento Central

Percorrer a rvore:
5

3 7

2 4 6

usando caminhamento central recupera as


chaves na ordem 1, 2, 3, 4, 5, 6 e 7.

Caminhamento central e impresso da rvore:

public void imprime ( ) { this . central ( this . raiz ) ; }

private void central (No p) {


i f (p ! = null ) {
central (p.esq) ;
System. out . println (p. reg . toString ( ) ) ;
central (p. dir ) ;
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 30

Anlise

O nmero de comparaes em uma pesquisa


com sucesso:

melhor caso : C(n) = O(1),


pior caso : C(n) = O(n),
caso medio : C(n) = O(log n).

O tempo de execuo dos algoritmos para


rvores binrias de pesquisa dependem
muito do formato das rvores.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1 31

Anlise

1. Para obter o pior caso basta que as chaves


sejam inseridas em ordem crescente ou
decrescente. Neste caso a rvore resultante
uma lista linear, cujo nmero mdio de
comparaes (n + 1)/2.

2. Para uma rvore de pesquisa randmica o


nmero esperado de comparaes para
recuperar um registro qualquer cerca de
1, 39 log n, apenas 39% pior que a rvore
completamente balanceada.

Uma rvore A com n chaves possui n + 1 ns


externos e estas n chaves dividem todos os
valores possveis em n + 1 intervalos. Uma
insero em A considerada randmica se
ela tem probabilidade igual de acontecer em
qualquer um dos n + 1 intervalos.

Uma rvore de pesquisa randmica com n


chaves uma rvore construida atravs de n
inseres randmicas sucessivas em uma
rvore inicialmente vazia.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2 32

rvores Binrias de Pesquisa com


Balanceamento
rvore completamente balanceada ns
externos aparecem em no mximo dois nveis
adjacentes.
Minimiza tempo mdio de pesquisa para uma
distribuio uniforme das chaves, onde cada
chave igualmente provvel de ser usada em
uma pesquisa.
Contudo, custo para manter a rvore
completamente balanceada aps cada
insero muito alto.
Para inserir a chave 1 na rvore do exemplo
esquerda e obter a rvore direita do mesmo
exemplo necessrio movimentar todos os
ns da rvore original.
Exemplo:

5 4

3 7 2 6

2 4 6 1 3 5 7
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2 33

Uma Forma de Contornar este


Problema
Procurar soluo intermediria que possa
manter rvore quase-balanceada, em vez
de tentar manter a rvore completamente
balanceada.
Objetivo: Procurar obter bons tempos de
pesquisa, prximos do tempo timo da rvore
completamente balanceada, mas sem pagar
muito para inserir ou retirar da rvore.

Heursticas: existem vrias heursticas


baseadas no princpio acima.
Gonnet e Baeza-Yates (1991) apresentam
algoritmos que utilizam vrios critrios de
balanceamento para rvores de pesquisa,
tais como restries impostas:
na diferena das alturas de subrvores de
cada n da rvore,
na reduo do comprimento do caminho
interno
ou que todos os ns externos apaream
no mesmo nvel.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2 34

Uma Forma de Contornar este


Problema

Comprimento do caminho interno:


corresponde soma dos comprimentos dos
caminhos entre a raiz e cada um dos ns
internos da rvore.

Por exemplo, o comprimento do caminho


interno da rvore esquerda na figura da
transparncia anterior
8 = (0 + 1 + 1 + 2 + 2 + 2).
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.1 35

rvores SBB

rvores B estrutura para memria


secundria. (Bayer R. e McCreight E.M.,
1972)

rvore 2-3 caso especial da rvore B.

Cada n tem duas ou trs subrvores.

Mais apropriada para memria primria.

Exemplo: Uma rvore 2-3 e a rvore B


binria correspondente(Bayer, R. 1971)
7 7

2,5 10 2 5 10

1 3,4 6 8,9 11 1 3 4 6 8 9 11
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.1 36

rvores SBB
rvore 2-3 rvore B binria (assimetria
inerente)
1. Referncias esquerda apontam para um
n no nvel abaixo.
2. Referncias direita podem ser verticais
ou horizontais.
Eliminao da assimetria nas rvores B
binrias rvores B binrias simtricas
(Symmetric Binary B-trees SBB)
rvore SBB uma rvore binria com 2 tipos
de referncias: verticais e horizontais, tal que:
1. todos os caminhos da raiz at cada n
externo possuem o mesmo nmero de
referncias verticais, e
2. no podem existir dois referncias
horizontais sucessivos.

3 5 9

1 2 4 6 7 8 10
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 37

Transformaes para Manuteno da


Propriedade SBB
O algoritmo para rvores SBB usa
transformaes locais no caminho de
insero ou retirada para preservar o
balanceamento.
A chave a ser inserida ou retirada sempre
inserida ou retirada aps o referncia vertical
mais baixo na rvore.
Dependendo da situao anterior insero
ou retirada, podem aparecer dois referncias
horizontais sucessivos
Neste caso: necessrio realizar uma
transformao.
Transformaes Propostas por Bayer R.
1972

2 3 1 2 3 2

1 1 3

(a) Esquerdaesquerda (EE)

1 3 1 2 3 2

2 1 3

(b) Esquerdadireita (ED)


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 38

Estrutura e operaes do dicionrio


para rvores SBB

Diferenas da rvore sem balanceamento:


constantes Horizontal e Vertical :
representam as inclinaes das
referncias s subrvores;
campo propSBB : utilizado para verificar
quando a propriedade SBB deixa de ser
satisfeita
campos incE e incD: indicam o tipo de
referncia (horizontal ou vertical) que sai
do n.

A operao inicializa implementada pelo


construtor da classe ArvoreSBB .

As demais operaes so implementadas


utilizando mtodos privados sobrecarregados.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 39

Estrutura e operaes do dicionrio


para rvores SBB

package cap5;
import cap4. Item ; / / vide programa do captulo 4
public class ArvoreSBB {
private static class No {
Item reg ; No esq, dir ; byte incE , incD;
}
private static final byte Horizontal = 0;
private static final byte Vertical = 1;
private No raiz ; private boolean propSBB;

/ / Entram aqui os mtodos privados das transparncias 21, 40,


41 e 48
public ArvoreSBB ( ) {
this . raiz = null ; this .propSBB = true ;
}
public Item pesquisa ( Item reg ) {
return this .pesquisa ( reg , this . raiz ) ; }
public void insere ( Item reg ) {
this . raiz = insere ( reg , null , this . raiz , true ) ; }
public void retira ( Item reg ) {
this . raiz = this . retira ( reg , this . raiz ) ; }
/ / Entra aqui o mtodo para imprimir a rvore da tranaparn-
cia 29
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 40

Mtodos para manuteno da


propriedade SBB

private No ee (No ap) {


No ap1 = ap.esq ; ap.esq = ap1. dir ; ap1. dir = ap;
ap1. incE = Vertical ; ap. incE = Vertical ; ap = ap1;
return ap;
}
private No ed (No ap) {
No ap1 = ap.esq ; No ap2 = ap1. dir ; ap1.incD = Vertical ;
ap. incE = Vertical ; ap1. dir = ap2.esq ; ap2.esq = ap1;
ap.esq = ap2. dir ; ap2. dir = ap; ap = ap2;
return ap;
}
private No dd (No ap) {
No ap1 = ap. dir ; ap. dir = ap1.esq ; ap1.esq = ap;
ap1.incD = Vertical ; ap.incD = Vertical ; ap = ap1;
return ap;
}
private No de (No ap) {
No ap1 = ap. dir ; No ap2 = ap1.esq ; ap1. incE = Vertical ;
ap.incD = Vertical ; ap1.esq = ap2. dir ; ap2. dir = ap1;
ap. dir = ap2.esq ; ap2.esq = ap; ap = ap2;
return ap;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 41

Mtodo para inserir na rvore SBB


private No insere ( Item reg , No pai , No filho , boolean filhoEsq ) {
i f ( f i l h o == null ) {
f i l h o = new No ( ) ; f i l h o . reg = reg ;
f i l h o . incE = Vertical ; f i l h o .incD = Vertical ;
f i l h o .esq = null ; f i l h o . dir = null ;
i f ( pai ! = null )
i f ( filhoEsq ) pai . incE = Horizontal ; else pai .incD = Horizontal ;
this .propSBB = false ;
}
else i f ( reg .compara ( f i l h o . reg) < 0) {
f i l h o .esq = insere ( reg , filho , f i l h o .esq, true ) ;
i f ( ! this .propSBB)
i f ( f i l h o . incE == Horizontal ) {
i f ( f i l h o .esq. incE == Horizontal ) {
f i l h o = this .ee ( f i l h o ) ; / / transformao esquerda-esquerda
i f ( pai ! = null )
i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ;
}
else i f ( f i l h o .esq.incD == Horizontal ) {
f i l h o = this .ed ( f i l h o ) ; / / transformao esquerda-direita
i f ( pai ! = null )
i f ( filhoEsq ) pai . incE=Horizontal ;
else pai .incD=Horizontal ;
}
}
else this .propSBB = true ;
}

/ / Continua na prxima transparncia


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 42

Mtodo para inserir na rvore SBB


else i f ( reg .compara ( f i l h o . reg) > 0) {
f i l h o . dir = insere ( reg , filho , f i l h o . dir , false ) ;
i f ( ! this .propSBB)
i f ( f i l h o .incD == Horizontal ) {
i f ( f i l h o . dir .incD == Horizontal ) {
f i l h o = this .dd ( f i l h o ) ; / / transformao direita-direita
i f ( pai ! = null )
i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ;
}
else i f ( f i l h o . dir . incE == Horizontal ) {
f i l h o = this .de ( f i l h o ) ; / / transformao direita-esquerda
i f ( pai ! = null )
i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ;
}
}
else this .propSBB = true ;
}
else {
System. out . println ( "Erro : Registro ja existente " ) ;
this .propSBB = true ;
}
return f i l h o ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 43

Exemplo

Insero de uma seqncia de chaves em


uma rvore SBB inicialmente vazia.
1. rvore esquerda obtida aps a
insero das chaves 7, 10, 5.
2. rvore do meio obtida aps a insero
das chaves 2, 4 na rvore anterior.
3. rvore direita obtida aps a insero
das chaves 9, 3, 6 na rvore anterior.

5 3 5 9

5 7 10 2 4 7 10 2 4 6 7 10
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 44

Procedimento Retira

Assim como o mtodo insere mostrado


anteriormente, o mtodo retira possui uma
verso privada, que foi sobrecarregada com
uma interface que contm um parmetro a
mais que a sua verso pblica.

O mtodo privado retira utiliza trs mtodos


auxiliares, a saber:
esqCurto (dirCurto) chamado quando um
n folha (que referenciado por uma
referncia vertical) retirado da subrvore
esquerda (direita), tornando-a menor na
altura aps a retirada;
Quando o n a ser retirado possui dois
descendentes, o mtodo antecessor
localiza o n antecessor para ser trocado
com o n a ser retirado.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 45

Mtodo auxiliar esqCurto para retirada


da rvore SBB
/ / Folha esquerda retirada => rvore curta na altura esquerda
private No esqCurto (No ap) {
i f (ap. incE == Horizontal ) {
ap. incE = Vertical ; this .propSBB = true ;
}
else i f (ap.incD == Horizontal ) {
No ap1 = ap. dir ; ap. dir = ap1.esq ; ap1.esq = ap; ap = ap1;
i f (ap.esq. dir . incE == Horizontal ) {
ap.esq = this .de (ap.esq ) ; ap. incE = Horizontal ;
}
else i f (ap.esq. dir .incD == Horizontal ) {
ap.esq = this .dd (ap.esq ) ; ap. incE = Horizontal ;
}
this .propSBB = true ;
}
else {
ap.incD = Horizontal ;
i f (ap. dir . incE == Horizontal ) {
ap = this .de (ap ) ; this .propSBB = true ;
}
else i f (ap. dir .incD == Horizontal ) {
ap = this .dd (ap ) ; this .propSBB = true ;
}
} return ap;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 46

Mtodo auxiliar dirCurto para retirada


da rvore SBB
/ / Folha direita retirada => rvore curta na altura direita
private No dirCurto (No ap) {
i f (ap.incD == Horizontal ) {
ap.incD = Vertical ; this .propSBB = true ;
}
else i f (ap. incE == Horizontal ) {
No ap1 = ap.esq ; ap.esq = ap1. dir ; ap1. dir = ap; ap = ap1;
i f (ap. dir .esq.incD == Horizontal ) {
ap. dir = this .ed (ap. dir ) ; ap.incD = Horizontal ;
}
else i f (ap. dir .esq. incE == Horizontal ) {
ap. dir = this .ee (ap. dir ) ; ap.incD = Horizontal ;
}
this .propSBB = true ;
}
else {
ap. incE = Horizontal ;
i f (ap.esq.incD == Horizontal ) {
ap = this .ed (ap ) ; this .propSBB = true ;
}
else i f (ap.esq. incE == Horizontal ) {
ap = this .ee (ap ) ; this .propSBB = true ;
}
} return ap;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 47

Mtodo auxiliar antecessor para retirada


da rvore SBB
private No antecessor (No q, No r ) {
i f ( r . dir ! = null ) {
r . dir = antecessor ( q, r . dir ) ;
i f ( ! this .propSBB) r = this . dirCurto ( r ) ;
}
else {
q. reg = r . reg ;
r = r .esq;
i f ( r ! = null ) this .propSBB = true ;
}
return r ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 48

Mtodo retira para retirada da rvore


SBB
private No retira ( Item reg , No ap) {
i f (ap == null ) {
System. out . println ( "Erro : Registro nao encontrado" ) ;
this .propSBB = true ;
}
else i f ( reg .compara (ap. reg ) < 0) {
ap.esq = retira ( reg , ap.esq) ;
i f ( ! this .propSBB)
ap = this .esqCurto (ap) ;
}
else i f ( reg .compara (ap. reg ) > 0) {
ap. dir = retira ( reg , ap. dir ) ;
i f ( ! this .propSBB) ap = this . dirCurto (ap) ;
}
else { / / encontrou o registro
this .propSBB = false ;
i f (ap. dir == null ) {
ap = ap.esq;
i f (ap ! = null ) this .propSBB = true ;
}
else i f (ap.esq == null ) {
ap = ap. dir ;
i f (ap ! = null )
this .propSBB = true ;
}
else {
ap.esq = antecessor (ap, ap.esq) ;
i f ( ! this .propSBB)
ap = this .esqCurto (ap) ;
}
}
return ap;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 49

Exemplo

Dada a rvore:

5 3 5 9

5 7 10 2 4 7 10 2 4 6 7 10

Resultado obtido quando se retira uma


seqncia de chaves da rvore SBB mais
direita acima:
A rvore esquerda obtida aps a
retirada da chave 7 da rvore direita
acima.
A rvore do meio obtida aps a retirada
da chave 5 da rvore anterior.
A rvore direita obtida aps a retirada
da chave 9 da rvore anterior.

3 5 9 4 9 4

2 4 6 10 2 3 6 10 2 3 6 10
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 50

Exemplo: Retirada de Ns de SBB

Caso 1: 4
4 2 4
2 10
2 6 10 1 3 6 10
1 3 6 12 t
6
1 3 2a chamada
DirCurto
1a chamada DirCurto

2 chamadas DirCurto

Caso 2:

4 4 4

2 10
2 6 8 10 2 8

1 3 6 8 12
1 3 1 3 6 10

1a chamada DirCurto
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 51

Exemplo: Retirada de Ns de SBB


Caso 3:
4
4

2 6 10 2 6 10

1 3 5 8 12 1 3 5 8

2 6

1 3 5 8 10

Se nodo 8 tem filho:

4 4

2 6 10 2 6 10

1 3 5 8 9 12 1 3 5 8 9

4
4
2 6 9
2 6
1 3 5 8 10
1 3 5 8 10
9
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 52

Anlise

Nas rvores SBB necessrio distinguir dois


tipos de alturas:
1. Altura vertical h necessria para manter
a altura uniforme e obtida atravs da
contagem do nmero de referncias
verticais em qualquer caminho entre a raiz
e um n externo.
2. Altura k representa o nmero mximo
de comparaes de chaves obtida atravs
da contagem do nmero total de
referncias no maior caminho entre a raiz
e um n externo.

A altura k maior que a altura h sempre que


existirem referncias horizontais na rvore.

Para uma rvore SBB com n ns internos,


temos que
h k 2h.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2 53

Anlise

De fato Bayer (1972) mostrou que

log(n + 1) k 2 log(n + 2) 2.

Custo para manter a propriedade SBB


Custo para percorrer o caminho de pesquisa
para encontrar a chave, seja para inser-la ou
para retir-la.

Logo: O custo O(log n).

Nmero de comparaes em uma pesquisa


com sucesso na rvore SBB

melhor caso : C(n) = O(1),


pior caso : C(n) = O(log n),
caso medio : C(n) = O(log n).

Observe: Na prtica o caso mdio para Cn


apenas cerca de 2% pior que o Cn para uma
rvore completamente balanceada, conforme
mostrado em Ziviani e Tompa (1982).
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4 54

Pesquisa Digital

Pesquisa digital baseada na representao


das chaves como uma seqncia de
caracteres ou de dgitos.

Os mtodos de pesquisa digital so


particularmente vantajosos quando as chaves
so grandes e de tamanho varivel.

Um aspecto interessante quanto aos mtodos


de pesquisa digital a possibilidade de
localizar todas as ocorrncias de uma
determinada cadeia em um texto, com tempo
de resposta logartmico em relao ao
tamanho do texto.
Trie
Patrcia
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1 55

Trie

Uma trie uma rvore M -ria cujos ns so


vetores de M componentes com campos
correspondentes aos dgitos ou caracteres
que formam as chaves.

Cada n no nvel i representa o conjunto de


todas as chaves que comeam com a mesma
seqncia de i dgitos ou caracteres.

Este n especifica uma ramificao com M


caminhos dependendo do (i + 1)-simo dgito
ou caractere de uma chave.

Considerando as chaves como seqncia


de bits (isto , M = 2), o algoritmo de
pesquisa digital semelhante ao de
pesquisa em rvore, exceto que, em vez de
se caminhar na rvore de acordo com o
resultado de comparao entre chaves,
caminha-se de acordo com os bits de
chave.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1 56

Exemplo

Dada as chaves de 6 bits:

B = 010010
C = 010011
H = 011000
J = 100001
M = 101000

0 1
1 0
0 1 0 1
0 H J Q
1
0 1
B C
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1 57

Insero das Chaves W e K na Trie


Binria

0 1
1 0
0 1 0 1
0 H J Q
1
0 1
B C

Faz-se uma pesquisa na rvore com a chave a


ser inserida. Se o n externo em que a pesquisa
terminar for vazio, cria-se um novo n externo
nesse ponto contendo a nova chave, exemplo: a
insero da chave W = 110110.

Se o n externo contiver uma chave cria-se um ou


mais ns internos cujos descendentes contero a
chave j existente e a nova chave. exemplo:
insero da chave K = 100010.

0 1
1 0 1
0 1 0 1 W
0 H 0 Q
1 0 1
0 1 J K
B C
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1 58

Consideraes Importantes sobre as


Tries

O formato das tries, diferentemente das


rvores binrias comuns, no depende da
ordem em que as chaves so inseridas e sim
da estrutura das chaves atravs da
distribuio de seus bits.

Desvantagem:
Uma grande desvantagem das tries a
formao de caminhos de uma s direo
para chaves com um grande nmero de
bits em comum.
Exemplo: Se duas chaves diferirem
somente no ltimo bit, elas formaro um
caminho cujo comprimento igual ao
tamanho delas, no importando quantas
chaves existem na rvore.
Caminho gerado pelas chaves B e C.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 59

Patricia - Practical Algorithm To


Retrieve Information Coded In
Alphanumeric

Criado por Morrison D. R. 1968 para


aplicao em recuperao de informao em
arquivos de grande porte.

Knuth D. E. 1973 novo tratamento


algoritmo.

Reapresentou-o de forma mais clara como


um caso particular de pesquisa digital,
essencialmente, um caso de rvore trie
binria.

Sedgewick R. 1988 apresentou novos


algoritmos de pesquisa e de insero
baseados nos algoritmos propostos por
Knuth.

Gonnet, G.H e Baeza-Yates R. 1991


propuzeram tambm outros algoritmos.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 60

Mais sobre Patricia


O algoritmo para construo da rvore
Patricia baseado no mtodo de pesquisa
digital, mas sem apresentar o inconveniente
citado para o caso das tries.
O problema de caminhos de uma s direo
eliminado por meio de uma soluo simples e
elegante: cada n interno da rvore contm o
ndice do bit a ser testado para decidir qual
ramo tomar.
Exemplo: dada as chaves de 6 bits:

B = 010010
C = 010011
H = 011000
J = 100001
Q = 101000

3 3

6 H J Q

B C
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 61

Insero da Chave K
1

3 3

6 H J Q

B C

Para inserir a chave K = 100010 na rvore acima, a


pesquisa inicia pela raiz e termina quando se chega ao
n externo contendo J.
Os ndices dos bits nas chaves esto ordenados da
esquerda para a direita. Bit de ndice 1 de K 1 a
subrvore direita Bit de ndice 3 subrvore esquerda
que neste caso um n externo.
Chaves J e K mantm o padro de bits 1x0xxx, assim
como qualquer outra chave que seguir este caminho
de pesquisa.
Novo n interno repe o n J, e este com n K sero
os ns externos descendentes.
O ndice do novo n interno dado pelo 1o bit diferente
das 2 chaves em questo, que o bit de ndice 5. Para
determinar qual ser o descendente esquerdo e o
direito, verifique o valor do bit 5 de ambas as chaves.

3 3

6 H 5 Q

B C J K
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 62

Insero da Chave W

A insero da chave W = 110110 ilustra um


outro aspecto.

Os bits das chaves K e W so comparados a


partir do primeiro para determinar em qual
ndice eles diferem, sendo, neste caso, os de
ndice 2.

Portanto: o ponto de insero agora ser no


caminho de pesquisa entre os ns internos de
ndice 1 e 3.

Cria-se a um novo n interno de ndice 2,


cujo descendente direito um n externo
contendo W e cujo descendente esquerdo a
subrvore de raiz de ndice 3.

3 2

6 H 3 W

B C 5 Q

J K
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 63

Estrutura de dados e operaes da


rvore Patricia

Em uma rvore Patricia existem dois tipos de


ns diferentes: internos e externos. Para
implementar essa caracterstica foi utilizado o
mecanismo de herana e polimorfismo da
linguagem Java.
package cap5;
public class ArvorePatricia {
private static abstract class PatNo { }
private static class PatNoInt extends PatNo {
int index;
PatNo esq, dir ;
}
private static class PatNoExt extends PatNo { char chave; }

private PatNo raiz ;


private int nbitsChave;

/ / Entram aqui os mtodos privados das transparncias 64, 65 e 68


public ArvorePatricia ( int nbitsChave) {
this . raiz = null ; this .nbitsChave = nbitsChave;
}
public void pesquisa (char k) { this .pesquisa (k, this . raiz ) ; }
public void insere (char k) { this . raiz = this .insere (k, this . raiz ) ; }
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 64

Mtodos Auxiliares
/ / Retorna o i-simo bit da chave k a partir da esquerda
private int bit ( int i , char k) {
i f ( i == 0) return 0;
int c = ( int )k;
for ( int j = 1; j <= this .nbitsChave i ; j ++) c = c/2;
return c % 2;
}
/ / Verifica se p n externo
private boolean eExterno (PatNo p) {
Class classe = p.getClass ( ) ;
return classe.getName( ) .equals(PatNoExt.class.getName( ) ) ;
}

Mtodo para criar n interno:


private PatNo criaNoInt ( int i , PatNo esq, PatNo dir ) {
PatNoInt p = new PatNoInt ( ) ;
p.index = i ; p.esq = esq; p. dir = dir ;
return p;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 65

Mtodos Auxiliares

Mtodo para criar n externo:


private PatNo criaNoExt (char k) {
PatNoExt p = new PatNoExt ( ) ;
p.chave = k;
return p;
}

Mtodo para pesquisa:


private void pesquisa (char k, PatNo t ) {
i f ( this .eExterno ( t ) ) {
PatNoExt aux = (PatNoExt) t ;
i f (aux.chave == k) System.out. println ( "Elemento encontrado" ) ;
else System.out. println ( "Elemento nao encontrado" ) ;
}
else {
PatNoInt aux = (PatNoInt) t ;
i f ( this . bit (aux.index, k) == 0) pesquisa (k, aux.esq) ;
else pesquisa (k, aux. dir ) ;
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 66

Descrio Informal do Algoritmo de


Insero

Cada chave k inserida de acordo com os


passos abaixo, partindo da raiz:
1. Se a subrvore corrente for vazia, ento
criado um n externo contendo a chave k
(isso ocorre somente na insero da
primeira chave) e o algoritmo termina.
2. Se a subrvore corrente for simplesmente
um n externo, os bits da chave k so
comparados, a partir do bit de ndice
imediatamente aps o ltimo ndice da
seqncia de ndices consecutivos do
caminho de pesquisa, com os bits
correspondentes da chave k 0 deste n
externo at encontrar um ndice i cujos
bits difiram. A comparao dos bits a partir
do ltimo ndice consecutivo melhora
consideravelmente o desempenho do
algoritmo. Se todos forem iguais, a chave
j se encontra na rvore e o algoritmo
termina; seno, vai-se para o Passo 4.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 67

Descrio Informal do Algoritmo de


Insero

Continuao:
3. Caso contrrio, ou seja, se a raiz da
subrvore corrente for um n interno,
vai-se para a subrvore indicada pelo bit
da chave k de ndice dado pelo n
corrente, de forma recursiva.
4. Depois so criados um n interno e um n
externo: o primeiro contendo o ndice i e o
segundo, a chave k. A seguir, o n interno
ligado ao externo pela referncia
subrvore esquerda ou direita,
dependendo se o bit de ndice i da chave k
seja 0 ou 1, respectivamente.
5. O caminho de insero percorrido
novamente de baixo para cima, subindo
com o par de ns criados no Passo 4 at
chegar a um n interno cujo ndice seja
menor que o ndice i determinado no
Passo 2. Esse o ponto de insero e o
par de ns inserido.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2 68

Algoritmo de insero
private PatNo insereEntre (char k , PatNo t , int i ) {
PatNoInt aux = null ;
i f ( ! this .eExterno ( t ) ) aux = (PatNoInt) t ;
i f ( this .eExterno ( t ) | | ( i < aux. index ) ) { / / Cria um novo n
externo
PatNo p = this . criaNoExt ( k ) ;
i f ( this . bit ( i , k) == 1) return this . criaNoInt ( i , t , p) ;
else return this . criaNoInt ( i , p, t ) ;
} else {
i f ( this . bit (aux. index , k) == 1)
aux. dir = this . insereEntre ( k , aux. dir , i ) ;
else aux.esq = this . insereEntre ( k , aux.esq, i ) ;
return aux;
}
}

private PatNo insere (char k , PatNo t ) {


i f ( t == null ) return this . criaNoExt ( k ) ;
else {
PatNo p = t ;
while ( ! this .eExterno (p) ) {
PatNoInt aux = (PatNoInt)p;
i f ( this . bit (aux. index , k) == 1) p = aux. dir ;
else p = aux.esq;
}
PatNoExt aux = (PatNoExt)p;
int i = 1; / / acha o primeiro bit diferente
while ( ( i <= this .nbitsChave)&&
( this . bit ( i , k) == this . bit ( i , aux.chave) ) ) i ++;
i f ( i > this .nbitsChave ) {
System. out . println ( "Erro : chave ja esta na arvore" ) ;
return t ;
}
else return this . insereEntre ( k , t , i ) ;
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5 69

Transformao de Chave (Hashing)

Os registros armazenados em uma tabela


so diretamente endereados a partir de uma
transformao aritmtica sobre a chave de
pesquisa.

Hash significa:
1. Fazer picadinho de carne e vegetais para
cozinhar.
2. Fazer uma baguna. (Websters New
World Dictionary)
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5 70

Transformao de Chave (Hashing)

Um mtodo de pesquisa com o uso da


transformao de chave constitudo de duas
etapas principais:
1. Computar o valor da funo de
transformao, a qual transforma a chave
de pesquisa em um endereo da tabela.
2. Considerando que duas ou mais chaves
podem ser transformadas em um mesmo
endereo de tabela, necessrio existir
um mtodo para lidar com colises.

Qualquer que seja a funo de


transformao, algumas colises iro ocorrer
fatalmente, e tais colises tm de ser
resolvidas de alguma forma.

Mesmo que se obtenha uma funo de


transformao que distribua os registros de
forma uniforme entre as entradas da tabela,
existe uma alta probabilidade de haver
colises.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5 71

Transformao de Chave (Hashing)

O paradoxo do aniversrio (Feller,1968,


p. 33), diz que em um grupo de 23 ou mais
pessoas, juntas ao acaso, existe uma chance
maior do que 50% de que 2 pessoas
comemorem aniversrio no mesmo dia.

Assim, se for utilizada uma funo de


transformao uniforme que enderece 23
chaves randmicas em uma tabela de
tamanho 365, a probabilidade de que haja
colises maior do que 50%.

A probabilidade p de se inserir N itens


consecutivos sem coliso em uma tabela de
tamanho M :
M 1 M 2 M N +1
p= ... =
M M M
N
Y M i+1 M!
= = N

i=1
M (M N )!M
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5 72

Transformao de Chave (Hashing)

Alguns valores de p para diferentes valores de


N ,onde M = 365.
N p
10 0,883
22 0,524
23 0,493
30 0,303

Para N pequeno a probabilidade p pode ser


aproximada por p N (N 1))
730
. Por exemplo,
para N = 10 ento p 87, 7%.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1 73

Funes de Transformao

Uma funo de transformao deve mapear


chaves em inteiros dentro do intervalo
[0..M 1], onde M o tamanho da tabela.

A funo de transformao ideal aquela


que:
1. Seja simples de ser computada.
2. Para cada chave de entrada, qualquer
uma das sadas possveis igualmente
provvel de ocorrer.

Como as transformaes sobre as chaves


so aritmticas, deve-se transformar as
chaves no-numricas em nmeros.

Em Java, basta realizar uma converso de


cada caractere da chave no numrica para
um nmero inteiro.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1 74

Mtodo mais Usado

Usa o resto da diviso por M .

h(K) = K mod M,

onde K um inteiro correspondente chave.

Cuidado na escolha do valor de M . M deve


ser um nmero primo, mas no qualquer
primo: devem ser evitados os nmeros
primos obtidos a partir de
bi j
onde b a base do conjunto de caracteres
(geralmente b = 64 para BCD, 128 para
ASCII, 256 para EBCDIC, ou 100 para alguns
cdigos decimais), e i e j so pequenos
inteiros.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1 75

Transformao de Chaves No
Numricas

As chaves no numricas devem ser


transformadas em nmeros:
n1
X
K= chave[i] p[i],
i=0

n o nmero de caracteres da chave.

chave[i] corresponde representao ASCII


ou Unicode do i-simo caractere da chave.

p[i] um inteiro de um conjunto de pesos


gerados randomicamente para 0 i n 1.

Vantagem de se usar pesos: Dois conjuntos


diferentes de pesos p1 [i] e p2 [i], 0 i n 1,
levam a duas funes de transformao
h1 (K) e h2 (K) diferentes.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1 76

Transformao de Chaves No
Numricas

Programa que gera um peso para cada


caractere de uma chave constituda de n
caracteres:

private int [ ] geraPesos ( int n) {


int p[ ] = new int [n ] ;
java . u t i l .Random rand = new java . u t i l .Random ( ) ;
for ( int i = 0; i < n ; i ++) p[ i ] = rand. nextInt (M) + 1;
return p;
}

Implementao da funo de
transformao:

private int h ( String chave, int [ ] pesos) {


int soma = 0;
for ( int i = 0; i < chave. length ( ) ; i ++)
soma = soma + ( ( int )chave. charAt ( i ) ) pesos[ i ] ;
return soma % this .M;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2 77

Listas Encadeadas

Uma das formas de resolver as colises


simplesmente construir uma lista linear
encadeada para cada endereo da tabela.
Assim, todas as chaves com mesmo
endereo so encadeadas em uma lista
linear.
Exemplo: Se a i-sima letra do alfabeto
representada pelo nmero i e a funo de
transformao h(Chave) = Chave mod M
utilizada para M = 7, o resultado da insero
das chaves P E S Q U I S A na tabela o
seguinte:
Por exemplo, h(A) = h(1) = 1,
h(E) = h(5) = 5, h(S) = h(19) = 5, e assim
por diante.
T

0 - U - nil
1 - A - nil
2 - P - I - nil
3 - Q - nil
4 - nil
5 - E - S - S - nil
6 - nil
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2 78

Estrutura e operaes do dicionrio


para listas encadeadas

Em cada entrada da lista devem ser


armazenados uma chave e um registro de
dados cujo tipo depende da aplicao.

A classe interna Celula utilizada para


representar uma entrada em uma lista de
chaves que so mapeadas em um mesmo
endereo i da tabela, sendo 0 i M 1.

O mtodo equals da classe Celula usado


para verificar se duas clulas so iguais (isto
, possuem a mesma chave).

A operao inicializa implementada pelo


construtor da classe TabelaHash.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2 79

Estrutura e operaes do dicionrio


para listas encadeadas
package cap5. listaenc ;
import cap3. autoreferencia . Lista ; / / vide Programas do ca-
ptulo 3
public class TabelaHash {
private static class Celula {
String chave ; Object item ;
public Celula ( String chave, Object item ) {
this .chave = chave ; this . item = item ;
}
public boolean equals ( Object obj ) {
Celula cel = ( Celula) obj ;
return chave. equals ( cel .chave) ;
}
}
private int M; / / tamanho da tabela
private Lista tabela [ ] ;
private int pesos [ ] ;
public TabelaHash ( int m, int maxTamChave) {
this .M = m; this . tabela = new Lista [ this .M] ;
for ( int i = 0; i < this .M; i ++)
this . tabela [ i ] = new Lista ( ) ;
this .pesos = this .geraPesos (maxTamChave) ;
}
/ / Entram aqui os mtodos privados da transparncia 76.
/ / Continua na prxima transparncia
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2 80

Estrutura e operaes do dicionrio


para listas encadeadas
public Object pesquisa ( String chave) {
int i = this .h (chave, this .pesos) ;
i f ( this . tabela [ i ] . vazia ( ) ) return null ; / / pesquisa
sem sucesso
else {
Celula cel=(Celula) this . tabela [ i ] . pesquisa(
new Celula(chave, null ) ) ;
i f ( cel == null ) return null ; / / pesquisa sem sucesso
else return cel . item ;
}
}
public void insere ( String chave, Object item ) {
i f ( this .pesquisa (chave) == null ) {
int i = this .h (chave, this .pesos) ;
this . tabela [ i ] . insere (new Celula (chave, item ) ) ;
}
else System. out . println ( "Registro ja esta presente" ) ;
}
public void retira ( String chave) throws Exception {
int i = this .h (chave, this .pesos) ;
Celula cel = ( Celula) this . tabela [ i ] . retira (
new Celula (chave, null ) ) ;
i f ( cel == null )
System. out . println ( "Registro nao esta presente" ) ;
} }
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2 81

Anlise

Assumindo que qualquer item do conjunto


tem igual probabilidade de ser endereado
para qualquer entrada da tabela, ento o
comprimento esperado de cada lista
encadeada N/M , em que N representa o
nmero de registros na tabela e M o tamanho
da tabela.

Logo: as operaes pesquisa, insere e retira


custam O(1 + N/M ) operaes em mdia,
sendo que a constante 1 representa o tempo
para encontrar a entrada na tabela, e N/M , o
tempo para percorrer a lista. Para valores de
M prximos de N , o tempo torna-se
constante, isto , independente de N .
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 82

Endereamento Aberto

Quando o nmero de registros a serem


armazenados na tabela puder ser
previamente estimado, ento no haver
necessidade de usar listas encadeadas para
armazenar os registros.

Existem vrios mtodos para armazenar N


registros em uma tabela de tamanho M > N ,
os quais utilizam os lugares vazios na prpria
tabela para resolver as colises. (Knuth,
1973, p.518)

No Endereamento aberto todas as chaves


so armazenadas na prpria tabela, sem o
uso de listas encadeadas em cada entrada
dela.

Existem vrias propostas para a escolha de


localizaes alternativas. A mais simples
chamada de hashing linear, onde a posio
hj na tabela dada por:

hj = (h(x) + j) mod M, para 1 j M 1.


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 83

Exemplo

Se a i-sima letra do alfabeto representada


pelo nmero i e a funo de transformao
h(chave) = chave mod M utilizada para
M = 7,

ento o resultado da insero das chaves


L U N E S na tabela, usando hashing linear
para resolver colises mostrado abaixo.

Por exemplo, h(L) = h(12) = 5,


h(U ) = h(21) = 0, h(N ) = h(14) = 0,
h(E) = h(5) = 5, e h(S) = h(19) = 5.
T
0 U
1 N
2 S
3
4
5 L
6 E
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 84

Estrutura e operaes do dicionrio


usando endereamento aberto

A tabela agora constituda por um arranjo


de clulas.

A classe interna Celula utilizada para


representar uma clula da tabela.

A operao inicializa implementada pelo


construtor da classe TabelaHash.

As operaes utilizam alguns mtodos


auxiliares durante a execuo.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 85

Estrutura e operaes do dicionrio


usando endereamento aberto
package cap5.endaberto;
public class TabelaHash {
private static class Celula {
String chave ; Object item ; boolean retirado ;
public Celula ( String chave, Object item ) {
this .chave = chave ; this . item = item ;
this . retirado = false ;
}
public boolean equals ( Object obj ) {
Celula cel = ( Celula) obj ;
return chave. equals ( cel .chave) ;
}
}
private int M; / / tamanho da tabela
private Celula tabela [ ] ;
private int pesos [ ] ;

/ / Entram aqui os mtodos privados da transparncia 76


public TabelaHash ( int m, int maxTamChave) {
this .M = m; this . tabela = new Celula [ this .M] ;
for ( int i = 0; i < this .M; i ++)
this . tabela [ i ] = null ; / / vazio
this .pesos = this .geraPesos (maxTamChave) ;
}
/ / Continua na prxima transparncia
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 86

Estrutura e operaes do dicionrio


usando endereamento aberto
public Object pesquisa ( String chave) {
int indice = this . pesquisaIndice (chave) ;
i f ( indice < this .M) return this . tabela [ indice ] . item ;
else return null ; / / pesquisa sem sucesso
}
public void insere ( String chave, Object item ) {
i f ( this .pesquisa (chave) == null ) {
int i n i c i a l = this .h (chave, this .pesos) ;
int indice = i n i c i a l ; int i = 0;
while ( this . tabela [ indice ] ! = null &&
! this . tabela [ indice ] . retirado &&
i < this .M)
indice = ( i n i c i a l + (++ i )) % this .M;
i f ( i < this .M) this . tabela [ indice ] =
new Celula (chave, item ) ;
else System. out . println ( "Tabela cheia" ) ;
} else System. out . println ( "Registro ja esta presente" ) ;
}
/ / Continua na prxima transparncia
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 87

Estrutura e operaes do dicionrio


usando endereamento aberto
public void retira ( String chave) throws Exception {
int i = this . pesquisaIndice (chave) ;
i f ( i < this .M) {
this . tabela [ i ] . retirado = true ;
this . tabela [ i ] . chave = null ;
} else System. out . println ( "Registro nao esta presente" ) ;
}
private int pesquisaIndice ( String chave) {
int i n i c i a l = this .h (chave, this .pesos) ;
int indice = i n i c i a l ; int i = 0;
while ( this . tabela [ indice ] ! = null &&
!chave. equals ( this . tabela [ indice ] . chave) &&
i < this .M) indice = ( i n i c i a l + (++ i )) % this .M;
i f ( this . tabela [ indice ] ! = null &&
chave. equals ( this . tabela [ indice ] . chave) )
return indice ;
else return this .M; / / pesquisa sem sucesso
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 88

Anlise
Seja = N/M o fator de carga da tabela.
Conforme demonstrado por Knuth (1973), o
custo de uma pesquisa com sucesso
 
1 1
C(n) = 1+
2 1

O hashing linear sofre de um mal chamado


agrupamento(clustering) (Knuth, 1973,
pp.520521).
Este fenmeno ocorre na medida em que a
tabela comea a ficar cheia, pois a insero
de uma nova chave tende a ocupar uma
posio na tabela que esteja contgua a
outras posies j ocupadas, o que deteriora
o tempo necessrio para novas pesquisas.
Entretanto, apesar do hashing linear ser um
mtodo relativamente pobre para resolver
colises os resultados apresentados so
bons.
O melhor caso, assim como o caso mdio,
O(1).
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3 89

Vantagens e Desvantagens de
Transformao da Chave
Vantagens:

Alta eficincia no custo de pesquisa, que


O(1) para o caso mdio.

Simplicidade de implementao.

Desvantagens:

Custo para recuperar os registros na ordem


lexicogrfica das chaves alto, sendo
necessrio ordenar o arquivo.

Pior caso O(N ).


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 90

Hashing Perfeito

Se h(xi ) = h(xj ) se e somente se i = j, ento


no h colises, e a funo de transformao
chamada de funo de transformao
perfeita ou funo hashing perfeita(hp).

Se o nmero de chaves N e o tamanho da


tabela M so iguais ( = N/M = 1), ento
temos uma funo de transformao
perfeita mnima.

Se xi xj e hp(xi ) hp(xj ), ento a ordem


lexicogrfica preservada. Nesse caso,
temos uma funo de transformao
perfeita mnima com ordem preservada.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 91

Vantagens e Desvantagens de Uma


Funo de Transformao Perfeita

No h necessidade de armazenar a chave,


pois o registro localizado sempre a partir do
resultado da funo de transformao.

Uma funo de transformao perfeita


especfica para um conjunto de chaves
conhecido.

A desvantagem no caso o espao ocupado


para descrever a funo de transformao hp.

Entretanto, possvel obter um mtodo com


M 1, 25N , para valores grandes de N .
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 92

Algoritmo de Czech, Havas e Majewski

Czech, Havas e Majewski (1992, 1997)


propem um mtodo elegante baseado em
grafos randmicos para obter uma funo
de transformao perfeita com ordem
preservada.

A funo de transformao do tipo:

hp(x) = (g(h1 (x)) + g(h2 (x))) mod N,

na qual h1 (x) e h2 (x) so duas funes no


perfeitas, x a chave de busca, e g um
arranjo especial que mapeia nmeros no
intervalo 0 . . . M 1 para o intervalo
0 . . . N 1.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 93

Problema Resolvido Pelo Algoritmo

Dado um grafo no direcionado G = (V, A),


onde |V | = M e |A| = N , encontre uma
funo g : V [0, N 1], definida como
hp(a = (u, v) A) = (g(u) + g(v)) mod N .

Em outras palavras, estamos procurando uma


atribuio de valores aos vrtices de G tal
que a soma dos valores associados aos
vrtices de cada aresta tomado mdulo N
um nmero nico no intervalo [0, N 1].

A questo principal como obter uma funo


g adequada. A abordagem mostrada a seguir
baseada em grafos e hipergrafos
randmicos.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 94

Exemplo

Chaves: 12 meses do ano abreviados para


os trs primeiros caracteres.
Objetivo: obter uma funo de transformao
perfeita hp de tal forma que o i-simo ms
mantido na (i 1)-sima posio da tabela
hash:
Chave x h1 (x) h2 (x) hp(x)
jan 10 11 0
fev 1 2 1
mar 8 9 2
abr 1 3 3
mai 0 5 4
jun 10 9 5
jul 0 3 6
ago 5 6 7
set 4 1 8
out 0 1 9
nov 3 2 10
dez 4 7 11
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 95

Grafo Randmico gerado

O problema de obter a funo g equivalente


a encontrar um grafo no direcionado
contendo M vrtices e N arestas.
0
11 9 1

0 6 1
10 2
3
5 10
4
9 3
8
2

8 11 4

7 7 5
6

Os vrtices so rotulados com valores no


intervalo 0 . . . M 1
As arestas definidas por (h1 (x), h2 (x)) para
cada uma das N chaves x.
Cada chave corresponde a uma aresta que
rotulada com o valor desejado para a funo
hp perfeita.
Os valores das duas funes h1 (x) e h2 (x)
definem os vrtices sobre os quais a aresta
incidente.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 96

Obteno da Funo g a Partir do


Grafo

Passo importante: conseguir um arranjo g


de vrtices para inteiros no intervalo
0 . . . N 1 tal que, para cada aresta
(h1 (x), h2 (x)), o valor de
hp(x) = g(h1 (x)) + g(h2 (x))) mod N seja igual
ao rtulo da aresta.

Algoritmo:
1. Qualquer vrtice no processado
escolhido e feito g[v] = 0.
2. As arestas que saem do vrtice v so
seguidas e o valor g(u) do vrtice u
destino rotulado com o valor da
diferena entre o valor da aresta (v, u) e
g(v), tomado mod N .
3. Procura-se o prximo componente
conectado ainda no visitado e os
mesmos passos descritos acima so
repetidos.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 97

Seguindo o Algoritmo para Obter g no


Exemplo dos 12 Meses do Ano
0
11 9 1

0 6 1
10 2
3
5 10
4
9 3
8
2

8 11 4

7 7 5
6

Chave x h1 (x) h2 (x) hp(x) v: g(v)


jan 10 11 0 0 0
fev 1 2 1 1 9
mar 8 9 2 2 4
abr 1 3 3 3 6
mai 0 5 4 4 11
(a) jun 10 9 5 (b) 5 4
jul 0 3 6 6 3
ago 5 6 7 7 0
set 4 1 8 8 0
out 0 1 9 9 2
nov 3 2 10 10 3
dez 4 7 11 11 9
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 98

Problema

Quando o grafo contm ciclos: o


mapeamento a ser realizado pode rotular de
novo um vrtice j processado e que tenha
recebido outro rtulo com valor diferente.

Por exemplo, se a aresta (5, 6), que a aresta


de rtulo 7, tivesse sido sorteada para a
aresta (8, 11), o algoritmo tentaria atribuir dois
valores distintos para o valor de g[11].

Para enxergar isso, vimos que se g[8] = 0,


ento g[11] deveria ser igual a 7, e no igual
ao valor 9 obtido acima.

Um grafo que permite a atribuio de dois


valores de g para um mesmo vrtice, no
vlido.

Grafos acclicos no possuem este problema.

Um caminho seguro para se ter sucesso


obter antes um grafo acclico e depois realizar
a atribuio de valores para o arranjo g.
Czech, Havas e Majewski (1992).
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 99

Primeiro Refinamento do
Procedimento para Atribuir Valores ao
Arranjo g
boolean rotuleDe ( int v , int c , Grafo G, int g [ ] ) {
boolean grafoRotulavel = true ;
i f (g[ v ] ! = Indefinido ) i f (g[ v ] ! = c)
grafoRotulavel = false ;
else {
g[ v ] = c ;
for (u G. listaAdjacentes ( v) )
rotuleDe ( u , (G. aresta ( v,u) g[ v]) % N, g) ;
}
return grafoRotulavel ;
}
boolean atribuig ( Grafo G, int g [ ] ) {
boolean grafoRotulavel = true ;
for ( int v = 0; v < M; v++) g[ v ] = Indefinido ;
for ( int v = 0; v < M; v++)
i f (g[ v] == Indefinido )
grafoRotulavel = rotuleDe ( v , 0 , G, g) ;
return grafoRotulavel ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 100

Algoritmo para Obter a Funo de


Transformao Perfeita
void obtemHashingPerfeito ( ) {
Ler conjunto de N chaves;
Escolha um valor para M ;
do {
Gera os pesos p1 [i] e p2 [i] para
0 i maxT amChave 1 ;
Gera o grafo G = (V, A) ;
grafoRotulavel = atribuig (G, g) ;
} while ( ! grafoRotulavel ) ;
Retorna p1 , p2 e g ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 101

Estruturas de dados e operaes para


obter a funo hash perfeita
package cap5.fhpm;
import java . io . ;
import cap7. listaadj . arranjo .Grafo ; / / vide Programas do captulo
7
public class FHPM {
private int p1[ ] , p2 [ ] ; / / pesos de h1 e h2
private int g [ ] ; / / funo g
private int N; / / nmero de chaves
private int M; / / nmero de vrtices
private int maxTamChave, nGrafosGerados, nGrafosConsiderados;
private final int Indefinido = 1;
/ / Entram aqui os mtodos privados das transparncias 76, 103 e 104
public FHPM ( int maxTamChave, int n, float c ) {
this .N = n ; this .M = ( int ) (cthis .N) ;
this .maxTamChave = maxTamChave; this .g = new int [ this .M] ;
}
public void obtemHashingPerfeito ( String nomeArqEnt)
throws Exception {
BufferedReader arqEnt = new BufferedReader (
new FileReader (nomeArqEnt) ) ;
String conjChaves[ ] = new String [ this .N] ;
this .nGrafosGerados = 0;
this .nGrafosConsiderados = 0; int i = 0;
/ / Continua na prxima transparncia
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 102

Estruturas de dados e operaes para


obter a funo hash perfeita
while ( ( i < this .N) &&
( (conjChaves[ i ] = arqEnt . readLine ( ) ) ! = null ) ) i ++;
i f ( i ! = this .N)
throw new Exception ( "Erro : Arquivo de entrada possui"+
"menos que "+
this .N + " chaves" ) ;
boolean grafoRotulavel = true ;
do {
Grafo grafo = this .geraGrafo (conjChaves) ;
grafoRotulavel = this . atribuig ( grafo ) ;
}while ( ! grafoRotulavel ) ;
arqEnt . close ( ) ;
}
public int hp ( String chave) {
return (g[h (chave, p1) ] + g[h (chave, p2)]) % N;
}
/ / Entram aqui os mtodos pblicos dos Programas 106 e 107
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 103

Gera um Grafo sem Arestas Repetidas


e sem Self-Loops
private Grafo geraGrafo ( String conjChaves [ ] ) {
Grafo grafo ; boolean grafoValido ;
do {
grafo = new Grafo ( this .M, this .N) ; grafoValido = true ;
this .p1 = this .geraPesos ( this .maxTamChave) ;
this .p2 = this .geraPesos ( this .maxTamChave) ;
for ( int i = 0; i < this .N; i ++) {
int v1 = this .h (conjChaves[ i ] , this .p1) ;
int v2 = this .h (conjChaves[ i ] , this .p2) ;
i f ( ( v1 == v2 ) | | grafo . existeAresta (v1 , v2 ) ) {
grafoValido = false ; grafo = null ; break;
} else {
grafo . insereAresta ( v1 , v2 , i ) ;
grafo . insereAresta ( v2 , v1 , i ) ;
}
}
this .nGrafosGerados ++;
} while ( ! grafoValido ) ;
return grafo ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 104

Rotula Grafo e Atribui Valores para O


Arranjo g
private boolean rotuleDe ( int v , int c , Grafo grafo ) {
boolean grafoRotulavel = true ;
i f ( this .g[ v ] ! = Indefinido ) {
i f ( this .g[ v ] ! = c ) {
this .nGrafosConsiderados++; grafoRotulavel = false ;
}
} else {
this .g[ v ] = c ;
i f ( ! grafo . listaAdjVazia ( v ) ) {
Grafo. Aresta adj = grafo . primeiroListaAdj ( v ) ;
while ( adj ! = null ) {
int u = adj .peso () this .g[ v ] ;
i f (u < 0) u = u + this .N;
grafoRotulavel = rotuleDe( adj . vertice2 ( ) ,u, grafo ) ;
i f ( ! grafoRotulavel ) break ; / / sai do loop
adj = grafo . proxAdj ( v ) ;
}
}
}
return grafoRotulavel ;
}

/ / Continua na prxima transparncia


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 105

Rotula Grafo e Atribui Valores para O


Arranjo g
private boolean atribuig ( Grafo grafo ) {
boolean grafoRotulavel = true ;
for ( int v = 0; v < this .M; v++) this .g[ v ] = Indefinido ;
for ( int v = 0; v < this .M; v++) {
i f ( this .g[ v] == Indefinido )
grafoRotulavel = this . rotuleDe ( v , 0 , grafo ) ;
i f ( ! grafoRotulavel ) break;
}
return grafoRotulavel ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 106

Mtodo para salvar no disco a funo


de transformao perfeita
public void salvar ( String nomeArqSaida) throws Exception {
BufferedWriter arqSaida = new BufferedWriter (
new FileWriter (nomeArqSaida) ) ;
arqSaida. write ( this .N + " (N) \n" ) ;
arqSaida. write ( this .M + " (M) \n" ) ;
arqSaida. write ( this .maxTamChave + " (maxTamChave) \n" ) ;

for ( int i = 0; i < this .maxTamChave; i ++)


arqSaida. write ( this .p1[ i ] + " " ) ;
arqSaida. write ( " (p1) \n" ) ;

for ( int i = 0; i < this .maxTamChave; i ++)


arqSaida. write ( this .p2[ i ] + " " ) ;
arqSaida. write ( " (p2) \n" ) ;

for ( int i = 0; i < this .M; i ++)


arqSaida. write ( this .g[ i ] + " " ) ;
arqSaida. write ( " (g) \n" ) ;

arqSaida. write ( "No. grafos gerados por geraGrafo: " +


this .nGrafosGerados + " \n" ) ;
arqSaida. write ( "No. grafos considerados por atribuig : " +
( this .nGrafosConsiderados + 1) + " \n" ) ;
arqSaida. close ( ) ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 107

Mtodo para ler do disco a funo de


transformao perfeita
public void ler ( String nomeArqFHPM ) throws Exception {
BufferedReader arqFHPM = new BufferedReader (
new FileReader (nomeArqFHPM ) ) ;
String temp = arqFHPM . readLine ( ) , valor = temp. substring(0 ,
temp.indexOf ( " " ) ) ;
this .N = Integer . parseInt ( valor ) ;
temp = arqFHPM . readLine ( ) ; valor = temp. substring(0 ,
temp.indexOf ( " " ) ) ;
this .M = Integer . parseInt ( valor ) ;
temp = arqFHPM . readLine ( ) ; valor = temp. substring(0 ,
temp.indexOf ( " " ) ) ;
this .maxTamChave = Integer . parseInt ( valor ) ;
temp = arqFHPM . readLine ( ) ; int inicio = 0;
this .p1 = new int [ this .maxTamChave] ;
for ( int i = 0; i < this .maxTamChave; i ++) {
int fim = temp.indexOf ( , inicio ) ;
valor = temp. substring ( inicio , fim ) ;
inicio = fim + 1; this .p1[ i ] = Integer . parseInt ( valor ) ;
}
temp = arqFHPM . readLine ( ) ; inicio = 0;
this .p2 = new int [ this .maxTamChave] ;
for ( int i = 0; i < this .maxTamChave; i ++) {
int fim = temp.indexOf ( , inicio ) ;
valor = temp. substring ( inicio , fim ) ;
inicio = fim + 1; this .p2[ i ] = Integer . parseInt ( valor ) ;
}
temp = arqFHPM . readLine ( ) ; inicio = 0;
this .g = new int [ this .M] ;
for ( int i = 0; i < this .M; i ++) {
int fim = temp.indexOf ( , inicio ) ; valor =
temp. substring ( inicio , fim ) ;
inicio = fim + 1; this .g[ i ] = Integer . parseInt ( valor ) ;
}
arqFHPM . close ( ) ;
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 108

Programa para gerar uma funo de


transformao perfeita
package cap5;
import java . io .;
import cap5.fhpm. FHPM ; / / vide transparncia 101
public class GeraFHPM {
public static void main ( String [ ] args ) {
BufferedReader in = new BufferedReader (
new InputStreamReader (System. in ) ) ;
try {
System. out . print ( "Numero de chaves: " ) ;
int n = Integer . parseInt ( in . readLine ( ) ) ;
System. out . print ( "Tamanho da maior chave: " ) ;
int maxTamChave = Integer . parseInt ( in . readLine ( ) ) ;
System. out . print ( "Nome do arquivo com chaves a serem lidas : " ) ;
String nomeArqEnt = in . readLine ( ) ;
System. out . print ( "Nome do arquivo para gravar a FHPM : " ) ;
String nomeArqSaida = in . readLine ( ) ;
FHPM fhpm = new FHPM (maxTamChave, n, 3 ) ;
fhpm.obtemHashingPerfeito (nomeArqEnt) ;
fhpm. salvar (nomeArqSaida) ;
} catch ( Exception e) {System. out . println (e.getMessage ( ) ) ; }
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 109

Programa para testar uma funo de


transformao perfeita
package cap5;
import java . io .;
import cap5.fhpm. FHPM ; / / vide transparncia 101
public class TestaFHPM {
public static void main ( String [ ] args ) {
BufferedReader in = new BufferedReader (
new InputStreamReader (System. in ) ) ;
try {
System. out . print ( "Nome do arquivo com a FHPM : " ) ;
String nomeArqEnt = in . readLine ( ) ;
FHPM fhpm = new FHPM (0 , 0 , 0);
fhpm. ler (nomeArqEnt) ;
System. out . print ( "Chave: " ) ; String chave = in . readLine ( ) ;
while ( ! chave.equals ( "aaaaaa" ) ) {
System. out . println ( "Indice : " + fhpm.hp (chave) ) ;
System. out . print ( "Chave: " ) ; chave = in . readLine ( ) ;
}
} catch ( Exception e) {System. out . println (e.getMessage ( ) ) ; }
}
}
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 110

Anlise

A questo crucial : quantas interaes so


necessrias para obter um grafo G = (V, A)
que seja rotulvel?

Para grafos arbitrrios, difcil achar uma


soluo para esse problema, isso se existir tal
soluo.

Entretanto, para grafos acclicos, a funo g


existe sempre e pode ser obtida facilmente.

Assim, a resposta a esta questo depende do


valor de M que escolhido no primeiro passo
do algoritmo.

Quanto maior o valor de M , mais esparso o


grafo e, conseqentemente, mais provvel
que ele seja acclico.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 111

Anlise

Segundo Czech, Havas e Majewski (1992),


quando M 2N a probabilidade de gerar
aleatoriamente um grafo acclico tende para
zero quando N cresce.

Isto ocorre porque o grafo se torna denso, e o


grande nmero de arestas pode levar
formao de ciclos.

Por outro lado, quando M > 2N , a


probabilidade de que um grafo randmico
contendo M vrtices e N arestas seja acclico
aproximadamente
r
M 2N
,
M

E o nmero esperado de grafos gerados at


que o primeiro acclico seja obtido :
r
M

M 2N
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 112

Anlise

Para M = 3N o nmero esperado de



iteraes 3, em mdia,
aproximadamente 1,7 grafos sero testados
antes que aparea um grafo acclico.

Logo, a complexidade de tempo para gerar a


funo de transformao proporcional ao
nmero de chaves a serem inseridas na
tabela hash, desde que M > 2N .

O grande inconveniente de usar M = 3N o


espao necessrio para armazenar o arranjo
g.

Por outro lado, considerar M < 2N pode


implicar na necessidade de gerar muitos
grficos randmicos at que um grafo acclico
seja encontrado.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 113

Outra Alternativa

No utilizar grafos tradicionais, mas sim


hipergrafos, ou r-grafos, nos quais cada
aresta conecta um nmero qualquer r de
vrtices.

Para tanto, basta usar uma terceira funo h3


para gerar um trigrafo com arestas
conectando trs vrtices, chamado de
3-grafo.

Em outras palavras, cada aresta uma tripla


do tipo (h1 (x), h2 (x), h3 (x)), e a funo de
transformao dada por:

h(x) = (g(h1 (x)) + g(h2 (x)) + g(h3 (x))) mod N.


Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 114

Outra Alternativa

Nesse caso, o valor de M pode ser prximo a


1, 23N .

Logo, o uso de trigrafos reduz o custo de


espao da funo de transformao perfeita,
mas aumenta o tempo de acesso ao
dicionrio.

Alm disso, o processo de rotulao no


pode ser feito como descrito.

Ciclos devem ser detectados previamente,


utilizando a seguinte propriedade de r-grafos:
Um r-grafo acclico se e somente se a
remoo repetida de arestas contendo
apenas vrtices de grau 1 (isto , vrtices
sobre os quais incide apenas uma aresta)
elimina todas as arestas do grafo.
Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4 115

Experimentos

# Chaves # Chamadas # Chamadas Tempo


geraGrafo atribuig (s)
10 3586 1 0.130
20 20795 16 0.217
30 55482 24 0.390
40 52077 33 0.432
50 47828 19 0.462
60 27556 10 0.313
70 26265 17 0.351
80 161736 92 1.543
90 117014 106 1.228
100 43123 26 0.559
Pesquisa em Memria
Secundria

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Wagner Meira Jr, Flvia Peligrinelli Ribeiro,


Nvio Ziviani e Charles Ornelas, Leonardo Rocha, Leonardo Mata
Projeto de Algoritmos Cap.1 Introduo 1

Introduo
Pesquisa em memria secundria: arquivos
contm mais registros do que a memria
interna pode armazenar.
Custo para acessar um registro algumas
ordens de grandeza maior do que o custo de
processamento na memria primria.
Medida de complexidade: custo de trasferir
dados entre a memria principal e secundria
(minimizar o nmero de transferncias).
Memrias secundrias: apenas um registro
pode ser acessado em um dado momento
(acesso seqencial).
Memrias primrias: acesso a qualquer
registro de um arquivo a um custo uniforme
(acesso direto).
Em um mtodo eficiente de pesquisa, o
aspecto sistema de computao importante.
As caractersticas da arquitetura e do sistema
operacional da mquina tornam os mtodos
de pesquisa dependentes de parmetros que
afetam seus desempenhos.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1 2

Modelo de Computao para Memria


Secundria - Memria Virtual

Normalmente implementado como uma


funo do sistema operacional.

Modelo de armazenamento em dois nveis,


devido necessidade de grandes
quantidades de memria e o alto custo da
memria principal.

Uso de uma pequena quantidade de memria


principal e uma grande quantidade de
memria secundria.

Programador pode enderear grandes


quantidades de dados, deixando para o
sistema a responsabilidade de trasferir o dado
da memria secundria para a principal.

Boa estratgia para algoritmos com pequena


localidade de referncia.

Organizao do fluxo entre a memria


principal e secundria extremamente
importante.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 3

Memria Virtual

Organizao de fluxo transformar o


endereo usado pelo programador na
localizao fsica de memria
correspondente.

Espao de Endereamento endereos


usados pelo programador.

Espao de Memria localizaes de


memria no computador.

O espao de endereamento N e o espao


de memria M podem ser vistos como um
mapeamento de endereos do tipo:
f : N M.

O mapeamento permite ao programador usar


um espao de endereamento que pode ser
maior que o espao de memria primria
disponvel.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 4

Memria Virtual: Sistema de


Paginao

O espao de endereamento dividido em


pginas de tamanho igual, em geral, mltiplos
de 512 bytes.

A memria principal dividida em molduras


de pginas de tamanho igual.

As molduras de pginas contm algumas


pginas ativas enquanto o restante das
pginas esto residentes em memria
secundria (pginas inativas).

O mecanismo possui duas funes:


1. Mapeamento de endereos determinar
qual pgina um programa est
endereando, encontrar a moldura, se
existir, que contenha a pgina.
2. Transferncia de pginas transferir
pginas da memria secundria para a
memria primria e transfer-las de volta
para a memria secundria quando no
esto mais sendo utilizadas.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 5

Memria Virtual: Sistema de


Paginao

Endereamento da pgina uma parte dos


bits interpretada como um nmero de
pgina e a outra parte como o nmero do
byte dentro da pgina (offset).

Mapeamento de endereos realizado


atravs de uma Tabela de Pginas.
a p-sima entrada contm a localizao p0
da Moldura de Pgina contendo a pgina
nmero p desde que esteja na memria
principal.

O mapeamento de endereos :
f (e) = f (p, b) = p0 + b, onde e o endereo do
programa, p o nmero da pgina e b o
nmero do byte.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 6

Memria Virtual: Mapeamento de


Endereos
N da N do
pgina byte
Endereo
de p b
programa

Tabela_de_Pginas Pgina p
-
- 
? ?
p0 p0 + b
p0 = nil pgina no
presente na
memria
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 7

Memria Virtual: Reposio de


Pginas

Se no houver uma moldura de pgina vazia


uma pgina dever ser removida da
memria principal.

Ideal remover a pgina que no ser


referenciada pelo perodo de tempo mais
longo no futuro.
tentamos inferir o futuro a partir do
comportamento passado.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 8

Memria Virtual: Polticas de


Reposio de Pginas
Menos Recentemente Utilizada (LRU):
um dos algoritmos mais utilizados,
remove a pgina menos recentemente
utilizada,
parte do princpio que o comportamento
futuro deve seguir o passado recente.
Menos Freqentemente Utilizada (LFU):
remove a pgina menos feqentemente
utilizada,
inconveniente: uma pgina recentemente
trazida da memria secundria tem um
baixo nmero de acessos registrados e
pode ser removida.
Ordem de Chegada (FIFO):
remove a pgina que est residente h
mais tempo,
algoritmo mais simples e barato de manter,
desvantagem: ignora o fato de que a
pgina mais antiga pode ser a mais
referenciada.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1 9

Memria Virtual: Poltica LRU

Toda vez que uma pgina utilizada ela


removida para o fim da fila.

A pgina que est no incio da fila a pgina


LRU.

Quando uma nova pgina trazida da


memria secundria ela deve ser colocada na
moldura que contm a pgina LRU.

Fim -

?
Pgina p
..
6
?
..
 Incio
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2 10

Memria Virtual: Estrutura de Dados

package cap6.umtipo;
class Registro {
private short chave;
/ / Outros componentes e mtodos de um registro
}
class Endereco {
private short p;
private byte b ; / / b [0, itensPorPagina 1]
/ / Mtodos para operar com um endereo
}
class Item {
private Registro reg ;
private Endereco esq, dir ;
/ / Mtodos para operar com um item
}
public class Pagina {
private Item pagina [ ] ;
public Pagina ( byte itensPorPagina ) {
/ / itensPorPagina = tamanhoDaPagina/tamanhoDoItem
this .pagina = new Item [ itensPorPagina ] ;
}
/ / Mtodos para operar com uma pgina
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2 11

Memria Virtual
Em casos em que precisamos manipular mais
de um arquivo ao mesmo tempo:
Deve-se utilizar os mecanismos de
Herana e Polimorfismo de Java que
permitem que uma pgina possa ser
definida como vrios tipos diferentes.
A fila de molduras nica cada moldura
deve ter indicado o arquivo a que se refere
aquela pgina.

package cap6. variostipos ;


public abstract class Pagina {
/ / Componentes e mtodos de uma pgina
}
class PaginaA extends Pagina {
/ / Componentes e mtodos de uma pgina do tipo A
}
class PaginaB extends Pagina {
/ / Componentes e mtodos de uma pgina do tipo B
}
class PaginaC extends Pagina {
/ / Componentes e mtodos de uma pgina do tipo C
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2 12

Memria Virtual

Procedimentos para comunicao com o


sistema de paginao:
obtemRegistro torna disponvel um
registro.
escreveRegistro permite criar ou alterar o
contedo de um registro.
descarregaPaginas varre a fila de
molduras para atualizar na memria
secundria todas as pginas que tenham
sido modificadas.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2 13

Memria Virtual - Transformao do


Endereo Virtual para Real
Quadrados resultados de processos ou
arquivos.
Retngulos processos transformadores de
informao.
P1 P3
Consulta p Determina Pgina
- tabela de - moldura
pginas - para pgina p0

6 p0
p ?
A2 P5
Fila Grava pgina
de na memria
molduras p secundria
Programa p0 p0
Usurio p0
A1 A3 p0
Tabela
6 de Memria 
pginas secundria Pgina

6 p6
p0 p
? p0 ?
P2 P4
Determina Recupera pgina
endereo  da memria 
p0 Pgina
real secundria
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.2 14

Acesso Seqencial Indexado


Utiliza o princpio da pesquisa seqencial
cada registro lido seqencialmente at
encontrar uma chave maior ou igual a chave
de pesquisa.
Providncias necessrias para aumentar a
eficincia:
o arquivo deve ser mantido ordenado pelo
campo chave do registro,
um arquivo de ndices contendo pares de
valores < x, p > deve ser criado, onde x
representa uma chave e p representa o
endereo da pgina na qual o primeiro
registro contm a chave x.
Estrutura de um arquivo seqencial
indexado para um conjunto de 15
registros:
3 14 25 41
1 2 3 4

1 3 5 7 11 2 14 17 20 21 3 25 29 32 36 4 41 44 48
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.2 15

Acesso Seqencial Indexado: Disco


Magntico

Dividido em crculos concntricos (trilhas).

Cilindro todas as trilhas verticalmente


alinhadas e que possuem o mesmo dimetro.

Latncia rotacional tempo necessrio para


que o incio do bloco contendo o registro a ser
lido passe pela cabea de leitura/gravao.

Tempo de busca (seek time) tempo


necessrio para que o mecanismo de acesso
desloque de uma trilha para outra (maior
parte do custo para acessar dados).

Acesso seqencial indexado = acesso


indexado + organizao seqencial,

Aproveitando caractersticas do disco


magntico e procurando minimizar o nmero
de deslocamentos do mecanismo de acesso
esquema de ndices de cilindros e de
pginas.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.2 16

Acesso Seqencial Indexado: Disco


Magntico

Para localizar o registro que contenha uma


chave de pesquisa so necessrios os
seguintes passos:
1. localize o cilindro correspondente chave
de pesquisa no ndice de cilindros;
2. desloque o mecanismo de acesso at o
cilindro correspondente;
3. leia a pgina que contm o ndice de
pginas daquele cilindro;
4. leia a pgina de dados que contm o
registro desejado.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.2.1 17

Acesso Seqencial Indexado: Discos


ticos de Apenas-Leitura (CD-ROM)
Grande capacidade de armazenamento (600
MB) e baixo custo para o usurio final.
Informao armazenada esttica.
A eficincia na recuperao dos dados
afetada pela localizao dos dados no disco e
pela seqncia com que so acessados.
Velocidade linear constante trilhas
possuem capacidade varivel e tempo de
latncia rotacional varia de trilha para trilha.
A trilha tem forma de uma espiral contnua.
Tempo de busca: acesso a trilhas mais
distantes demanda mais tempo que no disco
magntico. H necessidade de deslocamento
do mecanismo de acesso e mudanas na
rotao do disco.
Varredura esttica: acessa conjunto de trilhas
vizinhas sem deslocar mecanismo de leitura.
Estrutura seqencial implementada
mantendo-se um ndice de cilindros na
memria principal.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 18

rvores B

rvores n-rias: mais de um registro por


nodo.

Em uma rvore B de ordem m:


pgina raiz: 1 e 2m registros.
demais pginas: no mnimo m registros e
m + 1 descendentes e no mximo 2m
registros e 2m + 1 descendentes.
pginas folhas: aparecem todas no
mesmo nvel.

Os registros aparecem em ordem crescente


da esquerda para a direita.

Extenso natural da rvore binria de


pesquisa.

rvore B de ordem m = 2 com trs nveis:




30hhh
 hhh 

10 20 40 50
  `
``  
``
```
   `
`    


3489 11 13 17


25 28

33 36 43 45 48


52 55
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 19

rvores B - Estrutura e operaes do


dicionrio para rvore B

A estrutura de dados rvore B ser utilizada


para implementar o tipo abstrato de dados
Dicionrio e suas operaes: inicializa,
pesquisa, insere e retira.

A operao inicializa implementada pelo


construtor da classe ArvoreB . As demais
operaes so descritas a seguir.

A operao pesquisa implementada por um


mtodo privado sobrecarregado. Este mtodo
semelhante ao mtodo pesquisa para a
rvore binria de pesquisa.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 20

rvores B - Estrutura e operaes do


dicionrio para rvore B

package cap6;
import cap4. Item ; / / vide Programa do captulo 4
public class ArvoreB {
private static class Pagina {
int n ; Item r [ ] ; Pagina p [ ] ;
public Pagina ( int mm ) {
this .n = 0; this . r = new Item [ mm ] ;
this .p = new Pagina[ mm+1];
}
}
private Pagina raiz ;
private int m, mm ;
/ / Entra aqui o mtodo privado da transparncia 21
public ArvoreB ( int m) {
this . raiz = null ; this .m = m; this . mm = 2m;
}
public Item pesquisa ( Item reg ) {
return this .pesquisa ( reg , this . raiz ) ;
}
public void insere ( Item reg ) { vide transparncias 24 e
25 }

public void retira ( Item reg ) { vide transparncias 30, 31


e 32 }
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 21

rvores B - Mtodo para pesquisar na


rvore B

private Item pesquisa ( Item reg , Pagina ap) {


i f (ap == null ) return null ; / / Registro no encontrado
else {
int i = 0;
while ( ( i < ap.n1) && (reg .compara (ap. r [ i ] ) > 0 ) ) i ++;
i f ( reg .compara (ap. r [ i ]) == 0) return ap. r [ i ] ;
else i f ( reg .compara (ap. r [ i ]) < 0)
return pesquisa ( reg , ap.p[ i ] ) ;
else return pesquisa ( reg , ap.p[ i +1]);
}
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 22

rvores B - Insero

1. Localizar a pgina apropriada aonde o regisro


deve ser inserido.

2. Se o registro a ser inserido encontra uma


pgina com menos de 2m registros, o
processo de insero fica limitado pgina.

3. Se o registro a ser inserido encontra uma


pgina cheia, criada uma nova pgina, no
caso da pgina pai estar cheia o processo de
diviso se propaga.

Exemplo: Inserindo o registro com chave 14.



1 10

 ``
```
 
  `
23489 16 20 25 29
3 (a)


110 20

 ``
` `
 
  ` `
3489 25 29 (b)
2 3 14 16 4 
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 23

rvores B - Insero

Exemplo de insero das chaves: 20, 10, 40, 50,


30, 55, 3, 11, 4, 28, 36, 33, 52, 17, 25, 13, 45, 9,
43, 8 e 48

(a)
20

(b)
30 P
  PP 

10 20
40 50

(c) 10 20 30 40
( ( (
(
 Ph hhh
( ( 
(  P
 P hhh


3 4
11 13 17
25 28
33 36
50 52 55

(d)
30hhh
 hhh 

10 20 40 50
  ` `
`  
``
```
   ``     

3489 11 13 17


25 28
33 36
43 45 48
52 55
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 24

rvores B - Mtodo insereNaPagina

private void insereNaPagina


(Pagina ap, Item reg , Pagina apDir ) {
int k = ap.n 1;
while ( ( k >= 0) && (reg .compara (ap. r [ k ] ) < 0 ) ) {
ap. r [ k+1] = ap. r [ k ] ; ap.p[ k+2] = ap.p[ k+1]; k;
}
ap. r [ k+1] = reg ; ap.p[ k+2] = apDir ; ap.n++;
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 25

rvores B - Refinamento final do


mtodo insere
public void insere ( Item reg ) {
Item regRetorno [ ] = new Item [ 1 ] ;
boolean cresceu [ ] = new boolean[ 1 ] ;
Pagina apRetorno = this . insere ( reg , this . raiz , regRetorno , cresceu ) ;
i f ( cresceu [ 0 ] ) {
Pagina apTemp = new Pagina( this . mm ) ;
apTemp. r [0] = regRetorno [ 0 ] ;
apTemp.p[0] = this . raiz ;
apTemp.p[1] = apRetorno;
this . raiz = apTemp; this . raiz .n++;
} else this . raiz = apRetorno;
}
private Pagina insere ( Item reg , Pagina ap, Item [ ] regRetorno,
boolean [ ] cresceu ) {
Pagina apRetorno = null ;
i f (ap == null ) { cresceu[0] = true ; regRetorno[0] = reg ; }
else {
int i = 0;
while ( ( i < ap.n1) && (reg .compara (ap. r [ i ] ) > 0 ) ) i ++;
i f ( reg .compara (ap. r [ i ]) == 0) {
System. out . println ( "Erro : Registro ja existente " ) ;
cresceu[0] = false ;
}
else {
i f ( reg .compara (ap. r [ i ]) > 0 ) i ++;
apRetorno = insere ( reg , ap.p[ i ] , regRetorno , cresceu ) ;
i f ( cresceu[ 0 ] )
i f (ap.n < this . mm ) { / / Pgina tem espao
this .insereNaPagina (ap, regRetorno [ 0 ] , apRetorno) ;
cresceu[0] = false ; apRetorno = ap;
}

/ / Continua na prxima transparncia


Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 26

rvores B - Refinamento final do


mtodo insere
else { / / Overflow : Pgina tem que ser dividida
Pagina apTemp = new Pagina ( this . mm ) ; apTemp.p[0] = null ;
i f ( i <= this .m) {
this .insereNaPagina (apTemp,ap. r [ this . mm1],ap.p[ this . mm ] ) ;
ap.n;
this .insereNaPagina (ap, regRetorno [ 0 ] , apRetorno) ;
} else this .insereNaPagina (apTemp, regRetorno [ 0 ] , apRetorno) ;
for ( int j = this .m+1; j < this . mm ; j ++) {
this .insereNaPagina (apTemp, ap. r [ j ] , ap.p[ j +1]);
ap.p[ j +1] = null ; / / transfere a posse da memria
}
ap.n = this .m; apTemp.p[0] = ap.p[ this .m+1];
regRetorno[0] = ap. r [ this .m] ; apRetorno = apTemp;
}
}
}
return ( cresceu[ 0 ] ? apRetorno : ap) ;
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 27

rvores B - Remoo

Pgina com o registro a ser retirado folha:


1. retira-se o registro,
2. se a pgina no possui pelo menos de m
registros, a propriedade da rvore B
violada. Pega-se um registro emprestado
da pgina vizinha. Se no existir registros
suficientes na pgina vizinha, as duas
pginas devem ser fundidas em uma s.

Pagina com o registro no folha:


1. o registro a ser retirado deve ser
primeiramente substitudo por um registro
contendo uma chave adjacente.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 28

rvores B - Remoo

Exemplo: Retirando a chave 3.


4j 4j 6j
  HHH , ll
   ,
* j   ,, ll
2j 6 8  6 8  4j 8j
@
@  T    T   AA  AA
j j 5j7j9j jjj j 7j 9j
1 3 1 2  5 7 9 1 2 5
(a) Pgina vizinha possui mais do que m registros

4j 4j j
,, ll * ,
, ll
 
2j 6j j 6j 4 6 
 AA  AA    AA   T
j j 5j 7j j j jj
1 3 1 2  5 7 1 2 5 7
(b) Pgina vizinha possui exatamente m registros
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 29

rvores B - Remoo

Exemplo de remoo das chaves 45 30 28; 50 8


10 4 20 40 55 17 33 11 36; 3 9 52.

(a)
30hhh
 hhh 

10 20 40 50
  `
```  
``
```
   `     

3489
11 13 17
25 28
33 36

43 45 48
52 55

(b) 10 25 40 50
( ( ((
 Ph hhhh
( (
(  P
 P hh

 

3 4 8 9 11 13 17 20


33 36
43 48

52 55


(c)
13 P
  PP 

3 9 25 43 48 52


(d) 13 25 43 48

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 30

rvores B - Operao retira


public void retira ( Item reg ) {
boolean diminuiu [ ] = new boolean[ 1 ] ;
this . raiz = this . retira ( reg , this . raiz , diminuiu ) ;
i f ( diminuiu[0] && ( this . raiz .n == 0)) { / / rvore diminui na altura
this . raiz = this . raiz .p[ 0 ] ;
}
}
private Pagina retira ( Item reg , Pagina ap, boolean [ ] diminuiu ) {
i f (ap == null ) {
System. out . println ( "Erro : Registro nao encontrado" ) ;
diminuiu [0] = false ;
}
else {
int ind = 0;
while ( ( ind < ap.n1) && (reg .compara (ap. r [ ind ] ) > 0 ) ) ind++;
i f ( reg .compara (ap. r [ ind ] ) = = 0 ) { / / achou
i f (ap.p[ ind ] == null ) { / / Pgina folha
ap.n; diminuiu [0] = ap.n < this .m;
for ( int j = ind ; j < ap.n ; j ++) {
ap. r [ j ] = ap. r [ j +1]; ap.p[ j ] = ap.p[ j +1];
}
ap.p[ap.n] = ap.p[ap.n+1];
ap.p[ap.n+1] = null ; / / transfere a posse da memria
}
else { / / Pgina no folha: trocar com antecessor
diminuiu [0] = antecessor (ap, ind , ap.p[ ind ] ) ;
i f ( diminuiu [ 0 ] ) diminuiu [0] = reconstitui (ap.p[ ind ] , ap, ind ) ;
}
}
else { / / no achou
i f ( reg .compara (ap. r [ ind ]) > 0 ) ind++;
ap.p[ ind ] = retira ( reg , ap.p[ ind ] , diminuiu ) ;
i f ( diminuiu [ 0 ] ) diminuiu [0] = reconstitui (ap.p[ ind ] , ap, ind ) ;
}
}
return ap;
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 31

rvores B - Mtodo antecessor utilizado


no mtodo retira
private boolean antecessor(Pagina ap, int ind ,Pagina apPai ) {
boolean diminuiu = true ;
i f ( apPai.p[apPai.n] ! = null ) {
diminuiu = antecessor (ap, ind , apPai.p[apPai.n ] ) ;
i f ( diminuiu)
diminuiu=reconstitui ( apPai.p[apPai.n] ,apPai,apPai.n) ;
}
else {
ap. r [ ind ] = apPai. r[apPai.n ] ;
diminuiu = apPai.n < this .m;
}
return diminuiu ;
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 32

rvores B - Mtodo reconstitui utilizado


no mtodo retira
private boolean reconstitui (Pagina apPag, Pagina apPai , int posPai ) {
boolean diminuiu = true ;
i f ( posPai < apPai.n ) { / / aux = Pgina direita de apPag
Pagina aux = apPai.p[posPai+1];
int dispAux = (aux.n this .m + 1)/2;
apPag. r [apPag.n++] = apPai. r [posPai ] ; apPag.p[apPag.n] = aux.p[ 0 ] ;
aux.p[0] = null ; / / transfere a posse da memria
i f ( dispAux > 0 ) { / / Existe folga: transfere de aux para apPag
for ( int j = 0; j < dispAux 1; j ++) {
this .insereNaPagina (apPag, aux. r [ j ] , aux.p[ j +1]);
aux.p[ j +1] = null ; / / transfere a posse da memria
}
apPai. r [posPai] = aux. r [dispAux 1];
aux.n = aux.n dispAux;
for ( int j = 0; j < aux.n ; j ++) aux. r [ j ] = aux. r [ j+dispAux ] ;
for ( int j = 0; j <= aux.n ; j ++) aux.p[ j ] = aux.p[ j+dispAux ] ;
aux.p[aux.n+dispAux] = null ; / / transfere a posse da memria
diminuiu = false ;
}
else { / / Fuso: intercala aux em apPag e libera aux
for ( int j = 0; j < this .m; j ++) {
this .insereNaPagina (apPag, aux. r [ j ] , aux.p[ j +1]);
aux.p[ j +1] = null ; / / transfere a posse da memria
}
aux = apPai.p[posPai+1] = null ; / / libera aux
for ( int j = posPai ; j < apPai.n1; j ++) {
apPai. r [ j ] = apPai. r [ j +1]; apPai.p[ j +1] = apPai.p[ j +2];
}
apPai.p[apPai.n] = null ; / / transfere a posse da memria
diminuiu = apPai.n < this .m;
}
}

/ / Continua na prxima transparncia


Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1 33

rvores B - Mtodo reconstitui utilizado


no mtodo retira
else { / / aux = Pgina esquerda de apPag
Pagina aux = apPai.p[posPai1];
int dispAux = (aux.n this .m + 1)/2;
for ( int j = apPag.n1; j >= 0; j ) apPag. r [ j +1] = apPag. r [ j ] ;
apPag. r [0] = apPai. r [posPai1];
for ( int j = apPag.n ; j >= 0; j ) apPag.p[ j +1] = apPag.p[ j ] ;
apPag.n++;
i f ( dispAux > 0 ) { / / Existe folga: transfere de aux para apPag
for ( int j = 0; j < dispAux 1; j ++) {
this .insereNaPagina (apPag, aux. r [aux.nj 1], aux.p[aux.nj ] ) ;
aux.p[aux.nj ] = null ; / / transfere a posse da memria
}
apPag.p[0] = aux.p[aux.n dispAux + 1];
aux.p[aux.n dispAux + 1] = null ; / / transfere a posse da memria
apPai. r [posPai1] = aux. r [aux.n dispAux ] ;
aux.n = aux.n dispAux ; diminuiu = false ;
}
else { / / Fuso: intercala apPag em aux e libera apPag
for ( int j = 0; j < this .m; j ++) {
this .insereNaPagina (aux, apPag. r [ j ] , apPag.p[ j +1]);
apPag.p[ j +1] = null ; / / transfere a posse da memria
}
apPag = null ; / / libera apPag
apPai.p[apPai.n] = null ; / / transfere a posse da memria
diminuiu = apPai.n < this .m;
}
}
return diminuiu ;
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.2 34

rvores B* - Estrutura e operaes do


dicionrio para rvore B?
package cap6;
import cap4. Item ; / / vide Programa do captulo 4
public class ArvoreBEstrela {
private static abstract class Pagina {
int n ; Item chaves [ ] ;
}
private static class PaginaInt extends Pagina {
Pagina p [ ] ;
public PaginaInt ( int mm ) {
this .n = 0; this .chaves = new Item [ mm ] ;
this .p = new Pagina[ mm+1];
}
}
private static class PaginaExt extends Pagina {
Object registros [ ] ;
public PaginaExt ( int mm2) {
this .n = 0; this .chaves = new Item [ mm2];
this . registros = new Object [ mm2];
}
}
private Pagina raiz ;
private int mm , mm2;

/ / Entram aqui os mtodos privados apresentados na transparncia 36


public ArvoreBEstrela ( int mm , int mm2) {
this . raiz = null ; this . mm = mm ; this . mm2 = mm2;
}
public Object pesquisa ( Item chave) {
return this .pesquisa (chave, this . raiz ) ;
}
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.2 35

rvores B* - Pesquisa

Semelhante pesquisa em rvore B,

A pesquisa sempre leva a uma pgina folha,

A pesquisa no pra se a chave procurada for


encontrada em uma pgina ndice. O
apontador da direita seguido at que se
encontre uma pgina folha.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.2 36

rvores B* - Mtodo para pesquisar na


rvore B?
private Object pesquisa ( Item chave, Pagina ap) {
i f (ap == null ) return null ; / / Registro no encontrado
else {
i f ( this . eInterna (ap) ) {
int i = 0; PaginaInt aux = ( PaginaInt)ap;
while ( ( i < aux.n1) && (chave.compara (aux.chaves[ i ] ) > 0 ) ) i ++;
i f (chave.compara (aux.chaves[ i ]) < 0)
return pesquisa (chave, aux.p[ i ] ) ;
else return pesquisa (chave, aux.p[ i +1]);
}
else {
int i = 0; PaginaExt aux = (PaginaExt)ap;
while ( ( i < aux.n1) && (chave.compara (aux.chaves[ i ] ) > 0 ) ) i ++;
i f (chave.compara (aux.chaves[ i ]) == 0) return aux. registros [ i ] ;
return null ; / / Registro no encontrado
}
}
}

private boolean eInterna (Pagina ap) {


Class classe = ap. getClass ( ) ;
return classe .getName( ) . equals(PaginaInt .class.getName( ) ) ;
}
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.2 37

rvores B* - Insero e Remoo

Insero na rvore B*
Semelhante insero na rvore B,
Diferena: quando uma folha dividida em
duas, o algoritmo promove uma cpia da
chave que pertence ao registro do meio
para a pgina pai no nvel anterior, retendo
o registro do meio na pgina folha da
direita.

Remoo na rvore B*
Relativamente mais simples que em uma
rvore B,
Todos os registros so folhas,
Desde que a folha fique com pelo menos
metade dos registros, as pginas dos
ndices no precisam ser modificadas,
mesmo se uma cpia da chave que
pertence ao registro a ser retirado esteja
no ndice.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.3 38

Acesso Concorrente em rvore B*


Acesso simultneo a banco de dados por
mais de um usurio.
Concorrncia aumenta a utilizao e melhora
o tempo de resposta do sistema.
O uso de rvores B* nesses sistemas deve
permitir o processamento simultneo de
vrias solicitaes diferentes.
Necessidade de criar mecanismos chamados
protocolos para garantir a integridade tanto
dos dados quanto da estrutura.
Pgina segura: no h possibilidade de
modificaes na estrutura da rvore como
conseqncia de insero ou remoo.
insero pgina segura se o nmero de
chaves igual a 2m,
remoo pgina segura se o nmero de
chaves maior que m.
Os algoritmos para acesso concorrente fazem
uso dessa propriedade para aumentar o nvel
de concorrncia.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.3 39

Acesso Concorrente em rvore B* -


Protocolos de Travamentos

Quando uma pgina lida, a operao de


recuperao a trava, assim, outros processos,
no podem interferir com a pgina.

A pesquisa continua em direo ao nvel


seguinte e a trava liberada para que outros
processos possam ler a pgina .

Processo leitor executa uma operao de


recuperao

Processo modificador executa uma


operao de insero ou retirada.

Dois tipos de travamento:


Travamento para leitura permite um ou
mais leitores acessarem os dados, mas
no permite insero ou retirada.
Travamento exclusivo nenhum outro
processo pode operar na pgina e permite
qualquer tipo de operao na pgina.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 40

rvore B - Consideraes Prticas

Simples, fcil manuteno, eficiente e verstil.

Permite acesso seqencial eficiente.

Custo para recuperar, inserir e retirar


registros do arquivo logaritmico.

Espao utilizado , no mnimo 50% do espao


reservado para o arquivo,

Emprego onde o acesso concorrente ao


banco de dados necessrio, vivel e
relativamente simples de ser implementado.

Insero e retirada de registros sempre


deixam a rvore balanceada.

Uma rvore B de ordem m com N registros


contm no mximo cerca de logm+1 N
pginas.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 41

rvore B - Consideraes Prticas

Limites para a altura mxima e mnima de


uma rvore B de ordem m com N registros:
 
N +1
log2m+1 (N + 1) altura 1 + logm+1 2

Custo para processar uma operao de


recuperao de um registro cresce com o
logaritmo base m do tamanho do arquivo.

Altura esperada: no conhecida


analiticamente.

H uma conjectura proposta a partir do


clculo analtico do nmero esperado de
pginas para os quatro primeiros nveis (das
folha em direo raiz) de uma rvore 2-3
(rvore B de ordem m = 1).

Conjetura: a altura esperada de uma rvore


2-3 randmica com N chaves
h(N ) log7/3 (N + 1).
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 42

rvores B Randmicas - Outras


Medidas de Complexidade
A utilizao de memria cerca de ln 2.
Pginas ocupam 69% da rea
reservada aps N inseres randmicas
em uma rvore B inicialmente vazia.
No momento da insero, a operao mais
cara a partio da pgina quando ela passa
a ter mais do que 2m chaves. Envolve:
Criao de nova pgina, rearranjo das
chaves e insero da chave do meio na
pgina pai localizada no nvel acima.
P r{j parties}: probabilidade de que j
parties ocorram durante a N -sima
insero randmica.
rvore 2-3: P r{0 parties} = 74 ,
P r{1 ou mais parties} = 73
rvore B de ordem m:
P r{0 parties} = 1 (2 ln12)m + O(m2 ),
P r{1 ou + parties} = (2 ln12)m + O(m2 ).
rvore B de ordem m = 70: 99% das
vezes nada acontece em termos de
parties durante uma insero.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 43

rvores B Randmicas - Acesso


Concorrente

Foi proposta uma tcnica de aplicar um


travamento na pgina segura mais profunda
(Psmp) no caminho de insero.

Uma pgina segura se ela contm menos


do que 2m chaves.

Uma pgina segura a mais profunda se no


existir outra pgina segura abaixo dela.

J que o travamento da pgina impede o


acesso de outros processos, interessante
saber qual a probabilidade de que a pgina
segura mais profunda esteja no primeiro nvel.

rvore 2-3: P r{Psmp esteja no 1 nvel} = 47 ,


P r{Psmp esteja acima do 1 nvel} = 37

rvore B de ordem m:
P r{Psmp esteja no 1 nvel} =
1 (2 ln12)m + O(m2 ),
3
P r{Psmp esteja acima do 1 nvel} = 7
=
1
(2 ln 2)m
+ O(m 2
).
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 44

rvores B Randmicas - Acesso


Concorrente

Novamente, em rvores B de ordem m = 70:


99% das vezes a Psmp est em uma folha.
(Permite alto grau de concorrncia para
processos modificadores.)

Solues muito complicadas para permitir


concorrncia de operaes em rvores B no
trazem grandes benefcios.

Na maioria das vezes, o travamento ocorrer


em pginas folha. (Permite alto grau de
concorrncia mesmo para os protocolos mais
simples.)
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 45

rvore B - Tcnica de
Transbordamento (ou Overflow)

Assuma que um registro tenha de ser inserido


em uma pgina cheia, com 2m registros.

Em vez de particion-la, olhamos primeiro


para a pgina irm direita.

Se a pgina irm possui menos do que 2m


registros, um simples rearranjo de chaves
torna a partio desnecessria.

Se a pgina direita tambm estiver cheia ou


no existir, olhamos para a pgina irm
esquerda.

Se ambas estiverem cheias, ento a partio


ter de ser realizada.

Efeito da modificao: produzir uma rvore


com melhor utilizao de memria e uma
altura esperada menor.

Produz uma utilizao de memria de cerca


de 83% para uma rvore B randmica.
Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4 46

rvore B - Influncia do Sistema de


Paginao
O nmero de nveis de uma rvore B muito
pequeno (trs ou quatro) se comparado com
o nmero de molduras de pginas.
Assim, o sistema de paginao garante que a
pgina raiz esteja sempre na memria
principal (se for adotada a poltica LRU).
O esquema LRU faz tambm com que as
pginas a serem particionadas em uma
insero estejam automaticamente
disponveis na memria principal.
A escolha do tamanho adequado da ordem m
da rvore B geralmente feita levando em
conta as caractersticas de cada computador.
O tamanho ideal da pgina da rvore
corresponde ao tamanho da pgina do
sistema, e a transferncia de dados entre as
memrias secundria e principal realizada
pelo sistema operacional.
Estes tamanhos variam entre 512 bytes e
4.096 bytes, em mltiplos de 512 bytes.
Algoritmos em Grafos

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Charles Ornelas, Leonardo Rocha, Leonardo


Mata e Nivio Ziviani
Projeto de Algoritmos Cap.7 Algoritmos em Grafos 1

Motivao

Muitas aplicaes em computao


necessitam considerar conjunto de conexes
entre pares de objetos:
Existe um caminho para ir de um objeto a
outro seguindo as conexes?
Qual a menor distncia entre um objeto
e outro objeto?
Quantos outros objetos podem ser
alcanados a partir de um determinado
objeto?

Existe um tipo abstrato chamado grafo que


usado para modelar tais situaes.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos 2

Aplicaes

Alguns exemplos de problemas prticos que


podem ser resolvidos atravs de uma
modelagem em grafos:
Ajudar mquinas de busca a localizar
informao relevante na Web.
Descobrir os melhores casamentos entre
posies disponveis em empresas e
pessoas que aplicaram para as posies
de interesse.
Descobrir qual o roteiro mais curto para
visitar as principais cidades de uma regio
turstica.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 3

Conceitos Bsicos

Grafo: conjunto de vrtices e arestas.

Vrtice: objeto simples que pode ter nome e


outros atributos.

Aresta: conexo entre dois vrtices.


3 aresta

0 1 4

2 vrtice

Notao: G = (V, A)
G: grafo
V: conjunto de vrtices
A: conjunto de arestas
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 4

Grafos Direcionados

Um grafo direcionado G um par (V, A), onde


V um conjunto finito de vrtices e A uma
relao binria em V .
Uma aresta (u, v) sai do vrtice u e entra
no vrtice v. O vrtice v adjacente ao
vrtice u.
Podem existir arestas de um vrtice para
ele mesmo, chamadas de self-loops.

0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 5

Grafos No Direcionados

Um grafo no direcionado G um par (V, A),


onde o conjunto de arestas A constitudo de
pares de vrtices no ordenados.
As arestas (u, v) e (v, u) so consideradas
como uma nica aresta. A relao de
adjacncia simtrica.
Self-loops no so permitidos.

0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 6

Grau de um Vrtice

Em grafos no direcionados:
O grau de um vrtice o nmero de
arestas que incidem nele.
Um vrice de grau zero dito isolado ou
no conectado.
Ex.: O vrtice 1 tem 0 1 4
grau 2 e o vrtice 3
isolado.
3 2 5

Em grafos direcionados
O grau de um vrtice o nmero de
arestas que saem dele (out-degree) mais
o nmero de arestas que chegam nele
(in-degree).
Ex.: O vrtice 2 tem 0 1 4
in-degree 2, out-degree
2 e grau 4.
3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 7

Caminho entre Vrtices


Um caminho de comprimento k de um
vrtice x a um vrtice y em um grafo
G = (V, A) uma seqncia de vrtices
(v0 , v1 , v2 , . . . , vk ) tal que x = v0 e y = vk , e
(vi1 , vi ) A para i = 1, 2, . . . , k.
O comprimento de um caminho o nmero
de arestas nele, isto , o caminho contm os
vrtices v0 , v1 , v2 , . . . , vk e as arestas
(v0 , v1 ), (v1 , v2 ), . . . , (vk1 , vk ).
Se existir um caminho c de x a y ento y
alcanvel a partir de x via c.
Um caminho simples se todos os vrtices
do caminho so distintos.
Ex.: O caminho (0, 1, 2, 3) simples e tem
comprimento 3. O caminho (1, 3, 0, 3) no
simples.
0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 8

Ciclos

Em um grafo direcionado:
Um caminho (v0 , v1 , . . . , vk ) forma um ciclo
se v0 = vk e o caminho contm pelo
menos uma aresta.
O ciclo simples se os vrtices
v1 , v2 , . . . , vk so distintos.
O self-loop um ciclo de tamanho 1.
Dois caminhos (v0 , v1 , . . . , vk ) e
(v00 , v10 , . . . , vk0 ) formam o mesmo ciclo se
existir um inteiro j tal que vi0 = v(i+j) mod k
para i = 0, 1, . . . , k 1.

Ex.: O caminho (0, 1, 2, 3, 0) forma um ciclo. O


caminho(0, 1, 3, 0) forma o mesmo ciclo que os
caminhos (1, 3, 0, 1) e (3, 0, 1, 3).

0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 9

Ciclos

Em um grafo no direcionado:
Um caminho (v0 , v1 , . . . , vk ) forma um ciclo
se v0 = vk e o caminho contm pelo
menos trs arestas.
O ciclo simples se os vrtices
v1 , v2 , . . . , vk so distintos.

Ex.: O caminho (0, 1, 2, 0) um ciclo.

0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 10

Componentes Conectados

Um grafo no direcionado conectado se


cada par de vrtices est conectado por um
caminho.

Os componentes conectados so as pores


conectadas de um grafo.

Um grafo no direcionado conectado se ele


tem exatamente um componente conectado.

Ex.: Os componentes so: {0, 1, 2}, {4, 5} e {3}.

0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 11

Componentes Fortemente Conectados

Um grafo direcionado G = (V, A)


fortemente conectado se cada dois vrtices
quaisquer so alcanveis a partir um do
outro.

Os componentes fortemente conectados


de um grafo direcionado so conjuntos de
vrtices sob a relao so mutuamente
alcanveis.

Um grafo direcionado fortemente


conectado tem apenas um componente
fortemente conectado.

Ex.: {0, 1, 2, 3}, {4} e {5} so os componentes


fortemente conectados, {4, 5} no o pois o
vrtice 5 no alcanvel a partir do vrtice 4.

0 1 4

3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 12

Grafos Isomorfos

G = (V, A) e G0 = (V 0 , A0 ) so isomorfos se
existir uma bijeo f : V V 0 tal que
(u, v) A se e somente se (f (u), f (v)) A0 .

0 1

4 5

7 6

3 2

s w x t

v z y u
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 13

Subgrafos

Um grafo G0 = (V 0 , A0 ) um subgrafo de
G = (V, A) se V 0 V e A0 A.

Dado um conjunto V 0 V , o subgrafo


induzido por V 0 o grafo G0 = (V 0 , A0 ), onde
A0 = {(u, v) A|u, v V 0 }.

Ex.: Subgrafo induzido pelo conjunto de vrtices


{1, 2, 4, 5}.

0 1 4

3 2 5

1 4

2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 14

Verso Direcionada de um Grafo No


Direcionado

A verso direcionada de um grafo no


direcionado G = (V, A) um grafo
direcionado G0 = (V 0 , A0 ) onde (u, v) A0 se e
somente se (u, v) A.

Cada aresta no direcionada (u, v) em G


substituda por duas arestas direcionadas
(u, v) e (v, u)

Em um grafo direcionado, um vizinho de um


vrtice u qualquer vrtice adjacente a u na
verso no direcionada de G.
0 1 0 1

2 2
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 15

Verso No Direcionada de um Grafo


Direcionado

A verso no direcionada de um grafo


direcionado G = (V, A) um grafo no
direcionado G0 = (V 0 , A0 ) onde (u, v) A0 se e
somente se u 6= v e (u, v) A.

A verso no direcionada contm as arestas


de G sem a direo e sem os self-loops.

Em um grafo no direcionado, u e v so
vizinhos se eles so adjacentes.

0 1 4 0 1 4

3 2 5 3 2 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 16

Outras Classificaes de Grafos

Grafo ponderado: possui pesos associados


s arestas.

Grafo bipartido: grafo no direcionado


G = (V, A) no qual V pode ser particionado
em dois conjuntos V1 e V2 tal que (u, v) A
implica que u V1 e v V2 ou u V2 e v V1
(todas as arestas ligam os dois conjuntos V1 e
V2 ).

Hipergrafo: grafo no direcionado em que


cada aresta conecta um nmero arbitrrio de
vrtices.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 17

Grafos Completos

Um grafo completo um grafo no


direcionado no qual todos os pares de
vrtices so adjacentes.

Possui (|V |2 |V |)/2 = |V |(|V | 1)/2 arestas,


pois do total de |V |2 pares possveis de
vrtices devemos subtrair |V | self-loops e
dividir por 2 (cada aresta ligando dois vrtices
contada duas vezes).

O nmero total de grafos diferentes com |V |


vrtices 2|V |(|V |1)/2 (nmero de maneiras
diferentes de escolher um subconjunto a
partir de |V |(|V | 1)/2 possveis arestas).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1 18

rvores

rvore livre: grafo no direcionado acclico e


conectado. comum dizer apenas que o
grafo uma rvore omitindo o livre.

Floresta: grafo no direcionado acclico,


podendo ou no ser conectado.

rvore geradora de um grafo conectado


G = (V, A): subgrafo que contm todos os
vrtices de G e forma uma rvore.

Floresta geradora de um grafo G = (V, A):


subgrafo que contm todos os vrtices de G e
forma uma floresta.

(a) (b)
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2 19

O Tipo Abstratos de Dados Grafo

Importante considerar os algoritmos em


grafos como tipos abstratos de dados.

Conjunto de operaes associado a uma


estrutura de dados.

Independncia de implementao para as


operaes.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2 20

Operadores do TAD Grafo

1. Criar um grafo vazio.

2. Inserir uma aresta no grafo.

3. Verificar se existe determinada aresta no


grafo.

4. Obter a lista de vrtices adjacentes a


determinado vrtice.

5. Retirar uma aresta do grafo.

6. Imprimir um grafo.

7. Obter o nmero de vrtices do grafo.

8. Obter o transposto de um grafo direcionado.

9. Obter a aresta de menor peso de um grafo.


Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2 21

Operao Obter Lista de Adjacentes

1. Verificar se a lista de adjacentes de um


vrtice v est vazia. Retorna true se a lista de
adjacentes de v est vazia.

2. Obter o primeiro vrtice adjacente a um


vrtice v, caso exista. Retorna o endereo do
primeiro vrtice na lista de adjacentes de v.

3. Obter o prximo vrtice adjacente a um


vrtice v, caso exista. Retorna a prxima
aresta que o vrtice v participa.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2 22

Implementao da Operao Obter


Lista de Adjacentes

comum encontrar um pseudo comando do


tipo:
for u iista de adjacentes (v) do { faz algo com u }

O trecho de programa abaixo apresenta um


possvel refinamento do pseudo comando
acima.

i f ( ! grafo . listaAdjVazia ( v ) ) {
Aresta aux = grafo . primeiroListaAdj ( v ) ;
while (aux ! = null ) {
int u = aux. vertice2 ( ) ; int peso = aux.peso ( ) ;
aux = grafo . proxAdj ( v ) ;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1 23

Matriz de Adjacncia

A matriz de adjacncia de um grafo


G = (V, A) contendo n vrtices uma matriz
n n de bits, onde A[i, j] 1 (ou verdadeiro)
se e somente se existe um arco do vrtice i
para o vrtice j.

Para grafos ponderados A[i, j] contm o


rtulo ou peso associado com a aresta e,
neste caso, a matriz no de bits.

Se no existir uma aresta de i para j ento


necessrio utilizar um valor que no possa
ser usado como rtulo ou peso.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1 24

Matriz de Adjacncia - Exemplo

0 1 4 0 1 4

3 2 5 3 2 5

0 1 2 3 4 5 0 1 2 3 4 5
0 1 1 0 1 1
1 1 1 1 1 1
2 1 1 2 1 1
3 1 3
4 4
5 5
(a) (b)
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1 25

Matriz de Adjacncia - Anlise

Deve ser utilizada para grafos densos, onde


|A| prximo de |V |2 .

O tempo necessrio para acessar um


elemento independente de |V | ou |A|.

muito til para algoritmos em que


necessitamos saber com rapidez se existe
uma aresta ligando dois vrtices.

A maior desvantagem que a matriz


necessita (|V |2 ) de espao. Ler ou examinar
a matriz tem complexidade de tempo O(|V |2 ).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1 26

Matriz de Adjacncia - Implementao


A insero de um novo vrtice ou retirada de
um vrtice j existente pode ser realizada
com custo constante.
package cap7. matrizadj ;
public class Grafo {
public static class Aresta {
private int v1 , v2 , peso;
public Aresta ( int v1 , int v2 , int peso) {
this .v1 = v1 ; this .v2 = v2 ; this .peso = peso ; }
public int peso ( ) { return this .peso ; }
public int v1 ( ) { return this .v1 ; }
public int v2 ( ) { return this .v2 ; }
}
private int mat [ ] [ ] ; / / pesos do tipo inteiro
private int numVertices;
private int pos [ ] ; / / posio atual ao se percorrer os adjs de um vrtice v
public Grafo ( int numVertices ) {
this .mat = new int [numVertices ] [ numVertices ] ;
this .pos = new int [numVertices ] ; this .numVertices = numVertices;
for ( int i = 0; i < this .numVertices ; i ++) {
for ( int j = 0; j < this .numVertices ; j ++) this .mat[ i ] [ j ] = 0;
this .pos[ i ] = 1;
}
}
public void insereAresta ( int v1 , int v2 , int peso) {
this .mat[v1 ] [ v2] = peso ; }
public boolean existeAresta ( int v1 , int v2 ) {
return ( this .mat[v1 ] [ v2] > 0);
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1 27

Matriz de Adjacncia - Implementao


public boolean listaAdjVazia ( int v ) {
for ( int i =0; i < this .numVertices ; i ++)
i f ( this .mat[ v ] [ i ] > 0) return false ;
return true ;
}
public Aresta primeiroListaAdj ( int v ) {
/ / Retorna a primeira aresta que o vrtice v participa ou
/ / null se a lista de adjacncia de v for vazia
this .pos[ v] = 1; return this . proxAdj ( v ) ;
}
public Aresta proxAdj ( int v ) {
/ / Retorna a prxima aresta que o vrtice v participa ou
/ / null se a lista de adjacncia de v estiver no fim
this .pos[ v] ++;
while ( ( this .pos[ v] < this .numVertices) &&
( this .mat[ v ] [ this .pos[ v] ] = = 0 ) ) this .pos[ v]++;
i f ( this .pos[ v] == this .numVertices ) return null ;
else return new Aresta ( v , this .pos[ v ] , this .mat[ v ] [ this .pos[ v ] ] ) ;
}
public Aresta retiraAresta ( int v1 , int v2 ) {
i f ( this .mat[v1 ] [ v2] == 0) return null ; / / Aresta no existe
else {
Aresta aresta = new Aresta ( v1 , v2 , this .mat[v1 ] [ v2 ] ) ;
this .mat[v1 ] [ v2] = 0 ; return aresta ;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1 28

Matriz de Adjacncia - Implementao


public void imprime ( ) {
System. out . print ( " " );
for ( int i = 0; i < this .numVertices ; i ++)
System. out . print ( i + " " );
System. out . println ( ) ;
for ( int i = 0; i < this .numVertices ; i ++) {
System. out . print ( i + " " );
for ( int j = 0; j < this .numVertices ; j ++)
System. out . print ( this .mat[ i ] [ j ] + " " );
System. out . println ( ) ;
}
}
public int numVertices ( ) {
return this .numVertices;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2 29

Listas de Adjacncia usando


Estruturas Auto-Referenciadas

3 0 1 5
5
0 1 1 3 2 7
1
7 2
3 2 3

0 1 5
5
0 1 0 5 2 7
1
7 1 7
2
3 2
3

Um arranjo adj de |V | listas, uma para cada


vrtice em V .

Para cada u V , adj[u] contm todos os


vrtices adjacentes a u em G.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2 30

Listas de adjacncia - Anlise

Os vrtices de uma lista de adjacncia so


em geral armazenados em uma ordem
arbitrria.

Possui uma complexidade de espao


O(|V | + |A|)

Indicada para grafos esparsos, onde |A|


muito menor do que |V |2 .

compacta e usualmente utilizada na maioria


das aplicaes.

A principal desvantagem que ela pode ter


tempo O(|V |) para determinar se existe uma
aresta entre o vrtice i e o vrtice j, pois
podem existir O(|V |) vrtices na lista de
adjacentes do vrtice i.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2 31

Listas de Adjacncia usando


Estruturas Auto-Referenciadas -
Implementao

A seguir apresentamos a implementao do


tipo abstrato de dados grafo utilizando
listas encadeadas implementadas por meio
de estruturas auto-referenciadas para as sete
primeiras operaes definidas anteriormente.

A classe Aresta representa as informaes de


uma aresta para que os usurios da classe
Grafo possam acess-las.

A classe Celula utilizada para representar


uma entrada na lista de adjacncia de um
vrtice do grafo.

O mtodo equals usado para verificar se um


vrtice qualquer v adjacente a um outro
vrtice u ao se percorrer a lista de adjacentes
de u.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2 32

Listas de Adjacncia usando


Estruturas Auto-Referenciadas -
Implementao
package cap7. listaadj . autoreferencia ;
import cap3. autoreferencia . Lista ;

public class Grafo {


public static class Aresta {
private int v1 , v2 , peso;
public Aresta ( int v1 , int v2 , int peso) {
this .v1 = v1 ; this .v2 = v2 ; this .peso = peso;
}
public int peso ( ) { return this .peso ; }
public int v1 ( ) { return this .v1 ; }
public int v2 ( ) { return this .v2 ; }
}
private static class Celula {
int vertice , peso;
public Celula ( int v , int p) { this . vertice = v ; this .peso = p; }
public boolean equals ( Object obj ) {
Celula item = ( Celula ) obj ;
return ( this . vertice == item . vertice ) ;
}
}
private Lista adj [ ] ;
private int numVertices;
public Grafo ( int numVertices ) {
this . adj = new Lista [numVertices ] ; this .numVertices = numVertices;
for ( int i = 0; i < this .numVertices ; i ++) this . adj [ i ] = new Lista ( ) ;
}
public void insereAresta ( int v1 , int v2 , int peso) {
Celula item = new Celula ( v2 , peso) ;
this . adj [v1 ] . insere ( item ) ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2 33

Listas de Adjacncia usando


Estruturas Auto-Referenciadas -
Implementao
public boolean existeAresta ( int v1 , int v2 ) {
Celula item = new Celula ( v2, 0 ) ;
return ( this . adj [v1 ] . pesquisa ( item ) ! = null ) ;
}
public boolean listaAdjVazia ( int v ) {
return this . adj [ v ] . vazia ( ) ;
}
public Aresta primeiroListaAdj ( int v ) {
/ / Retorna a primeira aresta que o vrtice v participa ou
/ / null se a lista de adjacncia de v for vazia
Celula item = ( Celula ) this . adj [ v ] . primeiro ( ) ;
return item ! = null ? new Aresta ( v , item . vertice , item .peso ) : null ;
}
public Aresta proxAdj ( int v ) {
/ / Retorna a prxima aresta que o vrtice v participa ou
/ / null se a lista de adjacncia de v estiver no fim
Celula item = ( Celula ) this . adj [ v ] . proximo ( ) ;
return item ! = null ? new Aresta ( v , item . vertice , item .peso ) : null ;
}
public Aresta retiraAresta ( int v1 , int v2) throws Exception {
Celula chave = new Celula ( v2, 0 ) ;
Celula item = ( Celula ) this . adj [v1 ] . retira (chave) ;
return item ! = null ? new Aresta ( v1 , v2 , item .peso ) : null ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2 34

Listas de Adjacncia usando


Estruturas Auto-Referenciadas -
Implementao
public void imprime ( ) {
for ( int i = 0; i < this .numVertices ; i ++) {
System. out . println ( " Vertice " + i + " : " ) ;
Celula item = ( Celula ) this . adj [ i ] . primeiro ( ) ;
while ( item ! = null ) {
System. out . println ( " " + item . vertice + " ( " +item .peso+ " ) " ) ;
item = ( Celula ) this . adj [ i ] . proximo ( ) ;
}
}
}
public int numVertices ( ) {
return this .numVertices;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.3 35

Listas de Adjacncia usando Arranjos


3 cab prox peso
0 4 4
5
0 1 1 6 5
V
2 2 0
(a) 7 3 3 0
4 1 0 5
3 2 A 5 1 6 3
6 2 0 7

cab prox peso


0 4 4
5 1 6 5
0 1 V
2 7 7
3 3 0
(b) 7
4 1 0 5
3 2 5 0 6 5
A
6 2 0 7
7 1 0 7

cab: endereos do ltimo item da lista de


adjacentes de cada vrtice (nas |V | primeiras
posies) e os vrtices propriamente ditos
(nas |A| ltimas posies)
prox: endereo do prximo item da lista de
adjacentes.
peso: valor do peso de cada aresta do grafo
(nas ltimas |A| posies).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.3 36

Listas de Adjacncia usando Arranjos


- Implementao
package cap7. listaadj . arranjo ;
public class Grafo {
public static class Aresta {
private int v1 , v2 , peso;
public Aresta ( int v1 , int v2 , int peso) {
this .v1 = v1 ; this .v2 = v2 ; this .peso = peso;
}
public int peso ( ) { return this .peso ; }
public int v1 ( ) { return this .v1 ; }
public int v2 ( ) { return this .v2 ; }
}
private int cab [ ] , prox [ ] , peso [ ] ;
private int pos [ ] ; / / posio atual ao se percorrer os adjs de um vrtice v
private int numVertices , proxDisponivel ;
public Grafo ( int numVertices , int numArestas) {
int tam = numVertices + 2numArestas;
this .cab = new int [tam ] ; this . prox = new int [tam] ;
this .peso = new int [tam ] ; this .numVertices = numVertices;
this .pos = new int [ this .numVertices ] ;
for ( int i = 0; i < this .numVertices ; i ++) {
this . prox [ i ] = 0;
this .cab[ i ] = i ;
this .peso[ i ] = 0;
this .pos[ i ] = i ;
}
this . proxDisponivel = this .numVertices;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.3 37

Listas de Adjacncia usando Arranjos


- Implementao
public void insereAresta ( int v1 , int v2 , int peso) {
i f ( this . proxDisponivel == this .cab. length )
System. out . println ( "Nao ha espaco disponivel para a aresta" ) ;
else {
int ind = this . proxDisponivel++;
this . prox [ this .cab[v1 ] ] = ind ;
this .cab[ ind ] = v2 ; this .cab[v1] = ind ;
this . prox [ ind ] = 0 ; this .peso[ ind ] = peso;
}
}
public boolean existeAresta ( int v1 , int v2 ) {
for ( int i = this . prox [v1 ] ; i ! = 0 ; i = this . prox [ i ] )
i f ( this .cab[ i ] == v2) return true ;
return false ;
}
public boolean listaAdjVazia ( int v ) {
return ( this . prox [ v] == 0);
}
public Aresta primeiroListaAdj ( int v ) {
/ / Retorna a primeira aresta que o vrtice v participa ou
/ / null se a lista de adjacncia de v for vazia
this .pos[ v ] = v ;
return this . proxAdj ( v ) ;
}
public Aresta proxAdj ( int v ) {
/ / Retorna a prxima aresta que o vrtice v participa ou
/ / null se a lista de adjacncia de v estiver no fim
this .pos[ v ] = this . prox [ this .pos[ v ] ] ;
i f ( this .pos[ v] == 0) return null ;
else return new Aresta ( v, this .cab[pos[ v ] ] , this .peso[pos[ v ] ] ) ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.3 38

Listas de Adjacncia usando Arranjos


- Implementao
public Aresta retiraAresta ( int v1 , int v2 ) {
int i ;
for ( i = v1 ; this . prox [ i ] ! = 0 ; i = this . prox [ i ] )
i f ( this .cab[ this . prox [ i ]] == v2) break;
int ind = this . prox [ i ] ;
i f ( this .cab[ ind ] == v2 ) { / / encontrou aresta
Aresta aresta = new Aresta(v1 , v2 , this .peso[ ind ] ) ;
this .cab[ ind ] = this .cab. length ; / / marca como removido
i f ( this . prox [ ind ] == 0) this .cab[v1] = i ; / / ltimo vrtice
this . prox [ i ] = this . prox [ ind ] ;
return aresta ;
} else return null ;
}
public void imprime ( ) {
for ( int i = 0; i < this .numVertices ; i ++) {
System. out . println ( " Vertice " + i + " : " ) ;
for ( int j = this . prox [ i ] ; j ! = 0 ; j = this . prox [ j ] )
System. out . println ( " " + this .cab[ j ]+ " ( " +this .peso[ j ]+ " ) " ) ;
}
}
public int numVertices ( ) { return this .numVertices ; }
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 39

Busca em Profundidade

A busca em profundidade, do ingls


depth-first search), um algoritmo para
caminhar no grafo.

A estratgia buscar o mais profundo no


grafo sempre que possvel.

As arestas so exploradas a partir do vrtice


v mais recentemente descoberto que ainda
possui arestas no exploradas saindo dele.

Quando todas as arestas adjacentes a v


tiverem sido exploradas a busca anda para
trs para explorar vrtices que saem do
vrtice do qual v foi descoberto.

O algoritmo a base para muitos outros


algoritmos importantes, tais como verificao
de grafos acclicos, ordenao topolgica e
componentes fortemente conectados.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 40

Busca em Profundidade

Para acompanhar o progresso do algoritmo


cada vrtice colorido de branco, cinza ou
preto.

Todos os vrtices so inicializados branco.

Quando um vrtice descoberto pela


primeira vez ele torna-se cinza, e tornado
preto quando sua lista de adjacentes tenha
sido completamente examinada.

d[v]: tempo de descoberta

t[v]: tempo de trmino do exame da lista de


adjacentes de v.

Estes registros so inteiros entre 1 e 2|V | pois


existe um evento de descoberta e um evento
de trmino para cada um dos |V | vrtices.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 41

Busca em Profundidade -
Implementao
package cap7;
import cap7. listaadj . autoreferencia .Grafo;
public class BuscaEmProfundidade {
public static final byte branco = 0;
public static byte cinza = 1;
public static byte preto = 2;
private int d [ ] , t [ ] , antecessor [ ] ;
private Grafo grafo ;

public BuscaEmProfundidade ( Grafo grafo ) {


this . grafo = grafo ; int n = this . grafo .numVertices ( ) ;
d = new int [n ] ; t = new int [n ] ; antecessor = new int [n ] ;
}
private int visitaDfs ( int u, int tempo, int cor [ ] ) {
cor [u] = cinza ; this .d[u] = ++tempo;
i f ( ! this . grafo . listaAdjVazia (u ) ) {
Grafo. Aresta a = this . grafo . primeiroListaAdj (u) ;
while (a ! = null ) {
int v = a.v2 ( ) ;
i f ( cor [ v] == branco ) {
this . antecessor [ v ] = u;
tempo = this . visitaDfs ( v , tempo, cor ) ;
}
a = this . grafo . proxAdj (u) ;
}
}
cor [u] = preto ; this . t [u] = ++tempo;
return tempo;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 42

Busca em Profundidade -
Implementao
public void buscaEmProfundidade ( ) {
int tempo = 0; int cor [ ] = new int [ this . grafo .numVertices ( ) ] ;
for ( int u = 0; u < grafo .numVertices ( ) ; u++) {
cor [u] = branco ; this . antecessor [u] = 1;
}
for ( int u = 0; u < grafo .numVertices ( ) ; u++)
i f ( cor [u] == branco ) tempo = this . visitaDfs ( u, tempo, cor ) ;
}
public int d ( int v ) { return this .d[ v ] ; }
public int t ( int v ) { return this . t [ v ] ; }
public int antecessor ( int v ) { return this . antecessor [ v ] ; }
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 43

Busca em Profundidade - Exemplo


b( / ) b( / ) c(1/ ) b( / )
0 1 0 1

b( / ) b( / )

b( / ) 2 3 b( / ) 2 3

(a) (b)

c(1/ ) c(2/ ) c(1/ ) c(2/ )


0 1 0 1

b( / ) b( / )

b( / ) 2 3 c(3/ ) 2 3

(c) (d)

c(1/ ) c(2/ )
0 1

b( / )

p(3/4) 2 3

(e)
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 44

Busca em Profundidade - Exemplo


c(1/ ) p(2/5) p(1/6) p(2/5)

0 1 0 1

b( / ) b( / )

p(3/4) 2 3 p(3/4) 2 3

(f) (g)

p(1/6) p(2/5) p(1/6) p(2/5)


0 1 0 1

c(7/ ) p(7/8)

p(3/4) 2 3 p(3/4) 2 3

(h) (i)
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3 45

Busca em Profundidade - Anlise

Os dois anis do mtodo


buscaEmProfundidade tm custo O(|V |) cada
um, a menos da chamada do mtodo
visitaDfs(u, tempo, cor ) no segundo anel.

O mtodo visitaDfs chamado exatamente


uma vez para cada vrtice u V , desde que
visitaDfs seja chamado apenas para vrtices
brancos, e a primeira ao pintar o vrtice
de cinza.

Durante a execuo de visitaDfs(u, tempo,


cor ), o anel principal executado |adj[u]|
vezes.

Desde que
X
|adj[u]| = O(|A|),
uV

o tempo total de execuo de visitaDfs


O(|A|).

Logo, a complexidade total do mtodo


buscaEmProfundidade O(|V | + |A|).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3.1 46

Classificao de Arestas

Existem:

1. Arestas de rvore: so arestas de uma


rvore de busca em profundidade. A aresta
(u, v) uma aresta de rvore se v foi
descoberto pela primeira vez ao percorrer a
aresta (u, v).

2. Arestas de retorno: conectam um vrtice u


com um antecessor v em uma rvore de
busca em profundidade (inclui self-loops).

3. Arestas de avano: no pertencem rvore


de busca em profundidade mas conectam um
vrtice a um descendente que pertence
rvore de busca em profundidade.

4. Arestas de cruzamento: podem conectar


vrtices na mesma rvore de busca em
profundidade, ou em duas rvores diferentes.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3.1 47

Classificao de Arestas

Classificao de arestas pode ser til para


derivar outros algoritmos.

Na busca em profundidade cada aresta pode


ser classificada pela cor do vrtice que
alcanado pela primeira vez:
Branco indica uma aresta de rvore.
Cinza indica uma aresta de retorno.
Preto indica uma aresta de avano quando
u descoberto antes de v ou uma aresta
de cruzamento caso contrrio.
3/6 2/9 1/10
arv arv
2 1 0

arv ret arv


avan cruz

3 cruz 4 cruz 5
4/5 7/8 11/12
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3.2 48

Teste para Verificar se Grafo Acclico

A busca em profundidade pode ser usada


para verificar se um grafo acclico ou
contm um ou mais ciclos.

Se uma aresta de retorno encontrada


durante a busca em profundidade em G,
ento o grafo tem ciclo.

Um grafo direcionado G acclico se e


somente se a busca em profundidade em G
no apresentar arestas de retorno.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 49

Busca em Largura

Expande a fronteira entre vrtices


descobertos e no descobertos
uniformemente atravs da largura da
fronteira.

O algoritmo descobre todos os vrtices a uma


distncia k do vrtice origem antes de
descobrir qualquer vrtice a uma distncia
k + 1.

O grafo G(V, A) pode ser direcionado ou no


direcionado.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 50

Busca em Largura

Cada vrtice colorido de branco, cinza ou


preto.

Todos os vrtices so inicializados branco.

Quando um vrtice descoberto pela


primeira vez ele torna-se cinza.

Vrtices cinza e preto j foram descobertos,


mas so distinguidos para assegurar que a
busca ocorra em largura.

Se (u, v) A e o vrtice u preto, ento o


vrtice v tem que ser cinza ou preto.

Vrtices cinza podem ter alguns vrtices


adjacentes brancos, e eles representam a
fronteira entre vrtices descobertos e no
descobertos.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 51

Busca em Largura - Implementao


package cap7;
import cap3. autoreferencia . Fila ;
import cap7. listaadj . autoreferencia .Grafo;
public class BuscaEmLargura {
public static final byte branco = 0;
public static byte cinza = 1;
public static byte preto = 2;
private int d [ ] , antecessor [ ] ;
private Grafo grafo ;
public BuscaEmLargura ( Grafo grafo ) {
this . grafo = grafo ; int n = this . grafo .numVertices ( ) ;
this .d = new int [n ] ; this . antecessor = new int [n ] ;
}
private void visitaBfs ( int u, int cor [ ] ) throws Exception {
cor [u] = cinza ; this .d[u] = 0;
Fila f i l a = new Fila ( ) ; f i l a . enfileira (new Integer (u) ) ;
while ( ! f i l a . vazia ( ) ) {
Integer aux = ( Integer ) f i l a . desenfileira ( ) ; u = aux. intValue ( ) ;
i f ( ! this . grafo . listaAdjVazia (u ) ) {
Grafo. Aresta a = this . grafo . primeiroListaAdj (u) ;
while (a ! = null ) {
int v = a.v2 ( ) ;
i f ( cor [ v] == branco ) {
cor [ v ] = cinza ; this .d[ v ] = this .d[u] + 1;
this . antecessor [ v ] = u ; f i l a . enfileira (new Integer ( v ) ) ;
}
a = this . grafo . proxAdj (u) ;
}
}
cor [u] = preto ;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 52

Busca em Largura - Implementao


public void buscaEmLargura ( ) throws Exception {
int cor [ ] = new int [ this . grafo .numVertices ( ) ] ;
for ( int u = 0; u < grafo .numVertices ( ) ; u++) {
cor [u] = branco ; this .d[u] = Integer . MAX_VALUE ;
this . antecessor [u] = 1;
}
for ( int u = 0; u < grafo .numVertices ( ) ; u++)
i f ( cor [u] == branco ) this . visitaBfs ( u, cor ) ;
}
public int d ( int v ) { return this .d[ v ] ; }
public int antecessor ( int v ) { return this . antecessor [ v ] ; }
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 53

Busca em Largura - Exemplo


(a) (b)
c(0) b( ) b( ) p(0) c(1) b( )
0 1 4 0 1 4

3 2 5 3 2 5
b( ) b( ) b( ) c(1) b( ) b( )

F 0 F 1 3
0 1 1

(c) (d)
p(0) p(1) b( ) p(0) p(1) b( )
0 1 4 0 1 4

3 2 5 3 2 5
c(1) c(2) b( ) p(1) c(2) b( )

F 3 2 F 2
1 2 2
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 54

Busca em Largura - Exemplo


(e) (f)
p(0) p(1) b( ) p(0) p(1) c(0)
0 1 4 0 1 4

3 2 5 3 2 5
p(1) p(2) b( ) p(1) p(2) b( )

F F 4
0

(g) (h)
p(0) p(1) p(0) p(0) p(1) p(0)
0 1 4 0 1 4

3 2 5 3 2 5
p(1) p(2) c(1) p(1) p(2) p(1)

F 5 F
1
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 55

Busca em Largura - Anlise (para


listas de adjacncia)

O custo de inicializao do primeiro anel no


mtodo buscaEmLargura O(|V |).

O custo do segundo anel tambm O(|V |).

Mtodo visitaBfs: enfileirar e desenfileirar tm


custo O(1), logo, o custo total com a fila
O(|V |).

Cada lista de adjacentes percorrida no


mximo uma vez, quando o vrtice
desenfileirado.

Desde que a soma de todas as listas de


adjacentes O(|A|), o tempo total gasto com
as listas de adjacentes O(|A|).

Complexidade total: O(|V | + |A|).


Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4 56

Caminhos Mais Curtos

A busca em largura obtm o caminho mais


curto de u at v.

O procedimento VisitaBfs contri uma rvore


de busca em largura que armazenada na
varivel antecessor .

O programa abaixo imprime os vrtices do


caminho mais curto entre o vrtice origem e
outro vrtice qualquer do grafo, a partir do
vetor antecessor . obtido na busca em largura.

public void imprimeCaminho ( int origem , int v ) {


i f ( origem == v ) System. out . println ( origem ) ;
else i f ( this . antecessor [ v] == 1)
System. out . println ( "Nao existe caminho de " + origem + " ate " + v ) ;
else {
imprimeCaminho ( origem , this . antecessor [ v ] ) ;
System. out . println ( v ) ;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.5 57

Ordenao Topolgica

Ordenao linear de todos os vrtices, tal que


se G contm uma aresta (u, v) ento u
aparece antes de v.

Pode ser vista como uma ordenao de seus


vrtices ao longo de uma linha horizontal de
tal forma que todas as arestas esto
direcionadas da esquerda para a direita.

Pode ser feita usando a busca em


profundidade.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.5 58

Ordenao Topolgica

Os grafos direcionados acclicos so usados


para indicar precedncias entre eventos.

Uma aresta direcionada (u, v) indica que a


atividade u tem que ser realizada antes da
atividade v.

1/18 16/17 19/20


0 5 9
2/15 7/12
4/5 3 1 6 8 9/10

2 4 7
3/14 6/13 8/11

9 0 5 1 2 4 6 7 8 3
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.5 59

Ordenao Topolgica

Algoritmo para ordenar topologicamente um


grafo direcionado acclico G = (V, A):
1. Aplicar a busca em profundidade no grafo
G para obter os tempos de trmino t[u]
para cada vrtice u.
2. Ao trmino de cada vrtice, insira-o na
frente de uma lista linear encadeada.
3. Retornar a lista encadeada de vrtices.

A Custo O(|V | + |A|), uma vez que a busca


em profundidade tem complexidade de tempo
O(|V | + |A|) e o custo para inserir cada um
dos |V | vrtices na frente da lista linear
encadeada custa O(1).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.5 60

Ordenao Topolgica -
Implementao

Basta inserir uma chamada ao mtodo


inserePrimeiro no mtodo buscaDfs, logo aps
o momento em que o tempo de trmino t[u]
obtido e o vrtice pintado de preto.

Ao final, basta retornar a lista obtida.

/ / Insere antes do primeiro item da lista


public void inserePrimeiro ( Object item ) {
Celula aux = this . primeiro . prox ;
this . primeiro . prox = new Celula ( ) ;
this . primeiro . prox . item = item ;
this . primeiro . prox . prox = aux;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 61

Componentes Fortemente Conectados

Um componente fortemente conectado de


G = (V, A) um conjunto maximal de vrtices
C V tal que para todo par de vrtices u e v
em C, u e v so mutuamente alcanveis

Podemos particionar V em conjuntos Vi ,


1 i r, tal que vrtices u e v so
equivalentes se e somente se existe um
caminho de u a v e um caminho de v a u.

0 1 0 1 0,1,2

3 2 3 2 3

(a) (b) (c)


Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 62

Componentes Fortemente Conectados


- Algoritmo

Usa o transposto de G, definido


GT = (V, AT ), onde AT = {(u, v) : (v, u) A},
isto , AT consiste das arestas de G com
suas direes invertidas.

G e GT possuem os mesmos componentes


fortemente conectados, isto , u e v so
mutuamente alcanveis a partir de cada um
em G se e somente se u e v so mutuamente
alcanveis a partir de cada um em GT .
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 63

Componentes Fortemente Conectados


- Algoritmo

1. Aplicar a busca em profundidade no grafo G


para obter os tempos de trmino t[u] para
cada vrtice u.

2. Obter GT .

3. Aplicar a busca em profundidade no grafo GT ,


realizando a busca a partir do vrtice de
maior t[u] obtido na linha 1. Se a busca em
profundidade no alcanar todos os vrtices,
inicie uma nova busca em profundidade a
partir do vrtice de maior t[u] dentre os
vrtices restantes.

4. Retornar os vrtices de cada rvore da


floresta obtida na busca em profundidade na
linha 3 como um componente fortemente
conectado separado.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 64

Componentes Fortemente Conectados


- Exemplo

A parte (b) apresenta o resultado da busca


em profundidade sobre o grafo transposto
obtido, mostrando os tempos de trmino e a
classificao das arestas.

A busca em profundidade em GT resulta na


floresta de rvores mostrada na parte (c).
cruz
0 3
1/8 2/7 1/6 3/4
ret arv cruz
0 1 0 1
cruz arv arv ret 2

3 2 3 2 arv
cruz
4/5 3/6 7/8 2/5
1

(a) (b) (c)


Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 65

Componentes Fortemente Conectados


- Implementao
public Grafo grafoTransposto ( ) {
Grafo grafoT = new Grafo ( this .numVertices ) ;
for ( int v = 0; v < this .numVertices ; v++)
i f ( ! this . listaAdjVazia ( v ) ) {
Aresta adj = this . primeiroListaAdj ( v ) ;
while ( adj ! = null ) {
grafoT . insereAresta ( adj .v2 ( ) , adj .v1 ( ) , adj .peso ( ) ) ;
adj = this . proxAdj ( v ) ; }
}
return grafoT ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 66

Componentes Fortemente Conectados


- Implementao
package cap7;
import cap7. listaadj . autoreferencia .Grafo;
public class Cfc {
private static class TempoTermino {
private int numRestantes, t [ ] ;
private boolean restantes [ ] ;
public TempoTermino ( int numVertices ) {
t = new int [numVertices ] ;
restantes = new boolean[numVertices ] ;
numRestantes = numVertices;
}
public int maxTT ( ) {
int vMax = 0;
while ( ! this . restantes [vMax] ) vMax++;
for ( int i = 0; i < this . t . length ; i ++) {
i f ( this . restantes [ i ] ) {
i f ( this . t [ i ] > this . t [vMax] ) vMax = i ;
}
}
return vMax;
}
}
private Grafo grafo ;
public Cfc ( Grafo grafo ) {
this . grafo = grafo ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 67

Componentes Fortemente Conectados


- Implementao
private void visitaDfs ( Grafo grafo , int u, TempoTermino t t ) {
t t . restantes [u] = false ; t t .numRestantes ;
System. out . println ( " Vertice : "+u) ;
i f ( ! grafo . listaAdjVazia (u ) ) {
Grafo. Aresta a = grafo . primeiroListaAdj (u) ;
while (a ! = null ) {
int v = a.v2 ( ) ;
i f ( t t . restantes [ v ] ) { this . visitaDfs ( grafo , v , t t ) ; }
a = grafo . proxAdj (u) ;
}
}
}
public void obterCfc ( ) {
BuscaEmProfundidade dfs = new BuscaEmProfundidade ( this . grafo ) ;
dfs .buscaEmProfundidade ( ) ;
TempoTermino t t = new TempoTermino ( this . grafo .numVertices ( ) ) ;
for ( int u = 0; u < this . grafo .numVertices ( ) ; u++) {
t t . t [u] = dfs . t (u ) ; t t . restantes [u] = true ;
}
Grafo grafoT = this . grafo . grafoTransposto ( ) ;
while ( t t .numRestantes > 0) {
int vRaiz = t t .maxTT ( ) ;
System. out . println ( "Raiz da proxima arvore : " + vRaiz ) ;
this . visitaDfs ( grafoT , vRaiz , t t ) ;
}
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6 68

Componentes Fortemente Conectados


- Anlise

Utiliza o algoritmo para busca em


profundidade duas vezes, uma em G e outra
em GT . Logo, a complexidade total
O(|V | + |A|).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7 69

rvore Geradora Mnima - Aplicao

Projeto de redes de comunicaes


conectando n localidades.

Arranjo de n 1 conexes, conectando duas


localidades cada.

Objetivo: dentre as possibilidades de


conexes, achar a que usa menor quantidade
de cabos.

Modelagem:
G = (V, A): grafo conectado, no
direcionado.
V : conjunto de cidades.
A: conjunto de possveis conexes
p(u, v): peso da aresta (u, v) A, custo
total de cabo para conectar u a v.

Soluo: encontrar um subconjunto T A


que conecta todos os vrtices de G e cujo
peso total p(T ) = (u,v)T p(u, v)
P

minimizado.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7 70

rvore Geradora Mnima (AGM)

Como G0 = (V, T ) acclico e conecta todos


os vrtices, T forma uma rvore chamada
rvore geradora de G.

O problema de obter a rvore T conhecido


como rvore geradora mnima (AGM).

Ex.: rvore geradora mnima T cujo peso total


12. T no nica, pode-se substituir a aresta
(3, 5) pela aresta (2, 5) obtendo outra rvore
geradora de custo 12.

0 0
6 5
1 1
1 2 2 3 1 2 2 3
2 2
5 6 4 4 4
4 5 4 5
3 3
(a) (b)
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.1 71

AGM - Algoritmo Genrico

Uma estratgia gulosa permite obter a AGM


adicionando uma aresta de cada vez.

Invariante: Antes de cada iterao, S um


subconjunto de uma rvore geradora mnima.

A cada passo adicionamos a S uma aresta


(u, v) que no viola o invariante. (u, v)
chamada de uma aresta segura.
void GenericoAGM
1 S = ;
2 while ( S no constitui uma rvore geradora mnima)
3 (u, v) = seleciona (A) ;
4 i f ( aresta (u, v) segura para S ) S = S + {(u, v)}
5 return S ;

Dentro do while, S tem que ser um


subconjunto prprio da AGM T , e assim tem
que existir uma aresta (u, v) T tal que
(u, v) 6 S e (u, v) seguro para S.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.1 72

AGM - Definio de Corte

Um corte (V 0 , V V 0 ) de um grafo no
direcionado G = (V, A) uma partio de V .

Uma aresta (u, v) A cruza o corte


(V 0 , V V 0 ) se um de seus vrtices pertence
a V 0 e o outro vrtice pertence a V V 0 .

Um corte respeita um conjunto S de arestas


se no existirem arestas em S que o cruzem.

Uma aresta cruzando o corte que tenha custo


mnimo sobre todas as arestas cruzando o
corte uma aresta leve.
p
0
p 6 5 p
1
V 1 2 2 3 V
2
V V 5 4 V V
6 4
4 5
3
b b
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.1 73

AGM - Teorema para reconhecer


arestas seguras

Seja G = (V, A) um grafo conectado, no


direcionado, com pesos p sobre as arestas V .

seja S um subconjunto de V que est includo


em alguma AGM para G.

Seja (V 0 , V V 0 ) um corte qualquer que


respeita S.

Seja (u, v) uma aresta leve cruzando


(V 0 , V V 0 ).

Satisfeitas essas condies, a aresta (u, v)


uma aresta segura para S.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 74

AGM - Algoritmo de Prim

O algoritmo de Prim para obter uma AGM


pode ser derivado do algoritmo genrico.

O subconjunto S forma uma nica rvore, e a


aresta segura adicionada a S sempre uma
aresta de peso mnimo conectando a rvore a
um vrtice que no esteja na rvore.

A rvore comea por um vrtice qualquer (no


caso 0) e cresce at que gere todos os
vrtices em V .

A cada passo, uma aresta leve adicionada


rvore S, conectando S a um vrtice de
GS = (V, S).

De acordo com o teorema anterior, quando o


algoritmo termina, as arestas em S formam
uma rvore geradora mnima.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 75

Algoritmo de Prim - Exemplo


(a) (b) 0
0 0
6 5 6 5
1
1 2 2 3 1 3
2 2
5 6 4 4 1
4 5 4 5
3

(c) 0 (d) 0
0 0
2 2 2 2
1 3 1 3
2 2
1 1
4 5 4 4
6 4 6 4

(e) 0 (f) 0
0 0
2 2 2 2
1 3 1 3
2 2
1 1
4 5 4 5
5 4 3 4
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 76

Algoritmo de Prim - Heap Indireto


package cap7;
public class FPHeapMinIndireto {
private double p [ ] ;
private int n, pos [ ] , fp [ ] ;

public FPHeapMinIndireto (double p [ ] , int v [ ] ) {


this .p = p ; this . fp = v ; this .n = this . fp . length1;
this .pos = new int [ this .n ] ;
for ( int u = 0; u < this .n ; u++) this .pos[u] = u+1;
}
public void refaz ( int esq, int dir ) {
int j = esq 2 ; int x = this . fp [esq ] ;
while ( j <= dir ) {
i f ( ( j < dir ) && (this .p[ fp [ j ] ] > this .p[ fp [ j + 1 ] ] ) ) j ++;
i f ( this .p[ x] <= this .p[ fp [ j ] ] ) break;
this . fp [esq] = this . fp [ j ] ; this .pos[ fp [ j ] ] = esq;
esq = j ; j = esq 2;
}
this . fp [esq] = x ; this .pos[ x ] = esq;
}
public void constroi ( ) {
int esq = n / 2 + 1 ;
while (esq > 1 ) { esq; this . refaz (esq, this .n ) ; }
}
public int retiraMin ( ) throws Exception {
int minimo;
i f ( this .n < 1) throw new Exception ( "Erro : heap vazio" ) ;
else {
minimo = this . fp [ 1 ] ; this . fp [1] = this . fp [ this .n ] ;
this .pos[ fp [ this .n]] = 1; this . refaz ( 1 , this .n) ;
}
return minimo;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 77

Algoritmo de Prim - Heap Indireto


public void diminuiChave ( int i , double chaveNova) throws Exception {
i = this .pos[ i ] ; int x = fp [ i ] ;
i f (chaveNova < 0)
throw new Exception ( "Erro : chaveNova com valor incorreto " ) ;
this .p[ x ] = chaveNova;
while ( ( i > 1) && (this .p[ x] <= this .p[ fp [ i / 2 ] ] ) ) {
this . fp [ i ] = this . fp [ i / 2 ] ; this .pos[ fp [ i / 2 ] ] = i ; i /= 2;
}
this . fp [ i ] = x ; this .pos[ x ] = i ;
}
boolean vazio ( ) { return this .n == 0; }

O programa acima apresenta a classe


FPHeapMinIndireto com as estruturas de
dados e as operaes necessrias para
operar com um heap indireto.

O arranjo pos[v] fornece a posio do vrtice


v dentro do heap fp, permitindo assim que o
vrtice v possa ser acessado a um custo
O(1).

O acesso ao vrtice v necessrio para a


operao diminuiChave.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 78

Algoritmo de Prim - Implementao


package cap7;
import cap7. listaadj . autoreferencia .Grafo;
public class AgmPrim {
private int antecessor [ ] ;
private double p [ ] ;
private Grafo grafo ;
public AgmPrim ( Grafo grafo ) { this . grafo = grafo ; }
public void obterAgm ( int raiz ) throws Exception {
int n = this . grafo .numVertices ( ) ;
this .p = new double[n ] ; / / peso dos vrtices
int vs [ ] = new int [n+1]; / / vrtices
boolean itensHeap [ ] = new boolean[n ] ; this . antecessor = new int [n ] ;
for ( int u = 0; u < n ; u ++) {
this . antecessor [u] = 1;
p[u] = Double. MAX_VALUE ; / /
vs[u+1] = u ; / / Heap indireto a ser construdo
itensHeap[u] = true ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 79

Algoritmo de Prim - Implementao


p[ raiz ] = 0;
FPHeapMinIndireto heap = new FPHeapMinIndireto ( p, vs ) ;
heap. constroi ( ) ;
while ( !heap. vazio ( ) ) {
int u = heap. retiraMin ( ) ; itensHeap[u] = false ;
i f ( ! this . grafo . listaAdjVazia (u ) ) {
Grafo. Aresta adj = grafo . primeiroListaAdj (u) ;
while ( adj ! = null ) {
int v = adj .v2 ( ) ;
i f ( itensHeap[ v] && (adj .peso ( ) < this .peso ( v ) ) ) {
antecessor [ v ] = u ; heap.diminuiChave ( v , adj .peso ( ) ) ;
}
adj = grafo . proxAdj (u) ;
}
}
}
}

public int antecessor ( int u ) { return this . antecessor [u ] ; }


public double peso ( int u ) { return this .p[u ] ; }

public void imprime ( ) {


for ( int u = 0; u < this .p. length ; u++)
i f ( this . antecessor [u] != 1)
System. out . println ( " ( " +antecessor [u]+ " , " +u+ ") p: " +
peso (u) ) ;
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 80

Algoritmo de Prim - Implementao

A classe AgmPrim implementa o algoritmo de


Prim, cujo grafo de entrada G fornecido
atravs do construtor da classe AgmPrim.

O mtodo obterAgm recebe o vrtice raiz


como entrada.

O campo antecessor [v] armazena o


antecessor de v na rvore.

Quando o algoritmo termina, a fila de


prioridades fp est vazia, e a rvore geradora
mnima S para G :

S = {(v, antecessor [v]) : v V {raiz }}

Os mtodos pblicos antecessor , peso e


imprime so utilizados para permitir ao
usurio da classe AgmPrim obter o
antecessor de um certo vrtice, obter o peso
associado a um vrtice e imprimir as arestas
da rvore, respectivamente.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2 81

Algoritmo de Prim - Anlise

O corpo do anel while executado |V | vezes.

O mtodo refaz tem custo O(log |V |).

Logo, o tempo total para executar a operao


retira o item com menor peso O(|V | log |V |).

O while mais interno para percorrer a lista de


adjacentes O(|A|) (soma dos comprimentos
de todas as listas de adjacncia 2|A|).

O teste para verificar se o vrtice v pertence


ao heap A tem custo O(1).

Aps testar se v pertence ao heap e o peso


da aresta (u, v) menor do que p[v], o
antecessor de v armazenado em
antecessor [v] e uma operao diminuiChave
realizada sobre o heap na posio pos[v], a
qual tem custo O(log |V |).

Logo, o tempo total para executar o algoritmo


de Prim
O(|V log |V | + |A| log |V |) = O(|A| log |V |).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3 82

AGM - Algoritmo de Kruskal


Pode ser derivado do algoritmo genrico.
S uma floresta e a aresta segura adicionada
a S sempre uma aresta de menor peso que
conecta dois componentes distintos.
Considera as arestas ordenadas pelo peso.
(a) (b)
0 0
6 5
1
1 2 2 3 1 3
2 2
5 6 4 4
4 5 4 5
3

(c) (d)
0 0

1 3 1 3
2 2

4 5 4 5

(e) (f)
0 0

1 3 1 3
2 2

4 5 4 5
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3 83

AGM - Algoritmo de Kruskal

Sejam C1 e C2 duas rvores conectadas por


(u, v):
Como (u, v) tem de ser uma aresta leve
conectando C1 com alguma outra rvore,
(u, v) uma aresta segura para C1 .

guloso porque, a cada passo, ele adiciona


floresta uma aresta de menor peso.

Obtm uma AGM adicionando uma aresta de


cada vez floresta e, a cada passo, usa a
aresta de menor peso que no forma ciclo.

Inicia com uma floresta de |V | rvores de um


vrtice: em |V | passos, une duas rvores at
que exista apenas uma rvore na floresta.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3 84

Algoritmo de Kruskal - Implementao


Usa fila de prioridades para obter arestas em
ordem crescente de pesos.
Testa se uma dada aresta adicionada ao
conjunto soluo S forma um ciclo.
Tratar conjuntos disjuntos: maneira
eficiente de verificar se uma dada aresta
forma um ciclo. Utiliza estruturas dinmicas.
Os elementos de um conjunto so
representados por um objeto. Operaes:
Criar um novo conjunto cujo nico membro
x, o qual passa a ser seu representante.
Fazer a unio de dois conjuntos dinmicos
cujos representantes so x e y. A
operao une os conjuntos dinmicos que
contm x e y, digamos Cx e Cy , em um
novo conjunto que a unio desses dois
conjuntos.
Encontrar o conjunto de um dado
elemento x. Essa operao retorna uma
referncia ao representante do conjunto
(nico) contendo x.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3 85

Algoritmo de Kruskal - Implementao

Primeiro refinamento:
void Kruskal ( Grafo grafo )
ConjuntoDisjunto conj = new ConjuntoDisjunto ( ) ;
1. S = ;
2. for ( int v=0; v<grafo .numVertices ( ) ; v++) conj . criaConjunto (v ) ;
3. Ordena as arestas de A pelo peso;
4. for (cada ( u, v ) de A tomadas em ordem ascendente de peso)
5. i f ( conj . encontraConjunto (u) ! = conj . encontraConjunto ( v) )
6. S = S + {(u, v)} ;
7. conj . uniao ( u, v ) ;

A implementao das operaes uniao e


encontraConjunto deve ser realizada de forma
eficiente.

Esse problema conhecido na literatura


como Unio-EncontraConjunto.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3 86

AGM - Anlise do Algoritmo de Kruskal


A inicializao do conjunto S tem custo O(1).
Ordenar arestas (linha 3) custa O(|A| log |A|).
A linha 2 realiza |V | operaes criaConjunto.
O anel (linhas 4-7) realiza O(|A|) operaes
encontraConjunto e uniao, a um custo
O((|V | + |A|)(|V |)) onde (|V |) uma
funo que cresce lentamente ((|V |) < 4).
O limite inferior para construir uma estrutura
dinmica envolvendo m operaes
encontraConjunto e uniao e n operaes
criaConjunto m(n).
Como G conectado temos que
|A| |V | 1, e assim as operaes sobre
conjuntos disjuntos custam O(|A|(|V |).
Como (|V |) = O(log |A|) = O(log |V |), o
tempo total do algoritmo de Kruskal
O(|A| log |A|).
Como |A| < |V |2 , ento log |A| = O(log |V |), e
o custo do algoritmo de Kruskal tambm
O(|A| log |V |).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 87

Caminhos Mais Curtos - Aplicao


Um motorista procura o caminho mais curto
entre Diamantina e Ouro Preto. Possui mapa
com as distncias entre cada par de
intersees adjacentes.
Modelagem:
G = (V, A): grafo direcionado ponderado,
mapa rodovirio.
V : intersees.
A: segmentos de estrada entre
intersees
p(u, v): peso de cada aresta, distncia
entre intersees.
Pk
Peso de um caminho: p(c) = i=1 p(vi1 , vi )
Caminho mais curto:

c
n o
min p(c) : u ; v

se existir caminho de u a v
(u, v) =


caso contrrio

Caminho mais curto do vrtice u ao vrtice


v: qualquer caminho c com peso
p(c) = (u, v).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 88

Caminhos Mais Curtos

Caminhos mais curtos a partir de uma


origem: dado um grafo ponderado
G = (V, A), desejamos obter o caminho mais
curto a partir de um dado vrtice origem
s V at cada v V .

Muitos problemas podem ser resolvidos pelo


algoritmo para o problema origem nica:
Caminhos mais curtos com destino
nico: reduzido ao problema origem nica
invertendo a direo de cada aresta do
grafo.
Caminhos mais curtos entre um par de
vrtices: o algoritmo para origem nica
a melhor opo conhecida.
Caminhos mais curtos entre todos os
pares de vrtices: resolvido aplicando o
algoritmo origem nica |V | vezes, uma vez
para cada vrtice origem.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 89

Caminhos Mais Curtos

A representao de caminhos mais curtos em


um grafo G = (V, A) pode ser realizada por
um vetor chamado antecessor .

Para cada vrtice v V o antecessor [v] um


outro vrtice u V ou null (1).

O algoritmo atribui ao antecessor os rtulos de


vrtices de uma cadeia de antecessores com
origem em v e que anda para trs ao longo de
um caminho mais curto at o vrtice origem s.

Dado um vrtice v no qual


antecessor [v] 6= null , o mtodo
imprimeCaminho pode imprimir o caminho
mais curto de s at v.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 90

Caminhos Mais Curtos

Os valores em antecessor [v], em um passo


intermedirio, no indicam necessariamente
caminhos mais curtos.

Entretanto, ao final do processamento,


antecessor contm uma rvore de caminhos
mais curtos definidos em termos dos pesos
de cada aresta de G, ao invs do nmero de
arestas.

Caminhos mais curtos no so


necessariamente nicos.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 91

rvore de caminhos mais curtos

Uma rvore de caminhos mais curtos com


raiz em u V um subgrafo direcionado
G0 = (V 0 , A0 ), onde V 0 V e A0 A, tal que:
1. V 0 o conjunto de vrtices alcanveis a
partir de s G,
2. G0 forma uma rvore de raiz s,
3. para todos os vrtices v V 0 , o caminho
simples de s at v um caminho mais
curto de s at v em G.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 92

Algoritmo de Dijkstra

Mantm um conjunto S de vrtices cujos


caminhos mais curtos at um vrtice origem
j so conhecidos.

Produz uma rvore de caminhos mais curtos


de um vrtice origem s para todos os vrtices
que so alcanveis a partir de s.

Utiliza a tcnica de relaxamento:


Para cada vrtice v V o atributo p[v]
um limite superior do peso de um caminho
mais curto do vrtice origem s at v.
O vetor p[v] contm uma estimativa de um
caminho mais curto.

O primeiro passo do algoritmo inicializar os


antecessores e as estimativas de caminhos
mais curtos:
antecessor[v] = null para todo vrtice
v V,
p[u] = 0, para o vrtice origem s, e
p[v] = para v V {s}.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 93

Relaxamento

O relaxamento de uma aresta (u, v) consiste


em verificar se possvel melhorar o melhor
caminho at v obtido at o momento se
passarmos por u.

Se isto acontecer, p[v] e antecessor[v] devem


ser atualizados.

i f (p[ v] > p[u] + peso da aresta ( u, v) )


p[ v ] = p[u] + peso da aresta ( u, v ) ;
antecessor [ v ] = u;
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 94

Algoritmo de Dijkstra - 1o Refinamento


dijkstra ( Grafo grafo , int raiz )
1. for ( int v = 0; v < grafo .numVertices ( ) ; v++)
2. p[ v ] = I n f i n i t o ;
3. antecessor [ v] = 1;
4. p[ raiz ] = 0;
5. Constroi heap sobre vrtices do grafo ;
6 S = ;
7. while ( !heap. vazio ( ) )
8. u = heap. retiraMin ( ) ;
9 S = S + u;
10. for ( v grafo . listaAdjacentes (u) )
11. i f (p[ v] > p[u] + peso da aresta ( u, v) )
12. p[ v ] = p[u] + peso da aresta ( u, v ) ;
13. antecessor [ v ] = u;

Invariante: o nmero de elementos do heap


igual a V S no incio do anel while.
A cada iterao do while, um vrtice u
extrado do heap e adicionado ao conjunto S,
mantendo assim o invariante.
A operaoretiraMin obtm o vrtice u com o
caminho mais curto estimado at o momento
e adiciona ao conjunto S.
No anel da linha 10, a operao de
relaxamento realizada sobre cada aresta
(u, v) adjacente ao vrtice u.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 95

Algoritmo de Dijkstra - Exemplo


(a) (b) 0
0 0
1 10 1 10
1 10
1 3 4 1 3 4

5 1 6 5 1 6
2 3 2 3
2 2 3

(c) 0
0
1 10
1 10
1 3 4

5 1 6
2 3
6 2 3

Iterao S d[0] d[1] d[2] d[3] d[4]

(a)
(b) {0} 0 1 3 10
(c) {0, 1} 0 1 6 3 10
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 96

Algoritmo de Dijkstra - Exemplo


(d) 0 (e) 0
0 0
1 10 1 10
1 9 1 6
1 3 4 1 3 4

5 1 6 5 1 6
2 3 2 3
5 2 3 5 2 3

(f) 0
0
1 10
1 6
1 3 4

5 1 6
2 3
5 2 3

Iterao S d[0] d[1] d[2] d[3] d[4]

(d) {0, 1, 3} 0 1 5 3 9
(e) {0, 1, 3, 2} 0 1 5 3 6
(f) {0, 1, 3, 2, 4} 0 1 5 3 6
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 97

Algoritmo de Dijkstra

Para realizar de forma eficiente a seleo de


uma nova aresta, todos os vrtices que no
esto na rvore de caminhos mais curtos
residem no heap A baseada no campo p.

Para cada vrtice v, p[v] o caminho mais


curto obtido at o momento, de v at o vrtice
raiz.

O heap mantm os vrtices, mas a condio


do heap mantida pelo caminho mais curto
estimado at o momento atravs do arranjo
p[v], o heap indireto.

o arranjo pos[v] fornece a posio do vrtice v


dentro do heap, permitindo assim que o
vrtice v possa ser acessado a um custo O(1)
para a operao diminuiChave.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 98

Algoritmo de Dijkstra - Implementao


package cap7;
import cap7. listaadj . autoreferencia .Grafo;
public class Dijkstra {
private int antecessor [ ] ;
private double p [ ] ;
private Grafo grafo ;

public Dijkstra ( Grafo grafo ) { this . grafo = grafo ; }


public void obterArvoreCMC ( int raiz ) throws Exception {
int n = this . grafo .numVertices ( ) ;
this .p = new double[n ] ; / / peso dos vrtices
int vs [ ] = new int [n+1]; / / vrtices
this . antecessor = new int [n ] ;
for ( int u = 0; u < n ; u ++) {
this . antecessor [u] = 1;
p[u] = Double. MAX_VALUE ; / /
vs[u+1] = u ; / / Heap indireto a ser construdo
}
p[ raiz ] = 0;
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 99

Algoritmo de Dijkstra - Implementao


FPHeapMinIndireto heap = new FPHeapMinIndireto ( p, vs ) ;
heap. constroi ( ) ;
while ( !heap. vazio ( ) ) {
int u = heap. retiraMin ( ) ;
i f ( ! this . grafo . listaAdjVazia (u ) ) {
Grafo. Aresta adj = grafo . primeiroListaAdj (u) ;
while ( adj ! = null ) {
int v = adj .v2 ( ) ;
i f ( this .p[ v] > ( this .p[u] + adj .peso ( ) ) ) {
antecessor [ v ] = u;
heap.diminuiChave ( v , this .p[u] + adj .peso ( ) ) ;
}
adj = grafo . proxAdj (u) ;
}
}
}
}
public int antecessor ( int u ) { return this . antecessor [u ] ; }
public double peso ( int u ) { return this .p[u ] ; }
public void imprimeCaminho ( int origem , int v ) {
i f ( origem == v ) System. out . println ( origem ) ;
else i f ( this . antecessor [ v] == 1)
System. out . println ( "Nao existe caminho de " +origem+ " ate " +v ) ;
else {
imprimeCaminho ( origem , this . antecessor [ v ] ) ;
System. out . println ( v ) ;
}
}
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8 100

Porque o Algoritmo de Dijkstra


Funciona

O algoritmo usa uma estratgia gulosa:


sempre escolher o vrtice mais leve (ou o
mais perto) em V S para adicionar ao
conjunto soluo S,

O algorimo de Dijkstra sempre obtm os


caminhos mais curtos, pois cada vez que um
vrtice adicionado ao conjunto S temos que
p[u] = (r aiz, u).
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 101

O Tipo Abstrato de Dados Hipergrafo

Um hipergrafo ou rgrafo um grafo no


direcionado G = (V, A) no qual cada aresta
a A conecta r vrtices, sendo r a ordem do
hipergrafo.

Os grafos estudados at agora so 2-grafos


(ou hipergrafos de ordem 2).

So utilizados para auxiliar na obteno de


funes de transformao perfeitas mnimas.

A forma mais adequada para representar um


hipergrafo por meio de listas de incidncia.

Em uma representao de um grafo no


direcionado usando listas de incidncia, para
cada vrtice v do grafo mantida uma lista
das arestas que incidem sobre o vrtice v.

Essa uma estrutura orientada a arestas e


no a vrtices como as representaes.

Isso evita a duplicao das arestas ao se


representar um grafo no direcionado pela
verso direcionada correspondente.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 102

O Tipo Abstrato de Dados Hipergrafo

Operaes de um tipo abstrato de dados


hipergrafo:
1. Criar um hipergrafo vazio.
2. Inserir uma aresta no hipergrafo.
3. Verificar se existe determinada aresta no
hipergrafo.
4. Obter a lista de arestas incidentes em
determinado vrtice.
5. Retirar uma aresta do hipergrafo.
6. Imprimir um hipergrafo.
7. Obter o nmero de vrtices do hipergrafo.
8. Obter a aresta de menor peso de um
hipergrafo.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 103

O Tipo Abstrato de Dados Hipergrafo

Uma operao que aparece com freqncia


a de obter a lista de arestas incidentes em
determinado vrtice.

Para implementar esse operador precisamos


de trs operaes sobre hipergrafos, a saber:
1. Verificar se a lista de arestas incidentes
em um vrtice v est vazia.
2. Obter a primeira aresta incidente a um
vrtice v, caso exista.
3. Obter a prxima aresta incidente a um
vrtice v, caso exista.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 104

O Tipo Abstrato de Dados Hipergrafo


A estrutura de dados usada para representar
o hipergrafo orientada a arestas
As arestas so armazenadas em um arranjo
chamado arestas.
Em cada ndice a do arranjo arestas, so
armazenados os r vrtices da aresta a e o
seu peso.
As listas de arestas incidentes nos vrtices
so armazenadas em dois arranjos: prim
(ponto de entrada para a lista de arestas
incidentes) e prox (as arestas subseqentes).
Valores armazenados nos arranjos prim e
prox so obtidos pela equao a + i|A|, sendo
0 i r 1 e a um ndice de uma aresta.
Para se ter acesso a uma aresta a
armazenada em arestas[a] preciso tomar os
valores armazenados nos arranjos prim e
prox mdulo |A|.
O valor 1 utilizado para finalizar a lista.
prim deve possuir |V | entradas.
prox deve possuir r|A| entradas.
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 105

O Tipo Abstrato de Dados Hipergrafo -


Exemplo

Para descobrir quais so as arestas que


contm determinado vrtice v preciso
percorrer a lista de arestas que inicia em
prim[v] e termina quando
prox [. . . prim[v] . . .] = 1.

Exemplo, ao se percorrer a lista das arestas


do vrtice 2, os valores {4, 8, 5} so obtidos,
os quais representam as arestas que contm
o vrtice 2, ou seja,
{4 mod 5 = 4, 8 mod 5 = 3, 5 mod 5 = 0}.

(a) 0 (b) 0 1 2 3 4
5 arestas (1,2,0) (3,4,1) (3,5,2) (0,2,3) (2,3,4)
1
0 1 2 3 4 5
2 3
0 prim 3 0 4 9 6 7
4
2 0 1 2 3 4 5 6 7 8 9
3 prox 1 1 1 1 8 1 1 1 5 2
1 4
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 106

O Tipo Abstrato de Dados Hipergrafo -


Implementao
A varivel r utilizada para armazenar a
ordem do hipergrafo.
numVertices contm o nmero de vrtices do
hipergrafo.
proxDisponivel contm a prxima posio
disponvel para insero de uma nova aresta.
pos utilizado para reter a posio atual na
lista de incidncia de um vrtice v.
package cap7. listincidencia ;
public class HiperGrafo {
public static class Aresta {
private int vertices [ ] ;
private int peso;
public Aresta ( int vertices [ ] , int peso) {
this . vertices = vertices ;
this .peso = peso;
}
public int peso ( ) { return this .peso ; }
public int vertice ( int i ) { return this . vertices [ i ] ; }
public int [ ] vertices ( ) { return this . vertices ; }
public boolean equals ( Object aresta ) {
Aresta a = ( Aresta) aresta ;
i f (a. vertices . length ! = this . vertices . length ) return false ;
for ( int i = 0; i < this . vertices . length ; i ++)
i f ( this . vertices [ i ] ! = a. vertices [ i ] ) return false ;
return true ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 107

O Tipo Abstrato de Dados Hipergrafo -


Implementao
public String toString ( ) {
String res = " { " ; int i = 0;
for ( i = 0; i < this . vertices . length1; i ++)
res += this . vertices [ i ] + " , " ;
res += this . vertices [ i ] + " } ( " + this .peso + " ) " ;
return res ;
}
}
private int numVertices , proxDisponivel , r ;
private Aresta arestas [ ] ;
private int prim [ ] , prox [ ] ;
private int pos [ ] ;

public HiperGrafo ( int numVertices , int numArestas, int r ) {


this . arestas = new Aresta [numArestas] ;
this . prim = new int [numVertices ] ;
for ( int i = 0; i < numVertices ; i ++) this . prim [ i ] = 1;
this . prox = new int [ rnumArestas] ;
this .numVertices = numVertices;
this . proxDisponivel = 0;
this . r = r ;
this .pos = new int [numVertices ] ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 108

O Tipo Abstrato de Dados Hipergrafo -


Implementao
public void insereAresta ( int vertices [ ] , int peso) {
i f ( this . proxDisponivel == this . arestas . length )
System. out . println ( "Nao ha espaco disponivel para a aresta" ) ;
else {
int a = this . proxDisponivel++; int n = this . arestas . length ;
this . arestas [a] = new Aresta ( vertices , peso) ;
for ( int i = 0; i < this . r ; i ++) {
int ind = a + i n;
this . prox [ ind ] = this . prim [ this . arestas [a ] . vertices [ i ] ] ;
this . prim [ this . arestas [a ] . vertices [ i ] ] = ind ;
}
}
}
public boolean existeAresta ( int vertices [ ] ) {
for ( int v = 0; v < this . r ; v++)
for ( int i = this . prim [ vertices [ v ] ] ; i != 1; i = this . prox [ i ] ) {
int a = i % this . arestas . length ;
i f ( this . arestas [a ] . equals (new Aresta ( vertices , 0 ) ) )
return true ;
}
return false ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 109

O Tipo Abstrato de Dados Hipergrafo -


Implementao
public boolean listaIncVazia ( int v ) { return ( this . prim [ v] == 1); }
public Aresta primeiraListaInc ( int v ) {
/ / Retorna a primeira aresta incidente no vrtice v ou
/ / null se a lista de arestas incidentes em v for vazia
this .pos[ v ] = this . prim [ v ] ;
int a = this .pos[ v] % this . arestas . length ;
i f (a >= 0) return this . arestas [a ] ; else return null ;
}
public Aresta proxInc ( int v ) {
/ / Retorna a prxima aresta incidente no vrtice v ou null
/ / se a lista de arestas incidentes em v estiver no fim
this .pos[ v ] = this . prox [ this .pos[ v ] ] ;
int a = this .pos[ v] % this . arestas . length ;
i f (a >= 0) return this . arestas [a ] ; else return null ;
}
public Aresta retiraAresta ( int vertices [ ] ) {
int n = this . arestas . length , a = 0; Aresta aresta = null ;
for ( int i = 0; i < this . r ; i ++) {
int prev = 1, aux = this . prim [ vertices [ i ] ] ;
a = aux % n ; aresta = new Aresta ( vertices , 0 ) ;
while ( (aux >= 0) && (!this . arestas [a ] . equals ( aresta ) ) ) {
prev = aux ; aux = this . prox [aux ] ; a = aux % n ; }
i f (aux >= 0) { / / achou
i f ( prev == 1) this . prim [ vertices [ i ] ] = this . prox [aux ] ;
else this . prox [ prev ] = this . prox [aux ] ;
aresta = this . arestas [a ] ;
} else return null ; / / no achou
}
this . arestas [a] = null ; / / Marca como removido
return aresta ;
}
Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9 110

O Tipo Abstrato de Dados Hipergrafo -


Implementao
public void imprime ( ) {
for ( int i = 0; i < this .numVertices ; i ++) {
System. out . println ( " Vertice " + i + " : " ) ;
for ( int j = this . prim [ i ] ; j != 1; j = this . prox [ j ] ) {
int a = j % this . arestas . length ;
System. out . println ( " a : " + this . arestas [a ] ) ; }
}
}
public int numVertices ( ) { return this .numVertices ; }
}
Processamento de
Cadeias de
Caracteres

ltima alterao: 10 de Outubro de 2006

Transparncias
elaboradas por Charles Ornelas, Fabiano Botelho, Leonardo
Rocha, Leonardo Mata e Nivio Ziviani
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 1

Definio e Motivao

Cadeia de caracteres: seqncia de


elementos denominados caracteres.

Os caracteres so escolhidos de um conjunto


denominado alfabeto.
Ex.: em uma cadeia de bits o alfabeto {0, 1}.

Casamento de cadeias de caracteres ou


casamento de padro: encontrar todas as
ocorrncias de um padro em um texto.

Exemplos de aplicao:
edio de texto;
recuperao de informao;
estudo de seqncias de DNA em biologia
computacional.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 2

Notao

Texto: arranjo T [0..n 1] de tamanho n;

Padro: arranjo P [0..m 1] de tamanho


m n.

Os elementos de P e T so escolhidos de um
alfabeto finito de tamanho c.
Ex.: = {0, 1} ou = {a, b, . . . , z}.

Casamento de cadeias ou casamento de


padro: dados duas cadeias P (padro) de
comprimento |P | = m e T (texto) de
comprimento |T | = n, onde n  m, deseja-se
saber as ocorrncias de P em T .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 3

Categorias de Algoritmos

P e T no so pr-processados:
algoritmo seqencial, on-line e de
tempo-real;
padro e texto no so conhecidos a priori.
complexidade de tempo O(mn) e de
espao O(1), para pior caso.

P pr-processado:
algoritmo seqencial;
padro conhecido anteriormente
permitindo seu pr-processamento.
complexidade de tempo O(n) e de espao
O(m + c), no pior caso.
ex.: programas para edio de textos.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 4

Categorias de Algoritmos

P e T so pr-processados:
algoritmo constri ndice.
complexidade de tempo O(log n) e de
espao O(n).
tempo para obter o ndice grande, O(n)
ou O(n log n).
compensado por muitas operaes de
pesquisa no texto.
Tipos de ndices mais conhecidos:
Arquivos invertidos
rvores trie e rvores Patricia
Arranjos de sufixos
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 5

Exemplos: P e T so pr-processados

Diversos tipos de ndices: arquivos invertidos,


rvores trie e Patricia, e arranjos de sufixos.

Um arquivo invertido possui duas partes:


vocabulrio e ocorrncias.

O vocabulrio o conjunto de todas as


palavras distintas no texto.

Para cada palavra distinta, uma lista de


posies onde ela ocorre no texto
armazenada.

O conjunto das listas chamado de


ocorrncias.

As posies podem referir-se a palavras ou


caracteres.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 6

Exemplo de Arquivo Invertido


0 6 15 21 25 35 44 52
Texto exemplo. Texto tem palavras. Palavras exercem fascnio.

exe mplo 6
exe rcem 44
fas cnio 52
pal avras 25 35
tem 21
tex to 0 15
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 7

Arquivo Invertido - Tamanho


O vocabulrio ocupa pouco espao.
A previso sobre o crescimento do tamanho
do vocabulrio dada pela lei de Heaps.
Lei de Heaps: o vocabulrio de um texto em
linguagem natural contendo n palavras tem
tamanho V = Kn = O(n ), em que K e
dependem das caractersticas de cada texto.
K geralmente assume valores entre 10 e 100,
e uma constante entre 0 e 1, na prtica
ficando entre 0,4 e 0,6.
O vocabulrio cresce sublinearmente com o
tamanho do texto, em uma proporo perto
de sua raiz quadrada.
As ocorrncias ocupam muito mais espao.
Como cada palavra referenciada uma vez
na lista de ocorrncias, o espao necessrio
O(n).
Na prtica, o espao para a lista de
ocorrncias fica entre 30% e 40% do
tamanho do texto.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 8

Arquivo Invertido - Pesquisa

A pesquisa tem geralmente trs passos:


Pesquisa no vocabulrio: palavras e
padres da consulta so isoladas e
pesquisadas no vocabulrio.
Recuperao das ocorrncias: as listas de
ocorrncias das palavras encontradas no
vocabulrio so recuperadas.
Manipulao das ocorrncias: as listas de
ocorrncias so processadas para tratar
frases, proximidade, ou operaes
booleanas.

Como a pesquisa em um arquivo invertido


sempre comea pelo vocabulrio,
interessante mant-lo em um arquivo
separado.

Na maioria das vezes, esse arquivo cabe na


memria principal.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 9

Arquivo Invertido - Pesquisa


A pesquisa de palavras simples pode ser
realizada usando qualquer estrutura de dados
que torne a busca eficiente, como hashing,
rvore trie ou rvore B.
As duas primeiras tm custo O(m), onde m
o tamanho da consulta (independentemente
do tamanho do texto).
Guardar as palavras na ordem lexicogrfica
barato em termos de espao e competitivo
em desempenho, j que a pesquisa binria
pode ser empregada com custo O(log n),
sendo n o nmero de palavras.
A pesquisa por frases usando ndices mais
difcil de resolver.
Cada elemento da frase tem de ser
pesquisado separadamente e suas listas de
ocorrncias recuperadas.
A seguir, as listas tm de ser percorridas de
forma sicronizada para encontrar as posies
nas quais todas as palavras aparecem em
seqncia.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1 10

Arquivo Invertido Usando Trie


Arquivo invertido usando uma rvore trie
para o texto: Texto exemplo. Texto tem
palavras. Palavras exercem fascnio.
m exemplo: 7
x e
e r exercem: 45
f fascnio: 53
p
palavras: 26,36
t m tem: 22
e
x texto: 1, 16

O vocabulrio lido at o momento colocado


em uma rvore trie, armazenando uma lista
de ocorrncias para cada palavra.
Cada nova palavra lida pesquisada na trie:
Se a pesquisa sem sucesso, ento a
palavra inserida na rvore e uma lista de
ocorrncias inicializada com a posio
da nova palavra no texto.
Seno, uma vez que a palavra j se
encontra na rvore, a nova posio
inserida ao final da lista de ocorrncias.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 11

Casamento Exato

Consiste em obter todas as ocorrncias


exatas do padro no texto.
Ex.: ocorrncia exata do padro teste.
teste
os testes testam estes alunos . . .

Dois enfoques:

1. leitura dos caracteres do texto um a um:


algoritmos fora bruta, Knuth-Morris-Pratt e
Shift-And.

2. pesquisa de P em uma janela que desliza ao


longo de T , pesquisando por um sufixo da
janela que casa com um sufixo de P , por
comparaes da direita para a esquerda:
algoritmos Boyer-Moore-Horspool e
Boyer-Moore.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 12

Casamento Exato - Mtodos


Considerados

A classe CasamentoExato apresenta a


assinatura dos mtodos de casamento exato
implementados a seguir.

maxChar utilizada para representar o


tamanho do alfabeto considerado (caracteres
ASCII).

As cadeias de caracteres T e P so
representadas por meio da classe String.

package cap8;
public class CasamentoExato {
private static final int maxChar = 256;
/ / Assinatura dos mtodos para casamento exato considerados
public static void forcaBruta ( String T, int n, String P, int m)
public static void shiftAndExato ( String T, int n, String P, int m)
public static void bmh ( String T, int n, String P, int m)
public static void bmhs ( String T, int n, String P, int m)
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 13

Fora Bruta - Implementao

o algoritmo mais simples para casamento


de cadeias.

A idia tentar casar qualquer subcadeia no


texto de comprimento m com o padro.

public static void forcaBruta ( String T, int n, String P, int m) {


/ / Pesquisa P[0..m-1] em T[0..n-1]
for ( int i = 0; i < (n m + 1 ) ; i ++) {
int k = i ; int j = 0;
while ( ( j < m) && (T. charAt ( k) == P. charAt ( j ) ) ) { j ++; k++; }
i f ( j == m) System. out . println ( "Casamento na posicao : " + i ) ;
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 14

Fora Bruta - Anlise

Pior caso: Cn = m n.

O pior caso ocorre, por exemplo, quando P =


aab e T =aaaaaaaaaa.

Caso esperado:
c 1

Cn = c1 1 cm (n m + 1) + O(1)

O caso esperado muito melhor do que o


pior caso.

Em experimento com texto randmico e


alfabeto de tamanho c = 4, o nmero
esperado de comparaes
aproximadamente igual a 1,3.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 15

Autmatos

Um autmato um modelo de computao


muito simples.

Um autmato finito definido por uma tupla


(Q, I, F, , T ), onde Q um conjunto finito de
estados, entre os quais existe um estado
inicial I Q, e alguns so estados finais ou
estados de trmino F Q.

Transies entre estados so rotuladas por


elementos de {}, em que o alfabeto
finito de entrada e  a transio vazia.

As transies so formalmente definidas por


uma funo de transio T .

T associa a cada estado q Q um conjunto


{q1 , q2 , . . . , qk } de estados de Q para cada
{}.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 16

Tipos de Autmatos

Autmato finito no-determinista:


Quando T tal que existe um estado q
associado a um dado caractere para
mais de um estado, digamos
T (q, ) = {q1 , q2 , . . . , qk }, k > 1, ou existe
alguma transio rotulada por .
Neste caso, a funo de transio T
definida pelo conjunto de triplas
= {(q, , q 0 ), onde q Q, {}, e
q 0 T (q, ).

Autmato finito determinista:


Quando a funo de transio T definida
pela funo = Q  Q.
Neste caso, se T (q, ) = {q 0 }, ento
(q, ) = q 0 .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 17

Exemplo de Autmatos

Autmato finito no-determinista.


A partir do estado 0, atravs do caractere de
transio a possvel atingir os estados 2 e 3.
a
0 3

a c
1 2
b

Autmato finito determinista.


Para cada caractere de transio todos os
estados levam a um nico estado.
d
0 3

a c
1 2
b
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 18

Reconhecimento por Autmato

Uma cadeia reconhecida por (Q, I, F, , )


ou (Q, I, F, , ) se qualquer um dos
autmatos rotula um caminho que vai de um
estado inicial at um estado final.

A linguagem reconhecida por um autmato


o conjunto de cadeias que o autmato
capaz de reconher.

Ex.: a linguagem reconhecida pelo autmato


abaixo o conjunto de cadeias {a} e {abc} no
estado 3.
a
0 3

a c
1 2
b
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 19

Transies Vazias

So transies rotulada com uma cadeia


vazia , tambm chamadas de transies-,
em autmatos no-deterministas

No h necessidade de se ler um caractere


para caminhar atravs de uma transio
vazia.

Simplificam a construo do autmato.

Sempre existe um autmato equivalente que


reconhece a mesma linguagem sem
transies-.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 20

Estados Ativos

Se uma cadeia x rotula um caminho de I at


um estado q ento o estado q considerado
ativo depois de ler x.

Um autmato finito determinista tem no


mximo um estado ativo em um determinado
instante.

Um autmato finito no-determinista pode ter


vrios estados ativos.

Casamento aproximado de cadeias pode ser


resolvido por meio de autmatos finitos
no-deterministas.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 21

Ciclos em Autmatos

Os autmatos abaixo so acclicos pois as


transies no formam ciclos.
a d
0 3 0 3

a c a c
1 2 1 2
b b

Autmatos finitos cclicos, deterministas ou


no-deterministas, so teis para casamento
de expresses regulares

A linguagem reconhecida por um autmato


cclico pode ser infinita.

Ex: o autmato abaixo reconhece ba, bba, bbba,


bbbba, e assim por diante.
a

b 0 1
b

a
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 22

Exemplo de Uso de Autmato


O autmato abaixo reconhece P ={aabc}.
b
c
c
0 a 1 a 2 3 4
b c
a
b,c
b a

A pesquisa de P sobre um texto T com


alfabeto ={a, b, c} pode ser vista como a
simulao do autmato na pesquisa de P
sobre T .
No incio, o estado inicial ativa o estado 1.
Para cada caractere lido do texto, a aresta
correspondente seguida, ativando o estado
destino.
Se o estado 4 estiver ativo e um caractere c
lido o estado final se torna ativo, resultando
em um casamento de aabc com o texto.
Como cada caractere do texto lido uma vez,
a complexidade de tempo O(n), e de
espao m + 2 para vrtices e || m para
arestas.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 23

Knuth-Morris-Pratt (KMP)

O KMP o primeiro algoritmo (1977) cujo pior


caso tem complexidade de tempo linear no
tamanho do texto, O(n).

um dos algoritmos mais famosos para


resolver o problema de casamento de
cadeias.

Tem implementao complicada e na prtica


perde em eficincia para o Shift-And e o
Boyer-Moore-Horspool.

At 1971, o limite inferior conhecido para


busca exata de padres era O(mn).
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 24

KMP - 2DPDA

Em 1971, Cook provou que qualquer


problema que puder ser resolvido por um
autmato determinista de dois caminhos com
memria de pilha (Two-way Deterministic
Pushdown Store Automaton, 2DPDA) pode
ser resolvido em tempo linear por uma
mquina RAM.
O 2DPDA constitudo de:
uma fita apenas para leitura;
uma pilha de dados (memria temporria);
um controle de estado que permite mover
a fita para esquerda ou direita, empilhar ou
desempilhar smbolos, e mudar de estado.
# c 1 c 2 ... c n $ p 1 p 2 ... p m
Cabea de leitura

Controle c n Pilha
c n1
...
c 1

#
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 25

KMP - Casamento de cadeias no


2DPDA
# c 1 c 2 ... c n $ p 1 p 2 ... p m
Cabea de leitura

Controle c n Pilha
c n1
...
c 1

No autmato da acima, a entrada


constituda da cadeia #c1 c2 cn $p1 p2 pm .

A partir de # todos os caracteres so


empilhados at encontrar o caractere $.

A leitura cotinua at encontrar o caractere .

A seguir a leitura realizada no sentido


contrrio, iniciando por pn , comparado-o com
o ltimo caractere empilhado, no caso cn .

Esta operao repetida para os caracteres


seguintes, e se o caractere $ for atingido
ento as duas cadeias so iguais.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 26

KMP - Algoritmo

Primeira verso do KMP uma simulao


linear do 2DPDA

O algoritmo computa o sufixo mais longo no


texto que tambm 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.

O pr-processamento de P pode ser visto


como a construo econmica de um
autmato determinista que depois usado
para pesquisar pelo padro no texto.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 27

Shift-And

O Shift-And vezes mais rpido e muito mais


simples do que o KMP.

Pode ser estendido para permitir casamento


aproximado de cadeias de caracteres.

Usa o conceito de paralelismo de bit:


tcnica que tira proveito do paralelismo
intrnseco das operaes sobre bits dentro
de uma palavra de computador.
possvel empacotar muitos valores em
uma nica palavra e atualizar todos eles
em uma nica operao.

Tirando proveito do paralelismo de bit, o


nmero de operaes que um algoritmo
realiza pode ser reduzido por um fator de at
w, onde w o nmero de bits da palavra do
computador.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 28

Shift-And - Notao para Operaes


Usando Paralelismo de bit

Para denotar repetio de bit usado


exponenciao: 013 = 0111.

Uma seqncia de bits b0 . . . bc1 chamada


de mscara de bits de comprimento c, e
armazenada em alguma posio de uma
palavra w do computador.

Operaes sobre os bits da palavra do


computador:
|: operao or;
&: operao and;
: complementa todos os bits;
>>: move os bits para a direita e entra
com zeros esquerda (por exemplo,
b0 , b1 , . . . , bc2 , bc1 >> 2 =
00b0 , b1 , . . . , bc3 ).
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 29

Shift-And - Princpio de
Funcionamento

Mantm um conjunto de todos os prefixos de


P que casam com o texto j lido.

Utiliza o paralelismo de bit para atualizar o


conjunto a cada caractere lido do texto.

Este conjunto representado por uma


mscara de bits R = (b0 , b1 , . . . , bm1 ).

O algoritmo Shift-And pode ser visto como a


simulao de um autmato que pesquisa pelo
padro no texto (no-determinista para
simular o paralelismo de bit).

Ex.: Autmato no-determinista que reconhece


todos os prefixos de P ={teste}

t e s t e
0 1 2 3 4 5
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 30

Shift-And - Algoritmo

O valor 1 colocado na j-sima posio de


R = (b0 , b1 , . . . , bm1 ) se e somente se p0 . . . pj
um sufixo de t0 . . . ti , onde i corresponde
posio corrente no texto.

A j-sima posio de R dita estar ativa.

bm1 ativo significa um casamento.

R0 , o novo valor do conjunto R, calculado na


leitura do prximo caractere ti+1 .

A posio j + 1 no conjunto R0 ficar ativa se


e somente se a posio j estiver ativa em R e
ti+1 casa com pi+1 (p0 . . . pj era um sufixo de
t0 . . . ti e ti+1 casa com pj+1 ).

Com o uso de paralelismo de bit possvel


computar o novo conjunto com custo O(1).
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 31

Shift-And - Pr-processamento

O primeiro passo a construo de uma


tabela M para armazenar uma mscara de
bits b0 . . . , bm1 para cada caractere.
Ex.: mscaras de bits para os caracteres
presentes em P ={teste}.

0 1 2 3 4
M[t] 1 0 0 1 0
M[e] 0 1 0 0 1
M[s] 0 0 1 0 0

A mscara em M [t] 10010, pois o caractere


t aparece nas posies 0 e 3 de P .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 32

Shift-And - Pesquisa

O valor do conjunto inicializado como


R = 0m (0m significa 0 repetido m vezes).

Para cada novo caractere ti+1 lido do texto o


valor do conjunto R0 atualizado:
R0 = ((R >> 1) | 10m1 ) & M [T [i]].

A operao >> desloca todas as posies


para a direita no passo i + 1 para marcar
quais posies de P eram sufixos no passo i.

A cadeia vazia  tambm marcada como um


sufixo, permitindo um casamento na posio
corrente do texto (self-loop no incio do
autmato).

t e s t e
0 1 2 3 4 5

Do conjunto obtido at o momento, so


mantidas apenas as posies que ti+1 casa
com pj+1 , obtido com a operao and desse
conjunto de posies com o conjunto M [ti+1 ]
de posies de ti+1 em P .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 33

Exemplo de funcionamento do
Shif-And

Pesquisa do padro P ={teste} no texto


T ={os testes ...}.

Texto (R >> 1)|10m1 R0


o 1 0 0 0 0 0 0 0 0 0
s 1 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
t 1 0 0 0 0 1 0 0 0 0
e 1 1 0 0 0 0 1 0 0 0
s 1 0 1 0 0 0 0 1 0 0
t 1 0 0 1 0 1 0 0 1 0
e 1 1 0 0 1 0 1 0 0 1
s 1 0 1 0 0 0 0 1 0 0
1 0 0 1 0 0 0 0 0 0
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 34

Shift-And - Implementao
void Shift-And ( P = p0 p1 . . . pm1 , T = t0 t1 . . . tn1 )
/ / Pr-processamento
for ( c ) M [c] = 0m ;
for ( j = 0; j < m; j ++) M [pj ] = M [pj ] | 0j 10mj1 ;
/ / Pesquisa
R = 0m ;
for ( i = 0; i < n ; i ++)
R = ((R >> 1) | 10m1 ) & M [T [i]] ;
i f ( R & 0m1 1 6= 0m ) "Casamento na posicao i m + 1" ;

Anlise: O custo do algoritmo Shift-And


O(n), desde que as operaes possam ser
realizadas em O(1) e o padro caiba em
umas poucas palavras do computador.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 35

Boyer-Moore-Horspool (BMH)

Em 1977, foi publicado o algoritmo


Boyer-Moore (BM).

A idia pesquisar no padro no sentido da


direita para a esquerda, o que torna o
algoritmo muito rpido.

Em 1980, Horspool apresentou uma


simplificao no algoritmo original, to
eficiente quanto o algoritmo original, ficando
conhecida como Boyer-Moore-Horspool
(BMH).

Pela extrema simplicidade de implementao


e comprovada eficincia, o BMH deve ser
escolhido em aplicaes de uso geral que
necessitam realizar casamento exato de
cadeias.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 36

Funcionamento do BM e BMH

O BM e BMH pesquisa o padro P em uma


janela que desliza ao longo do texto T .

Para cada posio desta janela, o algoritmo


pesquisa por um sufixo da janela que casa
com um sufixo de P , com comparaes
realizadas no sentido da direita para a
esquerda.

Se no ocorrer uma desigualdade, ento uma


ocorrncia de P em T ocorreu.

Seno, o algoritmo calcula um deslocamento


que o padro deve ser deslizado para a
direita antes que uma nova tentativa de
casamento se inicie.

O BM original prope duas heursticas para


calcular o deslocamento: ocorrncia e
casamento.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 37

BM - Heurstica Ocorrncia
Alinha a posio no texto que causou a
coliso com o primeiro caractere no padro
que casa com ele;
Ex.: P ={cacbac}, T ={aabcaccacbac}.
012345678901
cacbac
aabcac cacbac
cacbac
cacbac
cacbac
cacbac

A partir da posio 5, da direita para a


esquerda, existe uma coliso na posio 3 de
T , entre b do padro e c do texto.
Logo, o padro deve ser deslocado para a
direita at o primeiro caractere no padro que
casa com c.
O processo repetido at encontrar um
casamento a partir da posio 6 de T .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 38

BM - Heurstica Casamento

Ao mover o padro para a direita, faa-o casar


com o pedao do texto anteriormente casado.

Ex.: P ={cacbac} no texto T ={aabcaccacbac}.

012345678901
cacbac
aabcaccacbac
cacbac
cacbac

Novamente, a partir da posio 5, da direita


para a esquerda, existe uma coliso na
posio 3 de T , entre o b do padro e o c do
texto.

Neste caso, o padro deve ser deslocado


para a direita at casar com o pedao do
texto anteriormente casado, no caso ac,
deslocando o padro 3 posies direita.

O processo repetido mais uma vez e o


casamento entre P e T ocorre.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 39

Escolha da Heurstica

O algoritmo BM escolhe a heurstica que


provoca o maior deslocamento do padro.

Esta escolha implica em realizar uma


comparao entre dois inteiros para cada
caractere lido do texto, penalizando o
desempenho do algoritmo com relao a
tempo de processamento.

Vrias propostas de simplificao ocorreram


ao longo dos anos.

As que produzem os melhores resultados so


as que consideram apenas a heurstica
ocorrncia.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 40

Algoritmo Boyer-Moore-Horspool
(BMH)

A simplificao mais importante devida a


Horspool em 1980.

Executa mais rpido do que o algoritmo BM


original.

Parte da observao de que qualquer


caractere j lido do texto a partir do ltimo
deslocamento pode ser usado para enderear
a tabela de deslocamentos.

Enderea a tabela com o caractere no texto


correspondente ao ltimo caractere do
padro.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 41

BMH - Tabela de Deslocamentos

Para pr-computar o padro o valor inicial de


todas as entradas na tabela de
deslocamentos feito igual a m.

A seguir, apenas para os m 1 primeiros


caracteres do padro so usados para obter
os outros valores da tabela.

Formalmente, d[x] = min{j tal que j =


m | (1 j < m & P [m j 1] = x)}.

Ex.: Para o padro P ={teste}, os valores de d


so d[t] = 1, d[e] = 3, d[s] = 2, e todos os outros
valores so iguais ao valor de |P |, nesse caso
m = 5.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 42

BMH - Implementao
public static void bmh ( String T, int n, String P, int m) {
/ / Pr-processamento do padro
int d[ ] = new int [maxChar] ;
for ( int j = 0; j < maxChar; j ++) d[ j ] = m;
for ( int j = 0; j < (m1); j ++) d[ ( int )P. charAt ( j ) ] = m j 1;
int i = m 1;
while ( i < n ) { / / Pesquisa
int k = i ; int j = m 1;
while ( ( j >= 0) && (T. charAt ( k) == P. charAt ( j ) ) ) { j ; k; }
i f ( j < 0)
System. out . println ( "Casamento na posicao : " + (k + 1));
i = i + d[ ( int )T. charAt ( i ) ] ;
}
}

d[(int)T.charAt(i)] equivale ao endereo na


tabela d do caractere que est na i-sima
posio no texto, a qual corresponde
posio do ltimo caractere de P .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 43

Algoritmo BMHS -
Boyer-Moore-Horspool-Sunday
Sunday (1990) apresentou outra simplificao
importante para o algoritmo BM, ficando
conhecida como BMHS.
Variante do BMH: enderear a tabela com o
caractere no texto correspondente ao prximo
caractere aps o ltimo caractere do padro,
em vez de deslocar o padro usando o ltimo
caractere como no algoritmo BMH.
Para pr-computar o padro, o valor inicial de
todas as entradas na tabela de
deslocamentos feito igual a m + 1.
A seguir, os m primeiros caracteres do padro
so usados para obter os outros valores da
tabela.
Formalmente d[x] = min{j tal que j =
m | (1 j m & P [m j] = x)}.
Para o padro P = teste, os valores de d
so d[t] = 2, d[e] = 1, d[s] = 3, e todos os
outros valores so iguais ao valor de |P | + 1.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 44

BMHS - Implementao

O pr-processamento do padro ocorre nas


duas primeiras linhas do cdigo.

A fase de pesquisa constituda por um anel


em que i varia de m 1 at n 1, com
incrementos d[(int)T.charAt(i + 1)], o que
equivale ao endereo na tabela d do
caractere que est na i + 1-sima posio no
texto, a qual corresponde posio do ltimo
caractere de P .

public static void bmhs ( String T, int n, String P, int m) {


/ / Pr-processamento do padro
int d[ ] = new int [maxChar] ;
for ( int j = 0; j < maxChar; j ++) d[ j ] = m + 1;
for ( int j = 0; j < m; j ++) d[ ( int )P. charAt ( j ) ] = m j ;
int i = m 1;
while ( i < n ) { / / Pesquisa
int k = i ; int j = m 1;
while ( ( j >= 0) && (T. charAt ( k) == P. charAt ( j ) ) ) { j ; k; }
i f ( j < 0)
System. out . println ( "Casamento na posicao : " + (k + 1));
i = i + d[ ( int )T. charAt ( i +1)];
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 45

BH - Anlise

Os dois tipos de deslocamento (ocorrncia e


casamento) podem ser pr-computados com
base apenas no padro e no alfabeto.

Assim, a complexidade de tempo e de espao


para esta fase O(m + c).

O pior caso do algoritmo O(nm).

O melhor caso e o caso mdio para o


algoritmo O(n/m), um resultado excelente
pois executa em tempo sublinear.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 46

BMH - Anlise

O deslocamento ocorrncia tambm pode ser


pr-computado com base apenas no padro
e no alfabeto.

A complexidade de tempo e de espao para


essa fase O(m + 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 no
pequeno e m no muito grande.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1 47

BMHS - Anlise

Na variante BMHS, seu comportamento


assinttico igual ao do algoritmo BMH.

Entretanto, os deslocamentos so mais


longos (podendo ser iguais a m + 1), levando
a saltos relativamente maiores para padres
curtos.

Por exemplo, para um padro de tamanho


m = 1, o deslocamento igual a 2m quando
no h casamento.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 48

Casamento Aproximado

O casamento aproximado de cadeias permite


operaes de insero, substituio e retirada
de caracteres do padro.

Ex.: Trs ocorrncias do padro teste em que


os casos de insero, substituio, retirada de
caracteres no padro acontecem:

1. um espao inserido entre o terceiro e quarto


caracteres do padro;

2. o ltimo caractere do padro substitudo


pelo caractere a;

3. o primeiro caractere do padro retirado.

tes te
testa
este
os testes testam estes alunos . . .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 49

Distncia de Edio

nmero k de operaes de insero,


substituio e retirada de caracteres
necessrio para transformar uma cadeia x em
outra cadeia y.

ed(P, P 0 ): distncia de edio entre duas


cadeias P e P 0 ; o menor nmero de
operaes necessrias para converter P em
P 0 , ou vice versa.
Ex.: ed(teste, estende) = 4, valor obtido por
meio de uma retirada do primeiro t de P e a
insero dos 3 caracteres nde ao final de P .

O problema do casamento aproximado de


cadeias o de encontrar todas as ocorrncias
em T de cada P 0 que satisfaz ed(P, P 0 ) k.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 50

Casamento Aproximado

A busca aproximada s faz sentido para


0 < k < m, pois para k = m toda subcadeia
de comprimento m pode ser convertida em P
por meio da substituio de m caracteres.

O caso em que k = 0 corresponde ao


casamento exato de cadeias.

O nvel de erro = k/m, fornece uma medida


da frao do padro que pode ser alterado.

Em geral < 1/2 para a maioria dos casos


de interesse.

Casamento aproximado de cadeias, ou


casamento de cadeias permitindo erros:
um nmero limitado k de operaes (erros)
de insero, de substituio e de retirada
permitido entre P e suas ocorrncias em T .

A pesquisa com casamento aproximado


modelado por autmato no-determinista.

O algoritmo de casamento aproximado de


cadeias usa o paralelismo de bit.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 51

Exemplo de Autmato para


Casamento Aproximado
P ={teste} e k = 1: (a)insero;
(b)substituio e (c)retirada.

t e s t e
0 1 2 3 4 5

(a)
e s t e
1 2 3 4 5


t e s t e
0 1 2 3 4 5

(b)
e s t e
1 2 3 4 5


t e s t e
0 1 2 3 4 5

(c)
e s t e
1 2 3 4 5

Casamento de caractere representado por


uma aresta horizontal. Avanamos em P e T .
O self-loop permite que uma ocorrncia se
inicie em qualquer posio em T .
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 52

Exemplo de Autmato para


Casamento Aproximado
Uma aresta vertical insere um caractere no
padro. Avanamos em T mas no em P .

t e s t e
0 1 2 3 4 5


e s t e
1 2 3 4 5

Uma aresta diagonal slida substitui um


caractere. Avanamos em T e P .

t e s t e
0 1 2 3 4 5

e s t e
1 2 3 4 5

Uma aresta diagonal tracejada retira um


caractere. Avanamos em P mas no em T
(transio-)

t e s t e
0 1 2 3 4 5

e s t e
1 2 3 4 5
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 53

Exemplo de Autmato para


Casamento Aproximado
P ={teste} e K = 2.
As trs operaes de distncia de edio
esto juntas em um nico autmato:
Linha 1: casamento exato (k = 0);
Linha 2: casamento aproximado
permitindo um erro (k = 1);
Linha 3: casamento aproximado
permitindo dois erros (k = 2).


t e s t e
0 1 2 3 4 5



t e s t e
0 1 2 3 4 5



t e s t e
0 1 2 3 4 5

Uma vez que um estado no autmato est


ativo, todos os estados nas linhas seguintes
na mesma coluna tambm esto ativos.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 54

Shift-And para Casamento


Aproximado

Utiliza paralelismo de bit.

Simula um autmato no-determinista.

Empacota cada linha j (0 < j k) do


autmato no-determinista em uma palavra
Rj diferente do computador.

Para cada novo caractere lido do texto todas


as transies do autmato so simuladas
usando operaes entre as k + 1 mscaras
de bits.

Todas as k + 1 mscaras de bits tm a


mesma estrutura e assim o mesmo bit
alinhado com a mesma posio no texto.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 55

Shift-And para Casamento


Aproximado
Na posio i do texto, os novos valores Rj0 ,
0 < j k, so obtidos a partir dos valores
correntes Rj :
R00 = ((R0 >> 1) | 10m1 ) & M [T [i]]
Rj0 = ((Rj >>
1) & M [T [i]]) | Rj1 | (Rj1 >>
0
1) | (Rj1 >> 1) | 10m1 , onde M a
tabela do algoritmo Shift-And para
casamento exato.
A pesquisa inicia com Rj = 1j 0mj .
R0 equivale ao algoritmo Shift-And para
casamento exato.
As outras linhas Rj recebem 1s (estados
ativos) tambm de linhas anteriores.
Considerando um automato para casamento
aproximado, a frmula para R0 expressa:
arestas horizontais indicando casamento;
verticais indicando insero;
diagonais cheias indicando substituio;
diagonais tracejadas indicando retirada.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 56

Shif-And para Casamento Aproximado


- Implementao
void Shift-And-Aproximado ( P = p0 p1 . . . pm1 , T = t0 t1 . . . tn1 , k )
/ / Pr-processamento
for ( c ) M [c] = 0m ;
for ( j = 0; j < m; j ++) M [pj ] = M [pj ] | 0j 10mj1 ;
/ / Pesquisa
for ( j = 0; j <= k ; j ++) Rj = 1j 0mj ;
for ( i = 0; i < n ; i ++)
Rant = R0 ;
Rnovo = ((Rant >> 1) | 10m1 ) & M [T [i]] ;
R0 = Rnovo ;
for ( j = 1; j <= k ; j ++)
Rnovo = ((Rj >> 1 & M [T [i]]) | Rant | ((Rant | Rnovo) >> 1) ;
Rant = Rj ;
Rj = Rnovo | 10m1 ;
i f ( Rnovo & 0m1 1 6= 0m ) "Casamento na posicao i" ;
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 57

Shif-And p/ Casam. Aprox. - Exemplo


Padro: teste. Texto: os testes testam.
Permitindo um erro (k = 1) de insero).
R00 = (R0 >> 1)|10m1 &M [T [i]] e
R10 = (R1 >> 1)&M [T [i]]|R0 |(10m1 )
Uma ocorrncia exata na posio 8 (e) e
duas, permitindo uma insero, nas posies
8 e 11 (s e e, respectivamente).
Texto (R0 >> 1)|10m1 R00 R1 >> 1 R10
o 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
s 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
t 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0
e 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 0 0 0
s 1 0 1 0 0 0 0 1 0 0 0 1 1 0 0 1 1 1 0 0
t 1 0 0 1 0 1 0 0 1 0 0 1 1 1 0 1 0 1 1 0
e 1 1 0 0 1 0 1 0 0 1 0 1 0 1 1 1 1 0 1 1
s 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 1 1 0 1
1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 0 1 0 0
t 1 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 0 1 0
e 1 1 0 0 0 0 1 0 0 0 0 1 0 0 1 1 1 0 0 1
s 1 0 1 0 0 0 0 1 0 0 0 1 1 0 0 1 1 1 0 0
t 1 0 0 1 0 1 0 0 1 0 0 1 1 1 0 1 0 1 1 0
a 1 1 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 1 0
m 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2 58

Shif-And p/ Casam. Aprox. - Exemplo


Padro: teste. Texto: os testes testam.
Permitindo um erro de insero, um de
retirada e um de substituio.
R00 = (R0 >> 1)|10m1 &M [T [i]] e
R10 = (R1 >> 1)&M [T [i]]|R0 |(R00 >>
1)|(R0 >> 1)|(10m1 ).
Uma ocorrncia exata na posio 8 (e) e
cinco, permitindo um erro, nas posies 6, 8,
11, 13 e 14 (t, s, e, t e a, respec.).
Texto (R0 >> 1)|10m1 R00 R1 >> 1 R10
o 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
s 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
t 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 0
e 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 1 1 1 0 0
s 1 0 1 0 0 0 0 1 0 0 0 1 1 1 0 1 1 1 1 0
t 1 0 0 1 0 1 0 0 1 0 0 1 1 1 1 1 1 1 1 1
e 1 1 0 0 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1
s 1 0 1 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 0
t 1 0 0 0 0 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0
e 1 1 0 0 0 0 1 0 0 0 0 1 1 0 1 1 1 1 0 1
s 1 0 1 0 0 0 0 1 0 0 0 1 1 1 0 1 1 1 1 0
t 1 0 0 1 0 1 0 0 1 0 0 1 1 1 1 1 1 1 1 1
a 1 1 0 0 1 0 0 0 0 0 0 1 1 1 1 1 1 0 1 1
m 1 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2 59

Compresso - Motivao

Exploso de informao textual disponvel


on-line:
Bibliotecas digitais.
Sistemas de automao de escritrios.
Bancos de dados de documentos.
World-Wide Web.

Somente a Web tem hoje bilhes de pginas


estticas disponveis.

Cada bilho de pginas ocupando


aproximadamente 10 terabytes de texto
corrido.

Em setembro de 2003, a mquina de busca


Google (www.google.com.br) dizia ter mais de
3,5 bilhes de pginas estticas em seu
banco de dados.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2 60

Caractersticas necessrias para


sistemas de recuperao de
informao

Mtodos recentes de compresso tm


permitido:
1. Pesquisar diretamente o texto comprimido
mais rapidamente do que o texto original.
2. Obter maior compresso em relao a
mtodos tradicionais, gerando maior
economia de espao.
3. Acessar diretamente qualquer parte do
texto comprimido sem necessidade de
descomprimir todo o texto desde o incio
(Moura, Navarro, Ziviani e Baeza-Yates,
2000; Ziviani, Moura, Navarro e
Baeza-Yates, 2000).

Compromisso espao X tempo:


vencer-vencer.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.1 61

Porque Usar Compresso


Compresso de texto - maneiras de
representar o texto original em menos
espao:
Substituir os smbolos do texto por outros
que possam ser representados usando um
nmero menor de bits ou bytes.
Ganho obtido: o texto comprimido ocupa
menos espao de armazenamento menos
tempo para ser lido do disco ou ser
transmitido por um canal de comunicao e
para ser pesquisado.
Preo a pagar: custo computacional para
codificar e decodificar o texto.
Avano da tecnologia: De acordo com
Patterson e Hennessy (1995), em 20 anos, o
tempo de acesso a discos magnticos tem se
mantido praticamente constante, enquanto a
velocidade de processamento aumentou
aproximadamente 2 mil vezes melhor
investir mais poder de computao em
compresso em troca de menos espao em
disco ou menor tempo de transmisso.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.1 62

Razo de Compresso

Definida pela porcentagem que o arquivo


comprimido representa em relao ao
tamanho do arquivo no comprimido.

Exemplo: se o arquivo no comprimido


possui 100 bytes e o arquivo comprimido
resultante possui 30 bytes, ento a razo de
compresso de 30%.

Utilizada para medir O ganho em espao


obtido por um mtodo de compresso.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.1 63

Outros Importantes Aspectos a


Considerar
Alm da economia de espao, deve-se
considerar:

Velocidade de compresso e de
descompresso.

Possibilidade de realizar casamento de


cadeias diretamente no texto comprimido.

Permitir acesso direto a qualquer parte do


texto comprimido e iniciar a descompresso a
partir da parte acessada:

Um sistema de recuperao de informao


para grandes colees de documentos
que estejam comprimidos necessitam
acesso direto a qualquer ponto do texto
comprimido.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2 64

Compresso de Textos em Linguagem


Natural
Um dos mtodos de codificao mais
conhecidos o de Huffman (1952):
A idia do mtodo atribuir cdigos mais
curtos a smbolos com freqncias altas.
Um cdigo nico, de tamanho varivel,
atribudo a cada smbolo diferente do texto.
As implementaes tradicionais do mtodo
de Huffman consideram caracteres como
smbolos.
Para aliar as necessidades dos algoritmos de
compresso s necessidades dos sistemas
de recuperao de informao apontadas
acima, deve-se considerar palavras como
smbolos a serem codificados.
Mtodos de Huffman baseados em
caracteres comprimem o texto para
aproximadamente 60%.
Mtodos de Huffman baseados em palavras
comprimem o texto para valores pouco acima
de 25%.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2 65

Vantagens dos Mtodos de Huffman


Baseados em Palavras

Permitem acesso randmico a palavras


dentro do texto comprimido.

Considerar palavras como smbolos significa


que a tabela de smbolos do codificador
exatamente o vocabulrio do texto.

Isso permite uma integrao natural entre o


mtodo de compresso e o arquivo invertido.

Permitem acessar diretamente qualquer parte


do texto comprimido sem necessidade de
descomprimir todo o texto desde o incio.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2 66

Famlia de Mtodos de Compresso


Ziv-Lempel

Substitui uma seqncia de smbolos por um


apontador para uma ocorrncia anterior
daquela seqncia.

A compresso obtida porque os


apontadores ocupam menos espao do que a
seqncia de smbolos que eles substituem.

Os mtodos Ziv-Lempel so populares pela


sua velocidade, economia de memria e
generalidade.

J o mtodo de Huffman baseado em


palavras muito bom quando a cadeia de
caracteres constitui texto em linguagem
natural.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2 67

Desvantagens dos Mtodos de


Ziv-Lempel para Ambiente de
Recuperao de Informao

necessrio iniciar a decodificao desde o


incio do arquivo comprimido Acesso
randmico muito caro.

muito difcil pesquisar no arquivo


comprimido sem descomprimir.

Uma possvel vantagem do mtodo


Ziv-Lempel o fato de no ser necesrio
armazenar a tabela de smbolos da maneira
com que o mtodo de Huffman precisa.

No entanto, isso tem pouca importncia em


um ambiente de recuperao de informao,
j que se necessita o vocabulrio do texto
para criar o ndice e permitir a pesquisa
eficiente.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 68

Compresso de Huffman Usando


Palavras

Tcnica de compresso mais eficaz para


textos em linguagem natural.

O mtodo considera cada palavra diferente do


texto como um smbolo.

Conta suas freqncias e gera um cdigo de


Huffman para as palavras.

A seguir, comprime o texto substituindo cada


palavra pelo seu cdigo.

Assim, a compresso realizada em duas


passadas sobre o texto:
1. Obteno da freqncia de cada palavra
diferente.
2. Realizao da compresso.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 69

Forma Eficiente de Lidar com Palavras


e Separadores

Um texto em linguagem natural constitudo


de palavras e de separadores.

Separadores so caracteres que aparecem


entre palavras: espao, vrgula, ponto, ponto
e vrgula, interrogao, e assim por diante.

Uma forma eficiente de lidar com palavras e


separadores representar o espao simples
de forma implcita no texto comprimido.

Nesse modelo, se uma palavra seguida de


um espao, ento, somente a palavra
codificada.

Seno, a palavra e o separador so


codificados separadamente.

No momento da decodificao, supe-se que


um espao simples segue cada palavra, a
no ser que o prximo smbolo corresponda a
um separador.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 70

Compresso usando codificao de


Huffman
Exemplo: para cada rosa rosa, uma
rosa uma rosa
a) 1 1 4 1 2 1 b) 4 1 2 1
para cada rosa , uma 2 rosa , uma
0 1
para cada

c) 4 2 d) 4 2
2 rosa 2 uma 4 rosa uma
0 1 0 1 0 1
para cada , 2 2
0 1 0 1
para cada ,

e) 4 f) 10
6 rosa 0 1
0 1
rosa 6
uma 4 0 1
0 1
uma 4
2 2 0 1
0 1 0 1
2 2
para cada ,
0 1 0 1
para cada ,

OBS: O algoritmo de Huffman uma abordagem


gulosa.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 71

rvore de Huffman

O mtodo de Huffman produz a rvore de


codificao que minimiza o comprimento do
arquivo comprimido.

Existem diversas rvores que produzem a


mesma compresso.

Por exemplo, trocar o filho esquerda de um


n por um filho direita leva a uma rvore de
codificao alternativa com a mesma razo
de compresso.

Entretanto, a escolha preferencial para a


maioria das aplicaes a rvore cannica.

Uma rvore de Huffman cannica quando a


altura da subrvore direita de qualquer n
nunca menor que a altura da subrvore
esquerda.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 72

rvore de Huffman

A representao do cdigo na forma de


rvore facilita a visualizao.

Sugere mtodos de codificao e


decodificao triviais:
Codificao: a rvore percorrida
emitindo bits ao longo de suas arestas.
Decodificao: os bits de entrada so
usados para selecionar as arestas.

Essa abordagem ineficiente tanto em


termos de espao quanto em termos de
tempo.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 73

Algoritmo Baseado na Codificao


Cannica com Comportamento Linear
em Tempo e Espao

O algoritmo atribudo a Moffat e Katajainen


(1995).

Calcula os comprimentos dos cdigos em


lugar dos cdigos propriamente ditos.

A compresso atingida a mesma,


independentemente dos cdigos utilizados.

Aps o clculo dos comprimentos, h uma


forma elegante e eficiente para a codificao
e a decodificao.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 74

O Algoritmo

A entrada do algoritmo um vetor A contendo


as freqncias das palavras em ordem
no-crescente.

Freqncias relativas frase exemplo: para


cada rosa rosa, uma rosa uma
rosa
4 2 1 1 1 1

Durante sua execuo, so utilizados


diversos vetores logicamente distintos, mas
capazes de coexistirem no mesmo vetor das
freqncias.

O algoritmo divide-se em trs fases:


1. Combinao dos ns.
2. Converso do vetor no conjunto das
profundidades dos ns internos.
3. Calculo das profundidades dos ns folhas.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 75

Primeira Fase - Combinao dos ns


1 2 n
a) ...

Freqncias

Folha Prox Raiz


1 n
b) ... ... ... ...

Freqncias Posies Pesos dos ndices pais


dos ns folhas disponveis ns internos ns internos

1 2 3 n
c) ...

Peso da ndices pais


rvore ns internos

A primeira fase baseada em duas


observaes:
1. A freqncia de um n s precisa ser
mantida at que ele seja processado.
2. No preciso manter apontadores para os
pais dos ns folhas, pois eles podem ser
inferidos.

Exemplo: ns internos nas profundidades


[0, 1, 2, 3, 3] teriam ns folhas nas
profundidades [1, 2, 4, 4, 4, 4].
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 76

Pseudocdigo para a Primeira Fase


void primeiraFase (A, n) {
raiz = n ; folha = n;
for ( prox = n ; prox >= 2; prox) {
/ / Procura Posio
i f ( ( no existe folha ) | | ( ( raiz > prox) && (A[ raiz ] <= A[ folha ] ) ) ) {
/ / N interno
A[ prox ] = A[ raiz ] ; A[ raiz ] = prox ; raiz;
}
else { / / N folha
A[ prox ] = A[ folha ] ; folha;
}
/ / Atualiza Freqncias
i f ( ( no existe folha ) | | ( ( raiz > prox) && (A[ raiz ] <= A[ folha ] ) ) ) {
/ / N interno
A[ prox ] = A[ prox ] + A[ raiz ] ; A[ raiz ] = prox ; raiz;
}
else { / / N folha
A[ prox ] = A[ prox ] + A[ folha ] ; folha;
}
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 77

Exemplo de processamento da
primeira fase

1 2 3 4 5 6 Prox Raiz Folha


a) 4 2 1 1 1 1 6 6 6
b) 4 2 1 1 1 1 6 6 5
c) 4 2 1 1 1 2 5 6 4
d) 4 2 1 1 1 2 5 6 3
e) 4 2 1 1 2 2 4 6 2
f) 4 2 1 2 2 4 4 5 2
g) 4 2 1 4 4 4 3 4 2
h) 4 2 2 4 4 4 3 4 1
i) 4 2 6 3 4 4 2 3 1
j) 4 4 6 3 4 4 2 3 0
k) 10 2 3 4 4 1 2 0
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 78

Segunda Fase - Converso do vetor no


conjunto das profundidades dos ns
internos
1 2 3 n
a) ...

Peso da ndices pais


rvore ns internos

Prox
1 2 n
b) ... ...

Profundidade ndices pais


dos ns internos ns internos

1 2 n
c) ...

Profundidade dos ns internos


Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 79

Pseudocdigo para a Segunda Fase


void segundaFase (A, n) {
A[2] = 0;
for ( prox = 3; prox <= n ; prox++) A[ prox ] = A[A[ prox ] ] + 1 ;
}

Profundidades dos ns internos obtida com a


segunda fase tendo como entrada o vetor
exibido na letra k) da transparncia 65:
0 1 2 3 3
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 80

Terceira Fase - Calculo das


profundidades dos ns folhas

1 2 n
a) ...

Profundidade dos ns internos

Prox Raiz
1 n
b) ... ... ...

Comprimento Posies Profundidade


dos cdigos disponveis dos ns internos

1 n
c) ...

Comprimento dos cdigos


Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 81

Pseudocdigo para a Terceira Fase


void terceiraFase (A, n) {
disp = 1; u = 0; h = 0; raiz = 2; prox = 1;
while ( disp > 0) {
while ( ( raiz <= n) && (A[ raiz ] == h ) ) { u++; raiz ++; }
while ( disp > u ) { A[ prox ] = h ; prox++; disp; }
disp = 2 u ; h++; u = 0;
}
}

Aplicando-se a Terceira Fase sobre:


0 1 2 3 3

Os comprimentos dos cdigos em nmero de


bits so obtidos:
1 2 4 4 4 4
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 82

Clculo do comprimento dos cdigos


a partir de um vertor de freqncias
void calculaCompCodigo (A, n) {
primeiraFase (A, n) ;
segundaFase (A, n) ;
terceiraFase (A, n) ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 83

Cdigo Cannico
Propriedades:
1. Os comprimentos dos cdigos obedecem
ao algoritmo de Huffman.
2. Cdigos de mesmo comprimento so
inteiros consecutivos.
A partir dos comprimentos obtidos, o clculo
dos cdigos propriamente dito trivial: o
primeiro cdigo composto apenas por zeros
e, para os demais, adiciona-se 1 ao cdigo
anterior e faz-se um deslocamento
esquerda para obter-se o comprimento
adequado quando necessrio.
Codificao Cannica Obtida:

i Smbolo Cdigo Cannico


1 rosa 0
2 uma 10
3 para 1100
4 cada 1101
5 ,t 1110
6 1111
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 84

Elaborao de Algoritmos Eficientes


para a Codificao e para a
Decodificao

Os algoritmos so baseados na seguinte


observao:
Cdigos de mesmo comprimento so
inteiros consecutivos.

Os algoritmos so baseados no uso de dois


vetores com maxCompCod elementos,sendo
maxCompCod o comprimento do maior cdigo.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 85

Vetores base e offset

Vetor base: indica, para um dado


comprimento c, o valor inteiro do primeiro
cdigo com esse comprimento.
O vetor Base calculado pela relao:
8
<0 se c = 1,
base[c] =
:2 (base[c 1] + wc1 ) caso contrrio,

sendo wc o nmero de cdigos com


comprimento c.
offset indica o ndice no vocabulrio da
primeira palavra de cada comprimento de
cdigo c.
Vetores base e offset para a tabela da
transparncia 71:

c base[c] offset[c]
1 0 1
2 2 2
3 6 2
4 12 3
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 86

Pseudocdigo para Codificao


Codigo codifica ( i , maxCompCod) {
c = 1;
while ( ( c + 1 <= maxCompCod) && ( i >= offset [ c + 1 ] ) ) c++;
codigo = i offset [ c ] + base[ c ] ;
return ( codigo , c ) ;
}

Obteno do cdigo:

O mtodo de codificao recebe como


parmetros o ndice i do smbolo a ser
codificado e o comprimento maxCompCod dos
vetores base e offset.

No anel while feito o clculo do


comprimento c de cdigo a ser utilizado.

A seguir, basta saber qual a ordem do cdigo


para o comprimento c (i offset[c]) e somar
esse valor base[c].
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 87

Exemplo de Codificao

Para a palavra i = 4 (cada):


1. Verifica-se que um cdigo de
comprimento 4.
2. Verifica-se tambm que o segundo
cdigo com esse comprimento.
3. Assim, seu cdigo 13
(4 offset[4] + base[4]), o que corresponde
a 1101 em binrio.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 88

Pseudocdigo para Decodificao


int decodifica (maxCompCod) {
c = 1; codigo = leBit (arqComp) ;
while ( ( codigo < < 1 ) >= base[ c + 1] && ( c + 1 <= maxCompCod ) ) {
codigo = (codigo < < 1) | leBit (arqComp) ; c++;
}
i = codigo base[ c ] + offset [ c ] ;
return i ;
}

O programa recebe como parmetro o


comprimento maxCompCod dos vetores base e
offset.

Na decodificao, o arquivo de entrada lido


bit-a-bit, adicionando-se os bits lidos ao
cdigo e comparando-o com o vetor Base.

O anel while mostra como identificar o cdigo


a partir de uma posio do arquivo
comprimido.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 89

Exemplo de Decodificao
Decodificao da seqncia de bits 1101:
c LeBit Codigo Codigo << 1 Base[c + 1]
1 1 1 - -
2 1 10 or 1 = 11 10 10
3 0 110 or 0 = 110 110 110
4 1 1100 or 1 = 1101 1100 1100

A primeira linha da tabela representa o


estado inicial do anel while quando j foi lido
o primeiro bit da seqncia, o qual foi
atribudo varivel codigo.
A linha dois e seguintes representam a
situao do anel while aps cada respectiva
iterao.
No caso da linha dois da tabela, o segundo bit
da seqncia foi lido (bit 1) e a varivel
codigo recebe o cdigo anterior deslocado
esquerda de um bit seguido da operao or
com o bit lido.
De posse do cdigo, base e offset so usados
para identificar qual o ndice i da palavra no
vocabulrio, sendo
i = codigo base[c] + offset[c].
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 90

Pseudocdigo para realizar a


compresso
void compressao (nomeArqTxt, nomeArqComp) {
arqComp = new RandomAccessFile (nomeArqComp, "rws" ) ;
arqTxt = new BufferedReader (new FileReader(nomeArqTxt) ) ;
/ / Primeira etapa
String palavra = null ; TabelaHash vocabulario ;
while ( existirem palavras ) {
palavra = proximaPalavra ( arqTxt ) ;
itemVoc = vocabulario .pesquisa ( palavra ) ;
i f ( itemVoc ! = null ) itemVoc. freq = itemVoc. freq + 1;
else vocabulario . insere ( palavra ) ;
}
/ / Segunda etapa
A[ ] = ordenaPorFrequencia ( vocabulario ) ; calculaCompCodigo (A, n) ;
maxCompCod = constroiVetores (A, n ) ; gravaVocabulario (A, arqComp) ;
/ / Terceira etapa
while ( existirem palavras ) {
palavra = proximaPalavra ( arqTxt ) ;
itemVoc = vocabulario .pesquisa ( palavra ) ;
codigo = codifica (itemVoc.ordem, maxCompCod) ;
escreve ( codigo , maxCompCod) ;
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 91

Pseudocdigo para realizar a


descompresso
void descompressao (nomeArqTxt, nomeArqComp) {
arqComp = new RandomAccessFile (nomeArqComp, "rws" ) ;
arqTxt = new BufferedWriter (new FileWriter (nomeArqTxt) ) ;
int maxCompCod = leVetores ( ) ;
String vocabulario [ ] = leVocabulario ( ) ;
while ( ( i = decodifica (maxCompCod)) >= 0) {
i f ( ( palavra anterior no delimitador) && (vocabulario[i] no delimitador ) )
arqTxt . write ( " " ) ;
arqTxt . write ( vocabulario [ i ] ) ;
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3 92

Codificao de Huffman Usando


Palavras - Anlise
A representao do cdigo de Huffman na
forma de uma rvore ineficiente em termos
de espao e de tempo (no usado na
prtica).
Codificao cannica: forma mais eficiente
baseada nos comprimentos dos cdigos em
vez dos cdigos propriamente ditos (Moffat e
Katajainen - 1995).
Feito in situ a partir de um vetor A contendo
as freqncias das palavras em ordem no
crescente a um custo O(n) em tempo e em
espao.
O algoritmo requer apenas os dois vetores
base e offset de tamanho maxCompCod , sendo
maxCompCod o comprimento do maior cdigo.
A decodificao tambm muito eficiente
pois apenas os vetores base e offset so
consultados.
No h necessidade de realizar a
decodificao bit a bit, como na rvore de
Huffman.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 93

Codificao de Huffman Usando Bytes

O mtodo original proposto por


Huffman (1952) tem sido usado como um
cdigo binrio.

Moura, Navarro, Ziviani e Baeza-Yates (2000)


modificaram a atribuio de cdigos de tal
forma que uma seqncia de bytes
associada a cada palavra do texto.

Conseqentemente, o grau de cada n passa


de 2 para 256. Essa verso chamada de
cdigo de Huffman pleno.

Outra possibilidade utilizar apenas 7 dos 8


bits de cada byte para a codificao, e a
rvore passa ento a ter grau 128.

Nesse caso, o oitavo bit usado para marcar


o primeiro byte do cdigo da palavra, sendo
chamado de cdigo de Huffman com
marcao.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 94

Exemplo de Cdigos Plenos e com


Marcao

O cdigo de Huffman com marcao ajuda na


pesquisa sobre o texto comprimido.

Exemplo:
Cdigo pleno para a palavra uma com 3
bytes 47 81 8.
Cdigo com marcao para a palavra
uma com 3 bytes 175 81 8
Note que o primeiro byte 175 = 47 + 128.

Assim, no cdigo com marcao o oitavo bit


1 quando o byte o primeiro do cdigo,
seno ele 0.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 95

rvore de Huffman orientada a bytes

A construo da rvore de Huffman orientada


a bytes pode ocasionar o aparecimento de
ns internos no totalmente preenchidos
quando a rvore no binria:

a) rvore ineficiente
...
... ...
254 ns vazios
256 elementos 256 elementos

b) rvore tima
...
... ...
254 elementos
256 elementos 2 elementos 254 ns vazios

Na Figura, o alfabeto possui 512 smbolos


(ns folhas), todos com a mesma freqncia
de ocorrncia.

O segundo nvel tem 254 espaos vazios que


poderiam ser ocupados com smbolos,
mudando o comprimento de seus cdigos de
2 para 1 byte.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 96

Movendo Ns Vazios para Nveis mais


Profundos

Um meio de assegurar que ns vazios


sempre ocupem o nvel mais baixo da rvore
combin-los com os ns de menores
freqncias.

O objetivo mov-los para o nvel mais


profundo da rvore.

Para isso, devemos selecionar o nmero de


smbolos que sero combinados com os ns
vazios.

Essa seleo dada pela equao


1 + ((n baseNum) mod (baseNum 1)).

No caso da Figura da transparncia anterior


igual a 1 + ((512 256) mod 255) = 2.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 97

Classe HuffmanByte
package cap8;
import java . io .;
import cap5.endaberto.TabelaHash;
import cap4. ordenacaointerna .Ordenacao;
public class HuffmanByte {
private int baseNum;
private int base [ ] , offset [ ] ;
private RandomAccessFile arqComp; / / Arquivo comprimido
private String nomeArqTxt; / / Nome do arquivo texto a ser comprimido
private String nomeArqDelim; / / Nome do arquivo que contm os delimita-
dores
private TabelaHash vocabulario ;
private static class Codigo {
int codigo ; int c ; / / Comprimento do cdigo
}
public HuffmanByte ( String nomeArqDelim, int baseNum, int m,
int maxTamChave) throws Exception {
this .baseNum = baseNum; this .base = null ; this . offset = null ;
this .nomeArqTxt = null ; this .nomeArqDelim = nomeArqDelim;
this . vocabulario = new TabelaHash (m, maxTamChave) ;
}
public void compressao ( String nomeArqTxt,
String nomeArqComp) throws Exception {
public void descompressao ( String nomeArqTxt,
String nomeArqComp) throws Exception {
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 98

Generalizao do Clculo dos


Comprimentos dos Cdigos
private void calculaCompCodigo (ItemVoc [ ] A, int n) {
int resto = 0;
i f (n > ( this .baseNum 1)) {
resto = 1 + ((n this .baseNum) % (this .baseNum 1));
i f ( resto < 2) resto = this .baseNum;
}
else resto = n 1;
/ / noInt: Nmero de ns internos
int noInt = 1 + ((n resto ) / ( this .baseNum 1));
int freqn = ( ( Integer )A[n ] . recuperaChave ( ) ) . intValue ( ) ;
for ( int x = (n 1); x >= (n resto + 1 ) ; x) {
int freqx = ( ( Integer )A[ x ] . recuperaChave ( ) ) . intValue ( ) ;
freqn = freqn + freqx ;
}
A[n ] . alteraChave (new Integer ( freqn ) ) ;
/ / Primeira Fase
int raiz = n ; int folha = n resto ; int prox ;
for ( prox = n 1; prox >= (n noInt + 1 ) ; prox) {
/ / Procura Posio
int freqraiz = ( ( Integer )A[ raiz ] . recuperaChave ( ) ) . intValue ( ) ;
i f ( ( folha < 1 ) | | ( ( raiz > prox) &&
( freqraiz <= (( Integer )A[ folha ] . recuperaChave ( ) ) . intValue ( ) ) ) ) {
/ / N interno
A[ prox ] . alteraChave (new Integer ( freqraiz ) ) ;
A[ raiz ] . alteraChave (new Integer ( prox ) ) ; raiz;
}
else { / / N folha
int freqfolha = ( ( Integer )A[ folha ] . recuperaChave ( ) ) . intValue ( ) ;
A[ prox ] . alteraChave (new Integer ( freqfolha ) ) ; folha;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 99

Generalizao do Clculo dos


Comprimentos dos Cdigos
/ / Atualiza Freqncias
for ( int x = 1; x <= (this .baseNum 1); x++) {
freqraiz = ( ( Integer )A[ raiz ] . recuperaChave ( ) ) . intValue ( ) ;
int freqprox = ( ( Integer )A[ prox ] . recuperaChave ( ) ) . intValue ( ) ;
i f ( ( folha < 1 ) | | ( ( raiz > prox) &&
( freqraiz <=((Integer )A[ folha ] . recuperaChave ( ) ) . intValue ( ) ) ) ) {
/ / N interno
A[ prox ] . alteraChave (new Integer ( freqprox + freqraiz ) ) ;
A[ raiz ] . alteraChave (new Integer ( prox ) ) ; raiz;
}
else { / / N folha
int freqfolha = ( ( Integer )A[ folha ] . recuperaChave ( ) ) . intValue ( ) ;
A[ prox ] . alteraChave(new Integer ( freqprox + freqfolha ) ) ; folha;
}
}
}
/ / Segunda Fase
A[ raiz ] . alteraChave (new Integer ( 0 ) ) ;
for ( prox = raiz + 1; prox <= n ; prox++) {
int pai = ( ( Integer )A[ prox ] . recuperaChave ( ) ) . intValue ( ) ;
int profundidadepai = ( ( Integer )A[ pai ] . recuperaChave ( ) ) . intValue ( ) ;
A[ prox ] . alteraChave (new Integer ( profundidadepai + 1));
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 100

Generalizao do Clculo dos


Comprimentos dos Cdigos
/ / Terceira Fase
int disp = 1; int u = 0; int h = 0; prox = 1;
while ( disp > 0) {
while ( ( raiz <= n) &&
( ( ( Integer )A[ raiz ] . recuperaChave ( ) ) . intValue () == h ) ) { u++; raiz ++;}
while ( disp > u) {
A[ prox ] . alteraChave (new Integer (h ) ) ; prox++; disp;
i f ( prox > n ) { u = 0; break ; }
}
disp = this .baseNum u ; h = h + 1; u = 0;
}
}

OBS: baseNum pode ser usada para


trabalharmos com quaisquer bases numricas
menores ou iguais a um byte. Por exemplo, para a
codificao plena o valor 256 e para a
codificao com marcao o valor 128.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 101

Mudanas em Relao ao
Pseudocdigo Apresentado

A mudana maior est no cdigo inserido


antes da primeira fase para eliminar o
problema causado por ns internos da rvore
no totalmente preenchidos.

Na primeira fase, as baseNum rvores de


menor custo so combinadas a cada passo,
em vez de duas como no caso da codificao
binria:
Isso feito pelo anel for introduzido na
parte que atualiza freqncias na primeira
fase.

A segunda fase no sofre alteraes.

A terceira fase recebe a varivel disp para


indicar quantos ns esto disponveis em
cada nvel.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 102

Codificao orientada a bytes


private Codigo codifica ( int ordem, int maxCompCod) {
Codigo cod = new Codigo ( ) ; cod. c = 1;
while ( (cod. c + 1 <= maxCompCod) && (ordem >= this . offset [cod. c + 1]))
cod. c++;
cod. codigo = ordem this . offset [cod. c ] + this .base[cod. c ] ;
return cod;
}

OBS: a codificao orientada a bytes no requer


nenhuma alterao em relao codificao
usando bits
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 103

Decodificao orientada a bytes


private int decodifica ( int maxCompCod) throws Exception {
int logBase2 = ( int ) (Math. log ( this .baseNum) /Math. log ( 2 ) ) ;
int c = 1; int codigo = this .arqComp.read ( ) ;
i f ( codigo < 0) return codigo ; / / Fim de arquivo
i f (logBase2 == 7) codigo = codigo 128; / / Remove o bit de marca-
cao
while ( ( ( c + 1) <= maxCompCod) &&
( ( codigo << logBase2) >= this .base[ c+1])) {
int codigoTmp = this .arqComp.read ( ) ;
codigo = (codigo << logBase2 ) | codigoTmp; c++; }
return ( codigo this .base[ c ] + this . offset [ c ] ) ;
}

Alteraes:

1. Permitir a leitura byte a byte do arquivo


comprimido, em vez de bit a bit. em relao
ao nmero de bits que devem ser deslocados
esquerda para se encontrar o comprimento
c do cdigo, o qual indexa os vetores base e
offset.

2. O nmero de bits que devem ser deslocados


esquerda para se encontrar o comprimento
c, o qualindexa os vetores base e offset,
dado por: log2 BaseNum
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 104

Clculo dos Vetores base e offset

O clculo do vetor offset no requer alterao


alguma.
Para generalizar o clculo do vetor base, basta
substituir o fator 2 por baseNum, como abaixo:
8
<0 se c = 1,
base[c] =
:baseNum (base[c 1] + wc1 ) caso contrrio.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 105

Construo dos Vetores base e offset


private int constroiVetores (ItemVoc A[ ] , int n) throws Exception {
int maxCompCod = ( ( Integer )A[n ] . recuperaChave ( ) ) . intValue ( ) ;
int wcs[ ] = new int [maxCompCod + 1 ] ; / / Ignora a posio 0
this . offset = new int [maxCompCod + 1 ] ; / / Ignora a posio 0
this .base = new int [maxCompCod + 1 ] ; / / Ignora a posio 0
for ( int i = 1; i <= maxCompCod; i ++) wcs[ i ] = 0;
for ( int i = 1; i <= n ; i ++) {
int freq = ( ( Integer )A[ i ] . recuperaChave ( ) ) . intValue ( ) ;
wcs[ freq ]++; this . offset [ freq ] = i wcs[ freq ] + 1;
}
this .base[1] = 0;
for ( int i = 2; i <= maxCompCod; i ++) {
this .base[ i ] = this .baseNum ( this .base[ i 1] + wcs[ i 1]);
i f ( this . offset [ i ] == 0) this . offset [ i ] = this . offset [ i 1];
}
/ / Salvando as tabelas em disco
this .arqComp. writeInt (maxCompCod) ;
for ( int i = 1; i <= maxCompCod; i ++) {
this .arqComp. writeInt ( this .base[ i ] ) ;
this .arqComp. writeInt ( this . offset [ i ] ) ; }
return maxCompCod;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 106

Extrao do prximo smbolo a ser


codificado
package cap8;
import java . u t i l . StringTokenizer ;
import java . io .;
public class ExtraiPalavra {
private BufferedReader arqDelim , arqTxt ;
private StringTokenizer palavras ;
private String delimitadores , palavraAnt , palavra ;
private boolean eDelimitador (char ch ) {
return ( this . delimitadores . indexOf (ch) >= 0);
}
public ExtraiPalavra ( String nomeArqDelim, String nomeArqTxt)
throws Exception {
this .arqDelim = new BufferedReader (new FileReader (nomeArqDelim) ) ;
this . arqTxt = new BufferedReader (new FileReader (nomeArqTxt) ) ;
/ / Os delimitadores devem estar juntos em uma nica linha do arquivo
this . delimitadores = arqDelim. readLine ( ) + " \ r \n" ;
this . palavras = null ; this . palavra = null ; this . palavraAnt = " " ;
}
public String proximaPalavra ( ) throws Exception{
String palavraTemp = " " ; String resultado = " " ;
i f ( this . palavra ! = null ) {
palavraTemp = palavra ; palavra = null ;
palavraAnt = palavraTemp ; return palavraTemp;
}
i f ( palavras == null | | ! palavras .hasMoreTokens ( ) ) {
String linha = arqTxt . readLine ( ) ;
i f ( linha == null ) return null ;
linha += " \n" ;
this . palavras=new StringTokenizer ( linha , this . delimitadores , true ) ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 107

Extrao do prximo smbolo a ser


codificado
String aux = this . palavras .nextToken ( ) ;
while ( eDelimitador (aux. charAt (0)) && palavras .hasMoreTokens ( ) ) {
palavraTemp += aux ; aux = this . palavras .nextToken ( ) ;
}
i f (palavraTemp. length () == 0) resultado = aux;
else {
this . palavra = aux;
i f (palavraTemp. length () == 1 && palavraTemp. equals( " ") &&
palavraAnt . length () > 0 && palavra . length () > 0 &&
! eDelimitador ( palavraAnt . charAt (0)) &&
! eDelimitador ( palavra . charAt ( 0 ) ) )
palavraTemp = palavraTemp. trim ( ) ;
resultado = palavraTemp;
} this . palavraAnt = resultado ; return resultado ;
}
public void fecharArquivos ( ) throws Exception {
this .arqDelim. close ( ) ; this . arqTxt . close ( ) ;
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 108

Classe para representar as


informaes de uma entrada do
vocabulrio
package cap8;
import cap4. Item ; / / vide Programa ??
public class ItemVoc implements Item {
private String palavra ;
private int freq , ordem;
/ / outros componentes do registro
public ItemVoc ( String palavra , int freq , int ordem) {
this . palavra = palavra ;
this . freq = freq ; this .ordem = ordem;
}
public int compara ( Item i t ) {
ItemVoc item = (ItemVoc) i t ;
i f ( this . freq < item . freq ) return 1;
else i f ( this . freq > item . freq ) return 1;
return 0;
}
public void alteraChave ( Object freq ) {
Integer ch = ( Integer ) freq ; this . freq = ch. intValue ( ) ;
}
public Object recuperaChave ( ) { return new Integer ( this . freq ) ; }
public void alteraOrdem ( int ordem) { this .ordem = ordem; }
public int recuperaOrdem ( ) { return this .ordem; }
public String palavra ( ) { return this . palavra ; }
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 109

Cdigo para Fazer a Compresso

O Cdigo para fazer a compresso dividio


em trs etapas:
1. Na primeira, as palavras so extradas do
texto a ser comprimido e suas respectivas
freqncias so contabilizadas.
2. Na segunda, so gerados os vetores base
e offset, os quais so gravados no arquivo
comprimido seguidamente do vocabulrio.
Para delimitar os smbolos do vocabulrio
no disco, cada um deles separado pelo
caractere zero.
3. Na terceira, o arquivo texto percorrido
pela segunda vez, sendo seus smbolos
novamente extrados, codificados e
gravados no arquivo comprimido.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 110

Cdigo para Fazer a Compresso


public void compressao ( String nomeArqTxt,
String nomeArqComp) throws Exception {
this .nomeArqTxt = nomeArqTxt;
this .arqComp = new RandomAccessFile (nomeArqComp, "rws" ) ;
this . primeiraEtapa ( ) ;
int maxCompCod = this .segundaEtapa ( ) ;
this . terceiraEtapa (maxCompCod) ;
this .arqComp. close ( ) ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 111

Primeira etapa da compresso


private void primeiraEtapa ( ) throws Exception {
ExtraiPalavra palavras = new ExtraiPalavra (nomeArqDelim, nomeArqTxt) ;
String palavra = null ;
while ( ( palavra = palavras .proximaPalavra ( ) ) ! = null ) {
/ / O primeiro espao depois da palavra no codificado
i f ( palavra . equals ( " " ) ) continue;
ItemVoc itemVoc = (ItemVoc) this . vocabulario .pesquisa ( palavra ) ;
i f ( itemVoc ! = null ) { / / Incrementa freqncia
int freq = ( ( Integer )itemVoc.recuperaChave ( ) ) . intValue ( ) ;
itemVoc. alteraChave (new Integer ( freq + 1));
} else { / / Insere palavra com freqncia 1
itemVoc = new ItemVoc ( palavra , 1 , 0 ) ;
this . vocabulario . insere ( palavra , itemVoc ) ;
}
}
palavras . fecharArquivos ( ) ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 112

Segunda etapa da compresso


private int segundaEtapa ( ) throws Exception {
ItemVoc A[ ] = this .ordenaPorFrequencia ( ) ;
int n = A. length 1;
this .calculaCompCodigo (A, n) ;
int maxCompCod = this . constroiVetores (A, n) ;
/ / Grava Vocabulrio
this .arqComp. writeInt (n) ;
for ( int i = 1; i <= n ; i ++) {
this .arqComp. writeChars (A[ i ] . palavra ( ) ) ;
this .arqComp. writeChar ( \0 ) ;
A[ i ] . alteraOrdem ( i ) ;
}
return maxCompCod;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 113

Mtodo para ordenar o vocabulrio por


freqncia
O objetivo desse mtodo recuperar as
entradas do vocabulrio, armazen-las
contigamente em um vetor e ordenar o vetor
obtido na ordem no crescente pela
freqncia das palavras no texto.
Para isso, foi criado o operador recuperaItens,
o qual retorna nas posies de 0 a n 1 do
vetor itens as n referncias s entradas do
vocabulrio, as quais so objetos do tipo
ItemVoc.
Recuperados os itens, o mtodo
ordenaPorFrequencia copia as referncias aos
objetos do tipo ItemVoc que representam as
entradas do vocabulrio do vetor aux para as
posies de 1 a n do vetor A.
Por fim, na classe ItemVoc o vetor A
ordenado de forma no crescente por suas
respectivas freqncias de ocorrncia
(Quicksort).
O mtodo ordenaPorFrequencia retorna o
vetor ordenado.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 114

Mtodo para ordenar o vocabulrio por


freqncia
private ItemVoc [ ] ordenaPorFrequencia ( ) {
Object aux[ ] = this . vocabulario . recuperaItens ( ) ;
ItemVoc A[ ] = new ItemVoc[aux. length +1]; / / Ignora a posio 0
for ( int i = 0; i < aux. length ; i ++) A[ i +1] = (ItemVoc)aux[ i ] ;
Ordenacao. quicksort (A, aux. length ) ;
return A;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 115

Operador para recuperar os objetos


contidos em uma tabela hash
public Object [ ] recuperaItens ( ) {
int n = 0;
for ( int i = 0; i < this .M; i ++)
i f ( this . tabela [ i ] ! = null && !this . tabela [ i ] . retirado ) n++;
Object itens [ ] = new Object [n ] ; n = 0;
for ( int i = 0; i < this .M; i ++)
i f ( this . tabela [ i ] ! = null && !this . tabela [ i ] . retirado )
itens [n++] = this . tabela [ i ] . item ;
return itens ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 116

Terceira etapa da compresso


private void terceiraEtapa ( int maxCompCod) throws Exception {
ExtraiPalavra palavras = new ExtraiPalavra (nomeArqDelim, nomeArqTxt) ;
String palavra = null ;
while ( ( palavra = palavras .proximaPalavra ( ) ) ! = null ) {
/ / O primeiro espao depois da palavra no codificado
i f ( palavra . equals ( " " ) ) continue;
ItemVoc itemVoc = (ItemVoc) this . vocabulario .pesquisa ( palavra ) ;
int ordem = itemVoc.recuperaOrdem ( ) ;
Codigo cod = this . codifica (ordem, maxCompCod) ;
this .escreve (cod, maxCompCod) ;
}
palavras . fecharArquivos ( ) ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 117

Mtodo escreve

O mtodo escreve recebe o cdigo e seu


comprimento c em um objeto do tipo Codigo.
O cdigo representado por um inteiro, o que
limita seu comprimento a, no mximo, 4 bytes
em um compilador que usa 4 bytes para
representar inteiros.
Primeiramente, o mtodo escreve extrai o
primeiro byte e, caso o cdigo de Huffman
utilizado seja o de marcao (baseNum =
128), coloca a marcao no oitavo bit,
fazendo uma operao or do byte com a
constante 128.
Esse byte ento colocado na primeira
posio do vetor saida.
No anel while, caso o comprimento c do
cdigo seja maior do que um, os demais
bytes so extrados e armazenados em
saida[i], em que 2 i c.
Por fim, o vetor de bytes saida gravado em
disco no anel for.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 118

Implementao do Mtodo escreve


private void escreve (Codigo cod, int maxCompCod) throws Exception {
int saida [ ] = new int [maxCompCod + 1 ] ; / / Ignora a posio 0
int logBase2 = ( int ) (Math. log ( this .baseNum) /Math. log ( 2 ) ) ;
int mask = ( int )Math.pow ( 2 , logBase2) 1;
int i = 1; int cTmp = cod. c ;
saida [ i ] = cod. codigo >> (logBase2(cod. c 1));
i f (logBase2 == 7) saida [ i ] = saida [ i ] | 1 2 8 ; / / Marcao
i ++; cod. c;
while (cod. c > 0) {
saida [ i ] = (cod. codigo >> (logBase2(cod. c 1))) & mask;
i ++; cod. c;
}
for ( i = 1; i <= cTmp; i ++) this .arqComp. writeByte ( saida [ i ] ) ;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 119

Descrio do Cdigo para Fazer a


Descompresso

O primeiro passo recuperar o modelo usado


na compresso. Para isso, l o alfabeto, o
vetor base, o vetor offset e o vetor vocabulario.

Em seguida, inicia a decodificao, tomando


o cuidado de adicionar um espao em branco
entre dois smbolos que sejam palavras.

O processo de decodificao termina quando


o arquivo comprimido totalmente percorrido.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 120

Cdigo para Fazer a Descompresso


public void descompressao ( String nomeArqTxt,
String nomeArqComp) throws Exception {
this .nomeArqTxt = nomeArqTxt;
this .arqComp = new RandomAccessFile (nomeArqComp, "rws" ) ;
BufferedReader arqDelim = new BufferedReader (
new FileReader ( this .nomeArqDelim) ) ;
BufferedWriter arqTxt = new BufferedWriter (
new FileWriter ( this .nomeArqTxt) ) ;
String delim = arqDelim. readLine ( ) + " \ r \n" ;
int maxCompCod = this . leVetores ( ) ;
String vocabulario [ ] = this . leVocabulario ( ) ;
int ind = 0; String palavraAnt = " " ;
while ( ( ind = this . decodifica (maxCompCod)) >= 0) {
i f ( ! eDelimitador ( delim , palavraAnt . charAt(0)) &&
! eDelimitador ( delim , vocabulario [ ind ] . charAt (0)))
arqTxt . write ( " " ) ;
arqTxt . write ( vocabulario [ ind ] ) ;
palavraAnt = vocabulario [ ind ] ;
}
arqTxt . close ( ) ;
}

OBS: Observe que na descompresso, o


vocabulrio representado por um vetor de
smbolos do tipo String.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 121

Mtodos auxiliares da descompresso


private int leVetores ( ) throws Exception {
int maxCompCod = this .arqComp. readInt ( ) ;
this . offset = new int [maxCompCod + 1 ] ; / / Ignora a posio 0
this .base = new int [maxCompCod + 1 ] ; / / Ignora a posio 0
for ( int i = 1; i <= maxCompCod; i ++) {
this .base[ i ] = this .arqComp. readInt ( ) ;
this . offset [ i ] = this .arqComp. readInt ( ) ;
}
return maxCompCod;
}
private String [ ] leVocabulario ( ) throws Exception{
int n = this .arqComp. readInt ( ) ;
String vocabulario [ ] = new String [n+1]; / / Ignora a posio 0
for ( int i = 1; i <= n ; i ++) {
vocabulario [ i ] = " " ; char ch;
while ( ( ch = this .arqComp.readChar ( ) ) ! = \0 ) {
vocabulario [ i ] += ch;
}
}
return vocabulario ;
}
private boolean eDelimitador ( String delim , char ch ) {
return ( delim . indexOf (ch) >= 0);
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 122

Resultados Experimentais

Mostram que no existe grande degradao


na razo de compresso na utilizao de
bytes em vez de bits na codificao das
palavras de um vocabulrio.

Por outro lado, tanto a descompresso quanto


a pesquisa so muito mais rpidas com uma
codificao de Huffman usando bytes do que
uma codificao de Huffman usando bits, isso
porque deslocamentos de bits e operaes
usando mscaras no so necessrias.

Os experimentos foram realizados em uma


mquina PC Pentium de 200 MHz com 128
megabytes de RAM.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4 123

Resultados Experimentais -
Comparao das tcnicas de
compresso sobre o arquivo WSJ
Dados sobre a coleo usada nos experimentos:

Texto Vocabulrio Vocab./Texto


Tam (bytes) #Palavras Tam (bytes) #Palavras Tamanho #Palavras
262.757.554 42.710.250 1.549.131 208.005 0,59% 0,48%

Razo de Tempo (min) de Tempo (min) de


Mtodo
Compresso Compresso Descompresso
Huffman binrio 27,13 8,77 3,08
Huffman pleno 30,60 8,67 1,95
Huffman com marcao 33,70 8,90 2,02
Gzip 37,53 25,43 2,68
Compress 42,94 7,60 6,78
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 124

Pesquisa em Texto Comprimido

Uma das propriedades mais atraentes do


mtodo de Huffman usando bytes em vez de
bits que o texto comprimido pode ser
pesquisado exatamente como qualquer texto
no comprimido.

Basta comprimir o padro e realizar uma


pesquisa diretamente no arquivo comprimido.

Isso possvel porque o cdigo de Huffman


usa bytes em vez de bits; de outra maneira, o
mtodo seria complicado ou mesmo
impossvel de ser implementado.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 125

Casamento Exato
Algoritmo:
Buscar a palavra no vocabulrio, podendo
usar busca binria nesta fase:
Se a palavra for localizada no vocabulrio,
ento o cdigo de Huffman com marcao
obtido.
Seno a palavra no existe no texto
comprimido.
A seguir, o cdigo pesquisado no texto
comprimido usando qualquer algoritmo para
casamento exato de padro.
Para pesquisar um padro contendo mais de
uma palavra, o primeiro passo verificar a
existncia de cada palavra do padro no
vocabulrio e obter o seu cdigo:
Se qualquer das palavras do padro no
existir no vocabulrio, ento o padro no
existir no texto comprimido.
Seno basta coletar todos os cdigos
obtidos e realizar a pesquisa no texto
comprimido.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 126

Mtodo para realizar busca no arquivo


comprimido
public void busca ( String nomeArqComp) throws Exception {
BufferedReader in = new BufferedReader (
new InputStreamReader (System. in ) ) ;
this .arqComp = new RandomAccessFile (nomeArqComp, "rws" ) ;
int maxCompCod = this . leVetores ( ) ;
String vocabulario [ ] = this . leVocabulario ( ) ;
int codigo ; String T = " " ; String P = " " ;
while ( ( codigo = this .arqComp.read ()) >= 0) T += (char)codigo ;
while ( true ) {
System. out . print ( "Padrao (ou s para sair ) : " ) ; P = in . readLine ( ) ;
i f (P. equals ( "s" ) ) break ; int ord = 1;
for ( ord = 1; ord < vocabulario . length ; ord++)
i f ( vocabulario [ ord ] . equals (P) ) break;
i f ( ord == vocabulario . length ) {
System. out . println ( "Padrao: " + P + " nao encontrado" ) ; continue;
}
Codigo cod = this . codifica ( ord , maxCompCod) ;
String Padrao = this . atribui (cod) ;
CasamentoExato.bmh (T, T. length ( ) , Padrao, Padrao. length ( ) ) ;
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 127

Mtodo para atribuir o cdigo ao


padro
private String atribui (Codigo cod) {
String P = " " ;
P += (char) ( (cod. codigo >> (7(cod. c 1))) | 128);
cod. c;
while (cod. c > 0) {
P += (char) ( (cod. codigo >> (7(cod. c 1))) & 127);
cod. c;
}
return P;
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 128

Programa para teste dos algoritmos de


compresso, descompresso e busca
exata em texto comprimido
package cap8;
import java . io .;
public class Huffman {
private static BufferedReader in = new BufferedReader (
new InputStreamReader (System. in ) ) ;
private static final int baseNum = 128;
private static final int m = 1001;
private static final int maxTamPalavra = 15;
private static void imprime ( String msg) {
System. out . print (msg) ;
}
public static void main ( String [ ] args ) throws Exception {
imprime ( "Arquivo com os delimitadores em uma linha : " ) ;
String nomeArqDelim = in . readLine ( ) ;
String opcao = " " ;
do {
imprime ( "\n" ) ;
imprime ( " Opcoes \n" ) ;
imprime ( "\n " ) ;
imprime ( " (c ) Compressao \n" ) ;
imprime ( " (d) Descompressao \n" ) ;
imprime ( " (p) Pesquisa no texto comprimido \n" ) ;
imprime ( " ( f ) Termina \n" ) ;
imprime ( "\n" ) ;
imprime ( " Opcao: " ) ; opcao = in . readLine ( ) ;
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 129

Programa para teste dos algoritmos de


compresso, descompresso e busca
exata em texto comprimido
i f (opcao.toLowerCase( ) . equals ( "c" ) ) {
imprime ( "Arquivo texto a ser comprimido: " ) ;
String nomeArqTxt = in . readLine ( ) ;
imprime ( "Arquivo comprimido a ser gerado: " ) ;
String nomeArqComp = in . readLine ( ) ;
HuffmanByte huff = new HuffmanByte (nomeArqDelim, baseNum,
m, maxTamPalavra) ;
huff .compressao (nomeArqTxt, nomeArqComp) ;
}
else i f (opcao.toLowerCase( ) . equals ( "d" ) ) {
imprime ( "Arquivo comprimido a ser descomprimido: " ) ;
String nomeArqComp = in . readLine ( ) ;
imprime ( "Arquivo texto a ser gerado: " ) ;
String nomeArqTxt = in . readLine ( ) ;
HuffmanByte huff = new HuffmanByte (nomeArqDelim, baseNum,
m, maxTamPalavra) ;
huff .descompressao (nomeArqTxt, nomeArqComp) ;
}
else i f (opcao.toLowerCase( ) . equals ( "p" ) ) {
imprime ( "Arquivo comprimido para ser pesquisado: " ) ;
String nomeArqComp = in . readLine ( ) ;
HuffmanByte huff = new HuffmanByte ( null , baseNum,
m, maxTamPalavra) ;
huff .busca (nomeArqComp) ;
}
} while ( !opcao.toLowerCase( ) . equals ( " f " ) ) ;
}
}
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 130

Casamento Aproximado
Algoritmo:

Pesquisar o padro no vocabulrio. Neste


caso, podemos ter:
Casamento exato, o qual pode ser uma
pesquisa binria no vocabulrio, e uma
vez que a palavra tenha sido encontrada a
folha correspondente na rvore de
Huffman marcada.
Casamento aproximado, o qual pode ser
realizado por meio de pesquisa seqencial
no vocabulrio, usando o algoritmo
Shift-And.
Neste caso, vrias palavras do vocabulrio
podem ser encontradas e a folha
correspondente a cada uma na rvore de
Huffman marcada.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 131

Casamento Aproximado
Algoritmo (Continuao):

A seguir, o arquivo comprimido lido byte a


byte, ao mesmo tempo que a rvore de
decodificao de Huffman percorrida
sincronizadamente.

Ao atingir uma folha da rvore:


se ela estiver marcada, ento existe
casamento com a palavra do padro.

Seja uma folha marcada ou no, o


caminhamento na rvore volta raiz ao
mesmo tempo que a leitura do texto
comprimido continua.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 132

Esquema geral de pesquisa para a


palavra uma permitindo 1 erro

ama

puma

uma
umas
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 133

Casamento Aproximado Usando uma


Frase como Padro

Frase: seqncia de padres (palavras), em


que cada padro pode ser desde uma palavra
simples at uma expresso regular complexa
permitindo erros.

Pr-Processamento:

Se uma frase tem j palavras, ento uma


mscara de j bits colocada junto a cada
palavra do vocabulrio (folha da rvore de
Huffman).

Para uma palavra x da frase, o i-simo bit da


mscara feito igual a 1 se x a i-sima
palavra da frase.

Assim, cada palavra i da frase pesquisada


no vocabulrio e a i-sima posio da
mscara marcada quando a palavra
encontrada no vocabulrio.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 134

Casamento Aproximado Usando uma


Frase como Padro
Leitura do Texto Comprimido:
O estado da pesquisa controlado por um
autmato finito no-determinista de j + 1
estados.
O autmato permite mover do estado i para o
estado i + 1 sempre que a i-sima palavra da
frase reconhecida.
O estado zero est sempre ativo e uma
ocorrncia relatada quando o estado j
ativado.
Os bytes do texto comprimido so lidos e a
rvore de Huffman percorrida como antes.
Cada vez que uma folha da rvore atingida,
sua mscara de bits enviada para o
autmato.
Um estado ativo i 1 ir ativar o estado i
apenas se o i-simo bit da mscara estiver
ativo.
Conseqentemente, o autmato realiza uma
transio para cada palavra do texto.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 135

Esquema geral de pesquisa para a


frase uma ro* rosa

rosa 011
roupa 010 XXX

azul 000

1XX X1X XX1


uma 100
rosas 011

O autmato pode ser implementado


eficientemente por meio do algoritmo
Shift-And
Separadores podem ser ignorados na
pesquisa de frases.
Da mesma maneira, os artigos, preposies
etc., tambm podem ser ignorados se for
conveniente.
Neste caso, basta ignorar as folhas
correspondentes na rvore de Huffman
quando a pesquisa chega a elas.
raro encontrar esta possibilidade em
sistemas de pesquisa on-line.
Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5 136

Tempos de pesquisa (em segundos)


para o arquivo WSJ, com intervalo de
confiana de 99%

Algoritmo k=0 k=1 k=2 k=3


Agrep 23,8 0,38 117,9 0,14 146,1 0,13 174,6 0,16
Pesquisa direta 14,1 0,18 15,0 0,33 17,0 0,71 22,7 2,23
Pesquisa com autmato 22,1 0,09 23,1 0,14 24,7 0,21 25,0 0,49
Problemas
N P-Completo e
Algoritmos
Aproximados

ltima alterao: 10 de Outubro de 2006

Transparncias elaboradas por Charles Ornelas, Leonardo Rocha, Leonardo


Mata, Elisa Tuler e Nivio Ziviani
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados 1

Introduo
Problemas intratveis ou difceis so comuns
na natureza e nas reas do conhecimento.
Problemas fceis: resolvidos por algoritmos
polinomiais.
Problemas difceis: somente possuem
algoritmos exponenciais para resolv-los.
A complexidade de tempo da maioria dos
problemas polinomial ou exponencial.
Polinomial: funo de complexidade
O(p(n)), em que p(n) um polinmio.
Ex.: algoritmos com pesquisa binria
(O(log n)), pesquisa sequencial (O(n)),
ordenao por insero (O(n2 )), e
multiplicao de matrizes (O(n3 )).
Exponencial: funo de complexidade
O(cn ), c > 1.
Ex.: problema do caixeiro-viajante
(PCV) (O(n!)).
Mesmo problemas de tamanho pequeno a
moderado no podem ser resolvidos por
algoritmos no-polinomiais.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 2

Problemas N P-Completo

A teoria de complexidade a ser apresentada


no mostra como obter algoritmos polinomiais
para problemas que demandam algoritmos
exponenciais, nem afirma que no existem.

possvel mostrar que os problemas para os


quais no h algoritmo polinomial conhecido
so computacionalmente relacionados.

Formam a classe conhecida como N P.

Propriedade: um problema da classe N P


poder ser resolvido em tempo polinomial se
e somente se todos os outros problemas em
N P tambm puderem.

Este fato um indcio forte de que dificilmente


algum ser capaz de encontrar um algoritmo
eficiente para um problema da classe N P.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 3

Classe N P - Problemas Sim/No

Para o estudo terico da complexidade de


algoritmos considera-se problemas cujo
resultado da computao seja sim ou no.

Verso do Problema do Caixeiro-Viajante


(PCV) cujo resultado do tipo sim/no:
Dados: uma constante k, um conjunto de
cidades C = {c1 , c2 , , cn } e uma
distncia d(ci , cj ) para cada par de cidades
ci , cj C.
Questo: Existe um roteiro para todas as
cidades em C cujo comprimento total seja
menor ou igual a k?

Caracterstica da classe N P: problemas


sim/no para os quais uma dada soluo
pode ser verificada facilmente.

A soluo pode ser muito difcil ou impossvel


de ser obtida, mas uma vez conhecida ela
pode ser verificada em tempo polinomial.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 4

Caminho em um Grafo

Considere um grafo com peso nas arestas,


dois vrtices i, j e um inteiro k > 0.
5 12 j

2 7 9 10 13

11 5 1
3 2 8 3

i 7 3

Fcil: Existe um caminho de i at j com peso


k?.
H um algoritmo eficiente com
complexidade de tempo O(A log V ), sendo
A o nmero de arestas e V o nmero de
vrtices (algoritmo de Dijkstra).

Difcil: Existe um caminho de i at j com


peso k?
No existe algoritmo eficiente.
equivalente ao PCV em termos de
complexidade.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 5

Colorao de um Grafo

Em um grafo G = (V, A), mapear C : V S,


sendo S um conjunto finito de cores tal que se
vw A ento c(v) 6= c(w) (vrtices adjacentes
possuem cores distintas).

O nmero cromtico X(G) de G o menor


nmero de cores necessrio para colorir G,
isto , o menor k para o qual existe uma
colorao C para G e |C(V )| = k.

O problema produzir uma colorao tima,


que a que usa apenas X(G) cores.

Formulao do tipo sim/no: dados G e um


inteiro positivo k, existe uma colorao de G
usando k cores?
Fcil: k = 2.
Difcil: k > 2.

Aplicao: modelar problemas de


agrupamento (clustering) e de horrio
(scheduling).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 6

Colorao de um Grafo - Otimizao


de Compiladores

Escalonar o uso de um nmero finito de


registradores (idealmente com o nmero
mnimo).

No trecho de programa a ser otimizado, cada


varivel tem intervalos de tempo em que seu
valor tem de permanecer inalterado, como
depois de inicializada e antes do uso final.

Variveis com interseo nos tempos de vida


til no podem ocupar o mesmo registrador.

Modelagem por grafo: vrtices representam


variveis e cada aresta liga duas variveis
que possuem interseo nos tempos de vida.

Colorao dos vrtices: atibui cada varivel a


um agrupamento (ou classe). Duas variveis
com a mesma cor no colidem, podendo
assim ser atribudas ao mesmo registrador.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 7

Colorao de um Grafo - Otimizao


de Compiladores

Evidentemente, no existe conflito se cada


vrtice for colorido com uma cor distinta.

O objetivo porm encontrar uma colorao


usando o mnimo de cores (computadores
tm um nmero limitado de registradores).

Nmero cromtico: menor nmero de cores


suficientes para colorir um grafo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 8

Colorao de um Grafo - Problema de


Horrio

Suponha que os exames finais de um curso


tenham de ser realizados em uma nica
semana.

Disciplinas com alunos de cursos diferentes


devem ter seus exames marcados em
horrios diferentes.

Dadas uma lista de todos os cursos e outra


lista de todas as disciplinas cujos exames no
podem ser marcados no mesmo horrio, o
problema em questo pode ser modelado
como um problema de colorao de grafos.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 9

Ciclo de Hamilton

Ciclo de Hamilton: ciclo simples (passa por


todos os vrtices uma nica vez).

Caminho de Hamilton: caminho simples


(passa por todos os vrtices uma nica vez).

Exemplo de ciclo de Hamilton: 0 1 4 2 3 0.


Exemplo de caminho de Hamilton: 0 1 4 2 3.
0 1

3 2

Existe um ciclo de Hamilton no grafo G?


Fcil: Grafos com grau mximo = 2
(vrtices com no mximo duas arestas
incidentes).
Difcil: Grafos com grau > 2.

um caso especial do PCV. Pares de


vrtices com uma aresta entre eles tem
distncia 1 e pares de vrtices sem aresta
entre eles tm distncia infinita.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1 10

Cobertura de Arestas
Uma cobertura de arestas de um grafo
G = (V, A) um subconjunto A0 A de k
arestas tal que todo v V parte de pelo
menos uma aresta de A0 .
O conjunto resposta para k = 4
A0 = {(0, 3), (2, 3), (4, 6), (1, 5)}.
0 1

3 4 5

2 6

Uma cobertura de vrtices um


subconjunto V 0 V tal que se (u, v) A
ento u V 0 ou v V 0 , isto , cada aresta do
grafo incidente em um dos vrtices de V 0 .
Na figura, o conjunto resposta V 0 = {3, 4, 5},
para k = 3.
Dados um grafo e um inteiro k > 0
Fcil: h uma cobertura de arestas k?.
Difcil: h uma cobertura de vrtices k?
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 11

Algoritmos No-Deterministas

Algoritmos deterministas: o resultado de


cada operao definido de forma nica.

Em um arcabouo terico, possvel remover


essa restrio.

Apesar de parecer irreal, este um conceito


importante e geralmente utilizado para definir
a classe N P.

Neste caso, os algoritmos podem conter


operaes cujo resultado no definido de
forma nica.

Algorimo no-determinista: capaz de


escolher uma dentre as vrias alternativas
possveis a cada passo.

Algoritmos no-deterministas contm


operaes cujo resultado no unicamente
definido, ainda que limitado a um conjunto
especificado de possibilidades.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 12

Funo escolhe(C)

Algoritmos no-deterministas utilizam uma


funo escolhe(C), que escolhe um dos
elementos do conjunto C de forma arbitrria.

O comando de atribuio X escolhe (1:n)


pode resultar na atribuio a X de qualquer
dos inteiros no intervalo [1, n].

A complexidade de tempo para cada


chamada da funo escolhe O(1).

Neste caso, no existe nenhuma regra


especificando como a escolha realizada.

Se um conjunto de possibilidades levam a


uma resposta, este conjunto escolhido
sempre e o algoritmo terminar com sucesso.

Em contrapartida, um algoritmo
no-determinista termina sem sucesso se e
somente se no h um conjunto de escolhas
que indique sucesso.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 13

Comandos sucesso e insucesso

Algoritmos no-deterministas utilizam


tambm dois comandos, a saber:
insucesso: indica trmino sem sucesso.
sucesso: indica trmino com sucesso.

Os comandos insucesso e sucesso so


usados para definir uma execuo do
algoritmo.

Esses comandos so equivalentes a um


comando de parada de um algoritmo
determinista.

Os comandos insucesso e sucesso tambm


tm complexidade de tempo O(1).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 14

Mquina No-Determinista

Uma mquina capaz de executar a funo


escolhe admite a capacidade de
computao no-determinista.

Uma mquina no-determinista capaz de


produzir cpias de si mesma quando diante
de duas ou mais alternativas, e continuar a
computao independentemente para cada
alternativa.

A mquina no-determinista que acabamos


de definir no existe na prtica, mas ainda
assim fornece fortes evidncias de que certos
problemas no podem ser resolvidos por
algoritmos deterministas em tempo
polinomial, conforme mostrado na definio
da classe N P-completo frente.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 15

Pesquisa No-Determinista

Pesquisar o elemento x em um conjunto de


elementos A[1 : n], n 1.

void pesquisaND ( x , A, 1 , n) {
j escolhe (A, 1 , n) ;
i f (A[ j ] == x ) sucesso ; else insucesso ;
}

Determina um ndice j tal que A[j] = x para


um trmino com sucesso ou ento insucesso
quando x no est presente em A.

O algoritmo tem complexidade


no-determinista O(1).

Para um algoritmo determinista a


complexidade O(n).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 16

Ordenao No-Determinista

Ordenar um conjunto A[1 : n] contendo n


inteiros positivos, n 1.

void ordenaND (A, 1 , n) {


for ( int i = 1; i <= n ; i ++) B[ i ] = 0;
for ( int i = 1; i <= n ; i ++) {
j escolhe (A, 1 , n) ;
i f (B[ j ] == 0) B[ j ] = A[ i ] ; else insucesso ;
}
}

Um vetor auxiliar B[1:n] utilizado. Ao final, B


contm o conjunto em ordem crescente.

A posio correta em B de cada inteiro de A


obtida de forma no-determinista pela
funo escolhe.

Em seguida, o comando de deciso verifica


se a posio B[j] ainda no foi utilizada.

A complexidade O(n). (Para um algoritmo


determinista a complexidade O(n log n))
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 17

Problema da Satisfabilidade

Considere um conjunto de variveis


booleanas x1 , x2 , , xn , que podem assumir
valores lgicos verdadeiro ou falso.

A negao de xi representada por xi .

Expresso booleana: variveis booleanas e


operaes ou () e e (). (tambm chamadas
respectivamente de adio e multiplicao).

Uma expresso booleana E contendo um


produto de adies de variveis booleanas
dita estar na forma normal conjuntiva.

Dada E na forma normal conjuntiva, com


variveis xi , 1 i n, existe uma atribuio
de valores verdadeiro ou falso s variveis
que torne E verdadeira (satisfaa)?

E1 = (x1 x2 ) (x1 x3 x2 ) (x3 )


satisfatvel (x1 = F , x2 = V , x3 = V ).

A expresso E2 = x1 x1 no satisfatvel.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1 18

Problema da Satisfabilidade

O algoritmo avalND(E, n) verifica se uma


expresso E na forma normal conjuntiva, com
variveis xi , 1 i n, satisfatvel.

void avalND (E, n) {


for ( int i = 1; i <= n ; i ++) {
xi escolhe ( true , false ) ;
i f ( E(x1 , x2 , , xn ) == true ) sucesso ; else insucesso ;
}
}

O algoritmo obtm uma das 2n atribuies


possveis de forma no-determinista em O(n).

Melhor algoritmo determinista: O(2n ).

Aplicao: definio de circuitos eltricos


combinatrios que produzam valores lgicos
como sada e sejam constitudos de portas
lgicas e, ou e no.

Neste caso, o mapeamento direto, pois o


circuito pode ser descrito por uma expresso
lgica na forma normal conjuntiva.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 19

Caracterizao das Classes P e N P

P: conjunto de todos os problemas que


podem ser resolvidos por algoritmos
deterministas em tempo polinomial.

N P: conjunto de todos os problemas que


podem ser resolvidos por algoritmos
no-deterministas em tempo polinomial.

Para mostrar que um determinado problema


est em N P, basta apresentar um algoritmo
no-determinista que execute em tempo
polinomial para resolver o problema.

Outra maneira encontrar um algoritmo


determinista polinomial para verificar que uma
dada soluo vlida.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 20

Existe Diferena entre P e N P?


P N P, pois algoritmos deterministas so
um caso especial dos no-deterministas.
A questo se P = N P ou P =
6 N P.
Esse o problema no resolvido mais famoso
que existe na rea de cincia da computao.
Se existem algoritmos polinomiais
deterministas para todos os problemas em
N P, ento P = N P.
Em contrapartida, a prova de que P =6 NP
parece exigir tcnicas ainda desconhecidas.
Descrio tentativa do mundo N P:

NP

Acredita-se que N P  P, pois para muitos


problemas em N P, no existem algoritmos
polinomiais conhecidos, nem um limite
inferior no-polinomial provado.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 21

N P P ou N P = P? - Conseqncias

Muitos problemas prticos em N P podem ou


no pertencer a P (no conhecemos nenhum
algoritmo determinista eficiente para eles).

Se conseguirmos provar que um problema


no pertence a P, ento temos um indcio de
que esse problema pertence a N P e que
esse problema to difcil de ser resolvido
quanto outros problemas N P.

Como no existe tal prova, sempre h


esperana de que algum descubra um
algoritmo eficiente.

Quase ningum acredita que N P = P.

Existe um esforo considervel para provar o


contrrio, mas a questo continua em aberto!
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 22

Transformao Polinomial

Sejam 1 e 2 dois problemas sim/no.

Suponha que um algoritmo A2 resolva 2 .

Se for possvel transformar 1 em 2 e a


soluo de 2 em soluo de 1 , ento A2
pode ser utilizado para resolver 1 .

Se pudermos realizar as transformaes nos


dois sentidos em tempo polinomial, ento 1
polinomialmente transformvel em 2 .

Dados Dados Soluo Soluo


de 1 de 2 para 2 para 1

Transformao Algoritmo A 2
Transformao
Polinomial Polinomial

Esse conceito importante para definir a


classe N P-completo.

Para apresentar um exemplo de


transformao polinomial vamos necessitar
das definies de conjunto independente de
vrtices e clique de um grafo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 23

Conjunto Independente de Vrtices de


um Grafo

O conjunto independente de vrtices de um


grafo G = (V, A) constitudo do subconjunto
V 0 V , tal que v, w V 0 (v, w)
/ A.

Todo par de vrtices de V 0 no adjacente


(V 0 um subgrafo totalmente desconectado).

Exemplo de cardinalidade 4: V 0 = {0, 2, 1, 6}.

0 1

3 4 5

2 6
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 24

Conjunto Independente de Vrtices -


Aplicao

Em problemas de disperso necessrio


encontrar grandes conjuntos independentes
de vrtices. Procura-se um conjunto de
pontos mutuamente separados.

Exemplo: identificar localizaes para


instalao de franquias.

Duas localizaes no podem estar perto o


suficiente para competir entre si.

Soluo: construir um grafo em que possveis


localizaes so representadas por vrtices,
e arestas so criadas entre duas localizaes
que esto prximas o suficiente para interferir.

O maior conjunto independente fornece o


maior nmero de franquias que podem ser
concedidas sem prejudicar as vendas.

Em geral, cunjuntos independentes evitam


conflitos entre elementos.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 25

Clique de um grafo

Clique de um grafo G = (V, A) constitudo


do subconjunto V 0 V , tal que
v, w V 0 (v, w) A.

Todo par de vrtices de V 0 adjacente (V 0


um subgrafo completo).

Exemplo de cardinalidade 3: V 0 = {3, 1, 4}.

0 1

3 4 5

2 6
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 26

Clique de um grafo - Aplicao

O problema de identificar agrupamentos de


objetos relacionados freqentemente se
reduz a encontrar grandes cliques em grafos.

Exemplo: empresa de fabricao de peas


por meio de injeo plstica que fornece para
diversas outras empresas montadoras.

Para reduzir o custo relativo ao tempo de


preparao das mquinas injetoras, pode-se
aumentar o tamanho dos lotes produzidos
para cada pea encomendada.

preciso identificar os clientes que adquirem


os mesmos produtos, para negociar prazos
de entrega comuns e assim aumentar o
tamanho dos lotes produzidos.

Soluo: construir um grafo com cada vrtice


representando um cliente e ligar com uma
aresta os que adquirem os mesmos produtos.

Um clique no grafo representa o conjunto de


clientes que adquirem os mesmos produtos.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 27

Transformao Polinomial

Considere 1 o problema clique e 2 o


problema conjunto independente de vrtices.

A instncia I de clique consiste de um grafo


G = (V, A) e um inteiro k > 0.

A instncia f (I) de conjunto independente


pode ser obtida considerando-se o grafo
complementar G de G e o mesmo inteiro k.

f (I) uma transformao polinomial:


1. G pode ser obtido a partir de G em tempo
polinomial.
2. G possui clique de tamanho k se e
somente se G possui conjunto
independente de vrtices de tamanho k.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 28

Transformao Polinomial

Se existe um algoritmo que resolve o conjunto


independente em tempo polinomial, ele pode
ser utilizado para resolver clique tambm em
tempo polinomial.

Diz-se que clique conjunto independente.

Denota-se 1 2 para indicar que 1


polinomialmente transformvel em 2 .

A relao transitiva (1 2 e
2 3 1 3 ).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 29

Problemas N P-Completo e N P-Difcil

Dois problemas 1 e 2 so
polinomialmente equivalentes se e
somente se 1 2 e 2 1 .

Exemplo: problema da satisfabilidade. Se


SAT 1 e 1 2 , ento SAT 2 .

Um problema N P-difcil se e somente se


SAT (satisfabilidade redutvel a ).

Um problema de deciso denominado


N P-completo quando:
1. N P ;.
2. Todo problema de deciso 0
N P-completo satisfaz 0 .
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 30

Problemas N P-Completo e N P-Difcil

Um problema de deciso que seja


N P-difcil pode ser mostrado ser
N P-completo exibindo um algoritmo
no-determinista polinomial para .

Apenas problemas de deciso (sim/no)


podem ser N P-completo.

Problemas de otimizao podem ser


N P-difcil, mas geralmente, se 1 um
problema de deciso e 2 um problema de
otimizao, bem possvel que 1 2 .

A dificuldade de um problema N P-difcil no


menor do que a dificuldade de um problema
N P-completo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 31

Exemplo - Problema da Parada

um exemplo de problema N P-difcil que


no N P-completo.

Consiste em determinar, para um algoritmo


determinista qualquer A com entrada de
dados E, se o algoritmo A termina (ou entra
em um loop infinito).

um problema indecidvel. No h algoritmo


de qualquer complexidade para resolv-lo.

Mostrando que SAT problema da parada:


Considere o algoritmo A cuja entrada
uma expresso booleana na forma normal
conjuntiva com n variveis.
Basta tentar 2n possibilidades e verificar
se E satisfatvel.
Se for, A pra; seno, entra em loop.
Logo, o problema da parada N P-difcil,
mas no N P-completo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 32

Teorema de Cook
Existe algum problema em N P tal que se ele
for mostrado estar em P, implicaria P = N P?
Teorema de Cook: Satisfabilidade (SAT) est
em P se e somente se P = N P.
Ou seja, se existisse um algoritmo polinomial
determinista para satisfabilidade, ento todos
os problemas em N P poderiam ser
resolvidos em tempo polinomial.
A prova considera os dois sentidos:
1. SAT est em N P (basta apresentar um
algoritmo no-determinista que execute
em tempo polinomial). Logo, se P = N P,
ento SAT est em P.
2. Se SAT est em P, ento P = N P. A
prova descreve como obter de qualquer
algoritmo polinomial no determinista de
deciso A, com entrada E, uma frmula
Q(A, E) de modo que Q satisfatvel se e
somente se A termina com sucesso para
E. O tempo necessrio para construir Q
O(p3 (n) log(n)), em que n o tamanho de
E e p(n) a complexidade de A.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 33

Prova do Teorema de Cook


A prova, bastante longa, mostra como
construir Q a partir de A e E.
A expresso booleana Q longa, mas pode
ser construda em tempo polinomial no
tamanho de E.
Prova usa definio matemtica da Mquina
de Turing no-determinista (MTND), capaz
de resolver qualquer problema em N P.
incluindo uma descrio da mquina e de
como instrues so executadas em
termos de frmulas booleanas.
Estabelece uma correspondncia entre todo
problema em N P (expresso por um programa
na MTnd) e alguma instncia de SAT.
Uma instncia de SAT corresponde
traduo do programa em uma frmula
booleana.
A soluo de SAT corresponde simulao
da mquina executando o programa em cima
da frmula obtida, o que produz uma soluo
para uma instncia do problema inicial dado.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 34

Prova de que um Problema


N P-Completo

So necessrios os seguintes passos:


1. Mostre que o problema est em N P.
2. Mostre que um problema N P-completo
conhecido pode ser polinomialmente
transformado para ele.

possvel porque Cook apresentou uma


prova direta de que SAT N P-completo,
alm do fato de a reduo polinomial ser
transitiva (SAT 1 & 1 2
SAT 2 ).

Para ilustrar como um problema pode ser


provado ser N P-completo, basta considerar
um problema j provado ser N P-completo e
apresentar uma reduo polinomial desse
problema para .
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 35

PCV N P-completo - Parte 1 da Prova

Mostrar que o Problema do Caixeiro-Viajante


(PCV) est em N P.

Prova a partir do problema ciclo de


Hamilton, um dos primeiros que se provou
ser N P-completo.

Isso pode ser feito:


apresentando (como abaixo) um algoritmo
no-determinista polinomial para o PCV ou
mostrando que, a partir de uma dada
soluo para o PCV, esta pode ser
verificada em tempo polinomial.

void PCVND ( ) {
i = 1;
for ( int t = 1; t <= v ; t ++) {
j escolhe( i , lista_adj ( i ) ) ;
antecessor [ j ] = i ;
}
}
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 36

PCV N P-completo - Parte 2 da Prova

Apresentar uma reduo polinomial do ciclo


de Hamilton para o PCV.

Pode ser feita conforme o exemplo abaixo.

2 2
1 1
1 2 1 2
1 1
1 1
1 5 1 5 2
1 1
1 1
4 3 4 3
1 1

Dado um grafo representando uma instncia


do ciclo de Hamilton, construa uma instncia
do PCV como se segue:
1. Para cidades use os vrtices.
2. Para distncias use 1 se existir um arco no
grafo original e 2 se no existir.

A seguir, use o PCV para achar um roteiro


menor ou igual a V .

O roteiro o ciclo de Hamilton.


Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 37

Classe N P-Intermediria

Segunda descrio tentativa do mundo N P,


assumindo P =
6 N P.

NP
NPC
NPI
P

Existe uma classe intermediria entre P e


N P chamada N PI.

N PI seria constituda por problemas nos


quais ningum conseguiu uma reduo
polinomial de um problema N P-completo
para eles, onde N PI = N P -
(P N P-completo).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 38

Membros Potenciais de N PI

Isomorfismo de grafos: Dados G = (V, E) e


G0 = (V, E 0 ), existe uma funo f : V V , tal
que (u, v) E (f (u), f (v)) E 0 ?
Isomorfismo o problema de testar se
dois grafos so o mesmo.
Suponha que seja dado um conjunto de
grafos e que alguma operao tenha de
ser realizada sobre cada grafo.
Se pudermos identificar quais grafos so
duplicatas, eles poderiam ser descartados
para evitar trabalho redundante.

Nmeros compostos: Dado um inteiro


positivo k, existem inteiros m, n > 1 tais que
k = mn?
Princpio da criptografia RSA: fcil
encontrar nmeros primos grandes, mas
difcil fatorar o produto de dois deles.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2 39

Classe N P-Completo - Resumo

Problemas que pertencem a N P, mas que


podem ou no pertencer a P.

Propriedade: se qualquer problema


N P-completo puder ser resolvido em tempo
polinomial por uma mquina determinista,
ento todos os problemas da classe podem,
isto , P = N P.

A falha coletiva de todos os pesquisadores


para encontrar algoritmos eficientes para
estes problemas pode ser vista como uma
dificuldade para provar que P = N P.

Contribuio prtica da teoria: fornece um


mecanismo que permite descobrir se um
novo problema fcil ou difcil.

Se encontrarmos um algoritmo eficiente para


o problema, ento no h dificuldade. Seno,
uma prova de que o problema
N P-completo nos diz que o problema to
difcil quanto todos os outros problemas
difceis da classe N P-completo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2 40

Problemas Exponenciais
desejvel resolver instncias grandes de
problemas de otimizao em tempo razovel.
Os melhores algoritmos para problemas
N P-completo tm comportamento de pior
caso exponencial no tamanho da entrada.
Para um algoritmo que execute em tempo
proporcional a 2N , no garantido obter
resposta para todos os problemas de
tamanho N 100.
Independente da velocidade do computador,
ningum poderia esperar por um algoritmo
que leva 2100 passos para terminar sua tarefa.
Um supercomputador poderia resolver um
problema de tamanho N = 50 em 1 hora, ou
N = 51 em 2 horas, ou N = 59 em um ano.
Mesmo um computador paralelo contendo um
milho de processadores, (sendo cada
processador um milho de vezes mais rpido
que o melhor processador que possa existir)
no seria suficiente para chegar a N = 100.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2 41

O Que Fazer para Resolver Problemas


Exponenciais?

Usar algoritmos exponenciais eficientes


aplicando tcnicas de tentativa e erro.

Usar algoritmos aproximados. Acham uma


resposta que pode no ser a soluo tima,
mas garantido ser prxima dela.

Concentrar no caso mdio. Buscar algoritmos


melhores que outros neste quesito e que
funcionem bem para as entradas de dados
que ocorrem usualmente na prtica.
Existem poucos algoritmos exponenciais
que so muito teis na prtica.
Exemplo: Simplex (programao linear).
Complexidade de tempo exponencial no
pior caso, mas muito rpido na prtica.
Tais exemplos so raros. A grande maioria
dos algoritmos exponenciais conhecidos
no muito til.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 42

Ciclo de Hamilton - Tentativa e Erro

Ex.: encontrar um ciclo de Hamilton em um


grafo.

Obter algoritmo tentativa e erro a partir de


algoritmo para caminhamento em um grafo.

O algoritmo para caminhamento em um grafo


faz uma busca em profundidade no grafo em
tempo O(|V | + |A|).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 43

Ciclo de Hamilton - Tentativa e Erro

package cap9;
import cap7. matrizadj .Grafo;
public class BuscaEmProfundidade {
private int d [ ] ;
private Grafo grafo ;
public BuscaEmProfundidade ( Grafo grafo ) {
this . grafo = grafo ; int n = this . grafo .numVertices ( ) ;
d = new int [n ] ; }
private int visita ( int u, int tempo) {
this .d[u] = ++tempo;
i f ( ! this . grafo . listaAdjVazia (u ) ) {
Grafo. Aresta a = this . grafo . primeiroListaAdj (u) ;
while (a ! = null ) {
int v = a.v2 ( ) ;
i f ( this .d[ v] == 0) tempo = this . visita ( v , tempo) ;
a = this . grafo . proxAdj (u) ; }
}
return tempo;
}
public void buscaEmProfundidade ( ) {
int tempo = 0;
for ( int u = 0; u < grafo .numVertices ( ) ; u++)
this .d[u] = 0;
this . visita ( 0 , tempo) ;
}
}
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 44

Ciclo de Hamilton - Tentativa e Erro

O mtodo visita, quando aplicado ao grafo


abaixo a partir do vrtice 0, obtm o caminho
0 1 2 4 3 5 6, o qual no um ciclo simples.

1 2 3 4 5 6
0
2 6 0 1 2 6
1
1 1 2 4
1 3 2 1
5 1 2 6 2 4
2 4
4 3 2 1
2 1
4 4 2 1
5

Para encontrar um ciclo de Hamilton, caso


exista, devemos visitar os vrtices do grafo de
outras maneiras.

A rigor, o melhor algoritmo conhecido resolve


o problema tentando todos os caminhos
possveis.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 45

Ciclo de Hamilton - Tentando Todas as


Possibilidades
Para tentar todas as possibilidades, vamos
alterar o mtodo Visita.
Desmarca o vrtice j visitado no caminho
anterior e permite que seja visitado
novamente em outra tentativa.

private int visita ( int u, int tempo) {


this .d[u] = ++tempo;
i f ( ! this . grafo . listaAdjVazia (u ) ) {
Grafo. Aresta a = this . grafo . primeiroListaAdj (u) ;
while (a ! = null ) {
int v = a.v2 ( ) ;
i f ( this .d[ v] == 0) tempo = this . visita ( v , tempo) ;
a = this . grafo . proxAdj (u) ; }
}
tempo; this .d[u] = 0;
return tempo;
}

O custo proporcional ao nmero de


chamadas para o mtodo Visita.
Para um grafo completo, (arestas ligando
todos os pares de ns) existem N ! ciclos
simples. Custo proibitivo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 46

Ciclo de Hamilton - Tentando Todas as


Possibilidades

Para o grafo

0
2 6
1
1 3 2 1
5 1 2 6
2 4
4
2 1
4

A rvore de caminhamento :

1 5 6

2 3 4 3 4 4

4 4 5 2 3 5 6 1 4 1 2 3 6 1 2 3 5

3 5 6 2 5 6 4 5 3 2 4 1 2 6 2 3 1 1 2 3 1 1 5 3

5 3 2 6 4 2 6 2 1 3 2 5 3 2 1

6 5 2

0 0

Existem duas respostas: 0 5 3 1 2 4 6 0 e


0 6 4 2 1 3 5 0.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 47

Ciclo de Hamilton - Tentativa e Erro


com Poda
Diminuir nmero de chamadas a Visita
fazendo poda na rvore de caminhamento.
No exemplo anterior, cada ciclo obtido duas
vezes, caminhando em ambas as direes.
Insistindo que o n 2 aparea antes do 0 e do
1, no precisamos chamar Visita para o n 1
a no ser que o n 2 j esteja no caminho.
rvore de caminhamento obtida:
0

5 6

3 4 4

4 2 3 6 2 3 5

2 6 1 1 5 3

1 3 3

0
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 48

Ciclo de Hamilton - Tentativa e Erro


com Poda

Entretanto, esta tcnica no sempre


possvel de ser aplicada.

Suponha que se queira um caminho de custo


mnimo que no seja um ciclo e passe por
todos os vrtices: 0 6 4 5 3 1 2 soluo.

Neste caso, a tcnica de eliminar simetrias


no funciona porque no sabemos a priori se
um caminho leva a um ciclo ou no.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1 49

Ciclo de Hamilton - Branch-and-Bound

Outra sada para tentar diminuir o nmero de


chamadas a Visita por meio da tcnica de
branch-and-bound.

A ideia cortar a pesquisa to logo se saiba


que no levar a uma soluo.

Corta chamadas a Visita to logo se chegue a


um custo para qualquer caminho que seja
maior que um caminho soluo j obtido.

Exemplo: encontrando 0 5 3 1 2 4 6, de custo


11, no faz sentido continuar no caminho 0 6
4 1, de custo 11 tambm.

Neste caso, podemos evitar chamadas a


Visita se o custo do caminho corrente for
maior ou igual ao melhor caminho obtido at
o momento.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2 50

Heursticas para Problemas


N P-Completo

Heurstica: algoritmo que pode produzir um


bom resultado (ou at a soluo tima), mas
pode tambm no obter soluo ou obter
uma distante da tima.

Uma heurstica pode ser determinista ou


probabilstica.

Pode haver instncias em que uma heurstica


(probabilstica ou no) nunca vai encontrar
uma soluo.

A principal diferena entre uma heurstica


probabilstica e um algoritmo Monte Carlo
que o algoritmo Monte Carlo tem que
encontrar uma soluo correta com uma certa
probabilidade (de preferncia alta) para
qualquer instncia do problema.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2 51

Heurstica para o PCV

Algoritmo do vizinho mais prximo, heurstica


gulosa simples:
1. Inicie com um vrtice arbitrrio.
2. Procure o vrtice mais prximo do ltimo
vrtice adicionado que no esteja no
caminho e adicione ao caminho a aresta
que liga esses dois vrtices.
3. Quando todos os vrtices estiverem no
caminho, adicione uma aresta conectando
o vrtice inicial e o ltimo vrtice
adicionado.

Complexidade: O(n2 ), sendo n o nmero de


cidades, ou O(d), sendo d o conjunto de
distncias entre cidades.

Aspecto negativo: embora todas as arestas


escolhidas sejam localmente mnimas, a
aresta final pode ser bastante longa.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2 52

Heurstica para o PCV

0 1 2 3 4 5
0 3 10 11 7 25
5 1
1 8 12 9 26
2 9 4 20
4 2 3 5 15
3 4 18

Caminho timo para esta instncia: 0 1 2 5 3


4 0 (comprimento 58).

Para a heurstica do vizinho mais prximo, se


iniciarmos pelo vrtice 0, o vrtice mais
prximo o 1 com distncia 3.

A partir do 1, o mais prximo o 2, a partir do


2 o mais prximo o 4, a partir do 4 o mais
prximo o 3, a partir do 3 restam o 5 e o 0.

O comprimento do caminho 0 1 2 4 3 5 0 60.


Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2 53

Heurstica para o PCV

Embora o algoritmo do vizinho mais prximo


no encontre a soluo tima, a obtida est
bem prxima do timo.

Entretanto, possvel encontrar instncias


em que a soluo obtida pode ser muito ruim.

Pode mesmo ser arbitrariamente ruim, uma


vez que a aresta final pode ser muito longa.

possvel achar um algoritmo que garanta


encontrar uma soluo que seja
razoavelmente boa no pior caso, desde que a
classe de instncias consideradas seja
restrita.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 54

Algoritmos Aproximados para


Problemas N P-Completo

Para projetar algoritmos polinomiais para


resolver um problema de otimizao
N P-completo necessrio relaxar o
significado de resolver.

Removemos a exigncia de que o algoritmo


tenha sempre de obter a soluo tima.

Procuramos algoritmos eficientes que no


garantem obter a soluo tima, mas sempre
obtm uma prxima da tima.

Tal soluo, com valor prximo da tima,


chamada de soluo aproximada.

Um algoritmo aproximado para um


problema um algoritmo que gera
solues aproximadas para .

Para ser til, importante obter um limite


para a razo entre a soluo tima e a
produzida pelo algoritmo aproximado.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 55

Medindo a Qualidade da Aproximao

O comportamento de algoritmos aproximados


quanto A qualidade dos resultados (no o
tempo para obt-los) tem de ser monitorado.

Seja I uma instncia de um problema e


seja S (I) o valor da soluo tima para I.

Um algoritmo aproximado gera uma soluo


possvel para I cujo valor S(I) maior (pior)
do que o valor timo S (I).

Dependendo do problema, a soluo a ser


obtida pode minimizar ou maximizar S(I).

Para o PCV, podemos estar interessados em


um algoritmo aproximado que minimize S(I):
obtm o valor mais prximo possvel de S (I).

No caso de o algoritmo aproximado obter a


soluo tima, ento S(I) = S (I).
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 56

Algoritmos Aproximados - Definio

Um algoritmo aproximado para um problema


um algoritmo polinomial que produz uma
soluo S(I) para uma instncia I de .

O comportamento do algoritmo A descrito


pela razo de aproximao

S(I)
RA (I) = ,
S (I)

que representa um problema de minimizao

No caso de um problema de maximizao, a


razo invertida.

Em ambos os casos, RA (I) 1.


Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 57

Algoritmos Aproximados para o PCV

Seja G = (V, A) um grafo no direcionado,


completo, especificado por um par (N, d).

N o conjunto de vrtices do grafo (cidades),


e d uma funo distncia que mapeia as
arestas em nmeros reais, em que d satisfaz:
1. d(i, j) = d(j, i) i, j N ,
2. d(i, j) > 0 i, j N ,
3. d(i, j) + d(j, k) d(i, k) i, j, k N

1a propriedade: a distncia da cidade i at


outra adjacente j igual de j at i.

Quando isso no acontece, temos o problema


conhecido como PCV Assimtrico

2a propriedade: apenas distncias positivas.

3a propriedade: desigualdade triangular. A


distncia de i at j somada com a de j at k
deve ser maior do que a distncia de i at k.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 58

Algoritmos Aproximados para o PCV

Quando o problema exige distncias no


restritas desigualdade triangular, basta
adicionar uma constante k a cada distncia.

Exemplo: as trs distncias envolvidas so 2,


3 e 10, que no obedecem desigualdade
triangular pois 2 + 3 < 10. Adicionando k = 10
s trs distncias obtendo 12, 13 e 20, que
agora satisfazem a desigualdade triangular.

O problema alterado ter a mesma soluo


tima que o problema anterior, apenas com o
comprimento da rota tima diferindo de n k.

Cabe observar que o PCV equivale a


encontrar no grafo G = (V, A) um ciclo de
Hamilton de custo mnimo.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 59

rvore Geradora Mnima (AGM)

Considere um grafo G = (V, A), sendo V as n


cidades e A as distncias entre cidades.

Uma rvore geradora uma coleo de n 1


arestas que ligam todas as cidades por meio
de um subgrafo conectado nico.

A rvore geradora mnima a rvore


geradora de custo mnimo.

Existem algoritmos polinomiais de custo


O(|A| log |V |) para obter a rvore geradora
mnima quando o grafo de entrada dado na
forma de uma matriz de adjacncia.

Grafo e rvore geradora mnima


correspondente:

0 0
2 6 2
1 1
1 3 2 1 1 3 1
5 1 2 6 5 1 2 6
2 4 2
4
2 1 1
4 4
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 60

Limite Inferior para a Soluo do PCV


a Partir da AGM

A partir da AGM, podemos derivar o limite


inferior para o PCV.

Considere uma aresta (x1 , x2 ) do caminho


timo do PCV. Remova a aresta e ache um
caminho iniciando em x1 e terminando em x2 .

Ao retirar uma aresta do caminho timo,


temos uma rvore geradora que consiste de
um caminho que visita todas as cidades.

Logo, o caminho timo para o PCV


necessariamente maior do que o
comprimento da AGM.

O limite inferior para o custo deste caminho


a AGM.

Logo, Otimo P CV > AGM .


Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 61

Limite Superior de Aproximao para


o PCV

A desigualdade triangular permite utilizar a


AGM para obter um limite superior para a
razo de aproximao com relao ao
comprimento do caminho timo.

Vamos considerar um algoritmo que visita


todas as cidades, mas pode usar somente as
arestas da AGM.

Uma possibilidade iniciar em um vrtice


folha e usar a seguinte estratgia:
Se houver aresta ainda no visitada
saindo do vrtice corrente, siga essa
aresta para um novo vrtice.
Se todas as arestas a partir do vrtice
corrente tiverem sido visitadas, volte para
o vrtice adjacente pela aresta pela qual o
vrtice corrente foi inicialmente alcanado.
Termine quando retornar ao vrtice inicial.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 62

Limite Superior de Aproximao para


o PCV - Busca em Profundidade

O algoritmo descrito anteriormente a Busca


em Profundidade aplicada AGM.

Verifica-se que:
o algoritmo visita todos os vrtices.
nenhuma aresta visitada mais do que
duas vezes.

Obtm um caminho que visita todas as


cidades cujo custo menor ou igual a duas
vezes o custo da rvore geradora mnima.

Como o caminho timo maior do que o


custo da AGM, ento o caminho obtido no
mximo duas vezes o custo do caminho
timo. CaminhoP CV < 2OtimoP CV .

Restrio: algumas cidades so visitadas


mais de uma vez.

Para contornar o problema, usamos a


desigualdade triangular.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 63

Limite Superior de Aproximao para


o PCV - Desigualdade Triangular
Introduzimos curto-circuitos que nunca
aumentam o comprimento total do caminho.
Inicie em uma folha da AGM, mas sempre
que a busca em profundidade for voltar para
uma cidade j visitada, salte para a prxima
ainda no visitada.
A rota direta no maior do que a anterior
indireta, em razo da desigualdade triangular.
Se todas as cidades tiverem sido visitadas,
volte para o ponto de partida.

(a) (b) (c)

O algoritmo constri um caminho soluo


para o PCV porque cada cidade visitada
apenas uma vez, exceto a cidade de partida.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 64

Limite Superior de Aproximao para


o PCV - Desigualdade Triangular
O caminho obtido no maior que o caminho
obtido em uma busca em profundidade, cujo
comprimento no mximo duas vezes o do
caminho timo.
Os principais passos do algoritmo so:
1. Obtenha a rvore geradora mnima para o
conjunto de n cidades, com custo O(n2 ).
2. Aplique a busca em profundidade na AGM
obtida com custo O(n), a saber:
Inicie em uma folha (grau 1).
Siga uma aresta no utilizada.
Se for retornar para uma cidade j
visitada, salte para a prxima ainda no
visitada (rota direta menor que a indireta
pela desigualdade triangular).
Se todas as cidades tiverem sido
visitadas, volte cidade de origem.
Assim, obtivemos um algoritmo polinomial de
custo O(n2 ), com uma razo de aproximao
garantida para o pior caso de RA 2.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 65

Como Melhorar o Limite Superior a


Partir da AGM

No algoritmo anterior um caminho para o


caixeiro-viajante pode ser obtido dobrando os
arcos da AGM, o que leva a um pior caso para
a razo de aproximao no mximo igual a 2.

Melhora-se a garantia de um fator 2 para o


pior caso, utilizando o conceito de grafo
Euleriano.

Um grafo Euleriano um grafo conectado no


qual todo vrtice tem grau par.

Um grafo Euleriano possui um caminho


Euleriano, um ciclo que passa por todas as
arestas exatamente uma vez.

O caminho Euleriano em um grafo Euleriano,


pode ser obtido em tempo O(n), usando a
busca em profundidade.

Podemos obter um caminho para o PCV a


partir de uma AGM, usando o caminho
Euleriano e a tcnica de curto-circuito.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 66

Como Melhorar o Limite Superior a


Partir da AGM

Passos do algoritmo:
Suponha uma AGM que tenha cidades do
PCV como vrtices.
Dobre suas arestas para obter um grafo
Euleriano.
Encontre um caminho Euleriano para esse
grafo.
Converta-o em um caminho do
caixeiro-viajante usando curto-circuitos.

Pela desigualdade triangular, o caminho do


caixeiro-viajante no pode ser mais longo do
que o caminho Euleriano e,
conseqentemente, de comprimento no
mximo duas vezes o comprimento da AGM.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 67

Casamento Mnimo com Pesos

Christophides props uma melhoria no


algoritmo anterior utilizando o conceito de
casamento mnimo com pesos em grafos.

Dado um conjunto contendo um nmero par


de cidades, um casamento uma coleo de
arestas M tal que cada cidade a
extremidade de exatamente um arco em M .

Um casamento mnimo aquele para o qual o


comprimento total das arestas mnimo.

Todo vrtice parte de exatamente uma


aresta do conjunto M .

Pode ser encontrado com custo O(n3 ).


Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 68

Casamento Mnimo com Pesos


Considere a AGM T de um grafo.
Alguns vrtices em T j possuem grau par,
assim no precisariam receber mais arestas
se quisermos transformar a rvore em um
grafo Euleriano.
Os nicos vrtices com que temos de nos
preocupar so os vrtices de grau mpar.
Existe sempre um nmero par de vrtices de
grau mpar, desde que a soma dos graus de
todos os vrtices tenha de ser par porque
cada aresta contada exatamente uma vez.
Uma maneira de construir um grafo Euleriano
que inclua T simplesmente obter um
casamento para os vrtices de grau mpar.
Isto aumenta de um o grau de cada vrtice de
grau mpar. Os de de grau par no mudam.
Se adicionamos em T um casamento mnimo
para os vrtices de grau mpar, obtemos um
grafo Euleriano que tem comprimento mnimo
dentre aqueles que contm T .
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 69

Casamento Mnimo com Pesos -


Exemplo

(a) (b)

(c) (d)

a. Uma rvore geradora mnima T .


b. T mais um casamento mnimo dos vrtices
de grau mpar.
c. Caminho de Euler em (b).
d. Busca em profundidade com curto-circuito.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 70

Casamento Mnimo com Pesos

Basta agora determinar o comprimento do


grafo de Euler.

Caminho do caixeiro-viajante em que podem


ser vistas seis cidades correspondentes aos
vrtices de grau mpar enfatizadas.

timo PVC

O caminho determina os casamentos M e M 0 .


Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 71

Casamento Mnimo com Pesos

Seja I uma instncia do PCV, e Comp(T ),


Comp(M ) e Comp(M 0 ), respectivamente, a
soma dos comprimentos de T , M e M 0 .

Pela desigualdade triangular devemos ter


que: Comp(M ) + Comp(M 0 ) Otimo(I),

Assim, ou M ou M 0 tm de ter comprimento


menor ou igual a Otimo(I)/2.

Logo, o comprimento de um casamento


mnimo para os vrtices de grau mpar de T
tem tambm de ter comprimento no mximo
Otimo(I)/2.

Desde que o comprimento de M menor do


que o caminho do caixeiro-viajante timo,
podemos concluir que o comprimento do
grafo Euleriano construdo :
3
Comp(I) < Otimo(I).
2
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 72

Casamento Mnimo com Pesos -


Algoritmo de Christophides

Os principais passos do algoritmo de


Christophides so:
1. Obtenha a AGM T para o conjunto de n
cidades, com custo O(n2 ).
2. Construa um casamento mnimo M para o
conjunto de vrtices de grau mpar em T ,
com custo O(n3 ).
3. Encontre um caminho de Euler para o
grafo Euleriano obtido com a unio de T e
M , e converta o caminho de Euler em um
caminho do caixeiro-viajante usando
curto-circuitos, com um custo de O(N ).

Assim obtivemos um algoritmo polinomial de


custo O(n3 ), com uma razo de aproximao
garantida para o pior caso de RA < 3/2.
Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3 73

Algoritmo de Christophides - Pior


Caso

Exemplo de pior caso do algoritmo de


Christofides:
5

1 1 1 1 1

1 1 1 1 1 1 1 1 1 1
1 1 1 1

A AGM e o caminho timo so:

AGM 1 1 1 1 1 1 1 1 1 1

1 1 1 1 1
timo 1

1 1 1 1

Neste caso, para uma instncia I:


3
C(I) = [Otimo(I) 1],
2
em que o Otimo(I) = 11, C(I) = 15, e
AGM = 10.

Você também pode gostar