原文地址:http://www.phppan.com/2009/12/zend-hashtable/

在PHP的Zend引擎中,有一个数据结构非常重要,它无处不在,是PHP数据存储的核心,各种常量、变量、函数、类、对象等都用它来组织,这个数据结构就是HashTable。

HashTable在通常的数据结构教材中也称作散列表,哈希表。其基本原理比较简单(如果你对其不熟悉,请查阅随便一本数据结构教材或在网上搜 索),但PHP的实现有其独特的地方。理解了HashTable的数据存储结构,对我们分析PHP的源代码,特别是Zend Engine中的虚拟机的实现时,有很重要的帮助。它可以帮助我们在大脑中模拟一个完整的虚拟机的形象。它也是PHP中其它一些数据结构如数组实现的基 础。

Zend HashTable的实现结合了双向链表和向量(数组)两种数据结构的优点,为PHP提供了非常高效的数据存储和查询机制。

一、 HashTable的数据结构

在Zend Engine中的HashTable的实现代码主要包括zend_hash.h, zend_hash.c这两个文件中。Zend HashTable包括两个主要的数据结构,其一是Bucket(桶)结构,另一个是HashTable结构。Bucket结构是用于保存数据的容器,而 HashTable结构则提供了对所有这些Bucket(或桶列)进行管理的机制。

typedef struct bucket {
ulong h; /* Used for numeric indexing */
uint nKeyLength; /* key长度 */
void *pData; /* 指向Bucket中保存的数据的指针 */
void *pDataPtr; /* 指针数据 */
struct bucket *pListNext; /* 指向HashTable桶列中下一个元素 */
struct bucket *pListLast; /* 指向HashTable桶列中前一个元素 */
struct bucket *pNext; /* 指向具有同一个hash值的桶列的后一个元素 */
struct bucket *pLast; /* 指向具有同一个hash值的桶列的前一个元素 */
const char *arKey; /* 必须是最后一个成员,key名称*/
/* 旧版 char arKey[1]; 必须是最后一个成员,key名称*/
} Bucket;

在Zend HashTable中,每个数据元素(Bucket)有一个键名(key),它在整个HashTable中是唯一的,不能重复。根据键名可以唯一确定 HashTable中的数据元素。键名有两种表示方式。

  • 第一种方式使用字符串arKey作为键名,该字符串的长度为nKeyLength。注意到在上面的 数据结构中arKey虽然只是一个长度为1的字符数组,但它并不意味着key只能是一个字符。实际上Bucket是一个可变长的结构体,由于arKey是 Bucket的最后一个成员变量,通过arKey与nKeyLength结合可确定一个长度为nKeyLength的key。这是C语言编程中的一个比较 常用的技巧。
  • 另一种键名的表示方式是索引方式,这时nKeyLength总是0,长整型字段h就表示该数据元素的键名。
  • 简单的来说,即如果 nKeyLength=0,则键名为h;否则键名为arKey, 键名的长度为nKeyLength。

当nKeyLength > 0时,并不表示这时的h值就没有意义。事实上,此时它保存的是arKey对应的hash值。

不管hash函数怎么设计,冲突都是不可避免的,也就是说不同的arKey可能有相同的hash值。

具有相同hash值的Bucket保存在HashTable的arBuckets数组(参考下面的解释)的同一个索 引对应的桶列中。这个桶列是一个双向链表,其前向元素,后向元素分别用pLast, pNext来表示。新插入的Bucket放在该桶列的最前面。

在Bucket中,实际的数据是保存在pData指针指向的内存块中,通常这个内存块是系统另外分配的。但有一种情况例外,就是当Bucket保存的数据是一个指针时,HashTable将不会另外请求系统分配空间来保存这个指针,而是直接将该指针保存到pDataPtr中,然后再将pData指向 本结构成员的地址。这样可以提高效率,减少内存碎片。由此我们可以看到PHP HashTable设计的精妙之处。如果Bucket中的数据不是一个指针,pDataPtr为NULL。

HashTable中所有的Bucket通过pListNext, pListLast构成了一个双向链表。最新插入的Bucket放在这个双向链表的最后。

注意在一般情况下,Bucket并不能提供它所存储的数据大小的信息。所以在PHP的实现中,Bucket中保存的数据必须具有管理自身大小的能力。

