Anda di halaman 1dari 116

Pesquisa em Memria Primria

ltima alterao: 10 de Outubro de 2006

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

Transparncias

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 especco. 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 denio 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)) this . registros[++ this .n] = reg ; } } throw new Exception ( "Erro : A tabela esta cheia" ) ;

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

Pesquisa Seqencial
Cada registro contm um campo chave que identica o registro. A Interface Item denida 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 inuncia nos algoritmos. O mtodo pesquisa retorna o ndice do registro que contm a chave passada como parmetro no registro reg ; caso no esteja presente, o valor retornado zero. Essa implementao no suporta mais de um registro com a mesma chave.

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

10

Pesquisa Seqencial
Utilizao de um registro sentinela na posio zero do array: 1. Garante que a pesquisa sempre termina: se o ndice retornado por Pesquisa for zero, a pesquisa foi sem sucesso. 2. No necessrio testar se i > 0, devido a isto: o anel interno da funo Pesquisa extremamente simples: o ndice i decrementado e a chave de pesquisa comparada com a chave que est no registro. isto faz com que esta tcnica seja conhecida como pesquisa seqencial rpida.

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

11

Pesquisa Seqencial
Anlise Pesquisa com sucesso: melhor caso : C (n) = 1 pior caso caso m edio : C (n) = n : C (n) = (n + 1)/2

Pesquisa sem sucesso: C (n) = n + 1. O algoritmo de pesquisa seqencial a melhor escolha para o problema de pesquisa em tabelas com at 25 registros.

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

12

Pesquisa Binria
Pesquisa em tabela pode ser mais eciente 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 que apenas um registro cuja chave diferente da procurada, signicando uma pesquisa sem sucesso.

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

13

Exemplo de Pesquisa Binria para a Chave G


1 Chaves iniciais: A A 2 B B 3 C C 4 D D 5 E E E 6 F F F 7 G G G G 8 H H H H

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

14

Algoritmo de Pesquisa binria


O algoritmo foi feito com um mtodo da classe Tabela apresentada anteriormente.
public int binaria ( Item chave) { i f ( this .n == 0) return 0; int esq = 1 , dir = this .n, i ; do { i = (esq + dir ) / 2 ; i f (chave.compara ( this . registros [ i ] ) > 0 ) esq = i + 1; } while ( (chave.compara ( this . registros [ i ] ) ! = 0 ) && (esq <= dir ) ) ; i f (chave.compara ( this . registros [ i ]) == 0) return i ; else return 0; } else dir = i 1;

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

15

Pesquisa Binria
Anlise A cada iterao do algoritmo, o tamanho da tabela dividido ao meio. Logo: o nmero de vezes que o tamanho da tabela dividido ao meio cerca de log n. Ressalva: o custo para manter a tabela ordenada alto: a cada insero na posio p da tabela implica no deslocamento dos registros a partir da posio p para as posies seguintes. Conseqentemente, a pesquisa binria no deve ser usada em aplicaes muito dinmicas.

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

16

rvores de Pesquisa
A rvore de pesquisa uma estrutura de dados muito eciente para armazenar informao. Particularmente adequada quando existe necessidade de considerar todos ou alguma combinao de: 1. Acesso direto e seqencial ecientes. 2. Facilidade de insero e retirada de registros. 3. Boa taxa de utilizao de memria. 4. Utilizao de memria primria e secundria.

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

17

rvores Binrias de Pesquisa sem Balanceamento


Para qualquer n que contenha um registro
R

Temos a relao invariante


E R D

1. Todos os registros com chaves menores esto na subrvore esquerda. 2. Todos os registros com chaves maiores esto na subrvore direita.

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

18

rvores Binrias de Pesquisa sem Balanceamento


Exemplo
5 3 2 1 4 6 7

O nvel do n raiz 0. Se um n est no nvel i ento a raiz de suas subrvores esto no nvel i + 1. A altura de um n o comprimento do caminho mais longo deste n at um n folha. A altura de uma rvore a altura do n raiz.

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

19

Implementao do Tipo Abstrato de Dados Dicionrio usando a Estrutura de Dados rvore Binria de Pesquisa
Estrutura de dados: Contm as operaes inicializa , pesquisa , insere e retira . A operao inicializa implementada pelo construtor da classe ArvoreBinaria .

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

20

Implementao do Tipo Abstrato de Dados Dicionrio usando a Estrutura de Dados rvore Binria de Pesquisa
package cap5; import cap4. Item ; / / vide programa do captulo 4 public class ArvoreBinaria { private static class No { Item reg ; No esq, dir ; } private No raiz ; / / Entram aqui os mtodos privados das transparncias 21, 22 e 26 public ArvoreBinaria ( ) { this . raiz = null ; } public Item pesquisa ( Item reg ) { return this .pesquisa ( reg , this . raiz ) ; } public void insere ( Item reg ) { this . raiz = this . insere ( reg , this . raiz ) ; } public void retira ( Item reg ) { this . raiz = this . retira ( reg , this . raiz ) ; } }

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

21

Mtodo para Pesquisar na rvore


Para encontrar um registro com uma chave reg : Compare-a com a chave que est na raiz . Se menor, v para a subrvore esquerda. Se maior, v para a subrvore direita. Repita o processo recursivamente, at que a chave procurada seja encontrada ou um n folha atingido. Se a pesquisa tiver sucesso ento o registro contendo a chave passada em reg retornado.
private Item pesquisa ( Item reg , No p) { i f (p == null ) return null ; / / Registro no encontrado else i f ( reg .compara (p. reg) < 0) return pesquisa ( reg , p.esq) ; else i f ( reg .compara (p. reg) > 0) return pesquisa ( reg , p. dir ) ; else return p. reg ; }

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

22

Procedimento para Inserir na rvore


Atingir uma referncia null em um processo de pesquisa signica 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 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 ( ) ) ; } } } import java . io . ;

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

24

Procedimento para Retirar x da rvore


Alguns comentrios: 1. A retirada de um registro no to simples quanto a insero. 2. Se o n que contm o registro a ser retirado possui no mximo um descendente a operao simples. 3. No caso do n conter dois descendentes o registro a ser retirado deve ser primeiro: substitudo pelo registro mais direita na subrvore esquerda; ou pelo registro mais esquerda na subrvore direita.

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

25

Exemplo da Retirada de um Registro da rvore


5 3 2 1 4 6 7

Assim: para retirar o registro com chave 5 na rvore basta troc-lo pelo registro com chave 4 ou pelo registro com chave 6, e ento retirar o n que recebeu o registro com chave 5.

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

26

Mtodo para retirar reg da rvore


private No antecessor (No q, No r ) { i f ( r . dir ! = null ) r . dir = antecessor ( q, r . dir ) ; else { q. reg = r . reg ; r = r .esq ; } return r ; } private No retira ( Item reg , No p) { i f (p == null ) System. out . println ( "Erro : Registro nao encontrado" ) ; else i f ( reg .compara (p. reg) < 0) p.esq = retira ( reg , p.esq) ; else i f ( reg .compara (p. reg) > 0) p. dir = retira ( reg , p. dir ) ; else { i f (p. dir == null ) p = p.esq; else i f (p.esq == null ) p = p. dir ; else p.esq = antecessor ( p, p.esq) ; } return p; }

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

27

Outro Exemplo de Retirada de N


bye and be easy to

bye to be

and

be

be to and to

and

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

28

