雙重散列是線性開型尋址散列(開放尋址法)中的沖突解決技術。雙重散列使用在發生沖突時將第二個散列函數應用於鍵的想法。
此算法使用:
(hash1(key) + i * hash2(key)) % TABLE_SIZE
來進行雙哈希處理。hash1() 和 hash2() 是哈希函數,而 TABLE_SIZE 是哈希表的大小。當發生碰撞時,我們通過重復增加 步長i 來尋找鍵。
第一個Hash函數:hash1(key) = key % TABLE_SIZE。
1 /** 2 * 計算首次的Hash值 3 * 4 * @param key 5 * @return 6 */ 7 private int hash1(int key) { 8 return (key % TABLE_SIZE); 9 }
第二個Hash函數是:hash2(key) = PRIME – (key % PRIME),其中 PRIME 是小於 TABLE_SIZE 的質數。
1 /** 2 * 發生碰撞是時繼續計算Hash值 3 * 4 * @param key 5 * @return 6 */ 7 private int hash2(int key) { 8 return (PRIME - (key % PRIME)); 9 }
第二個Hash函數表現好的特征:
-
絕對不會產生 0 索引
-
能在整個HashTable 循環探測
-
計算會快點
-
與第一個Hash函數互相獨立
-
PRIME 與 TABLE_SIZE 是 “相對質數”
Java實現代碼:
1 package algorithm.hash; 2 3 /** 4 * 雙重哈希 5 */ 6 public class DoubleHash { 7 private static final int TABLE_SIZE = 13; // 哈希表大小 8 private static int PRIME = 7; // 散列函數值 9 10 private int[] hashTable; 11 private int curr_size; // 當前表中存的元素 12 13 public DoubleHash() { 14 this.hashTable = new int[TABLE_SIZE]; 15 this.curr_size = 0; 16 for (int i = 0; i < TABLE_SIZE; i++) 17 hashTable[i] = -1; 18 } 19 20 private boolean isFull() { 21 return curr_size == TABLE_SIZE; 22 } 23 24 /** 25 * 計算首次的Hash值 26 * 27 * @param key 28 * @return 29 */ 30 private int hash1(int key) { 31 return (key % TABLE_SIZE); 32 } 33 34 /** 35 * 發生碰撞是時繼續計算Hash值 36 * 37 * @param key 38 * @return 39 */ 40 private int hash2(int key) { 41 return (PRIME - (key % PRIME)); 42 } 43 44 /** 45 * 向Hash表中存值 46 * 47 * @param key 48 */ 49 private void insertHash(int key) { 50 /* 表是否已滿 */ 51 if (isFull()) { 52 return; 53 } 54 55 /* 獲取首次的Hash值 */ 56 int index = hash1(key); 57 58 // 如果發生碰撞 59 if (hashTable[index] != -1) { 60 /* 計算第二次的Hash值 */ 61 int index2 = hash2(key); 62 int i = 1; 63 while (true) { 64 /* 再次合成新的地址 */ 65 int newIndex = (index + i * index2) % TABLE_SIZE; 66 67 // 如果再次尋找時沒有發生碰撞,把key存入表中的對應位置 68 if (hashTable[newIndex] == -1) { 69 hashTable[newIndex] = key; 70 break; 71 } 72 i++; 73 } 74 } else { 75 // 一開始沒有發生碰撞 76 hashTable[index] = key; 77 } 78 curr_size++; // Hash表中當前所存元素數量加1 79 } 80 81 /** 82 * 打印Hash表 83 */ 84 private void displayHash() { 85 for (int i = 0; i < TABLE_SIZE; i++) { 86 if (hashTable[i] != -1) 87 System.out.println(i + " --> " + hashTable[i]); 88 else 89 System.out.println(i); 90 } 91 } 92 93 public static void main(String[] args) { 94 int[] a = {19, 27, 36, 10, 64}; 95 96 DoubleHash doubleHash = new DoubleHash(); 97 for (int i = 0; i < a.length; i++) 98 doubleHash.insertHash(a[i]); 99 100 doubleHash.displayHash(); 101 } 102 103 }