步驟
- 首先需要初始化一個二進制的數組,長度設爲 L(圖中爲 8),同時初始值全爲 0 。
- 寫入一個 A1=1000 的數據時,需要進行 H 次 hash 函數的運算(這裏爲 2 次);與 HashMap 有點類似,通過算出的 HashCode 與 L 取模後定位到 0、2 處,將該處的值設爲 1。
- A2=2000 也是同理計算後將 4、7 位置設爲 1。
- 當有一個 B1=1000 需要判斷是否存在時,也是做兩次 Hash 運算,定位到 0、2 處,此時他們的值都爲 1 ,所以認爲 B1=1000 存在於集合中。
- 當有一個 B2=3000 時,也是同理。第一次 Hash 定位到 index=4 時,數組中的值爲 1,所以再進行第二次 Hash 運算,結果定位到 index=5 的值爲 0,所以認爲 B2=3000 不存在於集合中。
總結
整個的寫入、查詢的流程就是這樣,彙總起來就是:
- 對寫入的數據做 H 次 hash 運算定位到數組中的位置,同時將數據改爲 1 。當有數據查詢時也是同樣的方式定位到數組中。 一旦其中的有一位爲 0 則認爲數據肯定不存在於集合,否則數據可能存在於集合中。
- 注意:Bloom Filter 有一定的誤報率,這個誤報率和 Hash 算法的次數 H,以及數組長度 L 都是有關的。
- 業界更好的解決方案布隆過濾:Google guava 包
代碼實現
public class BloomFilters {
/**
* 數組長度
*/
private int arraySize;
/**
* 數組
*/
private int[] array;
public BloomFilters(int arraySize) {
this.arraySize = arraySize;
array = new int[arraySize];
}
/**
* 寫入數據
* @param key
*/
public void add(String key) {
int first = hashcode_1(key);
int second = hashcode_2(key);
int third = hashcode_3(key);
array[first % arraySize] = 1;
array[second % arraySize] = 1;
array[third % arraySize] = 1;
}
/**
* 判斷數據是否存在
* @param key
* @return
*/
public boolean check(String key) {
int first = hashcode_1(key);
int second = hashcode_2(key);
int third = hashcode_3(key);
int firstIndex = array[first % arraySize];
if (firstIndex == 0) {
return false;
}
int secondIndex = array[second % arraySize];
if (secondIndex == 0) {
return false;
}
int thirdIndex = array[third % arraySize];
if (thirdIndex == 0) {
return false;
}
return true;
}
/**
* hash 算法1
* @param key
* @return
*/
private int hashcode_1(String key) {
int hash = 0;
int i;
for (i = 0; i < key.length(); ++i) {
hash = 33 * hash + key.charAt(i);
}
return Math.abs(hash);
}
/**
* hash 算法2
* @param data
* @return
*/
private int hashcode_2(String data) {
final int p = 16777619;
int hash = (int) 2166136261L;
for (int i = 0; i < data.length(); i++) {
hash = (hash ^ data.charAt(i)) * p;
}
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return Math.abs(hash);
}
/**
* hash 算法3
* @param key
* @return
*/
private int hashcode_3(String key) {
int hash, i;
for (hash = 0, i = 0; i < key.length(); ++i) {
hash += key.charAt(i);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return Math.abs(hash);
}
}