Caminhamento Central
Aps construda a rvore, pode ser necessrio percorrer todos os registros que compem a tabela ou arquivo. Existe mais de uma ordem de caminhamento em rvores, mas a mais til a chamada ordem de caminhamento central. O caminhamento central mais bem expresso em termos recursivos: 1. caminha na subrvore esquerda na ordem central; 2. visita a raiz; 3. caminha na subrvore direita na ordem central. Uma caracterstica importante do caminhamento central que os ns so visitados de forma ordenada.

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

29

Caminhamento Central
Percorrer a rvore:
5 3 2 1 4 6 7

usando caminhamento central recupera as chaves na ordem 1, 2, 3, 4, 5, 6 e 7. Caminhamento central e impresso da rvore:
public void imprime ( ) { this . central ( this . raiz ) ; } private void central (No p) { i f (p ! = null ) { central (p.esq) ; System. out . println (p. reg . toString ( ) ) ; central (p. dir ) ; } }

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

30

Anlise
O nmero de comparaes em uma pesquisa com sucesso: melhor caso : C (n) = O(1), pior caso caso m edio : C (n) = O(n), : C (n) = O(log n).

O tempo de execuo dos algoritmos para rvores binrias de pesquisa dependem muito do formato das rvores.

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

31

Anlise
1. Para obter o pior caso basta que as chaves sejam inseridas em ordem crescente ou decrescente. Neste caso a rvore resultante uma lista linear, cujo nmero mdio de comparaes (n + 1)/2. 2. Para uma rvore de pesquisa randmica o nmero esperado de comparaes para recuperar um registro qualquer cerca de 1, 39 log n, apenas 39% pior que a rvore completamente balanceada. Uma rvore A com n chaves possui n + 1 ns externos e estas n chaves dividem todos os valores possveis em n + 1 intervalos. Uma insero em A considerada randmica se ela tem probabilidade igual de acontecer em qualquer um dos n + 1 intervalos. Uma rvore de pesquisa randmica com n chaves uma rvore construida atravs de n inseres randmicas sucessivas em uma rvore inicialmente vazia.

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

32

rvores Binrias de Pesquisa com Balanceamento


rvore completamente balanceada ns externos aparecem em no mximo dois nveis adjacentes. Minimiza tempo mdio de pesquisa para uma distribuio uniforme das chaves, onde cada chave igualmente provvel de ser usada em uma pesquisa. Contudo, custo para manter a rvore completamente balanceada aps cada insero muito alto. Para inserir a chave 1 na rvore do exemplo esquerda e obter a rvore direita do mesmo exemplo necessrio movimentar todos os ns da rvore original. Exemplo:
5 3 2 4 6 7 1 2 3 5 4 6 7

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

33

Uma Forma de Contornar este Problema


Procurar soluo intermediria que possa manter rvore quase-balanceada, em vez de tentar manter a rvore completamente balanceada. Objetivo: Procurar obter bons tempos de pesquisa, prximos do tempo timo da rvore completamente balanceada, mas sem pagar muito para inserir ou retirar da rvore. Heursticas: existem vrias heursticas baseadas no princpio acima. Gonnet e Baeza-Yates (1991) apresentam algoritmos que utilizam vrios critrios de balanceamento para rvores de pesquisa, tais como restries impostas: na diferena das alturas de subrvores de cada n da rvore, na reduo do comprimento do caminho interno ou que todos os ns externos apaream no mesmo nvel.

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

34

Uma Forma de Contornar este Problema


Comprimento do caminho interno: corresponde soma dos comprimentos dos caminhos entre a raiz e cada um dos ns internos da rvore. Por exemplo, o comprimento do caminho interno da rvore esquerda na gura da transparncia anterior 8 = (0 + 1 + 1 + 2 + 2 + 2).

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

35

rvores SBB
rvores B estrutura para memria secundria. (Bayer R. e McCreight E.M., 1972) rvore 2-3 caso especial da rvore B. Cada n tem duas ou trs subrvores. Mais apropriada para memria primria. Exemplo: Uma rvore 2-3 e a rvore B binria correspondente(Bayer, R. 1971)
7 2,5 1 3,4 6 8,9 10 11 1 2 3 5 4 6 8 7 10 9 11

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

36

rvores SBB
rvore 2-3 rvore B binria (assimetria inerente) 1. Referncias esquerda apontam para um n no nvel abaixo. 2. Referncias direita podem ser verticais ou horizontais. Eliminao da assimetria nas rvores B binrias rvores B binrias simtricas (Symmetric Binary B-trees SBB) rvore SBB uma rvore binria com 2 tipos de referncias: verticais e horizontais, tal que: 1. todos os caminhos da raiz at cada n externo possuem o mesmo nmero de referncias verticais, e 2. no podem existir dois referncias horizontais sucessivos.
3 1 2 4 6 5 7 9 8 10

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

37

Transformaes para Manuteno da Propriedade SBB


O algoritmo para rvores SBB usa transformaes locais no caminho de insero ou retirada para preservar o balanceamento. A chave a ser inserida ou retirada sempre inserida ou retirada aps o referncia vertical mais baixo na rvore. Dependendo da situao anterior insero ou retirada, podem aparecer dois referncias horizontais sucessivos Neste caso: necessrio realizar uma transformao. Transformaes Propostas por Bayer R. 1972
2 1 (a) Esquerdaesquerda (EE) 3 1 2 3 1 2 3

1 2

3 1

2 3

(b) Esquerdadireita (ED)

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

38

Estrutura e operaes do dicionrio para rvores SBB


Diferenas da rvore sem balanceamento: constantes Horizontal e Vertical : representam as inclinaes das referncias s subrvores; campo propSBB : utilizado para vericar quando a propriedade SBB deixa de ser satisfeita campos incE e incD : indicam o tipo de referncia (horizontal ou vertical) que sai do n. A operao inicializa implementada pelo construtor da classe ArvoreSBB . As demais operaes so implementadas utilizando mtodos privados sobrecarregados.

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

39

Estrutura e operaes do dicionrio para rvores SBB


package cap5; import cap4. Item ; / / vide programa do captulo 4 public class ArvoreSBB { private static class No { Item reg ; No esq, dir ; byte incE , incD; } private static final byte Horizontal = 0; private static final byte Vertical = 1; private No raiz ; private boolean propSBB; / / Entram aqui os mtodos privados das transparncias 21, 40, 41 e 48 public ArvoreSBB ( ) { this . raiz = null ; this .propSBB = true ; } public Item pesquisa ( Item reg ) { return this .pesquisa ( reg , this . raiz ) ; } public void insere ( Item reg ) { this . raiz = insere ( reg , null , this . raiz , true ) ; } public void retira ( Item reg ) { this . raiz = this . retira ( reg , this . raiz ) ; } / / Entra aqui o mtodo para imprimir a rvore da tranaparncia 29 }

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

40

Mtodos para manuteno da propriedade SBB


