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;
}

std::hash的更多相关文章

  1. std::hash实现太简单分布不匀

    std::hash实现太简单分布不匀(金庆的专栏 2017.5)#include <iostream>#include <functional>using namespace ...

  2. std::hash<std::pair<int, int> >

    标题是搞笑的 ! 这个问题只需要 since C++11 问题:怎么让 unordered_map 支持使用 pair 作为 key? 如果你能把两个东西压到一个基本类型里那么就不用解决这个问题了 . ...

  3. Bitset<>用于unordered container时的默认hash函数

    自从c++11起,bitset用于unordered container,将会提供默认的hash函数. 在gcc中,相关代码如下: // DR 1182. /// std::hash speciali ...

  4. std::shared_ptr(二)

    Defined in header <memory>       template< class T > class shared_ptr;   (since C++11)   ...

  5. C++ std::unordered_map使用std::string和char *作key对比

    最近在给自己的服务器框架加上统计信息,其中一项就是统计创建的对象数,以及当前还存在的对象数,那么自然以对象名字作key.但写着写着,忽然纠结是用std::string还是const char *作ke ...

  6. STL标准库-一个万用的hash function

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 在前面我介绍过hash的使用,本次主要介绍一下Hash Function Hash Function即获得hash code的函 ...

  7. 5-14 电话聊天狂人 (25分) HASH

    给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人. 输入格式: 输入首先给出正整数NN(\le 10^5≤10​5​​),为通话记录条数.随后NN行,每行给出一条通话记录.简单起见,这里只列出 ...

  8. hashmap C++实现分析及std::unordered_map拓展

    今天想到哈希函数,好像解决冲突的只了解了一种链地址法而且也很模糊,就查了些资料复习一下 1.哈希Hash 就是把任意长度的输入,通过哈希算法,变换成固定长度的输出(通常是整型),该输出就是哈希值. 这 ...

  9. STL: unordered_map 自定义键值使用

    使用Windows下 RECT 类型做unordered_map 键值 1. Hash 函数 计算自定义类型的hash值. struct hash_RECT { size_t operator()(c ...

随机推荐

  1. 【高并发】Redis如何助力高并发秒杀系统,看完这篇我彻底懂了!!

    写在前面 之前,我们在<[高并发]高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!>一文中,详细讲解了高并发秒杀系统的架构设计,其中,我们介绍了可以使用Redis存储秒杀商品的库存数量.很 ...

  2. 使用阿里云OSS的服务端签名后直传功能

    网站一般都会有上传功能,而对象存储服务oss是一个很好的选择.可以快速的搭建起自己的上传文件功能. 该文章以使用阿里云的OSS功能为例,记录如何在客户端使用阿里云的对象存储服务. 服务端签名后直传 背 ...

  3. vue自适应布局的n中方法

    在index.html中 head标签中 <script> //通过window.screen.width获取屏幕的宽度 var offWidth = window.screen.widt ...

  4. php第五天-正则表达式,字符串的匹配与查找函数,数组切割

    在php中有两套正则表达式,两者功能相似,一套是由PCRE,使用"preg_"为前缀命名的函数,一套是由POSIX拓展提供的,使用以"ereg_"命名的函数 0 ...

  5. 浅谈Java多线程

    线程与进程 什么是进程? 当一个程序进入内存中运行起来它就变为一个进程.因此,进程就是一个处于运行状态的程序.同时进程具有独立功能,进程是操作系统进行资源分配和调度的独立单位. 什么是线程? 线程是进 ...

  6. Java反应式框架Reactor中的Mono和Flux

    1. 前言 最近写关于响应式编程的东西有点多,很多同学反映对Flux和Mono这两个Reactor中的概念有点懵逼.但是目前Java响应式编程中我们对这两个对象的接触又最多,诸如Spring WebF ...

  7. Python练习题 015:一颗自由落地的球

    [Python练习题 015] 一球从100米高度自由落下,每次落地后反跳回原高度的一半,再落下.求它在第10次落地时,共经过多少米?第10次反弹多高? ----------------------- ...

  8. 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现

    088 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 02 封装的代码实现 本文知识点:Java封装的代码实现 说明:因为时间紧张,本人写博客过程中只 ...

  9. 【题解】[USACO08MAR]Land Acquisition G

    Link 题目大意:给定\(n\)个二元组,每次可以选择一组,花费是组内最大的长乘以最大的宽.问消掉所有二元组的最小代价. \(\text{Solution:}\) \(dp\)写的不够啊-- 先挖掘 ...

  10. Linux 安装Navicat Premium 15

    参考:https://gitee.com/andisolo/navicat-keygen 安装 aptitude 管理软件 $ sudo apt-get install aptitude 安装Navi ...