std::hash


std::hash

由於C++11引入了哈希表數據結構std::unordered_mapstd::unordered_set,所以對於基本類型也實現了標准的哈希函數std::hash,標准並沒有規定具體的實現,只是提了幾個要求:

  • 不能拋出異常
  • 對於相等的鍵必須產生相等的哈希值
  • 對於不相等的鍵產生碰撞的可能性必須最小接近 size_t 最大值的倒數

FNV哈希算法

在msvc中就是用的FNV哈希算法作為std::hash的實現。
FNV哈希算法全名為Fowler-Noll-Vo算法,是以三位發明人Glenn Fowler,Landon Curt Noll,Phong Vo的名字來命名的,最早在1991年提出。FNV能快速hash大量數據並保持較小的沖突率,它的高度分散使它適用於hash一些非常相近的字符串。
FNV算法有三個版本:FNV-0(已廢棄)、FNV-1和FNV-1a。
變量說明:

  • hash值:一個n位的unsigned int型hash值
  • offset_basis:初始的哈希值
  • FNV_prime:FNV用於散列的質數
  • octet_of_data:8位數據(即一個字節)

FNV_prime的取值:

  • 32 bit FNV_prime = 2^24 + 2^8 + 0x93 = 16777619
  • 64 bit FNV_prime = 2^40 + 2^8 + 0xb3 = 1099511628211
  • 128 bit FNV_prime = 2^88 + 2^8 + 0x3b = 309485009821345068724781371
  • 256 bit FNV_prime = 2^168 + 2^8 + 0x63 =374144419156711147060143317175368453031918731002211
  • 512 bit FNV_prime = 2^344 + 2^8 + 0x57 = 35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759
  • 1024 bit FNV_prime = 2^680 + 2^8 + 0x8d = 5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573

offset_basis的取值:

  • 32 bit offset_basis = 2166136261
  • 64 bit offset_basis = 14695981039346656037
  • 128 bit offset_basis = 144066263297769815596495629667062367629
  • 256 bit offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557
  • 512 bit offset_basis = 9659303129496669498009435400716310466090418745672637896108374329434462657994582932197716438449813051892206539805784495328239340083876191928701583869517785
  • 1024 bit offset_basis = 1419779506494762106872207064140321832088062279544193396087847491461758272325229673230371772215086409652120235554936562817466910857181476047101507614802975596980407732015769245856300321530495715015740364446036355050512711285966361610267868082893823963790439336411086884584107735010676915

算法描述

FNV-1描述:

hash = offset_basis
for each octet_of_data to be hashed
    hash = hash * FNV_prime
    hash = hash xor octet_of_data
return hash

FNV-1a描述:

hash = offset_basis 
for each octet_of_data to be hashed
    hash = hash xor octet_of_data
    hash = hash * FNV_prime
return hash

FNV-1a和FNV-1的唯一區別就是xor和multiply的順序不同,他們所采用的FNV_prime和offset_basis都相同,有人認為FNV-1a在進行小數據(小於4個字節)哈希時有更好的性能。

FNV-1a代碼實現(C++)

using Byte = uint8_t;

constexpr uint64_t c_offsetBasis = 14695981039346656037;
constexpr uint64_t c_FNVPrime = 1099511628211;

uint64_t fnv1a(Byte* bs, size_t len) {
    uint64_t h = c_offsetBasis;
    for (size_t i = 0; i < len; ++i) {
        h = h ^ bs[i];
        h = h * c_FNVPrime;
    }
    return h;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM