關於雜湊表中碰撞(collision)的說明,下列何者正確?
- A能從雜湊值求出原本的鍵
- B不同的鍵求出相同的雜湊值(存放位置)
- C相同的鍵每次執行都求出不同的雜湊值
雜湊表是以雜湊函數將鍵對應到表中的位置,使搜尋只需大致固定時間的資料結構。本工具以表格顯示依序放入鍵時,在哪個位置發生碰撞、最後儲存在哪裡。切換碰撞的處理方法,即可確認搜尋所需的工作量如何變化。
收藏與最近使用的工具只儲存在這個瀏覽器(localStorage)中。
搜尋 –
探測次數是儲存(或找到)鍵之前所檢查的位置數。鏈結法則計算鍵位於該位置串列中的第幾個。二次探測法視表的大小與負載因子而定,即使有空位也可能找不到。
其他輸入維持目前的值,只讓選擇的輸入在目前值的 1/4 到 4 倍之間變化時的結果。紅點是目前的值。
雜湊表是以雜湊函數從鍵計算出表中的位置,並把資料放在該位置的資料結構。若鍵分散得好,不論鍵有多少個,都能以大致固定的時間找到。但不同的鍵可能對應到同一個位置,這稱為碰撞。以 h(k) = k mod 7 將 10、17、24、3 放入大小 7 的表,4 個鍵全都對應到位置 3 而發生碰撞。碰撞無法避免,因此如何處理會左右效能。
鏈結法是將對應到同一位置的鍵以鏈結串列串起來的方法。表不會滿溢,刪除也很簡單,但追蹤串列需要額外的搜尋時間,而且會存取記憶體中分散的位置。開放定址法是在碰撞時尋找表中其他空位並放入的方法,依移動方式分為線性探測法(每次 1 格)、二次探測法(1、4、9 … 格)與雙重雜湊法(依各鍵決定的間隔)。超過表大小的鍵無法放入,刪除時也需要「已刪除」的標記。
鍵的數量除以表的大小所得的值稱為負載因子。負載因子越高,碰撞越多,尤其是開放定址法的探測次數會急遽增加。線性探測法容易形成已占用位置連續相接的區塊,撞上該區塊的鍵又會讓區塊更長,這稱為聚集。二次探測法與雙重雜湊法藉由改變移動方式來減少這種聚集。請比較範例「線性探測產生聚集的例子」與「以二次探測與雙重雜湊分散」的平均探測次數。實際的雜湊表在負載因子超過約 0.5~0.75 時,會擴大表並重新放入所有鍵(重新雜湊)。
好的雜湊函數會將鍵平均分散到整個表。使用 k mod m 時,選擇質數作為 m,即使鍵有規律(全是偶數、全是 10 的倍數等),也不容易偏斜。若只是單純加總字串的字元碼,像範例中的 cat、act、tac 這種只是字母順序不同的鍵一定會碰撞,因此實際上會採取對每個字元乘上權重再加總等做法。雜湊表廣泛用於程式語言的字典(關聯陣列)、資料庫的雜湊索引、快取的查詢等各種地方。
正確答案:C. 位置6
4個鍵除以7的餘數都是3,因此都會先檢查位置3。10放入位置3;17因位置3已被占用而放入位置4;24因位置3、4已被占用而放入位置5。3因位置3、4、5都已被占用,所以存放在位置6。如此可見,線性探測法會使被占用的位置聚集在一起(叢集),越晚來的鍵需要檢查的次數越多。
正確答案:A. 鏈結法在負載因子超過1時也能存放,但開放定址法無法存放超過表大小的元素,且負載因子接近1時搜尋次數會急遽增加
鏈結法把相同位置的元素串成串列,因此元素數超過表的大小也能存放,但串列的平均長度與負載因子成正比增加,搜尋的工作量也隨之增加。開放定址法只存放在表中,元素數最多只能到表的大小,負載因子接近1時尋找空位的次數會急遽增加。無論哪種方法,負載因子超過設定值(例如約0.5~0.75)時,通常都會放大表格並重新放入所有元素(重新雜湊)。開放定址法也會發生碰撞,是靠尋找空位置來處理。
負載因子低時,開放定址法(尤其是線性探測法)依序檢查表中連續的位置,容易命中快取,因此常常比較快。負載因子變高後,開放定址法的探測次數會急遽增加,此時鏈結法較為穩定。
因為使用 k mod m 時,若鍵與 m 有公因數,被使用的位置就會偏斜。例如 m = 10 而鍵全是偶數時,只會用到偶數位置。若 m 是質數,就不容易發生這種偏斜。已知二次探測法在 m 為質數且負載因子在 0.5 以下時,一定能找到空位。
若鍵分散得好,平均為 O(1)(與資料數量無關,固定)。但在所有鍵都碰撞到同一位置的最差情況下,會變成 O(n)。
日本基本資訊技術士考試等資訊類證照考試,常給定雜湊函數與碰撞的處理方法,要求回答依序放入鍵時某個鍵的儲存位置。請選擇範例,將表中「檢查的位置」與自己的答案比較看看。