Transformação de Chave. (Hashing)

Documentos relacionados
Pesquisa em memória primária: hashing. Algoritmos e Estruturas de Dados II

Módulo 18 - Tabelas de Dispersão

A inserção da chave 6 da árvore acima resulta na árvore abaixo.

Matrizes esparsas: definição

Hashing: conceitos. Hashing

Linguagem C: Listas Encadeadas

DAINF - Departamento de Informática

Estruturas de Dados. Módulo 17 - Busca. 2/6/2005 (c) Dept. Informática - PUC-Rio 1

Pesquisa Linear. Adriano J. Holanda 15/3/2016

Árvores B. Prof. Márcio Bueno. / Fonte: Material da Prof a Ana Eliza Lopes Moura

Análise de Algoritmos

TABELA HASH. Prof. André Backes. Princípio de funcionamento dos métodos de busca

Lista Encadeada (Linked List)

Árvores Binárias de Busca (ABB) 18/11

Medida do Tempo de Execução de um Programa. Bruno Hott Algoritmos e Estruturas de Dados I DECSI UFOP

Estruturas de Dados Aula 16: Árvores com Número Variável 13/06/2011

INF P3-23/06/07 Questão 1 Nome:

Listas Lineares Ordenadas

Programação de Computadores II. Cap. 17 Busca

Programação II. Busca em Vetor (search) Bruno Feijó Dept. de Informática, PUC-Rio

Árvores B. Hashing. Estrutura de Dados II Jairo Francisco de Souza

Classificação e Pesquisa de Dados. Aula 23 Organização de Arquivos: Arquivos Indexados, Diretos e Arquivos Invertidos

Programação: Vetores

INF1007: Programação 2 7 Busca em Vetores. 01/04/2014 (c) Dept. Informática - PUC-Rio 1

Estruturas de Dados. Módulo 11 Pilhas. 9/8/2005 (c) Dept. Informática - PUC-Rio 1

Estruturas de Dados I

Algoritmos e Estrutura de Dados. Aula 05 Estrutura de Dados: Listas (Parte II) Prof. Tiago A. E. Ferreira

Fundamentos de Algoritmos (5175/31)

INF1007: Programação 2 8 Listas Encadeadas. (c) Dept. Informática - PUC-Rio 1

indexação e hashing Construção de Índices e Funções Hash Diego Gomes Tomé - MSc. Informática Orientador: Prof. Dr. Eduardo Almeida October 13, 2016

Estados dos processos. Infra Estruturas Computacionais. A troca de contexto. Escalonamento de Processos. Escalonamento de Processos

Documento de uso exclusivo da unidade, não possui valor legal. 28/06/ :43:00. Matéria: Carga Horária Total. Prática: 44 Campo: 44

Módulo 5 Vetores e Alocação Dinâmica

Módulo 10 Listas Encadeadas

Estruturas de Dados. Filas em que a prioridade de remoção não é cronológica. Maior prioridade não é do elemento que ingressou primeiro

4 Variáveis. Unesp Campus de Guaratinguetá

Introdução Métodos de Busca Parte 1

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: ponteiros e alocação dinâmica

Listas e matrizes esparsas. SCC122 Estruturas de Dados

Árvores. Prof. César Melo DCC/ICE/UFAM

Algoritmos e Estruturas de Dados I (DCC/003) 2013/1. Estruturas Básicas. Aula Tópico 4

Árvores Binárias de Busca

Aula 10 Alocação Dinâmica de Memória Listas Encadeadas. prof Leticia Winkler

Introdução à Computação MAC0110

LP II Estrutura de Dados Estruturas Heterogêneas e Listas Lineares Estáticas. Prof. José Honorato Ferreira Nunes

ALGORITMOS E ESTRUTURAS DE DADOS CES-11

Sumário. Introdução à Ciência da Computação. Ponteiros em C. Introdução. Definição. Por quê ponteiros são importantes?

Agenda. Ideia. Buscar um item em um array. Função hash. Função hash. Hash Table. Introdução Definição Hash Table. Métodos de resolução de conflitos

PROGRAMAÇÃO I E N T R A DA E S A Í DA D E DA D O S

Exercícios. Alocação Dinâmica. Alocação dinâmica de memória. Alocação de memória. Alocação da Memória Principal. Alocação da Memória Principal