private No ee (No ap) { No ap1 = ap.esq ; ap.esq = ap1. dir ; ap1. dir = ap; ap1. incE = Vertical ; ap. incE = Vertical ; ap = ap1; return ap; } private No ed (No ap) { No ap1 = ap.esq ; No ap2 = ap1. dir ; ap1.incD = Vertical ; ap. incE = Vertical ; ap1. dir = ap2.esq ; ap2.esq = ap1; ap.esq = ap2. dir ; ap2. dir = ap; ap = ap2; return ap; } private No dd (No ap) { No ap1 = ap. dir ; ap. dir = ap1.esq ; ap1.esq = ap; ap1.incD = Vertical ; ap.incD = Vertical ; ap = ap1; return ap; } private No de (No ap) { No ap1 = ap. dir ; No ap2 = ap1.esq ; ap1. incE = Vertical ; ap.incD = Vertical ; ap1.esq = ap2. dir ; ap2. dir = ap1; ap. dir = ap2.esq ; ap2.esq = ap; ap = ap2; return ap; }

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

41

Mtodo para inserir na rvore SBB


private No insere ( Item reg , No pai , No filho , boolean filhoEsq ) { i f ( f i l h o == null ) { f i l h o = new No ( ) ; f i l h o . reg = reg ; f i l h o . incE = Vertical ; f i l h o .incD = Vertical ; f i l h o .esq = null ; f i l h o . dir = null ; i f ( pai ! = null ) i f ( filhoEsq ) pai . incE = Horizontal ; else pai .incD = Horizontal ; this .propSBB = false ; } else i f ( reg .compara ( f i l h o . reg) < 0) { f i l h o .esq = insere ( reg , filho , f i l h o .esq, true ) ; i f ( ! this .propSBB) i f ( f i l h o . incE == Horizontal ) { i f ( f i l h o .esq. incE == Horizontal ) { f i l h o = this .ee ( f i l h o ) ; / / transformao esquerda-esquerda i f ( pai ! = null ) i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ; } else i f ( f i l h o .esq.incD == Horizontal ) { f i l h o = this .ed ( f i l h o ) ; / / transformao esquerda-direita i f ( pai ! = null ) i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ; } } else this .propSBB = true ; } / / Continua na prxima transparncia

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

42

Mtodo para inserir na rvore SBB


else i f ( reg .compara ( f i l h o . reg) > 0) { f i l h o . dir = insere ( reg , filho , f i l h o . dir , false ) ; i f ( ! this .propSBB) i f ( f i l h o .incD == Horizontal ) { i f ( f i l h o . dir .incD == Horizontal ) { f i l h o = this .dd ( f i l h o ) ; / / transformao direita-direita i f ( pai ! = null ) i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ; } else i f ( f i l h o . dir . incE == Horizontal ) { f i l h o = this .de ( f i l h o ) ; / / transformao direita-esquerda i f ( pai ! = null ) i f ( filhoEsq ) pai . incE=Horizontal ; else pai .incD=Horizontal ; } } else this .propSBB = true ; } else { System. out . println ( "Erro : Registro ja existente " ) ; this .propSBB = true ; } return f i l h o ; }

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

43

Exemplo
Insero de uma seqncia de chaves em uma rvore SBB inicialmente vazia. 1. rvore esquerda obtida aps a insero das chaves 7, 10, 5. 2. rvore do meio obtida aps a insero das chaves 2, 4 na rvore anterior. 3. rvore direita obtida aps a insero das chaves 9, 3, 6 na rvore anterior.
5 5 7 10 2 4 7 10 2 3 4 5 6 7 9 10

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

44

Procedimento Retira
Assim como o mtodo insere mostrado anteriormente, o mtodo retira possui uma verso privada, que foi sobrecarregada com uma interface que contm um parmetro a mais que a sua verso pblica. O mtodo privado retira utiliza trs mtodos auxiliares, a saber: esqCurto (dirCurto ) chamado quando um n folha (que referenciado por uma referncia vertical) retirado da subrvore esquerda (direita), tornando-a menor na altura aps a retirada; Quando o n a ser retirado possui dois descendentes, o mtodo antecessor localiza o n antecessor para ser trocado com o n a ser retirado.

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

45

Mtodo auxiliar esqCurto para retirada da rvore SBB


/ / Folha esquerda retirada => rvore curta na altura esquerda private No esqCurto (No ap) { i f (ap. incE == Horizontal ) { ap. incE = Vertical ; this .propSBB = true ; } else i f (ap.incD == Horizontal ) { No ap1 = ap. dir ; ap. dir = ap1.esq ; ap1.esq = ap; ap = ap1; i f (ap.esq. dir . incE == Horizontal ) { ap.esq = this .de (ap.esq ) ; ap. incE = Horizontal ; } else i f (ap.esq. dir .incD == Horizontal ) { ap.esq = this .dd (ap.esq ) ; ap. incE = Horizontal ; } this .propSBB = true ; } else { ap.incD = Horizontal ; i f (ap. dir . incE == Horizontal ) { ap = this .de (ap ) ; this .propSBB = true ; } else i f (ap. dir .incD == Horizontal ) { ap = this .dd (ap ) ; this .propSBB = true ; } } return ap; }

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

46

Mtodo auxiliar dirCurto para retirada da rvore SBB


/ / Folha direita retirada => rvore curta na altura direita private No dirCurto (No ap) { i f (ap.incD == Horizontal ) { ap.incD = Vertical ; this .propSBB = true ; } else i f (ap. incE == Horizontal ) { No ap1 = ap.esq ; ap.esq = ap1. dir ; ap1. dir = ap; ap = ap1; i f (ap. dir .esq.incD == Horizontal ) { ap. dir = this .ed (ap. dir ) ; ap.incD = Horizontal ; } else i f (ap. dir .esq. incE == Horizontal ) { ap. dir = this .ee (ap. dir ) ; ap.incD = Horizontal ; } this .propSBB = true ; } else { ap. incE = Horizontal ; i f (ap.esq.incD == Horizontal ) { ap = this .ed (ap ) ; this .propSBB = true ; } else i f (ap.esq. incE == Horizontal ) { ap = this .ee (ap ) ; this .propSBB = true ; } } return ap; }

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

47

Mtodo auxiliar antecessor para retirada da rvore SBB


private No antecessor (No q, No r ) { i f ( r . dir ! = null ) { r . dir = antecessor ( q, r . dir ) ; i f ( ! this .propSBB) r = this . dirCurto ( r ) ; } else { q. reg = r . reg ; r = r .esq; i f ( r ! = null ) this .propSBB = true ; } return r ; }

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

48

Mtodo retira para retirada da rvore SBB


private No retira ( Item reg , No ap) { i f (ap == null ) { System. out . println ( "Erro : Registro nao encontrado" ) ; this .propSBB = true ; } else i f ( reg .compara (ap. reg ) < 0) { ap.esq = retira ( reg , ap.esq) ; i f ( ! this .propSBB) ap = this .esqCurto (ap) ; } else i f ( reg .compara (ap. reg ) > 0) { ap. dir = retira ( reg , ap. dir ) ; i f ( ! this .propSBB) ap = this . dirCurto (ap) ; } else { / / encontrou o registro this .propSBB = false ; i f (ap. dir == null ) { ap = ap.esq; i f (ap ! = null ) this .propSBB = true ; } else i f (ap.esq == null ) { ap = ap. dir ; i f (ap ! = null ) this .propSBB = true ; } else { ap.esq = antecessor (ap, ap.esq) ; i f ( ! this .propSBB) ap = this .esqCurto (ap) ; } } return ap; }

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

49

Exemplo
Dada a rvore:
5 5 7 10 2 4 7 10 2 3 4 5 6 7 9 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 4 5 6 9 10 2 3 4 6 9 10 2 3 4 6 10

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

50

Exemplo: Retirada de Ns de SBB


