You are on page 1of 809

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

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

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

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

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

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

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

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

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

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

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.

10

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

11

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

12

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

13

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

14

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

15

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

16

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

17

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

18

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
f (n) = n1 (1+2+3+ +n) =

1
n

n(n+1)
2

n+1

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

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;
}
}

20

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

21

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.
Logo f (n) = n 1 +

n1
2

3n
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



Contm o mximo


Contm o mnimo

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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;
}
}

24

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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,
n2
3n
+
=
2, para n > 0,
f (n) = n2 + n2
2
2
2
para o melhor caso, pior caso e caso mdio.

25

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.
f (n)

Os trs
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

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.

27

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

28

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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).

29

Projeto de Algoritmos Cap.1 Introduo Seo 1.3

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.

30

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1

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.

31

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)

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)

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

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.

34

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.1

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.

35

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)

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 )
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.
Dividindo por n2 leva a c1

1
3

2
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.
Alguns autores usam limn
definio da notao o.

g(n)
f (n)

= 0 para a

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.
Exemplo:

n2
2

= (n), mas

n2
2

6= (n2 ).

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


= , se o limite existir.
limn fg(n)
(n)

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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.

42

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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).

43

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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.

44

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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.

45

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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.

46

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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.

47

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

0,00001
s

0,00002
s

0,00003
s

0,00004
s

0,00005
s

0,00006
s

n2

0,0001
s

0,0004
s

0,0009
s

0,0016
s

0,0.35
s

0,0036
s

n3

0,001
s

0,008
s

0,027
s

0,64
s

0,125
s

0.316
s

n5

0,1
s

3,2
s

24,3
s

1,7
min

5,2
min

13
min

2n

0,001
s

1
s

17,9
min

12,7
dias

35,7
anos

366
sc.

3n

0,059
s

58
min

6,5
anos

3855
sc.

108
sc.

1013
sc.

Funo de

Computador

Computador

Computador

custo

atual

100 vezes

1.000 vezes

mais rpido

mais rpido

de tempo
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

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.

49

Projeto de Algoritmos Cap.1 Introduo Seo 1.3.2

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.

50

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
4

5 c3

c2

8
3

c4

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

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.

52

Projeto de Algoritmos Cap.1 Introduo Seo 1.4

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.

53

Projeto de Algoritmos Cap.1 Introduo Seo 1.4

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.

54

Projeto de Algoritmos Cap.1 Introduo Seo 1.4

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.

55

Projeto de Algoritmos Cap.1 Introduo Seo 1.4

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.

56

Projeto de Algoritmos Cap.1 Introduo Seo 1.4

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
=

=
O(n
)
(n

i)
=
1
2
2
2
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.

57

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

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 ).

59

Projeto de Algoritmos Cap.1 Introduo Seo 1.4

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.

60

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


T (n) = n

i
i=0 (1/3)

=n

1
1 31

3n

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
Px1
n
T (n) = i=0 3i + T ( 3x ) = n i=0 (1/3)i + 1 =
n(1( 31 )x )
(1 13 )

+1=

3n
2

12

Logo, o programa do exemplo O(n).

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

62

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

63

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

64

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

65

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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 ();

66

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

67

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

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

69

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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>();.

70

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

71

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

72

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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 ( ) ;
}
}

73

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

74

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

75

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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 (.).

76

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

77

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

78

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

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.*;

81

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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).

82

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

83

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

84

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

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.

86

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

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.

88

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

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.

90

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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).

91

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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).

92

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

93

Projeto de Algoritmos Cap.1 Introduo Seo 1.5

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.

94

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

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

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

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

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

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

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

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

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
2

7
4

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

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

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.

10

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.1

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.

11

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.1

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.

12

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.2

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)

13

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.2.2

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 ).

14

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

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.

16

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3

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 candidatos a movimento ) ;
}

17

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3

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

8
6

18

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.3

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 mostrados a seguir }
}

19

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 partir 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

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.

22

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.
para n 2,

T (n) = 1,

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:
T (n) = 2i1 T (n/2i1 ) +

Pi1

k
2
=
k=1

= 2i1 T (2) + 2i 2 = 2i1 + 2i 2 =

3n
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

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.

25

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4

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.

26

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4

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.

27

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.4

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 ).

28

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

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.

29

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:
T (n) = T (1) + 1 + 2 + + n 1 =

n(n1)

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

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.

31

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:
T (n) = 2i T (n/2i ) +

i1
X

k=0

i1
X

2k

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

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.

34

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6

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.

35

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,
mij =

0,

se i = j,

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

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.

37

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

m12 = 10.000

m23 = 1.000

m34 = 5.000

m13 = 1.200

m24 = 3.000

m14 = 2.200

m44 = 0

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6

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.

41

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6

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.

42

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.6

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.

43

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.7

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.

44

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.7

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).

45

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

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.

47

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.8

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.

48

Projeto de Algoritmos Cap.2 Paradigmas de Projeto de Algoritmos Seo 2.8

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).