SCC 202 Algoritmos e Estruturas de Dados I. Listas Lineares Encadeadas Alocação dinâmica

I Alocação dinâmica de memória é utilizada para alocar espaço de memória para armazenar conteúdos de variáveis;

Fundamentos de Programação

ESTRUTURAS COMPOSTAS. Variáveis Compostas Unidimensionais VETOR. Baseado nos slides de Rosely Sanches e Simone Senger de Souza

Fundamentos de Sistemas Operacionais

Pesquisa em Memória Secundária. Prof. Jonas Potros

Lista com descritor (continuação)

Algoritmos e Estruturas de Dados II IEC013

Organização de Arquivos. SCE-183 Algoritmos e Estruturas de Dados II

Ordenação Externa. Ordenação Externa. Ordenação Externa. Ordenação Externa

SCC122 - Estruturas de Dados. Lista Estática Seqüencial

C++ - Matrizes. Observ.: C++ não avisa quando o limite de uma matriz foi excedido. Providenciar a verificação é responsabilidade do programador.

Disciplina de Algoritmos e Programação

Linguagem C Princípios Básicos (parte 1)

Módulo 4. Listas Encadeadas. Algoritmos e Estruturas de Dados II C++ (Rone Ilídio)

a) Calcule o valor médio de CPI apresentado na execução deste programa P, utilizando-se C1 sem e com otimização.

AULA 14 ESTRUTURA DE DADOS

Compressão de Textos. Introdução. Introdução. Introdução. O volume de informação textual disponível on-line é imenso:

INF1007: Programação 2 6 Ordenação de Vetores. 01/10/2015 (c) Dept. Informática - PUC-Rio 1

1. Listas sequenciais versus listas ligadas. Lista sequencial

FUNDAMENTOS DE ARQUITETURAS DE COMPUTADORES MEMÓRIA CACHE CAPÍTULO 5. Cristina Boeres

Noções de algoritmos - Aula 1

LINGUAGEM C: ARRAY: VETORES E MATRIZES

SCC Capítulo 5 Métodos de Busca [3]

Anhanguera Educacional S.A. Centro Universitário Ibero-Americano

Introdução à Linguagem C++

Transcrição:

UNIVERSIDADE ESTADUAL DE MARINGÁ DEPARTAMENTO DE INFORMÁTICA Transformação de Chave (Hashing) e Gomes da Costa yandre@din.uem.br 1

Transformações de Chave, ou Tabela Hash, ou Tabelas de Dispersão; Hashing : fazer picadinho, ou fazer uma bagunça; Técnica que objetiva organizar um conjunto de dados, caracterizados por uma chave, de forma que o acesso tenha o menor custo possível; Em estruturas tradicionais (já estudadas), se os registros forem mantidos ordenados, algoritmos eficientes podem garantir busca à um custo O(log n); 2

Tabelas hash, se bem projetadas, podem garantir buscas à um custo constante O(1); Os registros armazenados em uma tabela são diretamente endereçados a partir de uma transformação aritmética sobre a chave de pesquisa; O preço pago por esta eficiência será o uso maior de memória; 3

Exemplo: Suponhamos um sistema acadêmico que utiliza como chave o número de matrícula do aluno (RA) composto por 7 dígitos numéricos; Para permitir a busca à um registro de um aluno com um custo constante poderia ser utilizada a sua própria matrícula como índice de um vetor vet; Se isto fosse feito, poderíamos acessar os dados do aluno cuja matrícula é mat através de vet[mat]; 4

Assim, o acesso ocorre em ordem constante, entretanto o custo de memória para manter esse acesso é muito alto; Vamos considerar que o registro correspondente a cada aluno tenha a seguinte estrutura: struct Aluno { int mat; char nome [80]; char email [30]; char turma; }; 5

Considerando que o número de matrícula é composto por 7 dígitos, ele poderia ser caracterizado por qualquer número entre 0 e 9.999.999; Assim, existe 10 milhões de possíveis números de matrícula; Para isto, seria necessário um vetor com 10 milhões de elementos, que poderia ser estabelecido por: #define MAX 10000000 Aluno vet[max]; 6

Dessa forma, o nome do aluno de matrícula mat é acessado simplesmente através de vet[mat].nome; Embora o acesso seja rápido o custo de memória é proibitivo; Para a struct definida anteriormente teríamos um gasto de 115 bytes de memória para cada aluno; Assim, o vetor descrito anteriormente consumiria 1.150.000.000 bytes, ou seja, acima de 1 Gbyte de memória; 7

