演算法學習,演算法學習網站
- Bloom filter簡介
- Bloom Filter計算方法
- Bloom Filter優點缺點
- 圖示說明
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_hclass 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);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> bool BloomFilter<Type>::Add(const Type &T){ int first = HasH(T); int second = HasH(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 = HasH(first); 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;}
這就是My Code了。