PHP关联数组与哈希表(hash table) 不指定

PHP中有一种数据类型非常重要,它就是关联数组,又称为哈希表(hash table),是一种非常好用的数据结构。

在程序中,我们可能会遇到需要消重的问题,举一个最简单的模型:

有一份用户名列表,存储了 10000 个用户名,没有重复项;

还有一份黑名单列表,存储了 2000 个用户名,格式与用户名列表相同;

现在需要从用户名列表中删除处在黑名单里的用户名,要求用尽量快的时间处理。

这个问题是一个小规模的处理量,如果实际一点,2 个表都可能很大,比如有 2 亿条记录。

我最开始想到的方法,就是做一个嵌套的循环,设用户名表有 M 条记录,黑名单列表有 N 条记录,那么,循环的次数是 M * N 次!

PHP 版代码:

01 <?php

02 foreach($arrayM as $keyM => $nameM) {

03 foreach($arrayN as $nameN) {

04 if ($nameM == $nameN) {

05 // 本行执行了 M * N 次!

06 unset($arrayM[$keyM]);

07 }

08 }

09 }

10 return $arrayM;

11 ?>

另一种方式,利用数组索引。

PHP 是一种弱类型的语言,不像 C 语言那样有严格的变量类型限制。C 语言的数组,每一个元素的类型必须一致,而且索引都是从
0 开始。

PHP 的数组,可以用字符串作为索引,也称为关联数组。

数组索引,有一个天然的限制就是不会重复,而且访问的时候不需要查找,可以直接定位。

还是刚才的那个问题,我们采用另一种办法。

把黑名单列表的用户名组织到一个数组里,数组的索引就是用户名。

然后,遍历用户列表的时候,只需直接用 isset 查询那个用户名是否存在即可。

PHP 版代码:

01 <?php

02 $arrayHash = array();

03 foreach($arrayN as $nameN) {

04 // 本行执行了 N 次。

05 $arrayHash[$nameN] = 1;

06 }

07

08 foreach($arrayM as $keyM => $nameM) {

09 if (isset($arrayHash[$nameM])) {

10 // 本行执行了 M 次!

11 unset($arrayM[$keyM]);

12 }

13 }

14 return $arrayM;

15 ?>

可以看到,优化过的代码,循环次数是 M + N 次。

假如 M 和 N 都是 10000,优化前,循环了 1 亿次;优化后,只循环了 20000 次,差了 5000 倍!

如果第二个程序耗时 1 秒,则第一个程序需要将近一个半小时!

=========================================================================

hash一个貌似比较复杂的东西,实际上理解起来并不那么夸张,这里做个笔记。

hash,中文翻译成杂乱的东西,有人也叫它杂凑,或者翻译成什么都不是的音译“哈希”。

简单说来,hash就是为了把一个复杂的字串,通过一定的转换,得到一个简单的数字(通常是数字)。

如"abcd" 用各个字符的值直接相加,再取对10的余数,既(a+b+c+d),来得到一个数字,比方说结果为5,那么这个5就能在一定意义上代表这个字串 abcd了。或者说这个5也可以说是这个字串的一个标记性的东西,而且是简化了的标记,所以又有人叫这个5为字串的摘要,或指纹。

这个5,有一个好的用处就是可以作为一个数组的下标来用,如我自己构造一个指针数组void* hash_array[10],那么我就可以把5那个位置上填上一个指针,如指向abcd字串。

这样的话,我如果要去查询一个字串是否存在,就不需要对一个数组使用字符串循环对比这样的慢操作,而直接先得到某个字串的hash值,再用这个hash值,在数组下标里直接找,这样速度要快上很多,特别是数据比较多的时候。

可以看到上面计算hash值时,出来的结果,可能并不是从0开始的,如我们算出的就是5。也就是说,这个5是在数组中的某个不确定的位置,或者可以叫做是一个杂凑出来的位置。其他位置可能一直就空着在。这就是这个数组或表格叫hash表的原因了。

但有个问题,上面的转换方法,直接相加,再取个余数,在字符串变为abdc时,结果得到的还是数字5。这个就是上面这个算法的一个问题了,即它不能保证一个唯一性。所以就出现了很多hash算法的研究,如MD4,MD5,SHA-1等,来保证唯一性。

但上面这个算法还是可以使用的,做法就是在abdc经过hash得到5后,去检查5是否被占用,如果占用了,那么就把数字加1,即为6,如果6没被占用,就填上值。如果后面某个字串算出一个值是6,但6已经被占用了,那么就再加1,再存。

取数据的时候,可以先算出hash值后,再看里面的内容是不是你想要的,如果不是,就加1去看,最后得到一个。

所以这里hash表的内容并不是象一般的数组最开始就组织好了的,而是后续慢慢往里增加的。

hash表里存的内容一般可以是一个指针,这个指针可以指向一个大的结构也是可以的。这个结构里可以有key, value信息。

