【C++】:STL詳解 —— 布隆過濾器

目錄

布隆過濾器的概念

布隆過濾器的優點?

布隆過濾器的缺點

布隆過濾器使用場景

布隆過濾器的實現


布隆過濾器的概念

布隆過濾器(Bloom Filter)?是一種空間效率極高的概率型數據結構,用于快速判斷一個元素是否屬于某個集合。其核心特點包括:

  • 空間高效:基于位數組(bit array)實現,占用內存遠小于傳統數據結構(如哈希表)。

  • 概率性判斷:可能返回“可能存在”(存在誤判,即假陽性),但絕不會返回“肯定不存在”(無假陰性)。

  • 不可刪除:標準布隆過濾器不支持元素刪除,但改進版(如計數布隆過濾器)通過替換位為計數器可實現刪除功能。

工作原理

  1. 數據結構

    • 使用一個長度為?m?的位數組(bit array),初始全為0。

    • 選擇?k?個獨立的哈希函數,每個函數將元素映射到位數組的某個位置。

  2. 插入元素

    • 對元素進行?k?次哈希計算,得到?k?個位下標。

    • 將位數組中這?k?個位置的值設為1。

  3. 查詢元素

    • 對元素進行?k?次哈希計算,檢查對應的?k?個位是否均為1:

      • 若有一位為0:元素一定不存在(無假陰性)。

      • 若全為1:元素可能存在(存在假陽性,即誤判)。

起源:?

  • 提出者與時間:由 Burton Howard Bloom 在1970年提出,旨在解決大規模數據下的成員查詢問題。

  • 背景:在早期計算機系統中,內存資源極其有限,傳統方法(如哈希表)無法高效處理海量數據。布隆過濾器通過犧牲一定準確性,換取了空間和時間的顯著優化。

布隆過濾器的優點?

布隆過濾器(Bloom Filter)的核心優勢在于通過概率性設計空間效率時間效率業務容忍度之間達到最佳平衡

一、空間效率極高(核心優勢)

比特級存儲

  • 使用位數組(bit array)存儲數據,每個元素僅占用若干比特位(而非存儲完整數據)。

對比示例

數據結構存儲1億元素所需內存存儲方式
哈希表(鏈地址法)~3.2GB存儲完整字符串+指針
紅黑樹~4.8GB字符串+平衡樹節點元數據
布隆過濾器114MB?(1%誤判率)僅存儲哈希映射的比特位

數學優化空間

  • 通過公式 ??m= -\frac{n\ln \epsilon }{\left ( \ln 2 \right )^{2}}?可精確計算所需內存,避免資源浪費。
    • k:哈希函數個數,m:布隆過濾器長度
    • n:已插入元素的數量,\epsilon:誤判率
  • 例如:1億用戶昵稱判重,1%誤判率僅需114MB,而哈希表需要3.2GB,內存節省28倍

二、查詢與插入速度極快

  1. 時間復雜度

    • 插入和查詢均為?O(k),k?為哈希函數數量(通常?k=5~10),接近常數時間?O(1)。

    • 對比傳統方案

      數據結構插入耗時查詢耗時
      哈希表O(1)O(1)
      紅黑樹O(log n)O(log n)
      布隆過濾器O(k)O(k)

三、誤判率可控且單向安全

  1. 數學可控性

    • 誤判率公式?\epsilon\approx \left ( 1-e^{-kn/m} \right )^{k},通過調整?m(位數組大小)和?k(哈希函數數量)以及 n(已插入元素的數量),可精確控制誤判率(如1%、0.1%)。

    • 參數調優工具化:可直接使用在線計算器(如Bloom Filter Calculator)生成最優參數。

  2. 業務安全性

    • 零假陰性(False Negative):若元素存在,布隆過濾器絕不會漏判。

    • 假陽性(False Positive):誤判僅導致額外校驗,不影響最終業務正確性。

靈活的變體與擴展性

  1. 支持功能擴展

    變體類型核心改進適用場景
    計數布隆過濾器用計數器替代比特位,支持刪除操作動態數據集(如實時黑名單)
    可擴展布隆過濾器動態添加新位數組層,支持容量擴容數據量持續增長的系統
    壓縮布隆過濾器使用Roaring Bitmap壓縮稀疏位數組內存敏感場景

布隆過濾器的缺點