Caso 1: 2 1 3 6 4 10 2 12 1 3 6 t 6 10 1 3 6 10 4 2 4

1a chamada DirCurto

2a chamada DirCurto

2 chamadas DirCurto

Caso 2: 4 2 1 3 6 10 8 12 2 1 3 4 6 8 10 1 2 3 6 4 8 10

1a

chamada DirCurto

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

51

Exemplo: Retirada de Ns de SBB


Caso 3: 4 2 1 3 5 6 8 10 12 1 2 3 5 6 8 4 10

4 2 1 3 5 8 6 10

Se nodo 8 tem filho: 4 2 1 3 5 6 8 10 9 2 12 1 3 5 4 6 8 10 9 4 4 2 2 1 3 5 6 8 9 10 1 3 5 8 10 6 9

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

52

Anlise
Nas rvores SBB necessrio distinguir dois tipos de alturas: 1. Altura vertical h necessria para manter a altura uniforme e obtida atravs da contagem do nmero de referncias verticais em qualquer caminho entre a raiz e um n externo. 2. Altura k representa o nmero mximo de comparaes de chaves obtida atravs da contagem do nmero total de referncias no maior caminho entre a raiz e um n externo. A altura k maior que a altura h sempre que existirem referncias horizontais na rvore. Para uma rvore SBB com n ns internos, temos que h k 2h.

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

53

Anlise
De fato Bayer (1972) mostrou que log (n + 1) k 2 log(n + 2) 2. Custo para manter a propriedade SBB Custo para percorrer o caminho de pesquisa para encontrar a chave, seja para inser-la ou para retir-la. Logo: O custo O(log n). Nmero de comparaes em uma pesquisa com sucesso na rvore SBB melhor caso : C (n) = O(1), pior caso caso m edio : C (n) = O(log n), : C (n) = O(log n).

Observe: Na prtica o caso mdio para Cn apenas cerca de 2% pior que o Cn para uma rvore completamente balanceada, conforme mostrado em Ziviani e Tompa (1982).

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

54

Pesquisa Digital
Pesquisa digital baseada na representao das chaves como uma seqncia de caracteres ou de dgitos. Os mtodos de pesquisa digital so particularmente vantajosos quando as chaves so grandes e de tamanho varivel. Um aspecto interessante quanto aos mtodos de pesquisa digital a possibilidade de localizar todas as ocorrncias de uma determinada cadeia em um texto, com tempo de resposta logartmico em relao ao tamanho do texto. Trie Patrcia

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

55

Trie
Uma trie uma rvore M -ria cujos ns so vetores de M componentes com campos correspondentes aos dgitos ou caracteres que formam as chaves. Cada n no nvel i representa o conjunto de todas as chaves que comeam com a mesma seqncia de i dgitos ou caracteres. Este n especica uma ramicao com M caminhos dependendo do (i + 1)-simo dgito ou caractere de uma chave. Considerando as chaves como seqncia de bits (isto , M = 2), o algoritmo de pesquisa digital semelhante ao de pesquisa em rvore, exceto que, em vez de se caminhar na rvore de acordo com o resultado de comparao entre chaves, caminha-se de acordo com os bits de chave.

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

56

Exemplo
Dada as chaves de 6 bits: B C J = 010010 = 010011 = 100001

H = 011000 M = 101000

0 1 0 0 1 0 1 1 0

1 0 1

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

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

W Q

H
0

0 1

J C

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

58

Consideraes Importantes sobre as Tries


O formato das tries, diferentemente das rvores binrias comuns, no depende da ordem em que as chaves so inseridas e sim da estrutura das chaves atravs da distribuio de seus bits. Desvantagem: Uma grande desvantagem das tries a formao de caminhos de uma s direo para chaves com um grande nmero de bits em comum. Exemplo: Se duas chaves diferirem somente no ltimo bit, elas formaro um caminho cujo comprimento igual ao tamanho delas, no importando quantas chaves existem na rvore. Caminho gerado pelas chaves B e C.

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

59

Patricia - Practical Algorithm To Retrieve Information Coded In Alphanumeric


Criado por Morrison D. R. 1968 para aplicao em recuperao de informao em arquivos de grande porte. Knuth D. E. 1973 novo tratamento algoritmo. Reapresentou-o de forma mais clara como um caso particular de pesquisa digital, essencialmente, um caso de rvore trie binria. Sedgewick R. 1988 apresentou novos algoritmos de pesquisa e de insero baseados nos algoritmos propostos por Knuth. Gonnet, G.H e Baeza-Yates R. 1991 propuzeram tambm outros algoritmos.

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

60

Mais sobre Patricia


O algoritmo para construo da rvore Patricia baseado no mtodo de pesquisa digital, mas sem apresentar o inconveniente citado para o caso das tries. O problema de caminhos de uma s direo eliminado por meio de uma soluo simples e elegante: cada n interno da rvore contm o ndice do bit a ser testado para decidir qual ramo tomar. Exemplo: dada as chaves de 6 bits: B = 010010 C = 010011 H = 011000 J = 100001 Q = 101000
1 3 6 B C H J 3 Q

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

61

Insero da Chave K
1 3 6 B C H J 3 Q

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, verique o valor do bit 5 de ambas as chaves.
1 3 6 B C H J 5 K 3 Q

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

62

Insero da Chave W
A insero da chave W = 110110 ilustra um outro aspecto. Os bits das chaves K e W so comparados a partir do primeiro para determinar em qual ndice eles diferem, sendo, neste caso, os de ndice 2. Portanto: o ponto de insero agora ser no caminho de pesquisa entre os ns internos de ndice 1 e 3. Cria-se a um novo n interno de ndice 2, cujo descendente direito um n externo contendo W e cujo descendente esquerdo a subrvore de raiz de ndice 3.
1 3 6 B C J H 5 K 3 Q 2 W

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 polimorsmo da linguagem Java.
package cap5; public class ArvorePatricia { private static abstract class PatNo { } private static class PatNoInt extends PatNo { int index; PatNo esq, dir ; } private static class PatNoExt extends PatNo { char chave; } private PatNo raiz ; private int nbitsChave; / / Entram aqui os mtodos privados das transparncias 64, 65 e 68 public ArvorePatricia ( int nbitsChave) { this . raiz = null ; this .nbitsChave = nbitsChave; } public void pesquisa ( char k) { this .pesquisa (k, this . raiz ) ; } public void insere ( char k) { this . raiz = this .insere (k, this . raiz ) ; } }

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

64

Mtodos Auxiliares
/ / Retorna o i-simo bit da chave k a partir da esquerda private int bit ( int i , char k) { i f ( i == 0) return 0; int c = ( int )k; for ( int j = 1; j <= this .nbitsChave i ; j ++) c = c/2; return c % 2; } / / Verica se p n externo private boolean eExterno (PatNo p) { Class classe = p.getClass ( ) ; return classe.getName( ) .equals(PatNoExt. class .getName( ) ) ; }

Mtodo para criar n interno:


private PatNo criaNoInt ( int i , PatNo esq, PatNo dir ) { PatNoInt p = new PatNoInt ( ) ; p.index = i ; p.esq = esq; p. dir = dir ; return p; }

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

65

Mtodos Auxiliares
Mtodo para criar n externo:
private PatNo criaNoExt ( char k) { PatNoExt p = new PatNoExt ( ) ; p.chave = k; return p; }

Mtodo para pesquisa:


private void pesquisa ( char k, PatNo t ) { i f ( this .eExterno ( t ) ) { PatNoExt aux = (PatNoExt) t ; i f (aux.chave == k) System.out. println ( "Elemento encontrado" ) ; else System.out. println ( "Elemento nao encontrado" ) ; } else { PatNoInt aux = (PatNoInt) t ; i f ( this . bit (aux.index, k) == 0) pesquisa (k, aux.esq) ; else pesquisa (k, aux. dir ) ; } }

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

66

Descrio Informal do Algoritmo de Insero


Cada chave k inserida de acordo com os passos abaixo, partindo da raiz: 1. Se a subrvore corrente for vazia, ento criado um n externo contendo a chave k (isso ocorre somente na insero da primeira chave) e o algoritmo termina. 2. Se a subrvore corrente for simplesmente um n externo, os bits da chave k so comparados, a partir do bit de ndice imediatamente aps o ltimo ndice da seqncia de ndices consecutivos do caminho de pesquisa, com os bits correspondentes da chave k deste n externo at encontrar um ndice i cujos bits diram. A comparao dos bits a partir do ltimo ndice consecutivo melhora consideravelmente o desempenho do algoritmo. Se todos forem iguais, a chave j se encontra na rvore e o algoritmo termina; seno, vai-se para o Passo 4.

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

67

Descrio Informal do Algoritmo de Insero


Continuao: 3. Caso contrrio, ou seja, se a raiz da subrvore corrente for um n interno, vai-se para a subrvore indicada pelo bit da chave k de ndice dado pelo n corrente, de forma recursiva. 4. Depois so criados um n interno e um n externo: o primeiro contendo o ndice i e o segundo, a chave k . A seguir, o n interno ligado ao externo pela referncia subrvore esquerda ou direita, dependendo se o bit de ndice i da chave k seja 0 ou 1, respectivamente. 5. O caminho de insero percorrido novamente de baixo para cima, subindo com o par de ns criados no Passo 4 at chegar a um n interno cujo ndice seja menor que o ndice i determinado no Passo 2. Esse o ponto de insero e o par de ns inserido.

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

68

Algoritmo de insero
private PatNo insereEntre ( char k , PatNo t , int i ) { PatNoInt aux = null ; i f ( ! this .eExterno ( t ) ) aux = (PatNoInt) t ; i f ( this .eExterno ( t ) | | ( i < aux. index ) ) { / / Cria um novo n externo PatNo p = this . criaNoExt ( k ) ; i f ( this . bit ( i , k) == 1) return this . criaNoInt ( i , t , p) ; else return this . criaNoInt ( i , p, t ) ; } else { i f ( this . bit (aux. index , k) == 1) aux. dir = this . insereEntre ( k , aux. dir , i ) ; else aux.esq = this . insereEntre ( k , aux.esq, i ) ; return aux; } } private PatNo insere ( char k , PatNo t ) { i f ( t == null ) return this . criaNoExt ( k ) ; else { PatNo p = t ; while ( ! this .eExterno (p) ) { PatNoInt aux = (PatNoInt)p; i f ( this . bit (aux. index , k) == 1) p = aux. dir ; else p = aux.esq; } PatNoExt aux = (PatNoExt)p; int i = 1; / / acha o primeiro bit diferente while ( ( i <= this .nbitsChave)&& ( this . bit ( i , k) == this . bit ( i , aux.chave) ) ) i ++; i f ( i > this .nbitsChave ) { System. out . println ( "Erro : chave ja esta na arvore" ) ; return t ; } else return this . insereEntre ( k , t , i ) ; } }

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

69

Transformao de Chave (Hashing)


Os registros armazenados em uma tabela so diretamente endereados a partir de uma transformao aritmtica sobre a chave de pesquisa. Hash signica: 1. Fazer picadinho de carne e vegetais para cozinhar. 2. Fazer uma baguna. (Websters New World Dictionary)

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

70

Transformao de Chave (Hashing)


Um mtodo de pesquisa com o uso da transformao de chave constitudo de duas etapas principais: 1. Computar o valor da funo de transformao, a qual transforma a chave de pesquisa em um endereo da tabela. 2. Considerando que duas ou mais chaves podem ser transformadas em um mesmo endereo de tabela, necessrio existir um mtodo para lidar com colises. Qualquer que seja a funo de transformao, algumas colises iro ocorrer fatalmente, e tais colises tm de ser resolvidas de alguma forma. Mesmo que se obtenha uma funo de transformao que distribua os registros de forma uniforme entre as entradas da tabela, existe uma alta probabilidade de haver colises.

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

71

Transformao de Chave (Hashing)


O paradoxo do aniversrio (Feller,1968, p. 33), diz que em um grupo de 23 ou mais pessoas, juntas ao acaso, existe uma chance maior do que 50% de que 2 pessoas comemorem aniversrio no mesmo dia. Assim, se for utilizada uma funo de transformao uniforme que enderece 23 chaves randmicas em uma tabela de tamanho 365, a probabilidade de que haja colises maior do que 50%. A probabilidade p de se inserir N itens consecutivos sem coliso em uma tabela de tamanho M : M N +1 M 1 M 2 ... = p= M M M
N

=
i=1

M i+1 M! = M (M N )!M N

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

72

Transformao de Chave (Hashing)


Alguns valores de p para diferentes valores de N ,onde M = 365.
N 10 22 23 30 p 0,883 0,524 0,493 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%.

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

73

Funes de Transformao
Uma funo de transformao deve mapear chaves em inteiros dentro do intervalo [0..M 1], onde M o tamanho da tabela. A funo de transformao ideal aquela que: 1. Seja simples de ser computada. 2. Para cada chave de entrada, qualquer uma das sadas possveis igualmente provvel de ocorrer. Como as transformaes sobre as chaves so aritmticas, deve-se transformar as chaves no-numricas em nmeros. Em Java, basta realizar uma converso de cada caractere da chave no numrica para um nmero inteiro.

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

74

Mtodo mais Usado


Usa o resto da diviso por M . h(K ) = K mod M, onde K um inteiro correspondente chave. Cuidado na escolha do valor de M . M deve ser um nmero primo, mas no qualquer primo: devem ser evitados os nmeros primos obtidos a partir de bi j onde b a base do conjunto de caracteres (geralmente b = 64 para BCD, 128 para ASCII, 256 para EBCDIC, ou 100 para alguns cdigos decimais), e i e j so pequenos inteiros.

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

75

Transformao de Chaves No Numricas


As chaves no numricas devem ser transformadas em nmeros:
n1

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

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

76

Transformao de Chaves No Numricas


Programa que gera um peso para cada caractere de uma chave constituda de n caracteres:
private int [ ] geraPesos ( int n) { int p[ ] = new int [n ] ; java . u t i l .Random rand = new java . u t i l .Random ( ) ; for ( int i = 0; i < n ; i ++) p[ i ] = rand. nextInt (M) + 1; return p; }

Implementao da funo de transformao:


private int h ( String chave, int [ ] pesos) { int soma = 0; for ( int i = 0; i < chave. length ( ) ; i ++) soma = soma + ( ( int )chave. charAt ( i ) ) pesos[ i ] ; return soma % this .M; }

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

77

