Mặc dù djb2
, như được trình bày trên stackoverflow bởi cnicutar , gần như chắc chắn là tốt hơn, tôi nghĩ cũng đáng để hiển thị các băm K&R :
1) Rõ ràng là một thuật toán băm khủng khiếp , như được trình bày trong K&R ấn bản đầu tiên ( nguồn )
unsigned long hash(unsigned char *str)
{
unsigned int hash = 0;
int c;
while (c = *str++)
hash += c;
return hash;
}
2) Có lẽ là một thuật toán băm khá tốt, như được trình bày trong K&R phiên bản 2 (được tôi xác minh trên trang 144 của cuốn sách); NB: hãy chắc chắn xóa % HASHSIZE
khỏi câu lệnh trả về nếu bạn định thực hiện điều chỉnh kích thước mô-đun-thành-độ dài mảng của bạn bên ngoài thuật toán băm. Ngoài ra, tôi khuyên bạn nên tạo kiểu trả về và "hashval" unsigned long
thay vì kiểu đơn giản unsigned
(int).
unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31*hashval;
return hashval % HASHSIZE;
}
Lưu ý rằng rõ ràng từ hai thuật toán rằng một lý do khiến hàm băm phiên bản đầu tiên quá khủng khiếp là bởi vì nó KHÔNG tính đến thứ tự ký tự chuỗi , do đó hash("ab")
sẽ trả về cùng giá trị hash("ba")
. Tuy nhiên, điều này không đúng với hàm băm phiên bản thứ 2, sẽ (tốt hơn nhiều!) Trả về hai giá trị khác nhau cho các chuỗi đó.
Các hàm băm GCC C ++ 11 được sử dụng cho unordered_map
(mẫu bảng băm) và unordered_set
(mẫu bộ băm) dường như như sau.
Mã:
// 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;
}