一个好的散列函数通常倾向于“为不相等的对象产生不相等的散列码”。理想情况下,散列函数应该把集合中不相等的实例均匀地分布到所有可能的散列值上。要想完全达到这种理想的情形是非常困难的。幸运的是,相对接近这种理想情形则并不太困难。

由Daniel J. Bernstein教授多年前在comp.lang.c发表的Times 33算法。 它是有史以来发布的最有效的哈希函数之一。

算法介绍

首先,引用一段关于Times 33的介绍:

DJBX33A (Daniel J. Bernstein, Times 33 with Addition)

This is Daniel J. Bernstein's popular `times 33' hash function as
posted by him years ago on comp.lang.c. It basically uses a function
like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
known hash functions for strings. Because it is both computed very
fast and distributes very well.

The magic of number 33, i.e. why it works better than many other
constants, prime or not, has never been adequately explained by
anyone. So I try an explanation: if one experimentally tests all
multipliers between 1 and 256 (as RSE did now) one detects that even
numbers are not useable at all. The remaining 128 odd numbers
(except for the number 1) work more or less all equally well. They
all distribute in an acceptable way and this way fill a hash table
with an average percent of approx. 86%.

If one compares the Chi^2 values of the variants, the number 33 not
even has the best value. But the number 33 and a few other equally
good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
advantage to the remaining numbers in the large set of possible
multipliers: their multiply operation can be replaced by a faster
operation based on just one shift plus either a single addition
or subtraction operation. And because a hash function has to both
distribute good and has to be very fast to compute, those few
numbers should be preferred and seems to be the reason why Daniel J.
Bernstein also preferred it.

-- Ralf S. Engelschall rse@engelschall.com

理解:

Times 33是Daniel J. Bernstein多年前在comp.lang.c上发表的哈希算法,这个算法已被广泛应用,是目前最好的字符串哈希算法之一。因为它不仅计算速度很快,而且分布比较均匀。

核心逻辑是这段代码:

hash(i) = hash(i-1) * 33 + str[i]

这个神奇的数字33,为什么用来计算哈希的效果会比其他许多常数(无论是否为质数)更有效,并没有人给过足够充分的解释。因此,Ralf S. Engelschall尝试通过自己的方法解释其原因。通过对1到256中的每个数字进行测试,发现偶数的哈希效果非常差,根据用不了。而剩下的128个奇数,除了1之外,效果都差不多。这些奇数在分布上都表现不错,对哈希表的填充覆盖大概在86%。

从哈希效果来看(Chi^2应该是指卡方分布),虽然33并不一定是最好的数值。但17、31、33、63、127和129等相对其他的奇数的一个很明显的优势是,由于这些奇数与16、32、64、128只相差1,可以通过移位(如1 << 4 = 16)和加减1来代替乘法,速度更快。

算法实现

DJB Hash Function

An algorithm produced by Professor Daniel J. Bernstein and shown first to the world on the usenet newsgroup comp.lang.c. It is one of the most efficient hash functions ever published.

unsigned int DJBHash(const char* str, unsigned int length){   unsigned int hash = 5381;   unsigned int i    = 0;

   for (i = 0; i < length; ++str, ++i)   {      hash = ((hash << 5) + hash) + (*str);   }

   return hash;}

http://www.partow.net/programming/hashfunctions/


djb2

this algorithm (k=33) was first reported by dan bernstein many years ago in comp.lang.c. another version of this algorithm (now favored by bernstein) uses xor: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why it works better than many other constants, prime or not) has never been adequately explained.

    unsigned long    hash(unsigned char *str)    {        unsigned long hash = 5381;        int c;

        while (c = *str++)            hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

        return hash;    }

http://www.cse.yorku.ca/~oz/hash.html


Java版本

以下是我实现的java版本

    /**     * 乘法运算版本     *      * @param value     * @return     */    public static int time33V1(String value) {        int hash = 0;        for (int i = 0; i < value.length(); i++) {            hash = 33 * hash + value.charAt(i);        }        return hash;    }    /**     * 位运算版本     *      * @param value     * @return     */    public static int time33V2(String value) {        int hash = 0;        for (int i = 0; i < value.length(); i++) {            hash = ((hash << 5) + hash) + value.charAt(i);        }        return hash;    }    /**     * 5381版本     *      * @param value     * @return     */    public static int time33V3(String value) {        int hash = 5381;        for (int i = 0; i < value.length(); i++) {            hash = ((hash << 5) + hash) + value.charAt(i);        }        return hash;    }

Java 1.8 String哈希方法

public int hashCode() {    int h = hash;    if (h == 0 && value.length > 0) {        char val[] = value;

        for (int i = 0; i < value.length; i++) {            h = 31 * h + val[i];        }        hash = h;    }    return h;}

几个常用实现选项

values chosen to initialize h and a for some of the popular implementations

其中

  • INITIAL_VALUE:哈希初始值
  • a:哈希乘数