Em uma situação prática, seria comum encontrar um cadastro com algo em torno de 1.000 alunos, o que necessitaria de apenas 115 Kbytes de memória para armazenamento; Uma forma de resolver o problema do gasto excessivo de memória, garantindo um acesso rápido, é através do uso de tabela hash; 8

Um método de pesquisa através de hashing, é constituído de duas etapas principais: Computar o valor da função de transformação (função hashing), a qual transforma a chave de pesquisa em um endereço de tabela; Considerando que duas ou mais chaves podem ser transformadas em um mesmo endereço de tabela, é necessário existir um método para lidar com colisões; 9

Mesmo que o número de registros a serem armazenados seja muito menor do que o tamanho da tabela, qualquer que seja a função de transformação, fatalmente ocorrerão algumas colisões; Paradoxo do aniversário (Feller, 1968): Em um grupo de 23 ou mais pessoas juntas ao acaso, a probabilidade de que 2 pessoas comemorem aniversário no mesmo dia é maior do que 50%. 10

Assim, em uma tabela com 365 endereços a probabilidade de colisão entre 23 chaves escolhidas aleatoriamente é maior do que 50%; Alta probabilidade de colisões, mesmo com distribuição uniforme; Exemplos: Armazenar registros cuja chave é o RG de pessoas, com 7 dígitos numéricos, em uma tabela com 10000 endereços; Armazenar registros cuja chave consiste de nomes compostos por até 16 letras (26 16 chaves possíveis) em uma tabela com 1000 endereços; 11

Funções de Transformação: Uma função de transformação deve mapear chaves em inteiros dentro do intervalo [0..M- 1], onde M é o tamanho da tabela; A função ideal é aquela que: seja simples de ser computada; para cada chave de entrada, qualquer uma das saídas possíveis é igualmente provável de ocorrer. Considerando que as transformações sobre as chaves são aritméticas, se houverem chaves não numéricas, elas devem ser transformadas em números; 12

Um dos métodos que funciona muito bem para a transformação de chave, utiliza o resto da divisão por M: h(k) = K mod M Onde K é um inteiro correspondente à chave; Este é um método muito simples; Cuidado na escolha do valor de M: Se M é par, então h(k) é par quando K é par, e h(k) é ímpar quando K é ímpar; Assim, uma boa estratégia é escolher um valor primo para M; 13

Um exemplo de função em linguagem C: const n=10, M=7; typedef char TipoChave[n]; int h(tipochave Chave) { int i, Soma=0; for (i=0; i<n; i++) Soma += Chave[i]; return (Soma % M); } 14

Exercício: Considere uma situação em que os itens de dados são identificados por uma chave composta por números inteiros de até 5 algarismos. Considere ainda que a função de transformação utilizada para endereçamento em uma tabela seja h(k)=k mod N, onde N é o tamanho da tabela. Considerando uma tabela de tamanho N=7, calcule os endereços para as seguintes chaves : 70013,10000, 7478, 197, 35019, 792, 10394, 5515, 8748, 15543. Trace um gráfico mostrando a distribuição destas chaves na tabela. Descreva a sua opinião a respeito da ocorrência (ou não) de colisões proporcionada pelas chaves descritas anteriormente e lance algumas hipóteses que possam viabilizar o tratamento de possíveis colisões em termos de estruturas de dados. 15

Um estudo de caso: Armazenar dados de alunos utilizando como chave o RA; Alta probabilidade de colisões, mesmo com distribuição uniforme; Identificando partes significativas da chave: Número de matrícula: 9 9 2 0 0 0 1 Indicadores seqüenciais Vestibular de ingresso Ano de ingresso Pode-se adotar uma parte da chave de acordo com o tamanho da tabela que se pretende utilizar; 16

Para armazenar apenas dados de alunos pertencentes à uma determinada turma: Considerando que: muitos alunos provavelmente ingressaram no mesmo ano; muitos alunos provavelmente ingressaram no mesmo vestibular; uma tabela de tamanho 100 seria suficiente para armazenar os dados dos alunos de uma turma; Poderiam ser tomados os dois últimos dígitos dos indicadores seqüenciais para compor a chave; 9 9 2 0 0 0 1 Indicadores seqüenciais Vestibular de ingresso Ano de ingresso 17