Listas Encadeadas
Uma das formas de resolver as colises simplesmente construir uma lista linear encadeada para cada endereo da tabela. Assim, todas as chaves com mesmo endereo so encadeadas em uma lista linear. Exemplo: Se a i-sima letra do alfabeto representada pelo nmero i e a funo de transformao h(Chave) = Chave mod M utilizada para M = 7, o resultado da insero das chaves P E S Q U I S A na tabela o seguinte: Por exemplo, h(A) = h(1) = 1, h(E ) = h(5) = 5, h(S ) = h(19) = 5, e assim por diante.
T 0 1 2 3 4 5 6

U A P Q
nil

- nil - nil - I - nil - S

nil

E
nil

- S

nil

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

78

Estrutura e operaes do dicionrio para listas encadeadas


Em cada entrada da lista devem ser armazenados uma chave e um registro de dados cujo tipo depende da aplicao. A classe interna Celula utilizada para representar uma entrada em uma lista de chaves que so mapeadas em um mesmo endereo i da tabela, sendo 0 i M 1. O mtodo equals da classe Celula usado para vericar se duas clulas so iguais (isto , possuem a mesma chave). A operao inicializa implementada pelo construtor da classe TabelaHash .

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

79

Estrutura e operaes do dicionrio para listas encadeadas


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

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

80

Estrutura e operaes do dicionrio para listas encadeadas


public Object pesquisa ( String chave) { int i = this .h (chave, this .pesos) ; i f ( this . tabela [ i ] . vazia ( ) ) return null ; / / pesquisa sem sucesso else { Celula cel=(Celula) this . tabela [ i ] . pesquisa( new Celula(chave, null ) ) ; i f ( cel == null ) return null ; / / pesquisa sem sucesso else return cel . item ; } } public void insere ( String chave, Object item ) { i f ( this .pesquisa (chave) == null ) { int i = this .h (chave, this .pesos) ; this . tabela [ i ] . insere (new Celula (chave, item ) ) ; } else System. out . println ( "Registro ja esta presente" ) ; } public void retira ( String chave) throws Exception { int i = this .h (chave, this .pesos) ; Celula cel = ( Celula) this . tabela [ i ] . retira ( new Celula (chave, null ) ) ; i f ( cel == null ) System. out . println ( "Registro nao esta presente" ) ; } }

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

81

Anlise
Assumindo que qualquer item do conjunto tem igual probabilidade de ser endereado para qualquer entrada da tabela, ento o comprimento esperado de cada lista encadeada N/M , em que N representa o nmero de registros na tabela e M o tamanho da tabela. Logo: as operaes pesquisa , insere e retira custam O(1 + N/M ) operaes em mdia, sendo que a constante 1 representa o tempo para encontrar a entrada na tabela, e N/M , o tempo para percorrer a lista. Para valores de M prximos de N , o tempo torna-se constante, isto , independente de N .

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

82

Endereamento Aberto
Quando o nmero de registros a serem armazenados na tabela puder ser previamente estimado, ento no haver necessidade de usar listas encadeadas para armazenar os registros. Existem vrios mtodos para armazenar N registros em uma tabela de tamanho M > N , os quais utilizam os lugares vazios na prpria tabela para resolver as colises. (Knuth, 1973, p.518) No Endereamento aberto todas as chaves so armazenadas na prpria tabela, sem o uso de listas encadeadas em cada entrada dela. Existem vrias propostas para a escolha de localizaes alternativas. A mais simples chamada de hashing linear, onde a posio hj na tabela dada por: hj = (h(x) + j ) mod M, para 1 j M 1.

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

83

Exemplo
Se a i-sima letra do alfabeto representada pelo nmero i e a funo de transformao h(chave ) = chave mod M utilizada para M = 7,

ento o resultado da insero das chaves L U N E S na tabela, usando hashing linear para resolver colises mostrado abaixo.

Por exemplo, h(L) = h(12) = 5, h(U ) = h(21) = 0, h(N ) = h(14) = 0, h(E ) = h(5) = 5, e h(S ) = h(19) = 5.
T 0 1 2 3 4 5 6 U N S

L E

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

84

Estrutura e operaes do dicionrio usando endereamento aberto


A tabela agora constituda por um arranjo de clulas. A classe interna Celula utilizada para representar uma clula da tabela. A operao inicializa implementada pelo construtor da classe TabelaHash . As operaes utilizam alguns mtodos auxiliares durante a execuo.

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

85

Estrutura e operaes do dicionrio usando endereamento aberto


package cap5.endaberto; public class TabelaHash { private static class Celula { String chave ; Object item ; boolean retirado ; public Celula ( String chave, Object item ) { this .chave = chave ; this . item = item ; this . retirado = false ; } public boolean equals ( Object obj ) { Celula cel = ( Celula) obj ; return chave. equals ( cel .chave) ; } } private int M; / / tamanho da tabela private Celula tabela [ ] ; private int pesos [ ] ; / / Entram aqui os mtodos privados da transparncia 76 public TabelaHash ( int m, int maxTamChave) { this .M = m; this . tabela = new Celula [ this .M] ; for ( int i = 0; i < this .M; i ++) this . tabela [ i ] = null ; / / vazio this .pesos = this .geraPesos (maxTamChave) ; } / / Continua na prxima transparncia

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

86

Estrutura e operaes do dicionrio usando endereamento aberto


public Object pesquisa ( String chave) { int indice = this . pesquisaIndice (chave) ; i f ( indice < this .M) return this . tabela [ indice ] . item ; else return null ; / / pesquisa sem sucesso } public void insere ( String chave, Object item ) { i f ( this .pesquisa (chave) == null ) { int i n i c i a l = this .h (chave, this .pesos) ; int indice = i n i c i a l ; int i = 0; while ( this . tabela [ indice ] ! = null && ! this . tabela [ indice ] . retirado && i < this .M) indice = ( i n i c i a l + (++ i )) % this .M; i f ( i < this .M) this . tabela [ indice ] = new Celula (chave, item ) ; else System. out . println ( "Tabela cheia" ) ; } else System. out . println ( "Registro ja esta presente" ) ; } / / Continua na prxima transparncia

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

87

Estrutura e operaes do dicionrio usando endereamento aberto


public void retira ( String chave) throws Exception { int i = this . pesquisaIndice (chave) ; i f ( i < this .M) { this . tabela [ i ] . retirado = true ; this . tabela [ i ] . chave = null ; } else System. out . println ( "Registro nao esta presente" ) ; } private int pesquisaIndice ( String chave) { int i n i c i a l = this .h (chave, this .pesos) ; int indice = i n i c i a l ; int i = 0; while ( this . tabela [ indice ] ! = null && !chave. equals ( this . tabela [ indice ] . chave) && i < this .M) indice = ( i n i c i a l + (++ i )) % this .M; i f ( this . tabela [ indice ] ! = null && chave. equals ( this . tabela [ indice ] . chave) ) return indice ; else return this .M; } } / / pesquisa sem sucesso

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

88

Anlise
Seja = N/M o fator de carga da tabela. Conforme demonstrado por Knuth (1973), o custo de uma pesquisa com sucesso 1 C (n) = 2 1 1+ 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 car cheia, pois a insero de uma nova chave tende a ocupar uma posio na tabela que esteja contgua a outras posies j ocupadas, o que deteriora o tempo necessrio para novas pesquisas. Entretanto, apesar do hashing linear ser um mtodo relativamente pobre para resolver colises os resultados apresentados so bons. O melhor caso, assim como o caso mdio, O(1).

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

89

Vantagens e Desvantagens de Transformao da Chave