一、存在誤判率(假陽性)

  • 核心問題
    布隆過濾器可能將不存在的元素誤判為存在,誤判率由公式??\epsilon\approx \left ( 1-e^{-kn/m} \right )^{k}?決定,無法完全消除。

  • 實際影響

    • 場景限制:在需要絕對準確性的領域(如金融交易、密碼驗證),誤判可能導致嚴重后果。

    • 二次校驗需求:需結合數據庫等權威存儲進行二次確認,增加系統復雜度。

    • 示例:若誤判率設為1%,每100次查詢可能有1次誤判,需額外訪問數據庫。

二、不支持刪除操作(標準版本)

  • 原因
    多個元素可能共享相同的位,刪除一個元素可能影響其他元素的判斷。

  • 解決方案與代價

    方案原理代價
    計數布隆過濾器用計數器替代位數組,記錄哈希命中次數內存增加4~8倍(每個計數器占4位)
    定期重建周期性地重新構建過濾器維護成本高,可能導致服務中斷
  • 示例
    計數布隆過濾器存儲1億元素需約456MB(原標準版114MB),內存占用顯著上升。

三、功能局限性

  • 僅支持存在性判斷
    無法獲取元素值、出現次數或其他元數據,應用場景受限。

    • 示例
      無法統計昵稱使用頻率,也無法實現黑白名單的優先級區分。

四、需預先確定數據規模

  • 參數設計挑戰
    位數組大小?m?和哈希函數數量?k?需基于預期元素數量?n?和誤判率???提前計算。若實際插入元素數?n′ ? n,誤判率急劇上升。

  • 動態調整方案

    方案原理代價
    可擴展布隆過濾器分層疊加多個布隆過濾器內存碎片化,查詢需遍歷多層
    動態擴容按需分配新位數組并遷移數據遷移期間性能下降,實現復雜
  • 示例
    若預期?n=1億,實際插入?2億 元素,誤判率可能從1%升至?13%(位數組未擴容時)。

布隆過濾器使用場景

一、緩存系統優化

1.?緩存穿透防護

  • 問題:惡意請求大量不存在的數據,繞過緩存直接沖擊數據庫。

  • 解決方案

    • 在緩存層(如Redis)前置布隆過濾器,存儲所有合法鍵。

    • 請求到達時,先通過布隆過濾器判斷鍵是否存在:

  • 效果
    • 減少99%以上的無效數據庫查詢(假設誤判率1%)。

    • 案例:Twitter使用布隆過濾器攔截不存在的推文ID查詢。

二、數據庫與存儲系統

1.?查詢預過濾

  • 場景:減少磁盤IO(如LSM-Tree中的SSTable查詢)。

  • 實現

    • 每個SSTable文件附加一個布隆過濾器。

    • 查詢時先檢查過濾器,僅在可能存在時訪問磁盤。

    • 案例:Apache Cassandra為每個SSTable維護布隆過濾器,減少90%的磁盤讀取。

2.?分布式數據同步

  • 場景:跨節點同步數據前預判差異。

  • 實現

    • 各節點維護本地數據的布隆過濾器。

    • 同步時交換過濾器,僅傳輸可能缺失的數據。

    • 案例:IPFS使用布隆過濾器優化DHT網絡中的數據同步。

三、網絡與安全

1.?惡意URL/內容過濾

  • 場景:快速攔截已知惡意請求。

  • 實現

    • 本地存儲惡意URL的布隆過濾器(如瀏覽器安全插件)。

    • 匹配成功時觸發詳細檢測,避免全量數據存儲。

    • 案例:Chrome瀏覽器用布隆過濾器預篩惡意網址。

2.?密碼字典防護

  • 場景:阻止用戶使用弱密碼。

  • 實現

    • 將常見弱密碼存入布隆過濾器。

    • 用戶設置密碼時快速判斷是否在弱密碼集中(允許誤判,后續人工審核)。

?

布隆過濾器的實現