49

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

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

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

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

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

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.
primeiro = 0
1
ltimo 1
maxTam 1

Itens
x1
x2
..
.
xn
..
.

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.1.1

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

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 encontrada
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

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

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

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.

14

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

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.

15

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

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;
}

16

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

...

7
8
9
10

...
Registro
Registro

nil
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
2
3
4
5
6
7

Registro

Registro

Registro

...

...

...

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 transparncia 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

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.

24

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2

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.

25

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2

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.

26

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.1

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.
primeiro = 0
1
topo 1
maxTam 1

Itens
x1
x2
..
.
xn
..
.

27

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.1

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

28

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.2.1

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 ;
}
}

29

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

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
6

topo

xn

30

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

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

31

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

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;
}
}

32

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

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.

33

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

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! ~

34

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 ; / /
cia 11

vide programa da transparn-

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

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.

38

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3

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.

39

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1

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

5
7

40

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1

Implementao de Filas por meio de


Arranjos
n

1
2

Frente

...

3
4

Tras

5
7

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.

41

Projeto de Algoritmos Cap.3 Estruturas de Dados Bsicas Seo 3.3.1

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

42

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

frente

trs

- nil

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

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 ) ;
}
}

46


Ordenao

ltima alterao: 10 de Outubro de 2006

Transparncias

elaboradas por Fabiano C. Botelho, Leonardo Rocha, Leonardo Mata e Nivio Ziviani

Projeto de Algoritmos Cap.4 Ordenao

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

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

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

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

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

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

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

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

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

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.

10

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1

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.

11

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1

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)
}

12

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

Chaves iniciais:

i=1

i=2

i=3

i=4

i=5

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:
C(n) =

n2
2

n
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

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.

15

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

Chaves iniciais:

i=2

i=3

i=4

i=5

i=6

As chaves em negrito representam a


seqncia destino.

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2

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.

17

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2

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.

18

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
pior caso
caso medio

: C(n) = (2 + 3 + + n) =
: C(n) =

n
1
2
1
(3 + 4 +
2
n2
3n
+
1
4
4

n2
+
2

+ n + 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
caso medio

: M (n) = (4 + 5 + + n + 2) =
: M (n) =

5n
n2
+
3
2
2
1
(5 + 6 +
2
n2
11n
+
3
4
4

+ n + 3) =

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.2

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.

21

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3

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.

22

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

Chaves iniciais:

h=4

h=2

h=1

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

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.

25

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3

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 )

26

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.3

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,

27

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

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.

28

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

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.

29

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

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.

30

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

31

Quicksort
Ilustrao do processo de partio:
1

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

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.

32

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:

D
E

3
4
5
A

O piv mostrado em negrito.

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

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.

35

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

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).

36

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.4

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.

37

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

38

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

39

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

40

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

41

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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).

42

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

43

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

2 R

5 N

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

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

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.

46

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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
}

47

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

48

Heapsort
Heaps
Algoritmo:
1

Chaves iniciais:

Esq = 3

Esq = 2

Esq = 1

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

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) ;
}
}

50

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)

(b)

i
E

(c)

i
A

(d)

U
U

i
U

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

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) ;
}

54

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

55

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

56

Heapsort
Exemplo de aplicao do Heapsort:
1

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

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.

57

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.5

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.

58

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

Quicksort

Heapsort

1,5

1,6

1,6

1,6

Registros na ordem ascendente:


500

5.000

10.000

30.000

Insero

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

Heapsort

2,5

2,7

2,7

2,9

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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.

62

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

Des

1,5

1,6

1,5

1,1

1,1

1,1

Ale

2,9

3,1

3,7

1,9

2,0

2,0

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

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.

64

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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.

65

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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.

66

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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.

67

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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).

68

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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.

69

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.6

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.

70

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

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.

71

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

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.

72

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

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.

74

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:
C(n) = kn
M (n) = 3k

k2
2

k
2

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

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.

76

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

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.

77

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

caso m
edio

: Ci (n) =

1
(1
i

+ 2 + + i) =

i+1
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))
= kn + n

caso m
edio

: C(n)

=
=

1
(3 + 4
2
kn
+n
2
2

k2
2

k
2

+ + k + 1 + (k + 1)(n k))

k2
4

k
4

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))
= kn + n

caso m
edio

: M (n)

=
=

1
(5 + 6
2
kn
+n
2
2

k2
2

3k
2

+ + k + 3 + (k + 1)(n k))

k2
4

5k
4

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

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 .

82

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 + k log n) =

O(n)

se k

O(k log n) se k >

n
log n
n
log n

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

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 ).

85

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

86

Quicksort Parcial
Chaves iniciais:

D
E

3
4
5
A

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

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).

88

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

89

Comparao entre os Mtodos de


Ordenao Parcial
Seleo

Quicksort

Insero

Insero2

Heapsort

2,5

1,2

1,7

1,2

2,8

1,1

2,8

n, k
1

n : 10

n : 10

k : 10
k : 10

n : 102 k : 100

1,1

1,4

4,5

1,9

2,4

1,2

