本文和大家重点讨论一下Perl关联数组和哈希表的概念,Perl关联数组,又称为哈希表(hashtable),是一种非常好用的数据结构。希望通过本文的介绍你对Perl关联数组的概念有深入的了解。
Perl关联数组和哈希表
Perl关联数组,又称为哈希表(hashtable),是一种非常好用的数据结构。
在程序中,我们可能会遇到需要消重的问题,举一个最简单的模型:
有一份用户名列表,存储了10000个用户名,没有重复项;
还有一份黑名单列表,存储了2000个用户名,格式与用户名列表相同;
现在需要从用户名列表中删除处在黑名单里的用户名,要求用尽量快的时间处理。
这个问题是一个小规模的处理量,如果实际一点,2个表都可能很大,比如有2亿条记录。
我最开始想到的方法,就是做一个嵌套的循环,设用户名表有M条记录,黑名单列表有N条记录,那么,循环的次数是M*N次!
PHP版代码:
- <?php
- foreach($arrayMas$keyM=>$nameM){
- foreach($arrayNas$nameN){
- if($nameM==$nameN){
- //本行执行了M*N次!
- unset($arrayM[$keyM]);
- }
- }
- }
- return$arrayM;
- ?>
另一种方式,利用数组索引。
PHP是一种弱类型的语言,不像C语言那样有严格的变量类型限制。C语言的数组,每一个元素的类型必须一致,而且索引都是从0开始。
PHP的数组,可以用字符串作为索引,也称为Perl关联数组。
数组索引,有一个天然的限制就是不会重复,而且访问的时候不需要查找,可以直接定位。
还是刚才的那个问题,我们采用另一种办法。
把黑名单列表的用户名组织到一个数组里,数组的索引就是用户名。
然后,遍历用户列表的时候,只需直接用isset查询那个用户名是否存在即可。
PHP版代码:
- <?php
- $arrayarrayHash=array();
- foreach($arrayNas$nameN){
- //本行执行了N次。
- $arrayHash[$nameN]=1;
- }
- foreach($arrayMas$keyM=>$nameM){
- if(isset($arrayHash[$nameM])){
- //本行执行了M次!
- unset($arrayM[$keyM]);
- }
- }
- return$arrayM;
- ?>
可以看到,优化过的代码,循环次数是M+N次。
假如M和N都是10000,优化前,循环了1亿次;优化后,只循环了20000次,差了5000倍!
如果第二个程序耗时1秒,则第一个程序需要将近一个半小时!
最近在做Perl的开发,Perl在处理文本的时候有很高的效率,同样,它也支持Perl关联数组!
只是语法和PHP的那种类C的方式有很大不同,以第二段代码为例,Perl版的实现:
- #!/usr/bin/perl
- my%arrayHash;
- for(my$i=0;$i<@arrayN;++$i){
- $arrayHash{$arrayN[$i]}=1;
- }
- for(my$i=0;$i<@arrayM;++$i){
- if($arrayHash{$arrayM[$i]}){
- $arrayM[$i]=undef;
- }
- }
Perl关联数组是@开头,哈希是以%开头,unset实际上就是undef。
Perl的哈希和数组都是有具体类型的,而且向函数传递变量的时候要传引用,我刚学时间不长,快被搞晕了。
不过,现在刚刚实现了一个以hash方式进行IP位置查找的算法,平均比较次数大概在3次左右,比传统的折半查找方式少了很多次,它大概需要8次以上的比较。
刚刚做了一个小的性能测试,对10万个IP进行查找,在我的台式机上,耗时15秒,平均每秒7500次,感觉还不错,呵呵。不过,还是喜欢PHP的数组,真的很强大 。