至于为何选择这些数字的更详细分析,请见下回分解。


题图:azquotes

参考

http://www.partow.net/programming/hashfunctions/

http://www.cse.yorku.ca/~oz/hash.html

https://en.wikipedia.org/wiki/Universal_hashing

《Effective Java中文版本》第2版

转载请注明来源:http://zhanjia.iteye.com/blog/2426782

个人公众号

二进制之路

经典的Times 33 哈希算法相关推荐

  1. 面试时遇到一致性哈希算法这样回答会让面试官眼前一亮

    [CSDN 编者按]很多人都知道什么是哈希函数,在后端面试和开发中会遇到"一致性哈希",那什么是一致性哈希呢,当面试官问到你又该如何给出漂亮的回答. 作者 | 丁威       责 ...

  2. 计算机视觉的几个经典算法 —— 最小二乘法 + RANSAC + 哈希算法(附DCT) + 图像聚类算法

    计算机视觉的几个经典算法 目录 计算机视觉的几个经典算法 1. 最小二乘法(寻找线性回归函数) 2. RANSAC(模型已知,参数未知) 2.1 RANSAC 与 最小二乘法的区别 2.2 RANSA ...

  3. 一文搞懂负载均衡中的一致性哈希算法

    一致性哈希算法在很多领域有应用,例如分布式缓存领域的 MemCache,Redis,负载均衡领域的 Nginx,各类 RPC 框架.不同领域场景不同,需要顾及的因素也有所差异,本文主要讨论在负载均衡中 ...

  4. 哪种一致性哈希算法才是解决分布式缓存问题的王者?

    哪种一致性哈希算法才是解决分布式缓存问题的王者? 一致性哈希是由Karger等人于1997年提出的一种特殊的哈希算法,目的是解决分布式缓存的问题,现在在分布式系统中有着广泛的应用.本文将对ketama ...

  5. 哈希算法(Hash Algorithm)初探

    不约而同的,几乎所有的流行的hash map都采用了DJB hash function,俗称"Times33"算法. Perl.Berkeley DB .Apache.MFC.ST ...

  6. 哈希分布与一致性哈希算法简介

    前言 在我们的日常web应用开发当中memcached可以算作是当今的标准开发配置了.相信memcache的基本原理大家也都了解过了,memcache虽然是分布式的应用服务,但分布的原则是由clien ...

  7. 白话解析:一致性哈希算法 consistent hashing

    在了解一致性哈希算法之前,最好先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那么,我们先来描述一下这个经典的分布式缓存的 ...

  8. 一致性哈希算法学习及JAVA代码实现分析

    1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目来获得水平横向扩展的方式则 ...

  9. 一文读懂哈希和一致性哈希算法

    哈希 Hash 算法介绍 哈希算法也叫散列算法, 不过英文单词都是 Hash, 简单一句话概括, 就是可以把任意长度的输入信息通过算法变换成固定长度的输出信息, 输出信息也就是哈希值, 通常哈希值的格 ...

最新文章

  1. wikioi 1083 Cantor表
  2. cufflinks基于dataframe数据绘制三维散点图(3d scatter plot)
  3. 【CVPR2020-Oral】上交华为:GPA跨域目标检测
  4. matlab中cell用法
  5. 若依前后端分离版怎样去掉登录验证码
  6. java jdbc连接oracle_Java使用JDBC连接Oracle 11gR2
  7. java 查找list中指定字符串出现的次数
  8. 为什么需要分布式配置中心
  9. python语音分割_Python 牺牲性能以提升程序员的工作效率
  10. C#/ASP.NET完善的DBHelper,配套Model生成器
  11. 使用免费的Open NFC simulator模拟器在BlackBerry模拟器上进行NFC程序调试
  12. 常见的三个网络协议的区别:TCP/IP、NetBEUI、IPX/SPX
  13. 抖音服务器维护中怎么改名字,抖音怎么更改名字
  14. BLE - 连接时触发配对
  15. 那些破事儿.........
  16. Java(十三)集合类(2)
  17. EditText自动弹出输入法问题
  18. DFS and BFS
  19. ESP8266模块SDK编程,连接未来之家服务器
  20. oracle erp日志,错误,什么地方看日志

热门文章

  1. 粗效过滤器安装技术参数
  2. 「 C++ MFC 」“读取.txt文档实例”讲解
  3. 麒麟合盛(APUS)李涛:APUS云重新定义“云联邦”
  4. 运维干到35岁,还能干多久?
  5. 装甲逆袭-加载NPC
  6. 洛谷P1873 [COCI 2011/2012 #5] EKO / 砍树(二分法)
  7. 短视频app搭建的技术难点是什么?
  8. 输入一个字符,将大写字母换小写,小写变大写
  9. Endnote X7 基本功能及实用笔记
  10. 女子连WiFi结果收到巨额话费单:有些WiFi其实是收费的