1,7

1,1

2,3

n : 103 k : 100

n : 10

n : 10

n : 10

n : 10

n : 10

n : 10

n : 10

n : 10

k : 10
k : 10

3,7

1,4

1,6

9,1

4,6

2,9

1,2

6,4

11,2

1,3

1,4

1,9

15,1

3,9

4,2

1,6

2,4

1,1

1,1

5,3

5,9

2,2

4,9

67

2,1

1,1

4,8

304

1,1

1,3

2,3

1445

33,1

43,3

1,7

1,9

k : 10
k : 10
k : 10
k : 10
k : 10
k : 10

n : 105 k : 103
5

n : 10

n : 10

k : 10

k : 10

n : 106 k : 100
6

n : 10

n : 10

n : 10

n : 10

n : 10

n : 10

3,9

1,2

1,3

8,1

6,6

2,7

7,3

83,1

3,2

1,1

6,6

k : 10
k : 10

690

2,2

1,1

5,7

6,4

1,9

1,7

1,8

k : 10
k : 10
k : 10
k : 10

n : 107 k : 100
7

n : 10

3,4

1,1

1,1

7,4

8,6

2,6

1,1

6,7

k : 10

82,1

2,6

1,1

6,8

3,1

1,1

6,6

1,1

1,2

2,6

2,2

1,2

n : 107 k : 107

1,7

n : 10

n : 10

n : 10

n : 10

n : 10

k : 10
k : 10
k : 10
k : 10
k : 10

Projeto de Algoritmos Cap.4 Ordenao Seo 4.1.7

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.

90

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2

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.

91

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2

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.

92

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2

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.

93

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2

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.

94

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1

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.

95

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

fita 3:

AAL

ACN

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1

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

97

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1

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
.
m
No exemplo acima, n=22, m=3 e f=3
temos:
22
P (n) = log3
= 2.
3
P (n) = logf

98

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.1

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.

99

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2

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.

100

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2

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.

101

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

E*

E*

E*

C*

A*

E*

C*

C*

E*

L*

E*

L*

L*

A*

A*

A*

A*

A*

N*

A*

A*

N*

C*

C*

N*

E*

E*

N*

N*

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

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2

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.

104

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.2

105

Implementao por meio de Seleo


por Substituio
Exemplo:
Entra

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

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.

106

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3

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.

107

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3

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.

108

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3

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.

109

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.3

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.

110

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4

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.

111

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4

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.

112

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

fita 2:

AACEN

AAD

AABCLO

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

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.

114

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

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.4

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.

116

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5

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.

117

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

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 }.

119

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5

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.

120

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5

121

Quicksort Externo
i Li

a)

Ls j

c)

Ls

e)

Ls

d)

j
7

f)

Li

Ls

3 3 10 6 1 7 7
Ei

4 5

h)

Ei
i

Li
Ls

5 3 10 6 1 7 7

i Ls Li

Li Ls

j)

3 3 10 6 1 7 7

3 1 10 6 1 7 7

i Ls Li

l)

Es

3 1 10 6 1 10 7
Ei

j
3

n)

4 5

4 5 6

Es

i Ls Li
4 5

j
3

4 5

Es

Li
Ls

Es

4 5

Ei

m) 3 1 10 6 6 10 7
Ei Es

3 4 5

Es

i
4 5

4 5 7

Ls

Es

3 1 10 6 1 10 7
Ei

Li

Ei
j

3 1 10 6 1 7 7

Es

Es

i Li Ls

Ls

Ei
j

Linf Lsup

5 3 10 6 1 7 4

Es

Li

i
4 5

rea

Es

Ei

5 3 10 6 1 7 7
Ei

k)

i
4 5

5 3 10 6 1 7 4

Es
Li

Ls

Ei

5 3 10 6 1 7 4
Ei

i)

b)

Es
Li

i Li

Linf Lsup

5 3 10 6 1 7 4
Ei

g)

rea

3 1 4 5 6 10 7
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 externo


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 subarquivo 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

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 ( ) ;
}

125

Projeto de Algoritmos Cap.4 Ordenao Seo 4.2.5

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 ( ) ;
}

126

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

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;
}

128

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

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.
Pior caso:

n2
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.

130

Pesquisa em Memria

Primria

ltima alterao: 10 de Outubro de 2006

Transparncias

elaboradas por Fabiano C. Botelho, Leonardo Rocha, Leonardo Mata e Nivio Ziviani

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria

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

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

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

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

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

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

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

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

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

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.

10

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.1

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.

11

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.2

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.

12

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.2

13

Exemplo de Pesquisa Binria para a


Chave G

Chaves iniciais:

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

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.

15

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3

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.

16

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
R

Temos a relao invariante


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

rvores Binrias de Pesquisa sem


Balanceamento
Exemplo
5
3
2

7
4

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.

18

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

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.

19

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

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 ) ;
}
}

20

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

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 ;
}

21

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

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.

24

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

Exemplo da Retirada de um Registro


da rvore
5
3
2

7
4

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.

