1. 程式人生 > >Bloom Filter(布隆過濾器)學習實現(C++實現)

Bloom Filter(布隆過濾器)學習實現(C++實現)

非常感謝評論裡指出了我程式碼裡的小問題。以下程式碼修改了一下,主要是在第二次 HasH 的時候有小問題。

Bloom filter簡介

Bloom filter 是由 Howard Bloom 在 1970 年提出的二進位制向量資料結構,它具有很好的空間和時間效率,被用來檢測一個元素是不是集合中的一個成員。如果檢測結果為是,該元素不一定在集合中;但如果檢測結果為否,該元素一定不在集合中。因此Bloom filter具有100%的召回率。這樣每個檢測請求返回有“在集合內(可能錯誤)”和“不在集合內(絕對不在集合內)”兩種情況,可見 Bloom filter 是犧牲了正確率和時間以節省空間。

以上文字來源

百度百科

Bloom Filter計算方法

如需要判斷一個元素是不是在一個集合中,我們通常做法是把所有元素儲存下來,然後通過比較知道它是不是在集合內,連結串列、樹都是基於這種思路,當集合內元素個數的變大,我們需要的空間和時間都線性變大,檢索速度也越來越慢。 Bloom filter 採用的是雜湊函式的方法,將一個元素對映到一個 m 長度的陣列上的一個點,當這個點是 1 時,那麼這個元素在集合內,反之則不在集合內。這個方法的缺點就是當檢測的元素很多的時候可能有衝突,解決方法就是使用 k 個雜湊 函式對應 k 個點,如果所有點都是 1 的話,那麼元素在集合內,如果有 0 的話,元素則不在集合內。

Bloom Filter優點缺點

優點

  • 插入時間和查詢時間都是常數。
  • 儲存的不是資料本身,安全性好。

缺點

  • 插入的元素越多,錯判性越大。
  • 不能刪除元素。

圖示說明

例如我們有一個簡單的Bloom Filter結構如下:(所有位都是0)

      [ 0 0 0 0 0 0 0 0 0 0 ]

第一次插入a用兩個雜湊函式,對映到1 4位置上,變為1.

      [ 1 0 0 1 0 0 0 0 0 0 ]

第二次插入b同樣的hash函式,對映到1 8位置上, 變為1.

      [ 1 0 0 1 0 0 0 1 0 0 ]

這樣就存放了a b兩個元素,當我們查詢a是否在的時候,兩次hash找到1 4

位置,發現同時為 1。則表明a存在。

但是假如我們查詢的d雜湊後對映到4 8位置,發現也同時為 1. 認為存在,這就出錯了,因為現在裡面只存放了a b沒有d

下面寫下我用C++寫的程式碼實現,比較簡單的實現了下,具體的Hash演算法我都簡略的寫了。

首先是標頭檔案Header.h

//
//  Header.h
//  BloomFilter
//
//  Created by Alps on 15/3/19.
//  Copyright (c) 2015年 chen. All rights reserved.
//

#ifndef BloomFilter_Header_h
#define BloomFilter_Header_h

class BitMap{
public:
    BitMap(){
        bitmap = NULL;
        size = 0;
    }
    BitMap(int size){
        bitmap = NULL;
        bitmap = new char[size];
        if (bitmap == NULL) {
            printf("ErroR In BitMap Constractor!\n");
        }else{
            memset(bitmap, 0x0, size * sizeof(char));
            this->size = size;
        }
    }

    int initBitMap(int size){
        bitmap = NULL;
        bitmap = new char[size];
        if (bitmap == NULL) {
            printf("ErroR In BitMap Constractor!\n");
            return 0;
        }else{
            memset(bitmap, 0x0, size * sizeof(char));
            this->size = size;
            return this->size;
        }
    }


    /*
     * set the index bit to 1;
     */
    int bitmapSet(int index){
        int addr = index/8;
        int addroffset = index%8;
        unsigned char temp = 0x1 << addroffset;
        if (addr > (size+1)) {
            return 0;
        }else{
            bitmap[addr] |= temp;
            return 1;
        }
    }

    /*
     * return if the index in bitmap is 1;
     */
    int bitmapGet(int index){
        int addr = index/8;
        int addroffset = index%8;
        unsigned char temp = 0x1 << addroffset;
        if (addr > (size + 1)) {
            return 0;
        }else{
            return (bitmap[addr] & temp) > 0 ? 1 : 0;
        }
    }

    /*
     * del the index from 1 to 0
     */
    int bitmapDel(int index){
        if (bitmapGet(index) == 0) {
            return 0;
        }
        int addr = index/8;
        int addroffset = index%8;
        unsigned char temp = 0x1 << addroffset;
        if (addr > (size + 1)) {
            return 0;
        }else{
            bitmap[addr] ^= temp;
            return 1;
        }
    }

private:
    char *bitmap;
    int size;
};

#endif

標頭檔案儲存好,放到工程路徑下。
下面是BloomFilter.cpp檔案了。

//
//  main.cpp
//  BloomFilter
//
//  Created by Alps on 15/3/18.
//  Copyright (c) 2015年 chen. All rights reserved.
//

#include <iostream>
#include "Header.h"
using namespace std;


template <class Type> class BloomFilter{
public:
    BloomFilter();
    BloomFilter(int length){
        bitmap.initBitMap(length);
        this->length = length;
    }
    bool Add(const Type &T);
    bool Contains(const Type &T);
    int HasH(const Type &T);
    int SecondHasH(const Type &T);
private:
    BitMap bitmap;
    int length;
};
template <class Type> int BloomFilter<Type>::HasH(const Type &T){
    int temp = (int) T;
    return temp%length;
}

template <class Type> int BloomFilter<Type>::SecondHasH(const Type &T){
    int temp = (int) T;
    return temp%9973;
    //這裡直接選了一個大素數 請各位自己優化自己的 HasH函式
    //不然會出現頻繁的雜湊衝突,並且把布隆過濾器的大小盡量放大一點幾百萬都可以
}

template <class Type> bool BloomFilter<Type>::Add(const Type &T){
    int first = HasH(T);
    int second = SecondHasH(first);
    if (bitmap.bitmapSet(first) && bitmap.bitmapSet(second)) {
        return true;
    }else{
        return false;
    }

}

template <class Type> bool BloomFilter<Type>::Contains(const Type &T){
    int first = HasH(T);
    int second =  SecondHasH(T);
    if (bitmap.bitmapGet(first) && bitmap.bitmapGet(second)) {
        return true;
    }else{
        return false;
    }
}




int main(int argc, const char * argv[]) {

    BloomFilter<int> bloom(10);

    bloom.Add(3);
    if (bloom.Contains(3)) {
        printf("true\n");
    }else{
        printf("false\n");
    }

    if (bloom.Contains(2)) {
        printf("true\n");
    }else{
        printf("false\n");
    }

    return 0;
}

這就是我的程式碼了。