#include <iostream>
#include <bitset>
#include <string>
#include <cmath>/*** @brief BKDR哈希函數* 經典字符串哈希算法,通過累乘素數種子實現* 種子通常選擇31/131/1313等質數*/
struct BKDRHash {size_t operator()(const std::string& s) {size_t value = 0;for (auto ch : s) {value = value * 131 + ch; // 131為常用素數種子}return value;}
};/*** @brief AP哈希函數* Arash Partow設計的哈希算法,通過位運算混合字符* 交替使用不同的位運算策略增強散列性*/
struct APHash {size_t operator()(const std::string& s) {size_t value = 0;for (size_t i = 0; i < s.size(); i++) {if ((i & 1) == 0) { // 偶數位置字符value ^= ((value << 7) ^ s[i] ^ (value >> 3));} else {            // 奇數位置字符value ^= (~((value << 11) ^ s[i] ^ (value >> 5)));}}return value;}
};/*** @brief DJB哈希函數* Daniel J. Bernstein提出的哈希算法* 初始值5381為魔法數,通過左移操作混合字符*/
struct DJBHash {size_t operator()(const std::string& s) {if (s.empty()) return 0;size_t value = 5381; // 初始魔法值for (auto ch : s) {value += (value << 5) + ch; // value * 33 + ch}return value;}
};/*** @brief 布隆過濾器模板類* @tparam N 位數組大小,需根據預期數據量計算得出* @tparam K 元素類型,默認為std::string* @tparam Hash1 第一個哈希函數策略* @tparam Hash2 第二個哈希函數策略* @tparam Hash3 第三個哈希函數策略*/
template<size_t N, class K = std::string,class Hash1 = BKDRHash,class Hash2 = APHash,class Hash3 = DJBHash>
class BloomFilter {
public:/*** @brief 插入元素* @param key 要插入的元素*/void Set(const K& key) {size_t i1 = Hash1()(key) % N; // 計算哈希位置1size_t i2 = Hash2()(key) % N; // 計算哈希位置2size_t i3 = Hash3()(key) % N; // 計算哈希位置3_bs.set(i1);  // 設置位數組_bs.set(i2);_bs.set(i3);}/*** @brief 檢查元素是否存在* @param key 要檢查的元素* @return true 可能存在(存在誤判概率)* @return false 絕對不存在*/bool Test(const K& key) const {// 三個位置中任一位置未設置即可確定不存在size_t i1 = Hash1()(key) % N;if (!_bs.test(i1)) return false;size_t i2 = Hash2()(key) % N;if (!_bs.test(i2)) return false;size_t i3 = Hash3()(key) % N;return _bs.test(i3); // 三個位置全設置返回可能存在}/*** @brief 清空過濾器(重置所有位)*/void Clear() {_bs.reset();}/*** @brief 獲取當前設置的比特位數量* @return size_t 已設置的位數量*/size_t GetUsedBits() const {return _bs.count();}/*** @brief 估算當前誤判率* @param element_count 假設已插入元素數量* @return double 誤判概率(0.0~1.0)*/double EstimateFalsePositiveRate(size_t element_count) const {if (element_count == 0) return 0.0;const double m = N;              // 位數組總大小const double k = 3.0;            // 哈希函數數量const double n = element_count;  // 假設的元素數量// 誤判率公式:(1 - e^(-k*n/m))^kconst double exponent = -k * n / m;return pow(1 - std::exp(exponent), k);}/*** @brief 估算當前存儲的元素數量* @return size_t 估算的元素數量*/size_t EstimateElementCount() const {const size_t used = GetUsedBits();if (used == 0) return 0;const double m = N;    // 位數組總大小const double k = 3.0;  // 哈希函數數量const double X = used; // 已設置的位數量// 元素數量估算公式:n ≈ -m/(k) * ln(1 - X/m)return static_cast<size_t>(-m/(k) * std::log(1 - X/m));}/*** @brief 獲取過濾器位數組容量* @return size_t 位數組總大小(bits)*/constexpr size_t Capacity() const noexcept {return N;}/*** @brief 獲取當前空間利用率* @return double 已用位比例(0.0~1.0)*/double LoadFactor() const {return static_cast<double>(GetUsedBits()) / N;}private:std::bitset<N> _bs; // 底層位數組存儲
};/* 使用示例 */
int main() {BloomFilter<1000000> bf; // 100萬位的布隆過濾器// 插入測試數據bf.Set("alice");bf.Set("bob");bf.Set("charlie");// 測試存在性std::cout << "Test alice: " << bf.Test("alice") << "\n";   // 1std::cout << "Test david: " << bf.Test("david") << "\n";   // 0// 獲取統計信息std::cout << "Used bits: " << bf.GetUsedBits() << "\n";std::cout << "Estimated elements: " << bf.EstimateElementCount() << "\n";std::cout << "Load factor: " << bf.LoadFactor() << "\n";std::cout << "False positive rate: " << bf.EstimateFalsePositiveRate(3) << "\n";// 清空過濾器bf.Clear();std::cout << "After clear, used bits: " << bf.GetUsedBits() << "\n";return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73573.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73573.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73573.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從Instagram到畫廊:社交平臺如何改變藝術家的展示方式

從Instagram到畫廊&#xff1a;社交平臺如何改變藝術家的展示方式 在數字時代&#xff0c;藝術家的展示方式正在經歷一場革命。社交平臺&#xff0c;尤其是Instagram&#xff0c;已經成為藝術家展示作品、與觀眾互動和建立品牌的重要渠道。本文將探討社交平臺如何改變藝術家的…

MySQL(事物上)

目錄 示例&#xff1a; 一 引入事物 1. 概念 2. 事物的4大特性 3. 為什么要有事物&#xff1f; 二 事物操作 1. 查看存儲引擎支持的事物 2. 事物的提交方式 2.1 查看事物的默認提交方式 2.2 設置事物的默認提交方式 2.3 查看事物的全局隔離級別 2.4 驗證事物的回滾…

Spring Boot 實現多數據源配置

一、配置流程 在 Spring Boot 中實現多數據源配置通常用于需要連接多個數據庫的場景。主要有以下幾個步驟&#xff1a; 配置多個數據源的連接信息。定義多個數據源的 Bean。為每個數據源配置MyBatis的SqlSessionFactory和事務管理器。為每個數據源定義Mapper接口和Mapper XML…

p5.js:繪制各種內置的幾何體,能旋轉

向 豆包 提問&#xff1a;請編寫 p5.js 示例&#xff0c; 繪制各種內置的幾何體&#xff0c;能讓這些幾何體緩慢旋轉。 cd p5-demo copy .\node_modules\p5\lib\p5.min.js . 此代碼創建了一個包含多個內置幾何體的 3D 場景&#xff0c;每個幾何體都有不同的顏色和位置。運行代…

結構體定義與應用

引言 到今天為止,c語言的基礎操作和基礎數據類型,就都已經結束了,大家都知道,如果要實現復雜的功能,大家都可以通過函數封裝調用,那么如果要實現基礎數據類型的封裝,該怎么辦呢?答案就是結構體。 在C語言編程中,結構體(struct)是非常重要的一個概念,它為程序員提供…

MindGYM:一個用于增強視覺-語言模型推理能力的合成數據集框架,通過生成自挑戰問題來提升模型的多跳推理能力。

2025-03-13&#xff0c;由中山大學和阿里巴巴集團的研究團隊提出了MindGYM框架&#xff0c;通過合成自挑戰問題來增強視覺-語言模型&#xff08;VLMs&#xff09;的推理能力。MindGYM框架通過生成多跳推理問題和結構化課程訓練&#xff0c;顯著提升了模型在推理深度和廣度上的表…

R語言零基礎系列教程-01-R語言初識與學習路線

代碼、講義、軟件回復【R語言01】獲取。 R語言初識 R是一個開放的統計編程環境&#xff0c;是一門用于統計計算和作圖的語言。“一切皆是對象”&#xff0c;數據、函數、運算符、環境等等都是對象。易學&#xff0c;代碼像偽代碼一樣簡潔&#xff0c;可讀性高強大的統計和可視…

PythonWeb開發框架—Flask-APScheduler超詳細使用講解

1.定時任務的兩種實現方式 1.1 用scheduler.task裝飾任務 安裝插件&#xff1a; pip install Flask-APScheduler pip install apscheduler 腳本實現&#xff1a; ###app.py##導入依賴庫 from flask import Flask import datetime import config from flask_apscheduler i…

python_巨潮年報pdf下載

目錄 前置&#xff1a; 步驟&#xff1a; step one: pip安裝必要包&#xff0c;獲取年報url列表 step two: 將查看url列表轉換為pdf url step three: 多進程下載pdf 前置&#xff1a; 1 了解一些股票的基本面需要看歷年年報&#xff0c;在巨潮一個個下載比較費時間&…

從0到1構建AI深度學習視頻分析系統--基于YOLO 目標檢測的動作序列檢查系統:(2)消息隊列與消息中間件

文章大綱 原始視頻隊列Python 內存視頻緩存優化方案(4GB 以內)一、核心參數設計二、內存管理實現三、性能優化策略四、內存占用驗證五、高級優化技巧六、部署建議檢測結果隊列YOLO檢測結果隊列技術方案一、技術選型矩陣二、核心實現代碼三、性能優化策略四、可視化方案對比五…

React Native 如何使用 Expo 快速開發?

React Native是當下熱門的跨平臺移動開發框架&#xff0c;而Expo則是它的重要開發工具之一。Expo提供了一套完整的開發環境&#xff0c;使開發者無需安裝Android Studio或Xcode也能快速運行React Native項目。它包含了眾多內置API&#xff0c;如相機、地理位置、推送通知等&…

中考英語之09從句

1 賓語從句 定義 在主從復合句中充當賓語&#xff0c;位于及物動詞、介詞或復合謂語之后的從句。 引導詞 綜述&#xff1a; that&#xff08;可省略&#xff09;、if/whether、連接代詞&#xff08;what、which、who、whom、whose 等&#xff09;和連接副詞&#xff08;when、…

平方矩陣問題

Ⅰ 回字形二維數組 #include <iostream> #include <iomanip> using namespace std; int main(){int n;while(cin>>n,n){for(int i0; i<n;i){for(int j0; j<n; j){int upi, downn-i1, leftj, rightn-j1;cout<<min(min(up,down),min(left,right)…

C++模版(復習)

1.泛型編程&#xff1a;編寫與類型無關的通用代碼&#xff0c;是代碼復用的一種手段。模板是泛型編程的基礎 2.函數模板的格式 template<typename T1,typename T2,…,typename Tn> 返回類型 函數名(參數列表) { ??//函數體 } 3.template<class T1,class T2,…,class…

【sklearn 05】sklearn功能模塊

sklearn功能模塊 分類&#xff1a;識別某個對象屬于那個類別回歸&#xff1a;預測與對象相關聯的連續值屬性聚類&#xff1a;將相似對象自動分組降維&#xff1a;減少要考慮的隨機變量的數量模型選擇&#xff1a;比較、驗證、選擇參數和模型預處理&#xff1a;特征提取和歸一化…

使用Qt創建懸浮窗口

在Qt中創建懸浮窗口&#xff08;如無邊框、可拖動的浮動面板或提示框&#xff09;可以通過以下方法實現。以下是幾種常見場景的解決方案&#xff1a; 方法1&#xff1a;使用無邊框窗口 鼠標事件拖動 適用于自定義浮動工具窗口&#xff08;如Photoshop的工具欄&#xff09;。 …

《P4387 【深基15.習9】驗證棧序列》

題目描述 給出兩個序列 pushed 和 poped 兩個序列&#xff0c;其取值從 1 到 n(n≤100000)。已知入棧序列是 pushed&#xff0c;如果出棧序列有可能是 poped&#xff0c;則輸出 Yes&#xff0c;否則輸出 No。為了防止騙分&#xff0c;每個測試點有多組數據&#xff0c;不超過 …

校園安全用電怎么保障?防觸電裝置來幫您

引言 隨著教育設施的不斷升級和校園用電需求的日益增長&#xff0c;校園電力系統的安全性和可靠性成為了學校管理的重要課題。三相智能安全配電裝置作為一種電力管理設備&#xff0c;其在校園中的應用不僅能夠提高電力系統的安全性&#xff0c;還能有效保障師生的用電安全&am…

【Git】--- 初識Git Git基本操作

Welcome to 9ilks Code World (??? ? ???) 個人主頁: 9ilk (??? ? ???) 文章專欄&#xff1a; Git 本篇我們來初步認識Git企業級應用是什么&#xff0c;有什么用以及Git基本操作。 &#x1f3e0; 初始Git 提出問題 在日常生活中&#xff0c;我們進行…

數據治理下半場:如何用文化變革撬動企業數字化轉型?

數據治理下半場:如何用文化變革撬動企業數字化轉型? 一、打破認知繭房:從"數據恐懼癥"到"數據生產力"二、重構協作生態:從"部門墻"到"數據共同體"三、建立責任體系:從"無人認領"到"終身責任制"?四、點燃創新…