25

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
to

be

bye
to

and
be

be

and

be
to
and

to

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

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.

28

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

29

Caminhamento Central
Percorrer a rvore:
5
3
2

7
4

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

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.

30

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.1

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.

31

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

3
2

7
4

2
1

6
3

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2

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.

33

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2

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).

34

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

2,5
1

3,4

10
6

8,9

11

10
6

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
1

5
4

9
7

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

(a) Esquerdaesquerda (EE)

2
1

(b) Esquerdadireita (ED)

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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.

38

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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 tranaparncia 29
}

39

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
5

10

3
7

10

5
4

9
7

10

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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.

44

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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;
}

45

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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;
}

46

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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 ;
}

47

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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;
}

48

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

49

Exemplo
Dada a rvore:
5
5

10

10

5
4

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
2

5
4

9
6

4
10

9
6

4
10

10

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

50

Exemplo: Retirada de Ns de SBB


Caso 1:

10
2

12

t
6

10

1a chamada DirCurto

10

2a chamada
DirCurto

2 chamadas DirCurto

Caso 2:
4
10

2
1

2
8

12

6
3

1a

10

2
1

chamada DirCurto

10

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

51

Exemplo: Retirada de Ns de SBB


Caso 3:

4
2
3

10

6
8

12

10

6
3

4
6

2
3

10

Se nodo 8 tem filho:


4

4
2
3

10

6
5

2
12 1

10
8

9
4

4
2
1

2
6
3

8
9

10

10

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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.

52

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.3.2.2

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).

53

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4

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

54

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1

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.

55

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1

Exemplo
Dada as chaves de 6 bits:
B

= 010010

= 010011

H = 011000
J

= 100001

M = 101000

H
1

56

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
0

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
0

0
0

H
1

0
1

J
C

W
Q

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.1

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.

58

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2

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.

59

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2

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
1
3
6
B

3
H

60

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2

Insero da Chave K
1
3
6
B

3
H

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.
1
3
6
B

3
H

5
J

61

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2

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.
1
3
6
B

2
H

5
J

62

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

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;
}

64

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

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.

66

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.4.2

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.

67

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

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)

69

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5

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.

70

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5

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 N +1
M 1 M 2

...
=
p=
M
M
M
N
Y
M i+1
M!
=
=

N
M
(M

N
)!M
i=1

71

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5

Transformao de Chave (Hashing)


Alguns valores de p para diferentes valores de
N ,onde M = 365.
N

10

0,883

22

0,524

23

0,493

30

0,303

Para N pequeno a probabilidade p pode ser


1))
aproximada por p N (N
. Por exemplo,
730
para N = 10 ento p 87, 7%.

72

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1

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.

73

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1

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.

74

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1

Transformao de Chaves No
Numricas
As chaves no numricas devem ser
transformadas em nmeros:
K=

n1
X
i=0

chave[i] p[i],

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.

75

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.1

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;
}

76

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
1
2
3
4
5
6

U
A
P
Q

- nil
- nil
- I
- nil

nil

nil

E
nil

- S

- S

nil

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2

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.

78

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.2

Estrutura e operaes do dicionrio


para listas encadeadas
package cap5. listaenc ;
import cap3. autoreferencia . Lista ; / / vide Programas do captulo 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

79

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

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 .

81

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3

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.

82

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3

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
1
2
3
4
5
6

U
N
S

L
E

83

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3

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.

84

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3

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

85

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

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).

88

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.3

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 ).

89

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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.

90

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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 .

91

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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.

92

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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.

93

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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

fev

mar

abr

mai

jun

10

jul

ago

set

out

nov

10

dez

11

94

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
10

6
3

2
10

3
8

11

8
7

4
5

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

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.

96

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
10

6
3

2
10

3
8

11

8
7

4
5

(a)

Chave x

h1 (x)

h2 (x)

hp(x)

v:

g(v)

jan

10

11

fev

mar

abr

mai

11

jun

10

jul

ago

set

out

nov

10

10

dez

11

11

(b)

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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).

98

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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 ;
}

99

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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 ;
}

100

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;
/ / Continua na prxima transparncia

int i = 0;

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

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 ( ) ;
}

106

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

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.

110

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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

111

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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.

112

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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.

113

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

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.

114

Projeto de Algoritmos - Cap.5 Pesquisa em Memria Primria Seo 5.5.4

115

Experimentos
# Chamadas

# Chamadas

Tempo

geraGrafo

atribuig

(s)

10

3586

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

# Chaves

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

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

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

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

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

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

Memria Virtual: Mapeamento de


Endereos
Endereo
de
programa

N da
pgina

N do
byte

Tabela_de_Pginas

Pgina p


?

p0 = nil pgina no
presente na
memria

p0

p0 + b

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.1

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

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

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

6
?

Pgina p
..
6
?

..

Incio

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2

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
}

10

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2

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
}

11

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.1.2

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.

12

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
-

Consulta
tabela de
pginas

P3
-

Determina
moldura
para pgina

p0

p
A2

Programa
Usurio

