zoukankan      html  css  js  c++  java
  • PHP关联数组和哈希表(hash table) 未指定

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

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

    有一份username列表。存储了 10000 个username,没有反复项;
    另一份黑名单列表,存储了 2000 个username,格式与username列表同样。
    如今须要从username列表中删除处在黑名单里的username,要求用尽量快的时间处理。

    这个问题是一个小规模的处理量,假设实际一点,2 个表都可能非常大,比方有 2 亿条记录。



    我最開始想到的方法,就是做一个嵌套的循环。设username表有 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 的数组,能够用字符串作为索引,也称为关联数组。
    数组索引,有一个天然的限制就是不会反复。并且訪问的时候不须要查找,能够直接定位。



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

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

    然后,遍历用户列表的时候,仅仅需直接用 isset 查询那个username是否存在就可以。

    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被用在加密等场合,但在一般的应用程序代码中,也能够用它来存简单的数据存储,代码的这样的高效率将是非常。

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    C# 小规模查找集合性能测试
    高级前端开发不可或缺的知识
    移动前端开发-单页应用(spa)模型
    移动开发之用视频做背景
    纯CSS打造忙碌光标
    移动前端开发之数据库操作篇
    如何从源码中学习javascript
    Deffered.js的实现原理
    Codeforces Round #381 (Div. 2)
    2017 ZSTU寒假排位赛 #6
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4815313.html
Copyright © 2011-2022 走看看