PHP Perl 關聯數組 哈希表 Hash Table


關聯數組,又稱爲哈希表(hash table),是一種很是好用的數據結構。
在程序中,咱們可能會遇到須要消重的問題,舉一個最簡單的模型:
有一份用戶名列表,存儲了 10000 個用戶名,沒有重複項;
還有一份黑名單列表,存儲了 2000 個用戶名,格式與用戶名列表相同;
如今須要從用戶名列表中刪除處在黑名單裏的用戶名,要求用盡可能快的時間處理。
這個問題是一個小規模的處理量,若是實際一點,2 個表均可能很大,好比有 2 億條記錄。
我最開始想到的方法,就是作一個嵌套的循環,設用戶名錶有 M 條記錄,黑名單列表有 N 條記錄,那麼,循環的次數是 M * N 次!
PHP 版代碼: php

<?php
foreach($arrayM as $keyM => $nameM) {
   foreach($arrayN as $nameN) {
   if ($nameM == $nameN) {
   // 本行執行了 M * N 次!
   unset($arrayM[$keyM]);
   }
   }
}
return $arrayM;
?>

另外一種方式,利用數組索引。
PHP 是一種弱類型的語言,不像 C 語言那樣有嚴格的變量類型限制。C 語言的數組,每個元素的類型必須一致,並且索引都是從 0 開始。
PHP 的數組,能夠用字符串做爲索引,也稱爲關聯數組。
數組索引,有一個自然的限制就是不會重複,並且訪問的時候不須要查找,能夠直接定位。
仍是剛纔的那個問題,咱們採用另外一種辦法。
把黑名單列表的用戶名組織到一個數組裏,數組的索引就是用戶名。
而後,遍歷用戶列表的時候,只需直接用 isset 查詢那個用戶名是否存在便可。
PHP 版代碼:
<?php
$arrayHash = array();
foreach($arrayN as $nameN) {
   // 本行執行了 N 次。
   $arrayHash[$nameN] = 1;
}

foreach($arrayM as $keyM => $nameM) {
   if (isset($arrayHash[$nameM])) {
   // 本行執行了 M 次!
   unset($arrayM[$keyM]);
   }
}
return $arrayM;
?>
能夠看到,優化過的代碼,循環次數是 M + N 次。
假如 M 和 N 都是 10000,優化前,循環了 1 億次;優化後,只循環了 20000 次,差了 5000 倍!
若是第二個程序耗時 1 秒,則第一個程序須要將近一個半小時!
最近在作 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 的數組,真的很強大!
God Bless PHP! 算法

相關文章
相關標籤/搜索