Assim, a tabela poderia ser dada por: Aluno* tab[100]; Neste caso, o acesso ao nome do aluno cujo número de matrícula é mat seria dado por: vet[mat%100]->nome; A função de busca que mapeia uma chave para um índice da tabela poderia ser: int hash (int mat) { return (mat%100); } 18

De forma geral, para uma tabela de tamanho N, a função poderia ser dada por: Na prática, costuma-se utilizar um número primo para estabelecer o tamanho da tabela; Para minimizar o número de colisões, utiliza-se como regra empírica [Celes et al., 2004]: Evitar taxa de ocupação superior a 75%; Taxas em torno de 50%, em geral, trazem bons resultados; Taxas menores do que 25% podem representar gasto excessivo de memória; int hash (int mat) { return (mat%n); } 19

Tratamento de colisões: Vamos considerar um vetor de ponteiros, dado por: #define N 127 typedef Aluno* Hash[N]; Uso da posição consecutiva livre: Os elementos que colidem são armazenados em posições da tabela ainda não ocupadas; Uma das estratégias consiste em buscar a próxima posição livre (utilizando incremento circular): x h(x) busca por posição livre o 20

Em uma busca, depois de mapeada a chave, procura-se a mesma no vetor até que ela ou uma posição vazia seja encontrada; Aluno* hsh_busca (Hash tab, int mat) { int h=hash(mat); while (tab[h]!= NULL) { if (tab[h]->mat == mat) return tab[h]; h=(h+1)%n; } return NULL; } 21

Uma função que insere ou modifica um elemento poderia ser dada por: Aluno* hsh_insere (Hash tab, int mat, char n[81], char e[41], char t) { int h=hash(mat); while (tab[h]!= NULL) { if (tab[h]->mat == mat) break; h=(h+1)%n; } if (tab[h]==null) { //não encontrou o elemento tab[h] = (Aluno*) malloc (sizeof (Aluno)); tab[h]->mat = mat; } strcpy (tab[h]->nome, n); // atribui ou modifica informação strcpy (tab[h]->email, e); tab[h]->turma = t; return tab[h]; } 22

Uso de listas encadeadas: Estratégia diferente, consiste em fazer com que cada elemento da tabela hash represente um ponteiro para uma lista encadeada; x h(x) 23

Neste caso, a estrutura poderia ser dada por: struct Aluno { int mat; char nome [80]; char email [30]; char turma; sturct Aluno* prox; }; 24

A operação de busca poderia ser descrita da seguinte forma: Aluno* hsh_busca (Hash tab, int mat) { int h = hash(mat); Aluno* a = tab[h]; while (a!= NULL) { if (a->mat == mat) return a; a = a->prox; } return NULL; } 25

Custo médio de uma consulta [Ziviani, 2002]: Uso de posição consecutiva livre: Considerando um fator de carga α dado por: α=q/n» Onde Q é a quantidade de elementos inseridos na estrutura e N é o tamanho da tabela; O custo médio é dado por: Custo médio = ½ (1+1/(1- α)) Lista encadeada: Custo médio = (1+ α) Onde α=q/n, e Q é a quantidade de elementos inseridos na estrutura e N é o tamanho da tabela; A constante 1 corresponde ao tempo gasto para cálculo da função hash; 26

Evolução do custo médio para posição 1 2 3 4 5 6 7 8 9 10 11 12 consecutiva livre: Q N Custo 10 100 1,06 20 100 1,13 25 100 1,17 30 100 1,21 40 100 1,33 50 100 1,50 60 100 1,75 70 100 2,17 75 100 2,50 80 100 3,00 90 100 5,50 99 100 50,50 Custo 60,00 40,00 20,00 0,00 Evolução do custo 1 3 5 7 9 11 Carga Custo 27

Referências Bibliográficas: Celes, Waldemar et al. Introdução a Estruturas de Dados. Rio de Janeiro: Elsevier, 2004; Pereira, Silvio do Lago. Estruturas de Dados Fundamentais. São Paulo: Érica, 1996; Wirth, Niklaus. Algoritmos e Estruturas de Dados. Rio de Janeiro: LTC, 1999; Ziviani, Nivio. Projeto de Algoritmos com implementações em Pascal e C. São Paulo: Pioneira Thomson Learning, 2002; 28