【資料結構】布隆過濾器——點陣圖擴充套件
阿新 • • 發佈:2018-12-26
本篇博文,旨在介紹一種可以快速檢索元素是否存在的資料結構 --- 布隆過濾器;本文從點陣圖和布隆過濾器的對比,討論了使用這兩種資料結構的不同情況;並介紹了布隆過濾器的幾種主要使用場景
布隆過濾器的引入
之前學習了點陣圖,可以快速的判斷一個整數是否存在於一個集合中
然而,現實生活中我們用的很多是字串,單用點陣圖處理不了字串,由此引來了點陣圖
布隆過濾器的思想
學過了雜湊表後我們知道字串雜湊演算法,可以將字串轉換為一個key值,然後存入點陣圖
但是,通過字串雜湊演算法後,也很有可能會造成雜湊衝突(多個字串對映成同一個key值),這樣誤判率就會很高
布隆過濾器的實現
於是,布隆過濾器就是採用同時進行多個字串雜湊演算法,進行對映;
假設我們用5個字串雜湊演算法進行對映,那麼在判斷一個字串是否存在時,只需判斷對應的五個位是否同時存在即可
布隆過濾器的程式碼實現
#pragma once #include<iostream> using namespace std; //包我們自己定義的點陣圖標頭檔案 #include"BitMap.h" //定義五個字串雜湊演算法 template<class T> struct BKDRHash { size_t operator()(const T str) { register size_t hash = 0; for (size_t i = 0; i < str.size(); ++i) { hash = hash * 131 + str[i]; } return hash; } }; template<class T> struct SDBMHash { size_t operator()(const T str) { register size_t hash = 0; for (size_t i = 0; i < str.size(); ++i) { hash = 65599 * hash + str[i]; } return hash; } }; template<class T> struct RSHash { size_t operator()(const T str) { register size_t hash = 0; size_t magic = 63689; for (size_t i = 0; i < str.size(); ++i) { hash = hash * magic + str[i]; magic *= 378551; } return hash; } }; template<class T> struct APHash { size_t operator()(const T str) { register size_t hash = 0; for (long i = 0; i < str.size(); ++i) { if ((i & 1) == 0) { hash ^= ((hash << 7) ^ str[i] ^ (hash >> 3)); } else { hash ^= (~((hash << 11) ^ str[i] ^ (hash >> 5))); } } return hash; } }; template<class T> struct JSHash { size_t operator()(const T str) { if (str.empty()) return 0; register size_t hash = 1315423911; for (size_t i = 0; i < str.size(); ++i) { hash ^= ((hash << 5) + str[i] + (hash >> 2)); } return hash; } }; //定義布隆過濾器,5個HashFunc是五種不同的字串雜湊演算法,用來輔助實現布隆過濾器 template<typename K = string, typename HashFunc1 = BKDRHash<K>, typename HashFunc2 = SDBMHash<K>, typename HashFunc3 = RSHash<K>, typename HashFunc4 = APHash<K>, typename HashFunc5 = JSHash<K>> class BoolmFilter { public: BoolmFilter(size_t num) :_bp(num*2*5) {} size_t HashFunC1(const K& num) { HashFunc1 hf; size_t index = hf(num); return index; } size_t HashFunC2(const K& num) { HashFunc2 hf; return hf(num); } size_t HashFunC3(const K& num) { HashFunc3 hf; return hf(num); } size_t HashFunC4(const K& num) { HashFunc4 hf; return hf(num); } size_t HashFunC5(const K& num) { HashFunc5 hf; return hf(num); } void Set(const K &num) { //用五中不同的字串雜湊演算法求出五個不同的值 size_t hf1 = HashFunC1(num); size_t hf2 = HashFunC2(num); size_t hf3 = HashFunC3(num); size_t hf4 = HashFunC4(num); size_t hf5 = HashFunC5(num); //測試五個雜湊值 //cout << hf1 << " " << hf2 << " " << hf3 << " " << hf4 << " " << hf5 << endl; //將五個值都放入點陣圖中 _bp.Set(hf1); _bp.Set(hf2); _bp.Set(hf3); _bp.Set(hf4); _bp.Set(hf5); } //Reset可以用引用計數來實現 //void Reset(); bool Find(K &num) { //分別判斷num對應的五個值是否存在於點陣圖中 //若有一個不存在,則返回FALSE,num必定不存在 //若都存在,則返回TRUE,但是不能確定一定存在 int hf1 = HashFunC1(num); if(_bp.Find(hf1) == false) return false; int hf2 = HashFunC2(num); if (_bp.Find(hf2) == false) return false; int hf3 = HashFunC3(num); if (_bp.Find(hf3) == false) return false; int hf4 = HashFunC4(num); if (_bp.Find(hf4) == false) return false; int hf5 = HashFunC5(num); if (_bp.Find(hf5) == false) return false; return true; } protected: //定義點陣圖 _bp; BitMap _bp; };
布隆過濾器和點陣圖的對比
點陣圖的優點:
可以快速的判斷一個整數是否存在於集合中
點陣圖的缺點:
就如同其優點中說的,只能判斷整數,無法處理其他型別的資料
布隆過濾器的優點:
1、在點陣圖的基礎上利用雜湊演算法進行擴充,使之可以處理字串型別的資料
2、時間複雜度O(k),【K表示字串雜湊演算法的個數】,其效率遠高於其他的演算法
布隆過濾器的缺點:
由於雜湊衝突,布隆過濾器有一定的誤判性,如何使用適量的字串雜湊演算法是需要考慮的問題
布隆過濾器的誤區:
使用字串雜湊演算法的數量越多越好?(錯)
這裡要說明,字串雜湊演算法過多,就會導致一個字串會佔好多個位,衝突的概率還會增大
所以,要使用適量的字串雜湊演算法
布隆過濾器的幾種主要應用場景:
(1)垃圾網站、郵件的過濾
(2)在爬蟲中,如何快速的判斷一個網頁是否爬過也是布隆過濾器的使用場合之一