Vantagens: Alta ecincia no custo de pesquisa, que O(1) para o caso mdio. Simplicidade de implementao. Desvantagens: Custo para recuperar os registros na ordem lexicogrca das chaves alto, sendo necessrio ordenar o arquivo. Pior caso O(N ).

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

90

Hashing Perfeito
Se h(xi ) = h(xj ) se e somente se i = j , ento no h colises, e a funo de transformao chamada de funo de transformao perfeita ou funo hashing perfeita(hp). Se o nmero de chaves N e o tamanho da tabela M so iguais ( = N/M = 1), ento temos uma funo de transformao perfeita mnima. Se xi xj e hp(xi ) hp(xj ), ento a ordem lexicogrca preservada. Nesse caso, temos uma funo de transformao perfeita mnima com ordem preservada.

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

91

Vantagens e Desvantagens de Uma Funo de Transformao Perfeita


No h necessidade de armazenar a chave, pois o registro localizado sempre a partir do resultado da funo de transformao. Uma funo de transformao perfeita especca para um conjunto de chaves conhecido. A desvantagem no caso o espao ocupado para descrever a funo de transformao hp. Entretanto, possvel obter um mtodo com M 1, 25N , para valores grandes de N .

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

92

Algoritmo de Czech, Havas e Majewski


Czech, Havas e Majewski (1992, 1997) propem um mtodo elegante baseado em grafos randmicos para obter uma funo de transformao perfeita com ordem preservada. A funo de transformao do tipo: hp(x) = (g (h1 (x)) + g (h2 (x))) mod N, na qual h1 (x) e h2 (x) so duas funes no perfeitas, x a chave de busca, e g um arranjo especial que mapeia nmeros no intervalo 0 . . . M 1 para o intervalo 0 . . . N 1.

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

93

Problema Resolvido Pelo Algoritmo


Dado um grafo no direcionado G = (V, A), onde |V | = M e |A| = N , encontre uma funo g : V [0, N 1], denida como hp(a = (u, v ) A) = (g (u) + g (v )) mod N . Em outras palavras, estamos procurando uma atribuio de valores aos vrtices de G tal que a soma dos valores associados aos vrtices de cada aresta tomado mdulo N um nmero nico no intervalo [0, N 1]. A questo principal como obter uma funo g adequada. A abordagem mostrada a seguir baseada em grafos e hipergrafos randmicos.

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

94

Exemplo
Chaves: 12 meses do ano abreviados para os trs primeiros caracteres. Objetivo: obter uma funo de transformao perfeita hp de tal forma que o i-simo ms mantido na (i 1)-sima posio da tabela hash:
Chave x jan fev mar abr mai jun jul ago set out nov dez h1 (x) 10 1 8 1 0 10 0 5 4 0 3 4 h2 (x) 11 2 9 3 5 9 3 6 1 1 2 7 hp(x) 0 1 2 3 4 5 6 7 8 9 10 11

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

95

Grafo Randmico gerado


O problema de obter a funo g equivalente a encontrar um grafo no direcionado contendo M vrtices e N arestas.
0 11 10 5 9 2 8 7 6 7 0 6 3 4 8 11 4 5 9 1 1 2 10 3

Os vrtices so rotulados com valores no intervalo 0 . . . M 1 As arestas denidas 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) denem os vrtices sobre os quais a aresta incidente.

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

96

Obteno da Funo g a Partir do Grafo


Passo importante: conseguir um arranjo g de vrtices para inteiros no intervalo 0 . . . N 1 tal que, para cada aresta (h1 (x), h2 (x)), o valor de hp(x) = g (h1 (x)) + g (h2 (x))) mod N seja igual ao rtulo da aresta. Algoritmo: 1. Qualquer vrtice no processado escolhido e feito g [v ] = 0. 2. As arestas que saem do vrtice v so seguidas e o valor g (u) do vrtice u destino rotulado com o valor da diferena entre o valor da aresta (v, u) e g (v ), tomado mod N . 3. Procura-se o prximo componente conectado ainda no visitado e os mesmos passos descritos acima so repetidos.

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

97

Seguindo o Algoritmo para Obter g no Exemplo dos 12 Meses do Ano


0 11 10 5 9 2 8 7 6
Chave x jan fev mar abr mai (a) jun jul ago set out nov dez h1 (x) 10 1 8 1 0 10 0 5 4 0 3 4 h2 (x) 11 2 9 3 5 9 3 6 1 1 2 7 hp(x) 0 1 2 3 4 5 6 7 8 9 10 11 (b) v: 0 1 2 3 4 5 6 7 8 9 10 11 g (v ) 0 9 4 6 11 4 3 0 0 2 3 9

9 6 3 4 8 11 7

1 1 2 10 3

4 5

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

98

Problema
Quando o grafo contm ciclos: o mapeamento a ser realizado pode rotular de novo um vrtice j processado e que tenha recebido outro rtulo com valor diferente. Por exemplo, se a aresta (5, 6), que a aresta de rtulo 7, tivesse sido sorteada para a aresta (8, 11), o algoritmo tentaria atribuir dois valores distintos para o valor de g [11]. Para enxergar isso, vimos que se g [8] = 0, ento g [11] deveria ser igual a 7, e no igual ao valor 9 obtido acima. Um grafo que permite a atribuio de dois valores de g para um mesmo vrtice, no vlido. Grafos acclicos no possuem este problema. Um caminho seguro para se ter sucesso obter antes um grafo acclico e depois realizar a atribuio de valores para o arranjo g . Czech, Havas e Majewski (1992).

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

99

Primeiro Renamento 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) ) } } 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 ; } rotuleDe ( u , (G. aresta ( v,u) g[ v]) % N, g) ;

return grafoRotulavel ;

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

100

Algoritmo para Obter a Funo de Transformao Perfeita


void obtemHashingPerfeito ( ) { Ler conjunto de N chaves; Escolha um valor para M ; do { Gera os pesos p1 [i] e p2 [i] para Gera o grafo G = (V, A) ; 0 i maxT amChave 1 ;

grafoRotulavel = atribuig (G, g) ; } while ( ! grafoRotulavel ) ; Retorna p1 , p2 e g ; }

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

101

Estruturas de dados e operaes para obter a funo hash perfeita