p0

Fila
de
molduras

p0

p
p0

p0

6
p
p0

?
P2

Determina
endereo
real

p0

?
P5
Grava pgina
na memria
secundria
p0
A3
Memria 
secundria Pgina

A1
Tabela
de
pginas

Pgina
p0

p6

P4
Recupera pgina
da memria 
Pgina
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

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

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.

15

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.2

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.

16

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.2.1

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.

17

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

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.

19

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1

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 }
}

20

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.

3489
2


1 10





``
```
`


16 20 25 29
3


10 20
1
``


` `

 
`

`

3489
25 29
14 16
2
3 
4 

(a)

(b)

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

(
(
hhh

(
Ph
(
P
hh
(
P
(

( 







h
11 13 17
25 28
33 36
50 52 55

3 4



(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

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++;
}

24

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

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.

27

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.1

28

rvores B - Remoo
Exemplo: Retirando a chave 3.
4j
 H

HH

 
2j
6 8 
@
@
 T
j
j
3
5j7j9j
1

4j
, ll
,
 
* j
6 8 
   T
jjj
1 2  5 7 9

6j
,, ll
8j
4j
 AA
  AA
j 7j 9j
1 2 5

(a) Pgina vizinha possui mais do que m registros


4j
,, ll
6j
2j
 AA
 AA
j
j
5j 7j
3
1

4j
, ll
* ,
j
6j
   AA
j j
1 2  5 7

j
 
4 6 
 T

jj
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

(
(
hhhh

(
Ph
(

(
P
(
h
P

(








h
11 13 17 20

3 4 8 9

33 36

43 48

52 55



(c)

13 P
 
PP

25 43 48 52

3 9



(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

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 ) ;
}
}

34

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.2

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.

35

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

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.

37

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.3

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.

38

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.3

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.

39

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4

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.

40

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4

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).

41

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4

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.

42

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 ),
P r{Psmp esteja acima do 1 nvel} =
1
2
+
O(m
).
(2 ln 2)m

3
7

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4

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.)

44

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4

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.

45

Projeto de Algoritmos Cap.6 Pesquisa em Memria Secundria Seo 6.3.4

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.

46


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

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

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

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
1

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

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

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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
grau 2 e o vrtice 3
isolado.

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
in-degree 2, out-degree
2 e grau 4.

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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

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

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

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

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

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

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

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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.

16

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.1

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).

17

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

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.

19

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2

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.

20

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2

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.

21

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

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.

23

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1

24

Matriz de Adjacncia - Exemplo


0

0 1 2 3 4 5
0
1
1
1
1 1
2
1 1
3 1
4
5

0 1 2 3 4 5
0
1 1
1 1
1
2 1 1
3
4
5

(a)

(b)

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1

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 ).

25

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.1

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);
}

26

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

5
0

1
7

2 7

0
1
7

1 3

5
0

1 5

1 5
0 5

2 7

1 7

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

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.

30

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.2

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.

31

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


cab

3
0

(a)

V
7

0
1
2
3
4
5
6

4
6
2
3
1
1
2

cab
5
0

(b)

7
3

0
1
2
3
4
5
6
7

4
6
7
3
1
0
2
1

prox peso
4
5
0
0
0
6
0

5
3
7

prox peso
4
5
7
0
0
6
0
0

5
5
7
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

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;
}

36

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.2.3

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 ] ] ) ;
}

37

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

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.

39

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3

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.

40

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3

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;
}

41

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3

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 ] ; }
}

42

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3

43

Busca em Profundidade - Exemplo


b( / )

b( / )

c(1/ )

b( / )

b( / )
b( / ) 2

b( / )
b( / ) 2

(a)

(b)

c(1/ )

c(2/ )

c(1/ )

c(2/ )

b( / )
b( / ) 2

b( / )
c(3/ ) 2

(c)

(d)
c(1/ )

c(2/ )

1
b( / )
p(3/4) 2

(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)

1
b( / )

b( / )
p(3/4) 2

p(3/4) 2

(g)

(f)
p(1/6)

p(2/5)

p(1/6)

p(2/5)

c(7/ )
p(3/4) 2

(h)

p(7/8)
p(3/4) 2

(i)

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3

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|).

45

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3.1

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.

46

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.
2/9

3/6
2

arv

arv

arv

ret

arv

1/10

cruz

avan
3
4/5

cruz

4
7/8

cruz

5
11/12

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.3.2

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.

48

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4

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.

49

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4

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.

50

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

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 ] ; }
}

52

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4

53

Busca em Largura - Exemplo


(b)

(a)
c(0)

b( )

b( )

p(0)

c(1)

b( )

b( )

b( )

b( )

c(1)

b( )

b( )

F 0
0

F 1 3
1 1

(c)

(d)

p(0)

p(1)

b( )

p(0)

p(1)

b( )

c(1)

c(2)

b( )

p(1)

c(2)

b( )

F 3 2
1 2

F 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)

p(1)

p(2)

b( )

p(1)

p(2)

b( )

F 4
0

(g)

