Sebbene djb2
, come presentato su stackoverflow da cnicutar , sia quasi certamente migliore, penso che valga la pena mostrare anche gli hash K&R :
1) Apparentemente un terribile algoritmo di hash, come presentato nella prima edizione di K&R ( fonte )
unsigned long hash(unsigned char *str)
{
unsigned int hash = 0;
int c;
while (c = *str++)
hash += c;
return hash;
}
2) Probabilmente un algoritmo hash abbastanza decente, come presentato nella versione 2 di K&R (verificato da me a pag. 144 del libro); NB: assicurati di rimuovere % HASHSIZE
dall'istruzione return se prevedi di eseguire il dimensionamento del modulo in base alla lunghezza del tuo array al di fuori dell'algoritmo hash. Inoltre, ti consiglio di fare il tipo return e "hashval" unsigned long
invece del semplice unsigned
(int).
unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31*hashval;
return hashval % HASHSIZE;
}
Si noti che è chiaro dai due algoritmi che uno dei motivi per cui l'hash della prima edizione è così terribile è perché NON prende in considerazione l' ordine dei caratteri delle stringhe , hash("ab")
quindi restituirebbe lo stesso valore di hash("ba")
. Tuttavia, non è così con l'hash della seconda edizione, che restituirebbe (molto meglio!) Due valori diversi per quelle stringhe.
Le funzioni hash di GCC C ++ 11 utilizzate per unordered_map
(un modello di tabella hash) e unordered_set
(un modello di set di hash) sembrano essere le seguenti.
Codice:
// 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;
}