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,中文翻譯成雜亂的東西,有人也叫它雜湊,或者翻譯成什么都不是的音譯“哈?!薄?br>
簡單說來,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, html' target='_blank'>value信息。
hash表也可以不是數組,你可以把它組織成一個鏈表,鏈表里的node的結構中可以有一個參數就是那個數字的hash_value,用來快速查找用。
雖然在很多時候hash被用在加密等場合,但在一般的應用程序代碼中,也可以用它來存貯簡單的數據,這樣代碼的效率會高很多。
PHP編程 鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。