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 相关文章推荐
通过php快速统计某个数据库中每张表的数据量
Sep 04 PHP
巧用php中的array_filter()函数去掉多维空值的代码分享
Sep 07 PHP
探讨PHP中this,self,parent的区别详解
Jun 08 PHP
合并ThinkPHP配置文件以消除代码冗余的实现方法
Jul 22 PHP
PHP扩展开发入门教程
Feb 26 PHP
jquery+php实现导出datatables插件数据到excel的方法
Jul 06 PHP
php中array_unshift()修改数组key注意事项分析
May 16 PHP
PHP+Ajax验证码验证用户登录
Jul 20 PHP
thinkPHP模板中for循环与switch语句用法示例
Nov 30 PHP
php简单计算年龄的方法(周岁与虚岁)
Dec 06 PHP
PHP常用排序算法实例小结【基本排序,冒泡排序,快速排序,插入排序】
Feb 07 PHP
php使用str_replace替换多维数组的实现方法分析
Jun 15 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
ThinkPHP中redirect用法分析
2014/12/05 PHP
jQuery获取json后使用zy_tmpl生成下拉菜单
2015/03/27 PHP
CI框架集成Smarty的方法分析
2016/05/17 PHP
PHP 将dataurl转成图片image方法总结
2016/10/14 PHP
Symfony2创建基于域名的路由相关示例
2016/11/14 PHP
PHP基于redis计数器类定义与用法示例
2018/02/08 PHP
php-fpm添加service服务的例子
2018/04/27 PHP
Yii框架使用PHPExcel导出Excel文件的方法分析【改进版】
2019/07/24 PHP
JavaScript中的对象化编程
2008/01/16 Javascript
Dojo 学习笔记入门篇 First Dojo Example
2009/11/15 Javascript
jQuery中:only-child选择器用法实例
2015/01/03 Javascript
JS中生成随机数的用法及相关函数
2016/01/09 Javascript
js事件冒泡、事件捕获和阻止默认事件详解
2016/08/04 Javascript
BootStrap的两种模态框方式
2017/05/10 Javascript
jQuery Jsonp跨域模拟搜索引擎
2017/06/17 jQuery
写一个移动端惯性滑动&amp;回弹Vue导航栏组件 ly-tab
2018/03/06 Javascript
node.js命令行教程图文详解
2019/05/27 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
2020/07/21 Javascript
js编写简易的计算器
2020/07/29 Javascript
Python发送email的3种方法
2015/04/28 Python
MySQL最常见的操作语句小结
2015/05/07 Python
python如何实现内容写在图片上
2018/03/23 Python
Python使用OpenCV进行标定
2018/05/08 Python
python下载的库包存放路径
2020/07/27 Python
python speech模块的使用方法
2020/09/09 Python
html5视频常用API接口的实战示例
2020/03/20 HTML / CSS
ABOUT YOU匈牙利:500个最受欢迎的时尚品牌
2019/07/19 全球购物
计算机维护专业推荐信
2014/02/27 职场文书
黄金搭档广告词
2014/03/21 职场文书
运动会口号16字
2014/06/07 职场文书
医学专业毕业生推荐信
2014/07/12 职场文书
公司委托书格式范文
2014/10/09 职场文书
2015年银行信贷员工作总结
2015/05/19 职场文书
导游词之寿县报恩寺
2020/01/19 职场文书
原生JS中应该禁止出现的写法
2021/05/05 Javascript
MongoDB连接数据库并创建数据等使用方法
2021/11/27 MongoDB