Tabela de hash na estrutura de dados: exemplo em Python

Índice:

Anonim

O que é Hashing?

Um hash é um valor de comprimento fixo e é gerado por meio de uma fórmula matemática. Os valores de hash são usados ​​na compactação de dados, criptologia, etc. Na indexação de dados, os valores de hash são usados ​​porque têm tamanho de comprimento fixo, independentemente dos valores usados ​​para gerá-los. Faz com que os valores de hash ocupem um espaço mínimo em comparação com outros valores de comprimentos variados.

Uma função hash emprega um algoritmo matemático para converter a chave em um hash. Uma colisão ocorre quando uma função hash produz o mesmo valor hash para mais de uma chave.

Neste tutorial de algoritmo, você aprenderá:

  • O que é Hashing?
  • O que é uma tabela de hash?
  • Funções Hash
  • Qualidades de uma boa função hash
  • Colisão
  • Operações de tabela de hash
  • Exemplo de Hash Table Python
  • Explicação do código da tabela de hash
  • Exemplo de dicionário Python
  • Análise de Complexidade
  • Aplicativos do mundo real
  • Vantagens das tabelas de hash
  • Desvantagens das tabelas de hash

O que é uma tabela de hash?

A HASH TABLE é uma estrutura de dados que armazena valores usando um par de chaves e valores. Cada valor é atribuído a uma chave exclusiva que é gerada usando uma função hash.

O nome da chave é usado para acessar seu valor associado. Isso torna a pesquisa de valores em uma tabela hash muito rápida, independentemente do número de itens na tabela hash.

Funções Hash

Por exemplo, se quisermos armazenar registros de funcionários, e cada funcionário for identificado exclusivamente por meio de um número de funcionário.

Podemos usar o número do funcionário como chave e atribuir os dados do funcionário como valor.

A abordagem acima exigirá espaço livre extra da ordem de (m * n 2 ), onde a variável m é o tamanho da matriz e a variável n é o número de dígitos do número do funcionário. Essa abordagem apresenta um problema de espaço de armazenamento.

Uma função hash resolve o problema acima obtendo o número do funcionário e usando-o para gerar um valor inteiro hash, dígitos fixos e otimizando o espaço de armazenamento. O objetivo de uma função hash é criar uma chave que será usada para fazer referência ao valor que queremos armazenar. A função aceita o valor a ser salvo e usa um algoritmo para calcular o valor da chave.

A seguir está um exemplo de uma função hash simples

h(k) = k1 % m

AQUI,

  • h (k) é a função hash que aceita um parâmetro k. O parâmetro k é o valor para o qual desejamos calcular a chave.
  • k 1 % m é o algoritmo para nossa função hash, em que k1 é o valor que queremos armazenar e m é o tamanho da lista. Usamos o operador de módulo para calcular a chave.

Exemplo

Vamos supor que temos uma lista com tamanho fixo de 3 e os seguintes valores

[1,2,3]

Podemos usar a fórmula acima para calcular as posições que cada valor deve ocupar.

A imagem a seguir mostra os índices disponíveis em nossa tabela hash.

Passo 1)

Calcule a posição que será ocupada pelo primeiro valor assim

h (1) = 1% 3

= 1

O valor 1 irá ocupar o espaço no índice 1

Passo 2)

Calcule a posição que será ocupada pelo segundo valor

h (2) = 2% 3

= 2

O valor 2 irá ocupar o espaço no índice 2

Etapa 3)

Calcule a posição que será ocupada pelo terceiro valor.

h (3) = 3% 3

= 0

O valor 3 irá ocupar o espaço no índice 0

Resultado final

Nossa tabela hash preenchida agora será a seguinte.

Qualidades de uma boa função hash

Uma boa função hash deve ter as seguintes qualidades.

  • A fórmula para gerar o hash deve usar o valor dos dados a serem armazenados no algoritmo.
  • A função hash deve gerar valores hash exclusivos, mesmo para dados de entrada com a mesma quantidade.
  • A função deve minimizar o número de colisões. As colisões ocorrem quando o mesmo valor é gerado para mais de um valor.
  • Os valores devem ser distribuídos de forma consistente em todos os hashes possíveis.

Colisão

Uma colisão ocorre quando o algoritmo gera o mesmo hash para mais de um valor.

Vejamos um exemplo.

