數據結構和算法之布隆過濾算法


布隆過濾

步驟
  1. 首先需要初始化一個二進制的數組,長度設爲 L(圖中爲 8),同時初始值全爲 0 。
  2. 寫入一個 A1=1000 的數據時,需要進行 H 次 hash 函數的運算(這裏爲 2 次);與 HashMap 有點類似,通過算出的 HashCode 與 L 取模後定位到 0、2 處,將該處的值設爲 1。
  3. A2=2000 也是同理計算後將 4、7 位置設爲 1。
  4. 當有一個 B1=1000 需要判斷是否存在時,也是做兩次 Hash 運算,定位到 0、2 處,此時他們的值都爲 1 ,所以認爲 B1=1000 存在於集合中。
  5. 當有一個 B2=3000 時,也是同理。第一次 Hash 定位到 index=4 時,數組中的值爲 1,所以再進行第二次 Hash 運算,結果定位到 index=5 的值爲 0,所以認爲 B2=3000 不存在於集合中。
總結

      整個的寫入、查詢的流程就是這樣,彙總起來就是:

  1. 對寫入的數據做 H 次 hash 運算定位到數組中的位置,同時將數據改爲 1 。當有數據查詢時也是同樣的方式定位到數組中。 一旦其中的有一位爲 0 則認爲數據肯定不存在於集合,否則數據可能存在於集合中。
  2. 注意:Bloom Filter 有一定的誤報率,這個誤報率和 Hash 算法的次數 H,以及數組長度 L 都是有關的。
  3. 業界更好的解決方案布隆過濾: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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章