Zend Hash table 详解--转的更多相关文章

  1. 数据结构基础-Hash Table详解(转)

    理解Hash 哈希表(hash table)是从一个集合A到另一个集合B的映射(mapping). 映射是一种对应关系,而且集合A的某个元素只能对应集合B中的一个元素.但反过来,集合B中的一个元素可能 ...

  2. CMU15445 (Fall 2019) 之 Project#2 - Hash Table 详解

    前言 该实验要求实现一个基于线性探测法的哈希表,但是与直接放在内存中的哈希表不同的是,该实验假设哈希表非常大,无法整个放入内存中,因此需要将哈希表进行分割,将多个键值对放在一个 Page 中,然后搭配 ...

  3. Python操作redis系列以 哈希(Hash)命令详解(四)

    # -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. Hset 命令用于 ...

  4. 【转载】BootStrap表格组件bootstrap table详解

    (转载,来源“脚本之家”,作者不详) 一.Bootstrap Table的引入 关于Bootstrap Table的引入,一般来说还是两种方法: 1.直接下载源码,添加到项目里面来.由于Bootstr ...

  5. Hash 表详解(哈希表)

    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列 ...

  6. 哈希表(hash)详解

     哈希表结构讲解: 哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度. ...

  7. Zend Studio安装详解

    本篇文章介绍Zend Stuido安装 PHP安装请参考 http://www.cnblogs.com/azhe-style/p/php_new_env_build.html 一.下载 百度Zend ...

  8. Lua基础之table详解

    概要:1.table特性:2.table的构造:3.table常用函数:4.table遍历:5.table面向对象 原文地址:http://blog.csdn.net/dingkun520wy/art ...

  9. 一致性hash算法详解

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179     一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT) ...

随机推荐

  1. [转]WIN2008 IIS7的日期格式

    最近项目升级服务器从32位升级到64位的WIN2008,日期显示格式非我们所期望的yyyy-M-d格式,原以为修改控制面板的日期格式即可,可是不行. 修改注册表问题解决. 修改方法: 运行注册表编辑器 ...

  2. SpringBoot (1) idea下的环境搭建及demo

    1.Spring Boot简介 wiki上的介绍: Spring Boot是Spring的常规配置解决方案,用于创建可以“运行”的独立的,生产级的基于Spring的应用程序.[22]它预先配置了Spr ...

  3. TPO-17 C1 Find materials for an opera paper

    TPO-17 C1 Find materials for an opera paper production n. 成果:产品:生产:作品 第 1 段 1.Listen to a conversati ...

  4. day05 字典 dict

    今日内容: 字典 成对的保存数据. 以key:value的形式保存 用{}表示,每一项内容都是key:value, 每项数据之间用逗号隔开 字典中的key是不能重复的. 存储是依靠着key来计算的. ...

  5. 深度学习论文笔记:Deep Residual Networks with Dynamically Weighted Wavelet Coefficients for Fault Diagnosis of Planetary Gearboxes

    这篇文章将深度学习算法应用于机械故障诊断,采用了“小波包分解+深度残差网络(ResNet)”的思路,将机械振动信号按照故障类型进行分类. 文章的核心创新点:复杂旋转机械系统的振动信号包含着很多不同频率 ...

  6. rhel6 mysql skip-grant-tables 添加用户报错 ERROR 1290

    不小心把数据库密码忘掉了, 这个时候我们只需要在数据库的配置文件里面添加 skip-grant-tables 然后重新启动服务,再登录数据库就不要我们输入密码了 这个时候我成功登录数据,可是不小心又把 ...

  7. 在windows和unbuntu上安装octave

    windows安装octave 安装wiki Octave ftp库 从上述的库中可以找到对应的版本的octave的exe安装程序,或者是zip等的压缩包,建议直接下载对应系统的exe执行文件.安装. ...

  8. linshi12

    #include<iostream> using namespace std; int main(){ int a[50]; a[1]=5; int i; for(i=2;;i++){ a ...

  9. Windows Forms编程实战学习:第二章 欢迎使用Visual Studio

    第二章 欢迎使用Visual Studio 1,AssemblyInfo文件 包含程序集的属性,向应用程序添加元数据 [assembly:<attribute>(<setting&g ...

  10. 解决Ubuntu(Linux)平台下Sublime Text 3 安装中文输入支持库后 开启gnome-terminal报错的问题

    在Ubuntu下安装Sublim Text3后发现无法输入中文,按照此链接的方法解决后.然后用下列代码配置C++的编译系统: { "cmd":["g++",&q ...