package cap5.fhpm; import java . io . ; import cap7. listaadj . arranjo .Grafo ; / / vide Programas do captulo 7 public class FHPM { private int p1[ ] , p2 [ ] ; / / pesos de h1 e h2 private int g [ ] ; / / funo g private int N; private int M; / / nmero de chaves / / 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

106

Mtodo para salvar no disco a funo de transformao perfeita


public void salvar ( String nomeArqSaida) throws Exception { BufferedWriter arqSaida = new BufferedWriter ( new FileWriter (nomeArqSaida) ) ; arqSaida. write ( this .N + " (N) \n" ) ; arqSaida. write ( this .M + " (M) \n" ) ; arqSaida. write ( this .maxTamChave + " (maxTamChave) \n" ) ; for ( int i = 0; i < this .maxTamChave; i ++) arqSaida. write ( this .p1[ i ] + " " ) ; arqSaida. write ( " (p1) \n" ) ; for ( int i = 0; i < this .maxTamChave; i ++) arqSaida. write ( this .p2[ i ] + " " ) ; arqSaida. write ( " (p2) \n" ) ; for ( int i = 0; i < this .M; i ++) arqSaida. write ( this .g[ i ] + " " ) ; arqSaida. write ( " (g) \n" ) ; arqSaida. write ( "No. grafos gerados por geraGrafo: " + this .nGrafosGerados + " \n" ) ; arqSaida. write ( "No. grafos considerados por atribuig : " + ( this .nGrafosConsiderados + 1) + " \n" ) ; arqSaida. close ( ) ; }

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

107

Mtodo para ler do disco a funo de transformao perfeita


public void ler ( String nomeArqFHPM ) throws Exception { BufferedReader arqFHPM = new BufferedReader ( new FileReader (nomeArqFHPM ) ) ; String temp = arqFHPM . readLine ( ) , valor = temp. substring(0 , temp.indexOf ( " " ) ) ; this .N = Integer . parseInt ( valor ) ; temp = arqFHPM . readLine ( ) ; valor = temp. substring(0 , temp.indexOf ( " " ) ) ; this .M = Integer . parseInt ( valor ) ; temp = arqFHPM . readLine ( ) ; valor = temp. substring(0 , temp.indexOf ( " " ) ) ; this .maxTamChave = Integer . parseInt ( valor ) ; temp = arqFHPM . readLine ( ) ; int inicio = 0; this .p1 = new int [ this .maxTamChave] ; for ( int i = 0; i < this .maxTamChave; i ++) { int fim = temp.indexOf ( , inicio ) ; valor = temp. substring ( inicio , fim ) ; inicio = fim + 1; this .p1[ i ] = Integer . parseInt ( valor ) ; } temp = arqFHPM . readLine ( ) ; inicio = 0; this .p2 = new int [ this .maxTamChave] ; for ( int i = 0; i < this .maxTamChave; i ++) { int fim = temp.indexOf ( , inicio ) ; valor = temp. substring ( inicio , fim ) ; inicio = fim + 1; this .p2[ i ] = Integer . parseInt ( valor ) ; } temp = arqFHPM . readLine ( ) ; inicio = 0; this .g = new int [ this .M] ; for ( int i = 0; i < this .M; i ++) { int fim = temp.indexOf ( , inicio ) ; valor = temp. substring ( inicio , fim ) ; inicio = fim + 1; this .g[ i ] = Integer . parseInt ( valor ) ; } arqFHPM . close ( ) ; }

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

108

Programa para gerar uma funo de transformao perfeita


package cap5; import java . io . ; import cap5.fhpm. FHPM ; / / vide transparncia 101 public class GeraFHPM { public static void main ( String [ ] args ) { BufferedReader in = new BufferedReader ( new InputStreamReader (System. in ) ) ; try { System. out . print ( "Numero de chaves: " ) ; int n = Integer . parseInt ( in . readLine ( ) ) ; System. out . print ( "Tamanho da maior chave: " ) ; int maxTamChave = Integer . parseInt ( in . readLine ( ) ) ; System. out . print ( "Nome do arquivo com chaves a serem lidas : " ) ; String nomeArqEnt = in . readLine ( ) ; System. out . print ( "Nome do arquivo para gravar a FHPM : " ) ; String nomeArqSaida = in . readLine ( ) ; FHPM fhpm = new FHPM (maxTamChave, n, 3 ) ; fhpm.obtemHashingPerfeito (nomeArqEnt) ; fhpm. salvar (nomeArqSaida) ; } catch ( Exception e) {System. out . println (e.getMessage ( ) ) ; } } }

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

109

Programa para testar uma funo de transformao perfeita


package cap5; import java . io . ; import cap5.fhpm. FHPM ; / / vide transparncia 101 public class TestaFHPM { public static void main ( String [ ] args ) { BufferedReader in = new BufferedReader ( new InputStreamReader (System. in ) ) ; try { System. out . print ( "Nome do arquivo com a FHPM : " ) ; String nomeArqEnt = in . readLine ( ) ; FHPM fhpm = new FHPM (0 , 0 , 0); fhpm. ler (nomeArqEnt) ; System. out . print ( "Chave: " ) ; String chave = in . readLine ( ) ; while ( ! chave.equals ( "aaaaaa" ) ) { System. out . println ( "Indice : " + fhpm.hp (chave) ) ; System. out . print ( "Chave: " ) ; chave = in . readLine ( ) ; } } catch ( Exception e) {System. out . println (e.getMessage ( ) ) ; } } }

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

110

Anlise
A questo crucial : quantas interaes so necessrias para obter um grafo G = (V, A) que seja rotulvel? Para grafos arbitrrios, difcil achar uma soluo para esse problema, isso se existir tal soluo. Entretanto, para grafos acclicos, a funo g existe sempre e pode ser obtida facilmente. Assim, a resposta a esta questo depende do valor de M que escolhido no primeiro passo do algoritmo. Quanto maior o valor de M , mais esparso o grafo e, conseqentemente, mais provvel que ele seja acclico.

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

111

Anlise
Segundo Czech, Havas e Majewski (1992), quando M 2N a probabilidade de gerar aleatoriamente um grafo acclico tende para zero quando N cresce. Isto ocorre porque o grafo se torna denso, e o grande nmero de arestas pode levar formao de ciclos. Por outro lado, quando M > 2N , a probabilidade de que um grafo randmico contendo M vrtices e N arestas seja acclico aproximadamente M 2N , M E o nmero esperado de grafos gerados at que o primeiro acclico seja obtido : M M 2N

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

112

Anlise
Para M = 3N o nmero esperado de iteraes 3, em mdia, aproximadamente 1,7 grafos sero testados antes que aparea um grafo acclico. Logo, a complexidade de tempo para gerar a funo de transformao proporcional ao nmero de chaves a serem inseridas na tabela hash, desde que M > 2N . O grande inconveniente de usar M = 3N o espao necessrio para armazenar o arranjo g. Por outro lado, considerar M < 2N pode implicar na necessidade de gerar muitos grcos randmicos at que um grafo acclico seja encontrado.

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

113

Outra Alternativa
No utilizar grafos tradicionais, mas sim hipergrafos, ou r-grafos, nos quais cada aresta conecta um nmero qualquer r de vrtices. Para tanto, basta usar uma terceira funo h3 para gerar um trigrafo com arestas conectando trs vrtices, chamado de 3-grafo. Em outras palavras, cada aresta uma tripla do tipo (h1 (x), h2 (x), h3 (x)), e a funo de transformao dada por: h(x) = (g (h1 (x)) + g (h2 (x)) + g (h3 (x))) mod N.

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

114

Outra Alternativa
Nesse caso, o valor de M pode ser prximo a 1, 23N . Logo, o uso de trigrafos reduz o custo de espao da funo de transformao perfeita, mas aumenta o tempo de acesso ao dicionrio. Alm disso, o processo de rotulao no pode ser feito como descrito. Ciclos devem ser detectados previamente, utilizando a seguinte propriedade de r-grafos: Um r-grafo acclico se e somente se a remoo repetida de arestas contendo apenas vrtices de grau 1 (isto , vrtices sobre os quais incide apenas uma aresta) elimina todas as arestas do grafo.

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

115

Experimentos
# Chaves 10 20 30 40 50 60 70 80 90 100 # Chamadas geraGrafo 3586 20795 55482 52077 47828 27556 26265 161736 117014 43123 # Chamadas atribuig 1 16 24 33 19 10 17 92 106 26 Tempo (s) 0.130 0.217 0.390 0.432 0.462 0.313 0.351 1.543 1.228 0.559

Anda mungkin juga menyukai