PHP数组实现方式、以及为什么这么实现、以及我对数组链表哈希表的理解

10 篇文章 0 订阅

数组是PHP最常用,最强大的数据类型了。我们知道PHP是C写的,而C语言当中数组是一块连续的存储空间,并且只能以数字作为数组下标。PHP当中则可以使用关联数组,主要是因为PHP使用哈希表来作为数组的存储方式。
简单来说,哈希表就是将我们动态分配的数组的下标通过哈希函数算出一个值,然后通过一张转换表(如果直接存放,可能会顺序不对),将真正的数据存放到Bucket结构体当中。正是因为这个转换的操作,所以PHP中使用foreach会比使用for更快,foreach直接遍历的是存放真实数据的Bucket结构部分。
PHP在实现数组类型主要使用了2个结构体一个hashTable,一个Bucket。通过链接法来解决hash冲突。当数据达到一定量,或者哈希函数设计不合理,就会发生哈希冲突,PHP使用的是time33哈希算法。因为算法已知,很多黑客可以通过这个来对网站或者程序进行攻击(dos攻击),PHP采用的是禁止用户提交的数据量来解决这个问题。。
当发生哈希冲突时,需要在链表中(为了解决冲突的双向链表)比较当前节点的键名是否正确,否则继续向下查找。PHP7中链表结构并没像传统链表一样在在内存中分散存储。我们直接读取 arData 整个数组,而不是通过堆(heap)获取内存地址分散的指针。这是 PHP7 性能提升的一个重要点。
我们首先要明白在计算机当中,数组是连续的内存空间,而基于内存的读取方式,使用探头读取磁盘上面的数据。当我读取连续空间的时候可以省去寻道和旋转的延迟,所以连续的内存空间有利于计算机将数据从磁盘啊读取到内存当中。当我们知道数组每个元素的长度,又知道数组的开始位置我们就可以知道任意第n个数据的位置,我们可以通过公式pos(n)=pos(0)+(n-1)*length 来求得第n个元素的位置,这也是为什么在计算机世界当中数组的下标是以0开头的,因为数组是最常用的数据结构,而省去这个-1的步骤会节省很多操作。所以我们可以知道数组适合读多写少的场景(类似mysql中的myisam),而同样的很常用的数据结构链表适合写多读少的场景类比mysql的innodb,链表在写操作是有很好的的性能,并且不需要申请连续的内存空间。这2种有利也有弊。那么有没有有折中的方案呢,那就是哈希表了。
哈希表主体思想就是将数据分散的映射到一个很大的数组上面。第一个重点是映射,我们需要通过函数将不同的值求得一个值,这个函数必须满足不同的输入能产生不同的输出,我们在读取这个值的时候只需要用这个函数同样得到哈希值在对数组长度求余就能得到这个值在数组当中的位置。我们知道数组的读取效率是很高的,这样我们就可以提高了查找效率,同时写入数据我们也不需要像数组插入删除需要移动数组,从而让写操作变得高效。当然哈希的确定就产生在哈希函数如果不够好或者存放数据的数组不够大就会出现哈希冲突了。
而为了我们的方便,php采用了哈希表来存储数组,同时增加了一个映射表来存储哈希值和实际存储数组位置之间的映射。达到了哈希表的高效又实现了数组的有序。
具体来说 首先数组的数据是按顺序存放在连续的数组空间上的,同时会根据数据的值产生一个哈希值,并将哈希值和当前值的数组下标的映射存到中间表里面。这样当我们遍历的时候就是使用foreach就是直接遍历的那个顺序数组。当我们需要单独读取某个值的时候根据哈希函数得到哈希值查找中间表得到顺序数组的下标就拿到了需要的数据。同时删除修改也和哈希表一样高效。
就这样实现了php当中使用最多的数组这一结构。当中这其中还有很多优化,但大体的思想是这样的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值