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 相关文章推荐
3
Oct 09 PHP
使用 eAccelerator加速PHP代码的目的
Mar 16 PHP
PHP 面向对象实现代码
Nov 11 PHP
PHP生成短网址方法汇总
Jul 12 PHP
Thinkphp框架中D方法与M方法的区别
Dec 23 PHP
关于PHP中协程和阻塞的一些理解与思考
Aug 11 PHP
PHP设计模式之装饰器模式定义与用法详解
Apr 02 PHP
PHP面向对象五大原则之单一职责原则(SRP)详解
Apr 04 PHP
PHP PDOStatement::fetchAll讲解
Jan 31 PHP
PHP扩展Swoole实现实时异步任务队列示例
Apr 13 PHP
PHP中类与对象功能、用法实例解读
Mar 27 PHP
PHP 出现 http500 错误的解决方法
Mar 09 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中的实现trim函数代码
2007/03/19 PHP
PHP 事务处理数据实现代码
2010/05/13 PHP
PHP支付系统设计与典型案例分享
2016/08/02 PHP
PHP设计模式入门之迭代器模式原理与实现方法分析
2020/04/26 PHP
使用Modello编写JavaScript类
2006/12/22 Javascript
在iframe里的页面编写js,实现在父窗口上创建动画效果展开和收缩的div(不变动iframe父窗口代码)
2011/12/20 Javascript
js中parseInt函数浅谈
2013/07/31 Javascript
tangram框架响应式加载图片方法
2013/11/21 Javascript
jquery操作select详解(取值,设置选中)
2014/02/07 Javascript
Js制作点击输入框时默认文字消失的效果
2015/09/05 Javascript
学习javascript面向对象 javascript实现继承的方式
2016/01/04 Javascript
NodeJS和BootStrap分页效果的实现代码
2016/11/07 NodeJs
纯js模仿windows系统日历
2017/02/04 Javascript
SelectPage v2.4 发布新增纯下拉列表和关闭分页功能
2017/09/07 Javascript
swiper 解决动态加载数据滑动失效的问题
2018/02/26 Javascript
函数式编程入门实践(一)
2019/04/20 Javascript
vue-loader中引入模板预处理器的实现
2019/09/04 Javascript
JS脚本实现定时到网站上签到/签退功能
2020/04/22 Javascript
webpack+express实现文件精确缓存的示例代码
2020/06/11 Javascript
mpvue 项目初始化及实现授权登录的实现方法
2020/07/20 Javascript
详解Java中String JSONObject JSONArray List转换
2020/11/13 Javascript
[03:11]DOTA2上海特锦赛小组赛第一日recap精彩回顾
2016/02/28 DOTA
[01:03:47]VP vs NewBee Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
python 生成器生成杨辉三角的方法(必看)
2017/04/10 Python
Python动态导入模块的方法实例分析
2018/06/28 Python
对python requests发送json格式数据的实例详解
2018/12/19 Python
python实现石头剪刀布小游戏
2021/01/20 Python
详解Django中views数据查询使用locals()函数进行优化
2020/08/24 Python
UI自动化定位常用实现方法代码示例
2020/10/27 Python
阿迪达斯西班牙官方网站:adidas西班牙
2016/07/21 全球购物
说一下Linux下有关用户和组管理的命令
2016/01/04 面试题
家长对小学生的评语
2014/01/28 职场文书
纠风工作实施方案
2014/03/15 职场文书
小学优秀班主任事迹材料
2014/05/17 职场文书
运动会广播稿50字
2015/08/19 职场文书
python基于tkinter制作下班倒计时工具
2021/04/28 Python