hash表也可以不是数组,你可以把它组织成一个链表,链表里的node的结构中可以有一个参数就是那个数字的hash_value,用来快速查找用。

虽然在很多时候hash被用在加密等场合,但在一般的应用程序代码中,也可以用它来存贮简单的数据,这样代码的效率会高很多。

PHP关联数组与哈希表(hash table) 不指定

时间: 2024-07-30 23:54:26

PHP关联数组与哈希表(hash table) 不指定的相关文章

哈希表(Hash table)(1)

哈希表(Hash table)经常被用来做字典(dictionary),或称符号表(symbol-table) 直接存取表(Direct-access table): ? 直接存取表(Direct-access table)的基本思想是:如果key的范围为0~m-1而且所有key都不相同, 那么可以设计一个数组T[0..m-1],让T[k]存放key为k的元素, 否则为空(NIL) ? 显然, 所有操作都是O(1)的 ? 问题:key的范围可能很大! 64位整数有18,446,744,073,7

哈希表 hash table

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数. 首先问题规模确定,例如5台服务器怎么把数据散落在5台上面呢,就用到了hash算法

什么叫哈希表(Hash Table)

散列表(也叫哈希表),是根据关键码值直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. - 数据结构中,有个时间算法复杂度O(n)的概念来衡量某种算法在时间效率上的优劣.哈希表的理想算法复杂度为O(1),也就是说利用哈希表查找某个值,系统所使用的时间在理想情况下为定值,这就是它的优势.那么哈希表是如何做到这一点的呢? - 我们定义一个很大的有序数组,想要得到位于该数组第n个位置的值,它的算法复杂度

[BS]散列表 哈希表 Hash table

<第五章> 散 列 散列表的实现常常叫做散列(hashing).散列是一种用于以常数平均时间执行插入.删除和查找的技术. 关于散列有一个很重要的概念:散列函数.散列函数是散列的关键处之一,散列函数又是基于映射机制的一种对应关系(一般是多对一的关系). 这章可以分为5个部分:一般想法,散列函数,分离链接法,开放定址法(可分为线性探测.平方探测.双散列).再散列.可扩散列. 本文只写到前四节.即:一般想法,散列函数,分离链接法,开放定址法(可分为线性探测.平方探测.双散列)() 第五章第一节:一般

哈希表Hash

大家都学过数据结构: 内存里面为了更好的管理对象,通常采用链表或者数据以及Hash表来存储数据. 数据存储 一下是数据存储到计算机的两种模式 线性的存储:数组---寻址方便,更新不好(连续的) 链式的存储: 链表----寻址不方便,更新方便.(不连续的) 为了提高检索的速度,我们可以采取Hash机制,key采取数据存储,方便寻址,其次我们可以利用链表方便更新数据的具体的值. 哈希表Hash,布布扣,bubuko.com

PowerShell【初级篇●Powershell数组和哈希表】

Powershell数组和哈希表 创建数组可以使用逗号.例如,$nums=2,0,1,2 对于连续的数字数组可以使用一个更快捷的方法.例如,$nums=1..5 如果数组中元素的类型为弱类型,默认可以存储不同类型的值.例如,$array=1,"2012世界末日",([System.Guid]::NewGuid()),(get-date) 使用@()创建数组.空数组.例如,$a= @() 1个元素的数组.例如,$a=,"moss" 使用@{}创建哈希表.例如,[ema

Exchange 2013 PowerShell数组和哈希表

示例: 你可以使用一个变量来存放一个数组,通过这个数组对变量分配多个值,在值之间,值需要用分隔号隔开,下面来创建一个示例: $servers = "EX1","EX2","EX3" 创建一个空的哈希表,可以使用如下语法: $hashtable = @{} 创建完哈希表后,我们可以对它进行赋值: $hashtable["server1"] = 1 $hashtable["server2"] = 2 $hash

4.PowerShell -- 数组,哈希表

1. PowerShell数组 声明数组 [email protected]("user1","user2","user3") 查看数组 $strUsers PS C:\Users\Administrator> $strUsers[0] user1 赋值 $strUsers[1]="marui" 重新查看数组元素 PS C:\Users\Administrator> $strUsers user1 marui us

58. C# -- 集合(动态数组,哈希表,排序列表,堆栈,队列,点阵列)

一.先来说说数组的不足(也可以说集合与数组的区别): 1.数组是固定大小的,不能伸缩.虽然System.Array.Resize这个泛型方法可以重置数组大小,但是该方法是重新创建新设置大小的数组,用的是旧数组的元素初始化.随后以前的数组就废弃!而集合却是可变长的 2.数组要声明元素的类型,集合类的元素类型却是object. 3.数组可读可写不能声明只读数组.集合类可以提供ReadOnly方法以只读方式使用集合. 4.数组要有整数下标才能访问特定的元素,然而很多时候这样的下标并不是很有用.集合也是