php的hash算法介绍


Posted in PHP onFebruary 13, 2014

Hash Table是PHP的核心,这话一点都不过分。

PHP的数组,关联数组,对象属性,函数表,符号表,等等都是用HashTable来做为容器的。

PHP的HashTable采用的拉链法来解决冲突, 这个自不用多说, 我今天主要关注的就是PHP的Hash算法, 和这个算法本身透露出来的一些思想。

PHP的Hash采用的是目前最为普遍的DJBX33A (Daniel J. Bernstein, Times 33 with Addition), 这个算法被广泛运用与多个软件项目,Apache, Perl和Berkeley DB等. 对于字符串而言这是目前所知道的最好的哈希算法,原因在于该算法的速度非常快,而且分类非常好(冲突小,分布均匀).

算法的核心思想就是:

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

在zend_hash.h中,我们可以找到在PHP中的这个算法:

static inline ulong zend_inline_hash_func(char *arKey, uint nKeyLength)
{
    register ulong hash = 5381;    /* variant with the hash unrolled eight times */
    for (; nKeyLength >= 8; nKeyLength -=  {
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
    }
    switch (nKeyLength) {
        case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 1: hash = ((hash << 5) + hash) + *arKey++; break;
        case 0: break;
EMPTY_SWITCH_DEFAULT_CASE()
    }
    return hash;
}

相比在Apache和Perl中直接采用的经典Times 33算法:

hashing function used in Perl 5.005:
  # Return the hashed value of a string: $hash = perlhash("key")
  # (Defined by the PERL_HASH macro in hv.h)
  sub perlhash
  {
      $hash = 0;
      foreach (split //, shift) {
          $hash = $hash*33 + ord($_);
      }
      return $hash;
  }

在PHP的hash算法中, 我们可以看出很处细致的不同.

首先, 最不一样的就是, PHP中并没有使用直接乘33, 而是采用了:

hash << 5 + hash

这样当然会比用乘快了.

然后, 特别要主意的就是使用的unrolled, 我前几天看过一片文章讲Discuz的缓存机制, 其中就有一条说是Discuz会根据帖子的热度不同采用不同的缓存策略, 根据用户习惯,而只缓存帖子的第一页(因为很少有人会翻帖子).

于此类似的思想, PHP鼓励8位一下的字符索引, 他以8为单位使用unrolled来提高效率, 这不得不说也是个很细节的,很细致的地方.

另外还有inline, register变量 … 可以看出PHP的开发者在hash的优化上也是煞费苦心

最后就是, hash的初始值设置成了5381, 相比在Apache中的times算法和Perl中的Hash算法(都采用初始hash为0), 为什么选5381呢? 具体的原因我也不知道, 但是我发现了5381的一些特性:

Magic Constant 5381:
1. odd number
2. prime number
3. deficient number

看了这些, 我有理由相信这个初始值的选定能提供更好的分类.
PHP 相关文章推荐
多重?l件?合查?(一)
Oct 09 PHP
php入门学习知识点一 PHP与MYSql连接与查询
Jul 14 PHP
php中设置index.php文件为只读的方法
Feb 06 PHP
php在window iis的莫名问题的测试方法
May 14 PHP
PHP设计模式之解释器模式的深入解析
Jun 13 PHP
php_screw安装使用教程(另一个PHP代码加密实现)
May 29 PHP
PHP中的多行字符串传递给JavaScript的两种方法
Jun 19 PHP
codeigniter上传图片不能正确识别图片类型问题解决方法
Jul 25 PHP
php flush无效,IIS7下php实时输出的方法
Aug 25 PHP
PHP面向对象程序设计组合模式与装饰模式详解
Dec 02 PHP
php 多继承的几种常见实现方法示例
Nov 18 PHP
Yii中特殊行为ActionFilter的使用方法示例
Oct 18 PHP
php去除字符串换行符示例分享
Feb 13 #PHP
php中url函数介绍及使用示例
Feb 13 #PHP
php中的filesystem文件系统函数介绍及使用示例
Feb 13 #PHP
php实现cc攻击防御和防止快速刷新页面示例
Feb 13 #PHP
php中hashtable实现示例分享
Feb 13 #PHP
php实现下载限制速度示例分享
Feb 13 #PHP
php解压文件代码实现php在线解压
Feb 13 #PHP
You might like
一个PHP操作Access类(PHP+ODBC+Access)
2007/01/02 PHP
用php将任何格式视频转为flv的代码
2009/09/03 PHP
PHP中常见的缓存技术实例分析
2015/09/23 PHP
php中preg_replace_callback函数简单用法示例
2016/07/21 PHP
浅析php如何实现App常用的秒发功能
2016/08/03 PHP
可以用来调试JavaScript错误的解决方案
2010/08/07 Javascript
jQuery弹性滑动导航菜单实现思路及代码
2013/05/02 Javascript
js内存泄露的几种情况详细探讨
2013/05/31 Javascript
鼠标滑在标题上显示图片的JS代码
2013/11/19 Javascript
javascript字符串替换及字符串分割示例代码
2013/12/12 Javascript
JS检测输入字符是否包含非法字符的示例代码
2014/02/11 Javascript
jQuery中size()方法用法实例
2014/12/27 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
2015/03/04 Javascript
超详细的JS弹出窗口代码大全
2020/04/18 Javascript
浅析如何利用JavaScript进行语音识别
2016/10/27 Javascript
js仿京东轮播效果 选项卡套选项卡使用
2017/01/12 Javascript
vuejs如何配置less
2017/04/25 Javascript
vue指令只能输入正数并且只能输入一个小数点的方法
2018/06/08 Javascript
vue 项目接口管理的实现
2019/01/17 Javascript
python使用smtplib模块通过gmail实现邮件发送的方法
2015/05/08 Python
python中kmeans聚类实现代码
2018/02/23 Python
在Python中使用Neo4j的方法
2019/03/14 Python
PyQt5笔记之弹出窗口大全
2019/06/20 Python
在Django admin中编辑ManyToManyField的实现方法
2019/08/09 Python
pytorch实现特殊的Module--Sqeuential三种写法
2020/01/15 Python
解决pytorch 交叉熵损失输出为负数的问题
2020/07/07 Python
python 解决函数返回return的问题
2020/12/05 Python
HTML5新增的标签和属性归纳总结
2018/05/02 HTML / CSS
亚马逊西班牙购物网站:amazon西班牙
2017/03/06 全球购物
美国高品质个性化珠宝销售网站:Jewlr
2018/05/03 全球购物
Feelunique美国:欧洲大型的在线美妆零售电商
2018/11/04 全球购物
数学考试作弊检讨书300字
2015/02/16 职场文书
拾金不昧表扬信怎么写
2015/05/04 职场文书
简短的36句中秋节祝福信息语句
2019/09/09 职场文书
SpringCloud Feign请求头删除修改的操作代码
2022/03/20 Java/Android
python中urllib包的网络请求教程
2022/04/19 Python