Embora djb2
, como apresentado no stackoverflow da cnicutar , seja quase certamente melhor, acho que vale a pena mostrar os hashes K&R também:
1) Aparentemente, um terrível algoritmo de hash, como apresentado na 1ª edição da K&R ( fonte )
unsigned long hash(unsigned char *str)
{
unsigned int hash = 0;
int c;
while (c = *str++)
hash += c;
return hash;
}
2) Provavelmente, um algoritmo de hash bastante decente, como apresentado na versão 2 da K&R (verificado por mim na p. 144 do livro); Nota: certifique-se de remover % HASHSIZE
da instrução de retorno se você planeja fazer o módulo dimensionar para o comprimento da matriz fora do algoritmo hash. Além disso, eu recomendo que você faça o retorno e o tipo "hashval" em unsigned long
vez do simples unsigned
(int).
unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31*hashval;
return hashval % HASHSIZE;
}
Observe que, pelos dois algoritmos, fica claro que um dos motivos pelo qual o hash da 1ª edição é tão terrível é porque NÃO leva em consideração a ordem dos caracteres da string , portanto hash("ab")
, retornaria o mesmo valor que hash("ba")
. Isto não é acontece com o hash da 2ª edição, no entanto, que (muito melhor!) Retornaria dois valores diferentes para essas strings.
As funções de hash do GCC C ++ 11 usadas para unordered_map
(um modelo de tabela de hash) e unordered_set
(um modelo de conjunto de hash) parecem ser as seguintes.
Código:
// Implementation of Murmur hash for 32-bit size_t.
size_t _Hash_bytes(const void* ptr, size_t len, size_t seed)
{
const size_t m = 0x5bd1e995;
size_t hash = seed ^ len;
const char* buf = static_cast<const char*>(ptr);
// Mix 4 bytes at a time into the hash.
while (len >= 4)
{
size_t k = unaligned_load(buf);
k *= m;
k ^= k >> 24;
k *= m;
hash *= m;
hash ^= k;
buf += 4;
len -= 4;
}
// Handle the last few bytes of the input array.
switch (len)
{
case 3:
hash ^= static_cast<unsigned char>(buf[2]) << 16;
[[gnu::fallthrough]];
case 2:
hash ^= static_cast<unsigned char>(buf[1]) << 8;
[[gnu::fallthrough]];
case 1:
hash ^= static_cast<unsigned char>(buf[0]);
hash *= m;
};
// Do a few final mixes of the hash.
hash ^= hash >> 13;
hash *= m;
hash ^= hash >> 15;
return hash;
}