`

经典的Times 33 哈希算法

阅读更多

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

由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

 

个人公众号

二进制之路

 

  • 大小: 11.7 KB
分享到:
评论

相关推荐

    php-perl哈希算法实现(times33哈希算法)

    Times33哈希算法,也称为DJBX33A(Daniel J. Bernstein, Times 33 with Addition),是一种简单而高效的字符串哈希算法。该算法在PHP和Perl中被广泛使用,是Apache Portable Runtime (APR)库的默认哈希函数。本文将...

    short-hash:从字符串中获取简短的哈希值。 使用Bernstein流行的“ times 33”哈希算法,但返回十六进制字符串而不是数字

    使用伯恩斯坦流行的“ times 33”哈希算法,但返回十六进制字符串而不是数字 这只是的方便包装。 安装 使用安装short-hash : npm install --save short-hash 用法 模块使用 var shortHash = require ( 'short-hash...

    PHP Hash算法:Times33算法代码实例

    总结起来,Times33和CRC33是两种不同类型的哈希算法,它们各有优缺点。Times33简单快速,适合对性能要求高的场景,而CRC33则在数据校验方面表现出色。在PHP中,开发者可以根据项目需求选择合适的哈希函数,确保数据...

    Hash 哈希学习的一些资料

    自己学习Hash时搜到的一些资料。包括rfc1321.txt MPQ Hash.txt Inside MoPaQ - Chapter 2 Fundamentals.mht 各种字符串HASH函数 打造最快的Hash表 & Times33 哈希算法(Hash Algorithm)初探 关于hash的一些问题等。

    哈希碰撞与生日攻击

    哈希算法的一个重要特性是,对于任何给定的输入,其输出始终相同,且即使是微小的变化也会导致完全不同的哈希值。然而,由于哈希值的长度是固定的,理论上存在两个不同的输入产生相同哈希值的情况,这种情况称为...

    php的hash算法介绍

    对比经典的Perl中的Times 33算法,PHP的实现更加高效。Perl的算法直接将每个字符的ASCII码与当前哈希值乘以33相加,而PHP的算法在乘以33的基础上还进行了位移(`)操作,这有助于增加哈希值的分布均匀性,从而降低...

    hash-string:基于 Daniel J. Bernstein 流行的“times 33”散列算法的字符串散列函数

    哈希字符串 基于 Daniel J. Bernstein 流行的“times 33”散列算法的字符串散列函数。 例子 console . log ( hash ( '{ test: true }' ) ) ;

    RSA加密算法实现附源代码

    - 计算模\( n = p \times q \)。 - 计算欧拉函数\( \phi(n) = (p-1)(q-1) \)。 - 选择一个整数\( e \),满足\( 1 (n) \)且\( e \)与\( \phi(n) \)互质。 - 计算\( d \)使得\( e \cdot d \equiv 1 (\text{mod} \...

    数据结构和算法分析试卷

    在实际应用中,哈希表的负载因子(即已存储元素的数量与哈希表大小的比例)通常会影响哈希表的性能。为了保持良好的性能,通常会控制负载因子在一个合理的范围内,例如小于0.7。 **总结**:哈希表的插入操作通常...

    用Java语言实现RSA加密算法

    加密过程中,每个字符都被转换为其哈希值,并使用公钥\( e \)进行加密。 #### 解密过程 ```java public static String[] decode(String[] de_text) { String[] result = new String[de_text.length]; for (int i ...

    常见算法题答案及解析

    ***o Sum:需要查找数组中两个数相加等于特定值的所有配对,使用哈希表可以在O(n)时间内完成。 ***o Sum II – Input array is sorted:此问题与Two Sum类似,但输入数组已经排序,可以使用双指针技巧降低空间复杂度...

    操作系统 LRU页面置换算法.pdf

    需要注意的是,此程序仅实现了LRU算法的基础逻辑,并没有涵盖所有可能的复杂情况,例如,当内存块已满且所有页面都被使用过时,需要决定替换哪个页面,这通常涉及到一个数据结构(如链表或哈希表)来跟踪页面的使用...

    data structure and algorithm.docx数据结构与算法

    You have estimated %d times.", i); } } getchar(); printf("Hello world!\n"); return 0; } ``` 以上代码展示了一个简单的游戏逻辑,玩家需要猜测商品的价格。这段代码使用了基本的输入输出函数以及条件...

    4、NOIP提高组竞赛复试中需要用到的算法或涉及到知识点.pdf

    - 分而治之的经典算法,通过选择一个“基准”值将数组分为两部分,使得左边的所有元素都小于或等于基准,右边的所有元素都大于或等于基准。 3. **堆排排序** - 利用堆数据结构所设计的一种排序算法,分为最大堆...

    DUILIB源码注释文档

    - `CStdStringMap`:基于哈希的字符串映射,使用times33哈希算法,提供键值对的高效查找。 6. **窗口和消息处理**: - `CWindowWnd`类:封装了窗口注册、超类化、子类化以及消息处理等功能。 - `...

    improving search times resolving external symbols in the timeliner system.pdf

    1. **设计哈希函数**:设计一个合适的哈希函数是哈希表成功的关键。好的哈希函数应该能够均匀分布数据,减少冲突的发生概率。 2. **冲突解决策略**:即使是最优秀的哈希函数也无法完全避免冲突的发生,因此还需要...

    计算机密码学考试试卷

    - **作用**: 素性检测主要用于加密算法中的密钥生成阶段,确保使用的数确实是素数,这对于保证算法的安全性至关重要。 #### 三、计算与证明解析 由于题目中的计算与证明部分涉及具体的数学计算,这里不一一列出...

Global site tag (gtag.js) - Google Analytics