(h)

p(0)

p(1)

p(0)

p(0)

p(1)

p(0)

p(1)

p(2)

c(1)

p(1)

p(2)

p(1)

F 5
1

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.4

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|).

55

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

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.

57

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

4/5 3

2/15

7/12

3/14

6/13

8/11

9/10

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.5

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).

59

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.5

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;
}

60

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

0,1,2

(a)

(b)

(c)

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6

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 .

62

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6

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.

63

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).
1/8

2/7

1/6

0
cruz

3
4/5

2
3/6

(a)

ret
arv

3/4

cruz

arv cruz

1
arv

3
2
cruz
7/8
2/5

(b)

ret

2
arv
1

(c)

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6

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 ;
}

65

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6

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 ;
}

66

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6

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 ) ;
}
}
}

67

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.6

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|).

68

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7

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
P
peso total p(T ) = (u,v)T p(u, v)
minimizado.

69

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

6
1

5
3

2
5
4

(a)

2
4

(b)

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.1

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 = ;

while ( S no constitui uma rvore geradora mnima)

(u, v) = seleciona (A) ;

i f ( aresta (u, v) segura para S ) S = S + {(u, v)}

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.

71

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
V

V V

5
2

p
3

V V

6 4
4
5
3

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.1

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.

73

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2

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.

74

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2

75

Algoritmo de Prim - Exemplo


(a)

(b)
0

6
1

6
3

0
5
1

2
5

6
4

(c)

2
1

(d)

0
0

0
2

2
1

2
1

3
2
1

2
1
6

(e)

(f)

2
1

2
1

2
1
5

2
1
5

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2

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;
}

76

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

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) ) ;
}
}

79

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2

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.

80

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.2

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 |).

81

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

6
1

5
3

3
2

2
5

6
4

4
4

(c)

(d)
0

2
4

2
5

(e)

(f)
0

2
4

2
5

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3

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.

83

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.7.3

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.

84

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

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 |).

86

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.
Peso de um caminho: p(c) =

Pk

i=1

p(vi1 , vi )

Caminho mais curto:


(u, v) =

n
o
c

min p(c) : u ; v
se existir caminho de u a 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

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.

88

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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.

89

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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.

90

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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.

91

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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}.

92

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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;

93

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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 ;

S = ;

7.

while ( !heap. vazio ( ) )

8.

u = heap. retiraMin ( ) ;

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.

94

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

95

Algoritmo de Dijkstra - Exemplo


(a)

(b)
0

1
1

10
4

3
1

5
2

10
4

(c)

10

6
3

0
0

1
1

10
4

3
1

5
2
6

10
6

Iterao

d[0]

d[1]

d[2]

d[3]

d[4]

(a)

(b)

{0}

10

(c)

{0, 1}

10

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

96

Algoritmo de Dijkstra - Exemplo


(d)

(e)

0
0

1
1

3
1

5
2
5

10

9
4

10

6
4

3
1
2

(f)

6
2

0
0

1
1

1
2

6
4

5
5

10

6
2

Iterao

d[0]

d[1]

d[2]

d[3]

d[4]

(d)

{0, 1, 3}

(e)

{0, 1, 3, 2}

(f)

{0, 1, 3, 2, 4}

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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.

97

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.8

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;

98

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

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).

100

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9

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.

101

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9

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.

102

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9

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.

103

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9

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.

104

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)

(b)

arestas

1
2

4
1

2
3
4

prim

0
1
2
3
4
(1,2,0) (3,4,1) (3,5,2) (0,2,3) (2,3,4)
0
3

1
0

2
4

3
9

4
6

5
7

0 1 2 3 4 5 6 7 8
prox 1 1 1 1 8 1 1 1 5

9
2

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9

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 ;
}

106

Projeto de Algoritmos Cap.7 Algoritmos em Grafos Seo 7.9

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 ] ;
}

107

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

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 ; }
}

110

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

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

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

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

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

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

Exemplo de Arquivo Invertido


0

15

21 25

35

44

52

Texto exemplo. Texto tem palavras. Palavras exercem fascnio.

exe mplo

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

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

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

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

Arquivo Invertido Usando Trie


Arquivo invertido usando uma rvore trie
para o texto: Texto exemplo. Texto tem
palavras.

Palavras exercem fascnio.


x

e
f fascnio: 53
p
palavras: 26,36
t
m
e
x

exemplo: 7

exercem: 45

tem: 22
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.

10

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

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)
}

12

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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 ) ;
}
}

13

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

Fora Bruta - Anlise


Pior caso: Cn = m n.
O pior caso ocorre, por exemplo, quando P =
aab e T =aaaaaaaaaa.
Caso esperado:

1
c
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.

14

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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
{}.

15

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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 .

16

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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

c
1

Autmato finito determinista.


Para cada caractere de transio todos os
estados levam a um nico estado.
d

c
1

17

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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

c
1

18

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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-.

19

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

20

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

c
1

c
1

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

b
a

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

Exemplo de Uso de Autmato


