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 无限分类的树类代码
Dec 03 PHP
PHP 页面编码声明方法详解(header或meta)
Mar 12 PHP
php实现ip白名单黑名单功能
Mar 12 PHP
PHP版微信公众平台红包API
Apr 02 PHP
PHP数组和explode函数示例总结
May 08 PHP
PHP中的流(streams)浅析
Jul 02 PHP
PHP实现仿Google分页效果的分页函数
Jul 29 PHP
基于php判断客户端类型
Oct 14 PHP
PHP7.1实现的AES与RSA加密操作示例
Jun 15 PHP
Yii2处理密码加密及验证的方法
May 12 PHP
关于PHP中interface的用处详解
Jul 26 PHP
深入解析PHP底层机制及相关原理
Dec 11 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
收音机鉴频器对声音的影响和频偏分析
2021/03/02 无线电
ThinkPHP多表联合查询的常用方法
2020/03/24 PHP
php编写的抽奖程序中奖概率算法
2015/05/14 PHP
php使用curl伪造浏览器访问操作示例
2019/09/30 PHP
javascript 触发事件列表 比较不错
2009/09/03 Javascript
javascript 进阶篇1 正则表达式,cookie管理,userData
2012/03/14 Javascript
js multiple全选与取消全选实现代码
2012/12/04 Javascript
一个不错的js html页面倒计时可精确到秒
2014/10/22 Javascript
[js高手之路]寄生组合式继承的优势详解
2017/08/28 Javascript
基于vue开发的在线付费课程应用过程
2018/01/25 Javascript
js html实现计算器功能
2018/11/13 Javascript
vue.js的vue-cli脚手架中使用百度地图API的实例
2019/01/21 Javascript
使用node搭建自动发图文微博机器人的方法
2019/03/22 Javascript
对TypeScript库进行单元测试的方法
2019/07/18 Javascript
vue 解决文本框被键盘遮住的问题
2019/11/06 Javascript
JavaScript之Blob对象类型的具体使用方法
2019/11/29 Javascript
python之模拟鼠标键盘动作具体实现
2013/12/30 Python
python3实现短网址和数字相互转换的方法
2015/04/28 Python
Python实现自动添加脚本头信息的示例代码
2016/09/02 Python
Python numpy 常用函数总结
2017/12/07 Python
python实现根据文件关键字进行切分为多个文件的示例
2018/12/10 Python
Python 输出时去掉列表元组外面的方括号与圆括号的方法
2018/12/24 Python
使用IDLE的Python shell窗口实例详解
2019/11/19 Python
django 装饰器 检测登录状态操作
2020/07/02 Python
viagogo波兰票务平台:演唱会、体育比赛、戏剧门票
2018/04/23 全球购物
求职简历推荐信范文
2013/12/02 职场文书
团日活动总结报告
2014/06/25 职场文书
幼儿园教师的自我评价范文
2014/09/17 职场文书
大学生操行评语大全
2014/12/31 职场文书
教师节作文之小学四年级
2019/09/03 职场文书
python爬不同图片分别保存在不同文件夹中的实现
2021/04/02 Python
python使用pymysql模块操作MySQL
2021/06/16 Python
PostgreSQL事务回卷实战案例详析
2022/03/25 PostgreSQL
Oracle数据库中通用的函数实例详解
2022/03/25 Oracle
Go语言的协程上下文的几个方法和用法
2022/04/11 Golang
python中使用redis用法详解
2022/12/24 Redis