Suponha que temos a seguinte lista de valores

[3,2,9,11,7]

Vamos supor que o tamanho da tabela hash seja 7 e usaremos a fórmula (k 1 % m) onde m é o tamanho da tabela hash.

A tabela a seguir mostra os valores de hash que serão gerados.

Chave Algoritmo de hash (k 1 % m) Valor Hash
3 3% 7 3
2 3% 7 2
9 3% 7 2
11 3% 7 4
7 3% 7 0

Como podemos ver nos resultados acima, os valores 2 e 9 têm o mesmo valor de hash e não podemos armazenar mais de um valor em cada posição.

O problema fornecido pode ser resolvido usando encadeamento ou sondagem. As seções a seguir discutem o encadeamento e a verificação em detalhes.

Encadeamento

O encadeamento é uma técnica usada para resolver o problema de colisão usando listas vinculadas, cada uma com índices exclusivos.

A imagem a seguir mostra a aparência de uma lista encadeada

Ambos 2 e 9 ocupam o mesmo índice, mas são armazenados como listas vinculadas. Cada lista possui um identificador único.

Benefícios das listas encadeadas

A seguir estão os benefícios das listas encadeadas:

  • Listas encadeadas apresentam melhor desempenho ao inserir dados, pois a ordem de inserção é O (1).
  • Não é necessário redimensionar uma tabela hash que usa uma lista encadeada.
  • Ele pode acomodar facilmente um grande número de valores, desde que haja espaço livre disponível.

Sondagem

A outra técnica usada para resolver a colisão é a sondagem. Ao usar o método de sondagem, se ocorrer uma colisão, podemos simplesmente seguir em frente e encontrar um slot vazio para armazenar nosso valor.

A seguir estão os métodos de sondagem:

Método Descrição
Sondagem Linear Tal como o nome sugere, este método procura slots vazios linearmente a partir da posição onde ocorreu a colisão e avançando. Se o fim da lista for alcançado e nenhum slot vazio for encontrado. A sondagem começa no início da lista.
Sondagem quadrática Este método usa expressões polinomiais quadráticas para encontrar o próximo slot livre disponível.
Hashing duplo Essa técnica usa um algoritmo de função hash secundária para encontrar o próximo slot livre disponível.

Usando nosso exemplo acima, a tabela de hash após o uso de sondagem teria a seguinte aparência:

Operações de tabela de hash

Aqui estão as operações suportadas por tabelas Hash:

  • Inserção - esta operação é usada para adicionar um elemento à tabela de hash
  • Pesquisando - esta operação é usada para pesquisar elementos na tabela de hash usando a chave
  • Excluindo - esta operação é usada para excluir elementos da tabela hash

Inserir operação de dados

A operação de inserção é usada para armazenar valores na tabela hash. Quando um novo valor é armazenado na tabela de hash, é atribuído um número de índice. O número do índice é calculado usando a função hash. A função hash resolve todas as colisões que ocorrem ao calcular o número do índice.

Pesquisa de operação de dados

A operação de pesquisa é usada para pesquisar valores na tabela hash usando o número do índice. A operação de pesquisa retorna o valor que está vinculado ao número do índice de pesquisa. Por exemplo, se armazenarmos o valor 6 no índice 2, a operação de pesquisa com o número de índice 2 retornará o valor 6.

Excluir operação de dados

A operação de exclusão é usada para remover um valor de uma tabela hash. Para excluir a operação é feita usando o número de índice. Depois que um valor é excluído, o número do índice é liberado. Ele pode ser usado para armazenar outros valores usando a operação de inserção.

Implementação de tabela de hash com exemplo de Python

Vejamos um exemplo simples que calcula o valor hash de uma chave

def hash_key( key, m):return key % mm = 7print(f'The hash value for 3 is {hash_key(3,m)}')print(f'The hash value for 2 is {hash_key(2,m)}')print(f'The hash value for 9 is {hash_key(9,m)}')print(f'The hash value for 11 is {hash_key(11,m)}')print(f'The hash value for 7 is {hash_key(7,m)}')

Explicação do código da tabela de hash