O autmato abaixo reconhece P ={aabc}.
b

c
0
b

c
a
b,c

a
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.

22

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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).

23

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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

... c

$ p 1 p 2 ... p m
Cabea de leitura

Controle

c n Pilha
c n1
...
c

24

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

KMP - Casamento de cadeias no


2DPDA
# c

... c

$ p 1 p 2 ... p m
Cabea de leitura

Controle

c n Pilha
c n1
...
c

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.

25

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

26

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

27

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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 ).

28

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}
0

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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).

30

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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

M[t]

M[e]

M[s]

A mscara em M [t] 10010, pois o caractere


t aparece nas posies 0 e 3 de P .

31

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).
0

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

R0

(R >> 1)|10m1

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

34

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

35

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

36

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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 .

37

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

38

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

39

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

40

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

41

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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 .

42

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

43

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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)];
}
}

44

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

45

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

46

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.1

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.

47

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2

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 . . .

48

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2

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.

49

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2

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.

50

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.

(a)
1

(b)

(c)

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 .

Uma aresta diagonal slida substitui um


caractere. Avanamos em T e P .

Uma aresta diagonal tracejada retira um


caractere. Avanamos em P mas no em T
(transio-)

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).

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

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.

54

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2

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.

55

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.1.2

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" ;

56

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

1 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 1 0 0 0 1 0 0 0 0

1 0 0 0

0 0 0 0 0 0 1 0 0 0 1 0 0 0 0

1 0 0 0

1 0 0 0 0 0 1 0 0 0 1 0 0 0 0

1 1 0 0

0 1 0 0 0 0 1 0 0 0 1 1 0 0 0

1 0 1 0

0 0 1 0 0 0 1 1 0 0 1 1 1 0 0

1 0 0 1

1 0 0 1 0 0 1 1 1 0 1 0 1 1 0

1 1 0 0

0 1 0 0 1 0 1 0 1 1 1 1 0 1 1

1 0 1 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 1 1 1 0 1 0 1 0 0

1 0 0 0

1 0 0 0 0 0 1 0 1 0 1 0 0 1 0

1 1 0 0

0 1 0 0 0 0 1 0 0 1 1 1 0 0 1

1 0 1 0

0 0 1 0 0 0 1 1 0 0 1 1 1 0 0

1 0 0 1

1 0 0 1 0 0 1 1 1 0 1 0 1 1 0

1 1 0 0

0 0 0 0 0 0 1 0 1 1 1 0 0 1 0

1 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

1 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 1 0 0 0 1 0 0 0 0

1 0 0 0

0 0 0 0 0 0 1 0 0 0 1 0 0 0 0

1 0 0 0

1 0 0 0 0 0 1 0 0 0 1 1 0 0 0

1 1 0 0

0 1 0 0 0 0 1 1 0 0 1 1 1 0 0

1 0 1 0

0 0 1 0 0 0 1 1 1 0 1 1 1 1 0

1 0 0 1

1 0 0 1 0 0 1 1 1 1 1 1 1 1 1

1 1 0 0

0 1 0 0 1 0 1 1 1 1 1 1 1 1 1

1 0 1 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 1 1 1 1 1 0 1 1 0

1 0 0 0

1 0 0 0 0 0 1 0 1 1 1 1 0 1 0

1 1 0 0

0 1 0 0 0 0 1 1 0 1 1 1 1 0 1

1 0 1 0

0 0 1 0 0 0 1 1 1 0 1 1 1 1 0

1 0 0 1

1 0 0 1 0 0 1 1 1 1 1 1 1 1 1

1 1 0 0

0 0 0 0 0 0 1 1 1 1 1 1 0 1 1

1 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

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.

59

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2

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.

60

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.1

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.

61

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.1

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.

62

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.1

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.

63

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2

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%.

64

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2

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.

65

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2

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.

66

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.2

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.

67

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

68

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

69

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
para

1
cada

c)

4
rosa

2
0
para

0
,

6
1

uma

b)

para

cada

2
uma

para

cada

10
0

1
6
1

uma

2
0

4
rosa

f)

2
uma

d)

4
rosa

rosa

1
cada

4
rosa

2
uma

2
uma

1
cada

e)

0
para

4
rosa

4
0

2
0
para

2
1
cada

0
,

OBS: O algoritmo de Huffman uma abordagem


gulosa.

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

71

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

72

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

73

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

74

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

b)

...

Prox

Raiz

...

Freqncias
Posies
dos ns folhas disponveis

...

...

Pesos dos
ns internos

ndices pais
ns internos

1 2 3

n
...

c)
Peso da
rvore

ndices pais
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

Exemplo de processamento da
primeira fase
1 2 3 4 5 6

a)
b)
c)
d)
e)

4 2 1 1 1 1

f)
g)
h)
i)
j)
k)

Prox Raiz Folha


6
6
6

4 2 1 1 1 1

4 2 1 1 1 2

4 2 1 1 1 2

4 2 1 1 2 2

4 2 1 2 2 4

4 2 1 4 4 4

4 2 2 4 4 4

