zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    2019年北航OO第三次博客总结
    2019年北航OO第二次博客总结
    2019年北航OO第一次博客总结
    BUAA_OO第四单元总结性博客作业——UML(Floyd实现规则检查?)
    BUAA_OO第三单元总结性博客作业——JML
    BUAA_OO第二单元总结性博客作业——多线程电梯架构
    BUAA_OO第一单元总结性博客作业——表达式求导
    免费虚拟主机 免费云服务器
    .net core API 使用swagger
    Socket学习
  • 原文地址:https://www.cnblogs.com/HachikoT/p/13752399.html
Copyright © 2011-2022 走看看