PHP關聯陣列與雜湊表(hash table) 不指定

來源:互聯網
上載者:User

PHP中有一種資料類型非常重要,它就是關聯陣列,又稱為雜湊表(hash table),是一種非常好用的資料結構。

在程式中,我們可能會遇到需要消重的問題,舉一個最簡單的模型:

有一份使用者名稱列表,儲存了 10000 個使用者名稱,沒有重複項;

還有一份黑名單列表,儲存了 2000 個使用者名稱,格式與使用者名稱列表相同;

現在需要從使用者名稱列表中刪除處在黑名單裡的使用者名稱,要求用盡量快的時間處理。

這個問題是一個小規模的處理量,如果實際一點,2 個表都可能很大,比如有 2 億條記錄。

我最開始想到的方法,就是做一個嵌套的迴圈,設使用者名稱表有 M 條記錄,黑名單列表有 N 條記錄,那麼,迴圈的次數是 M * N 次!

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 查詢那個使用者名稱是否存在即可。

查看本欄目更多精彩內容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/PHP/

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 秒,則第一個程式需要將近一個半小時!

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

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被用在加密等場合,但在一般的應用程式代碼中,也可以用它來存貯簡單的資料,這樣代碼的效率會高很多。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.