4 2 6 3 4 4

4 4 6 3 4 4

10 2 3 4 4

77

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

Segunda Fase - Converso do vetor no


conjunto das profundidades dos ns
internos
n

1 2 3
...

a)
Peso da
rvore

ndices pais
ns internos
Prox

1 2
...

b)

n
...

Profundidade ndices pais


dos ns internos ns internos
1 2

c)

n
...

Profundidade dos ns internos

78

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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

79

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

Terceira Fase - Calculo das


profundidades dos ns folhas
1 2

n
...

a)

Profundidade dos ns internos


Prox

1
...

b)

Raiz
...

n
...

Comprimento Posies
Profundidade
dos cdigos disponveis dos ns internos
1

c)

n
...
Comprimento dos cdigos

80

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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

81

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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) ;
}

82

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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

rosa

uma

10

para

1100

cada

1101

,t

1110

1111

83

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

84

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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:
base[c] =

8
<0

se c = 1,

: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]

12

85

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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].

86

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

87

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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.

88

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

Exemplo de Decodificao
Decodificao da seqncia de bits 1101:
c

LeBit

Codigo

Codigo << 1

Base[c + 1]

10 or 1 = 11

10

10

110 or 0 = 110

110

110

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].

89

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.3

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) ;
}
}

90

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

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.

92

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

93

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

94

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

95

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

96

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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 delimitadores
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 {
}

97

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

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.

101

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

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; / /
cao
while ( ( ( c + 1) <= maxCompCod) &&

Remove o bit de marca-

( ( 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

103

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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:
base[c] =

8
<0

se c = 1,

:baseNum (base[c 1] + wc1 ) caso contrrio.

104

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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;
}

105

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

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 ; }
}

108

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

109

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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 ( ) ;
}

110

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

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;
}

112

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

113

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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;
}

114

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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 ;
}

115

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

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.

117

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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 ] ) ;
}

118

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

119

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

120

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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);
}

121

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.4

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.

122

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

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

Mtodo

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

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.

124

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

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.

125

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

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;
}

127

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

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 " ) ) ;
}
}

129

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

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.

130

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

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.

131

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

Esquema geral de pesquisa para a


palavra uma permitindo 1 erro
ama

puma

uma
umas

132

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

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.

133

Projeto de Algoritmos Cap.8 Processamento de Cadeias de Caracteres Seo 8.2.5

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.

134

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

azul

000

XXX

1XX
uma

100

rosas

011

X1X

XX1

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

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

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

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

Caminho em um Grafo
Considere um grafo com peso nas arestas,
dois vrtices i, j e um inteiro k > 0.
5
2

11

10

13

5
3

12

1
2

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

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

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

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

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

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
4

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

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

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?

10

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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.

11

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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.

12

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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).

13

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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.

14

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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).

15

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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))

16

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.1

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.

17

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

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.

19

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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
P

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.

20

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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!

21

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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
de 1

Dados
de 2

Transformao
Polinomial

Soluo
para 2

Algoritmo A

Soluo
para 1

Transformao
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.

22

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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}.

23

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

24

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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}.

25

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

26

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

27

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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 ).

28

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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 .

29

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

30

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

31

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

32

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

33

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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 .

34

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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 ;
}
}

35

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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
1

1
1

1
1

5
1

1
4

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.

36

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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).

37

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

38

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.1.2

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.

39

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2

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.

40

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2

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.

41

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1

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|).

42

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

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

0
2
5

1 3

2
2

1
4
4

1
1

4
1

1
1

1
2

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.

44

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
2

1 3

1
1

4
1

A rvore de caminhamento :
0
1
2

4
3

5
4

4
6

5
6

4
2

2
4

4
4

4
2

1
6

1
2

Existem duas respostas: 0 5 3 1 2 4 6 0 e


0 6 4 2 1 3 5 0.

5
5

3
1
2

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1

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

4
2
1

2
6

4
6

5
0

47

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1

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.

48

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.1

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.

49

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2

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.

50

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2

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.

51

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2

Heurstica para o PCV


0
5

0
1
2

2
3

3
4

10

11

25

12

26

20

15
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.

52

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.2

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.

53

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

54

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

Medindo a Qualidade da Aproximao


O comportamento de algoritmos aproximados
qualidade dos resultados (no o
quanto A
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).

55

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

56

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

57

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

58

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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
2
5

1 3

1
4
4

1
2

0
1

1 3

1
4

59

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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 .

60

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

61

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

62

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

63

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

64

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

65

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

66

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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 ).

67

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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 .

68

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

69

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.
M
M
timo PVC

O caminho determina os casamentos M e M 0 .

70

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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

71

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

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.

72

Projeto de Algoritmos Cap.9 Problemas N P -Completo e Algoritmos Aproximados Seo 9.2.3

Algoritmo de Christophides - Pior


Caso
Exemplo de pior caso do algoritmo de
Christofides:
5
1

1
1

1
1

1
1

A AGM e o caminho timo so:


AGM

1
1

timo
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.

73

You might also like