AQUI,

  1. Define uma função hash_key que aceita a chave de parâmetros e m.
  2. Usa uma operação de módulo simples para determinar o valor de hash
  3. Define uma variável m que é inicializada com o valor 7. Este é o tamanho da nossa tabela hash
  4. Calcula e imprime o valor hash de 3
  5. Calcula e imprime o valor hash de 2
  6. Calcula e imprime o valor hash de 9
  7. Calcula e imprime o valor hash de 11
  8. Calcula e imprime o valor hash de 7

Executar o código acima produz os seguintes resultados.

The hash value for 3 is 3The hash value for 2 is 2The hash value for 9 is 2The hash value for 11 is 4The hash value for 7 is 0

Exemplo de dicionário Python

Python vem com um tipo de dados embutido chamado Dicionário. Um dicionário é um exemplo de tabela hash. Ele armazena valores usando um par de chaves e valores. Os valores de hash são gerados automaticamente para nós e todas as colisões são resolvidas para nós em segundo plano.

O exemplo a seguir mostra como você pode usar um tipo de dados de dicionário em python 3

employee = {'name': 'John Doe','age': 36,'position': 'Business Manager.'}print (f"The name of the employee is {employee['name']}")employee['position'] = 'Software Engineer'print (f"The position of {employee['name']} is {employee['position']}")employee.clear()print (employee)

AQUI,

  1. Define um funcionário variável do dicionário. O nome da chave é usado para armazenar o valor John Doe, idade armazena 36 e posição armazena o valor Business Manager.
  2. Recupera o valor do nome da chave e o imprime no terminal
  3. Atualiza o valor da posição-chave para o valor Engenheiro de Software
  4. Imprime os valores do nome e posição das chaves
  5. Exclui todos os valores que são armazenados em nossa variável de dicionário funcionário
  6. Imprime o valor do funcionário

Executar o código acima produz os seguintes resultados.

The name of the employee is John Doe.The position of John Doe is a Software Engineer.{}

Análise de Complexidade

As tabelas de hash têm uma complexidade de tempo média de O (1) no melhor cenário. O pior caso de complexidade de tempo é O (n). O pior cenário ocorre quando muitos valores geram a mesma chave hash e temos que resolver a colisão por meio de sondagem.

Aplicativos do mundo real

No mundo real, as tabelas de hash são usadas para armazenar dados para

  • Bancos de dados
  • Matrizes associativas
  • Jogos
  • Cache de memória

Vantagens das tabelas de hash

Aqui, estão os prós / benefícios de usar tabelas de hash:

  • As tabelas de hash têm alto desempenho ao pesquisar dados, inserir e excluir valores existentes.
  • A complexidade de tempo para tabelas hash é constante, independentemente do número de itens na tabela.
  • Eles funcionam muito bem mesmo ao trabalhar com grandes conjuntos de dados.

Desvantagens das tabelas de hash

Aqui, estão os contras do uso de tabelas de hash:

  • Você não pode usar um valor nulo como chave.
  • As colisões não podem ser evitadas ao gerar chaves usando. funções hash. As colisões ocorrem quando uma chave que já está em uso é gerada.
  • Se a função de hashing tiver muitas colisões, isso pode levar à diminuição do desempenho.

Resumo:

  • As tabelas de hash são usadas para armazenar dados usando um par de chaves e valores.
  • Uma função hash usa um algoritmo matemático para calcular o valor do hash.
  • Uma colisão ocorre quando o mesmo valor hash é gerado para mais de um valor.
  • O encadeamento resolve a colisão criando listas vinculadas.
  • A investigação resolve a colisão ao encontrar slots vazios na tabela hash.
  • A sondagem linear procura o próximo slot livre para armazenar o valor a partir do slot onde ocorreu a colisão.
  • A sondagem quadrática usa expressões polinomiais para encontrar o próximo slot livre quando ocorre uma colisão.
  • O hash duplo usa um algoritmo de função de hash secundário para encontrar o próximo slot livre quando ocorre uma colisão.
  • As tabelas de hash têm melhor desempenho quando comparadas a outras estruturas de dados.
  • A complexidade de tempo médio das tabelas de hash é O (1)
  • Um tipo de dados de dicionário em python é um exemplo de uma tabela hash.
  • As tabelas de hash suportam operações de inserção, pesquisa e exclusão.
  • Um valor nulo não pode ser usado como um valor de índice.
  • As colisões não podem ser evitadas em funções hash. Uma boa função hash minimiza o número de colisões que ocorrem para melhorar o desempenho.