【C++篇】位圖與布隆過濾器

目錄

一,位圖

1.1,位圖的概念

1.2,位圖的設計與實現

1.5,位圖的應用舉例

1.4,位圖常用應用場景

?二,布隆過濾器

2.1,定義:

?2.2,布隆過濾器的實現

2.3,?應用場景

三,海量數據處理問題

3.1,10億個整數求最大的前100個數

3.2,給兩個文件,分別有100億個query(查詢字符串),我們只有1G內存,如何找到兩個文件交集?


一,位圖

1.1,位圖的概念

位圖是一種高效的數據結構,通過二進制位(0或1)的數組來高效存儲和操作數據,常用于標記狀態或處理大規模數據。

位圖的優缺點:

優點:增刪查改快,節省空間

缺點:只適用于整形

核心特性

  • 空間高效:每個元素僅占1 bit,適合處理海量數據(如去重、統計)。

  • 快速操作:支持位運算(與、或、異或等)進行高效查詢和修改。

1.2,位圖的設計與實現

位圖本質是一個直接定址法的哈希表,每個整型值映射一個bit位。

?核心接口:

對于一個 整形值x。計算x對應的bit位:i=x/32,j=i%32,得到x在第i個整形的第j個bit位。

對于一個 整形值x。要將它放入到數據中,只需將x對應的bit位由0置為1?

對于一個 整形值x,將它從數據中刪除,只需將x對應的bit位由1置為0.

判斷一個值x存不存在

代碼:

//N空間大小,比特位
template<size_t N>
class bitset
{
public:bitset(){_bs.resize(N / 32 + 1);}//將x位置的bit值 置為1void set(const int& x){//第i個整型的第j個bit位size_t i = x / 32;size_t j = x % 32;_bs[i] |= (1 << j);}//刪除x位置//將x位置的bit值 置為0void reset(const int& x){//第i個整型的第j個bit位size_t i = x / 32;size_t j = x % 32;_bs[i] &= (~(1 << j));}//判斷x值在不在bool test(const int& x){//第i個整型的第j個bit位size_t i = x / 32;size_t j = x % 32;return _bs[i] & (1 << j);}
private:std::vector<int> _bs;
};

1.5,位圖的應用舉例

(1) 給40億個不重復的unsigned int的整數,沒排過序的,然后再給一個數,如何快速判斷這個數是否在那40億個數當中。

40億數據量太大,如果將40億個int數據變量完全存儲到內存中 可不得了,可以采用40億個位來存儲這些數據的狀態。

首先遍歷這40億個數,在位圖中將對應的位置為1,再對于給出的數,進行判斷即可。

(2) 在2.5億個整數中找出不重復的整數,注,內存不足以容納這2.5億個整數。

使用2個位圖,每個數分配2個位圖,用這兩個位圖來表示存儲狀態,00表示不存在,01表示出現一次,10表示多次,11無意義

代碼示例:


?? ?template<size_t N>
?? ?class twobitset
?? ?{
?? ?public:
?? ??? ?//添加x
?? ??? ?void set(const int& x)
?? ??? ?{
?? ??? ??? ?bool bit1 = bs1.test(x);
?? ??? ??? ?bool bit2 = bs2.test(x);
?? ??? ??? ?//出現0次->出現1次
?? ??? ??? ?if (!bit1 && !bit2)//00->01
?? ??? ??? ?{
?? ??? ??? ??? ?bs2.set(x);
?? ??? ??? ?}
?? ??? ??? ?//出現1次->出現2次
?? ??? ??? ?else if (!bit1 && bit2)//01-> 10
?? ??? ??? ?{
?? ??? ??? ??? ?bs1.set(x);
?? ??? ??? ??? ?bs2.reset(x);
?? ??? ??? ?}
?? ??? ??? ?//出現2次->出現多次
?? ??? ??? ?else if (bit1 && !bit2)//10 ->11
?? ??? ??? ?{
?? ??? ??? ??? ?bs2.set(x);
?? ??? ??? ?}
?? ??? ?}
?? ??? ?//獲取x的出現次數
?? ??? ?int getcount(const int& x)
?? ??? ?{
?? ??? ??? ?bool bit1 = bs1.test(x);
?? ??? ??? ?bool bit2 = bs2.test(x);

?? ??? ??? ?if (!bit1 && !bit2)//00
?? ??? ??? ?{
?? ??? ??? ??? ?return 0;
?? ??? ??? ?}
?? ??? ??? ?else if (!bit1 && bit2)//01
?? ??? ??? ?{
?? ??? ??? ??? ?return 1;
?? ??? ??? ?}
?? ??? ??? ?else if (bit1 && !bit2)//10?
?? ??? ??? ?{
?? ??? ??? ??? ?return 2;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?return 3;
?? ??? ??? ?}
?? ??? ?}
?? ?private:
?? ??? ?bitset<N> bs1;
?? ??? ?bitset<N> bs2;
?? ?};

1.4,位圖常用應用場景

  • 去重與存在性檢查
    例如,統計10億用戶中哪些已注冊,僅需約120MB內存(109÷8≈125MB109÷8≈125MB)。

  • 布隆過濾器(Bloom Filter)
    利用多個哈希函數和位圖實現概率型數據存在性判斷。

  • 數據庫索引
    快速篩選滿足條件的記錄(如性別為“男”的用戶)。

  • 內存管理
    操作系統用位圖標記內存頁的分配狀態。

?二,布隆過濾器

2.1,定義:

有一些場景,由大量數據需要判斷是否存在,而這些數據不是整形,比如string,就不能使用位圖了,這些場景就需要布隆過濾器來解決。利用多個哈希函數和位圖實現,哈希函數內容見上篇文章【哈希表】。

?核心原理

  • 位數組(Bit Array):長度為?m?的二進制數組,初始全為0。

  • 哈希函數集合:k個獨立的哈希函數,每個函數將元素映射到位數組的某個位置。

以string類型為例:

而這種沖突是無法避免的,因為位圖中只存儲了狀態,即0或1,無法改變。所以我們只能做到降低沖突概率,對于一個字符串,讓它映射到多個位置上。經過k個哈希函數的轉化,映射到k個位置,將這k位置都置為1。在查找時也是如此,經過k個哈希函數,k個位置都為1,才能說明該數據存在,否則就是與其他位置存在沖突,導致幾個位置位1,幾個位置為0,說明該數據不存在。

布隆過濾器優缺點:

?2.2,布隆過濾器的實現

下圖中 :

k代表哈希函數的個數

m為布隆過濾器的大小

n為插入的元素個數。

通過觀察誤判率的公式可得:在k一定的情況下,當n增加時,誤判率增加,當m增加時,誤判率越小。也就是哈希函數一定的情況下,插入元素越多時,誤判率增加,布隆過濾器長度越長時,誤判率減小。令X=m/n,可得,X越大,誤判率越小。

//哈希函數
struct HashFuncBKDR
{// @detail 本 算法由于在Brian Kernighan與Dennis Ritchie的《The CProgramming Language》// 一書被展示而得 名,是一種簡單快捷的hash算法,也是Java目前采用的字符串的Hash算法累乘因子為31。size_t operator()(const std::string& s){size_t hash = 0;for (auto ch : s){hash *= 31;hash += ch;}return hash;}
};
struct HashFuncAP
{// 由Arash Partow發明的一種hash算法。  size_t operator()(const std::string& s){size_t hash = 0;for (size_t i = 0; i < s.size(); i++){if ((i & 1) == 0) // 偶數位字符{hash ^= ((hash << 7) ^ (s[i]) ^ (hash >> 3));}else              // 奇數位字符{hash ^= (~((hash << 11) ^ (s[i]) ^ (hash >> 5)));}}return hash;}
};
struct HashFuncDJB
{// 由Daniel J. Bernstein教授發明的一種hash算法。 size_t operator()(const std::string& s){size_t hash = 5381;for (auto ch : s){hash = hash * 33 ^ ch;}return hash;}
};//布隆過濾器
//M布隆過濾器的長度
//N插入元素個數
//X=M/N 越大,誤判率越小
template<size_t  N,size_t X=5,class k=string,class Hash1= HashFuncBKDR,class Hash2= HashFuncAP,class Hash3= HashFuncDJB>
class BloomFilter
{
public:void set(const k& key){size_t hash1 = Hash1()(key) % M;size_t hash2 = Hash2()(key) % M;size_t hash3 = Hash3()(key) % M;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);}//可能存在誤判bool test(const k& key){//只要一個位置為0,就不存在size_t hash1 = Hash1()(key) % M;if (_bs.test(hash1) == 0)return false;size_t hash2 = Hash2()(key) % M;if (_bs.test(hash2) == 0)return false;size_t hash3 = Hash3()(key) % M;if (_bs.test(hash3) == 0)return false;return true;}
private:static const int M = N * X;bitset<M> _bs;
};

2.3,?應用場景

  1. 緩存穿透防護

    ? ? 在分布式緩存系統中,布隆過濾器可以?來解決緩存穿透的問題。緩存穿透是指惡意用戶請求?個不 存在的數據,導致請求直接訪問數據庫,造成數據庫壓力過?。布隆過濾器可以先判斷請求的數據是 否存在于布隆過濾器中,如果不存在,直接返回不存在,避免對數據庫的無效查詢。
  2. 爬蟲去重

    ? ?在爬蟲系統中,為了避免重復爬取相同的URL,可以使?布隆過濾器來進行URL去重。爬取到的URL可 以通過布隆過濾器進行判斷,已經存在的URL則可以直接忽略,避免重復的網絡請求和數據處理。
  3. 對數據庫查詢提效:

    ? 在數據庫中,布隆過濾器可以用來加速查詢操作。例如:一個app要快速判斷一個電話號碼是否注冊 過,可以使用布隆過濾器來判斷一個用戶電話號碼是否存在于表中,如果不存在,可以直接返回不存 在,避免對數據庫進行無用的查詢操作。如果在,再去數據庫查詢進行二次確認。
  4. 垃圾郵件過濾

    ? ?在垃圾郵件過濾系統中,布隆過濾器可以用來判斷郵件是否是垃圾郵件。系統可以將已知的垃圾郵件 的特征信息存儲在布隆過濾器中,當新的郵件到達時,可以通過布隆過濾器快速判斷是否為垃圾郵件,從而提高過濾的效率。

布隆過濾器通過犧牲一定的準確性,在海量數據去重快速過濾等場景中展現了不可替代的優勢,是分布式系統和大數據處理的基石技術之一。

三,海量數據處理問題

3.1,10億個整數求最大的前100個數

本題是topk問題,用堆解決,建一個100個數的小堆,讓這10億個整數分別與堆頂元素比較,如果大于堆頂元素,就交換,再調整堆。最后最大的前100個就保存在小堆中。

3.2,給兩個文件,分別有100億個query(查詢字符串),我們只有1G內存,如何找到兩個文件交集?

解法一:使用布隆過濾器存儲文件1,再遍歷文件2,看布隆過濾器中是否存在,存在就是交集。

解法二:

哈希切分,首先內存的訪問速度遠大于硬盤,大文件放到內存搞不定,那么我們可以考慮切分為

文件,再放進內存處理。

本質是相同的query在哈希切分過程中,一定進入的同一個小文件Ai和Bi,不可能出現A中的的 query進入Ai,但是B中的相同query進入了和Bj的情況,所以對Ai和Bi進行求交集即可,不需要Ai 和Bj求交集。

?哈希切分的問題就是每個??件不是均勻切分的,可能會導致某個小文件很大內存放不下。我們細 細分析?下某個小文件很?有兩種情況:1.這個小文件中?部分是同一個query。2.這個小文件是 有很多的不同query構成,本質是這些query沖突了。針對情況1,其實放到內存的set中是可以放 下的,因為set是去重的。針對情況2,需要換個哈希函數繼續二次哈希切分。所以我們遇到大?于1G小文件,可以繼續讀到set中找交集,若set.insert時拋出了異常(set插?數據拋異常只可能是 申請內存失敗了,不會有其他情況),那么就說明內存放不下是情況2,換個哈希函數進行二次哈希切分。

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

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

相關文章

VR觸感數據手套:觸感反饋賦予虛擬交互沉浸式體驗

隨著動作捕捉技術的蓬勃發展&#xff0c;動捕數據手套成為了手部動作捕捉與虛擬交互的便捷工具&#xff0c;為人們打開了通往虛擬世界的新大門。在眾多產品中&#xff0c;mHand Pro作為一款多功能兼具的VR動作捕捉數據手套&#xff0c;憑借其卓越的性能&#xff0c;在手部動作捕…

C# 結構體介紹

.NET學習資料 .NET學習資料 .NET學習資料 一、結構體的定義與基本使用 &#xff08;一&#xff09;定義結構體 在 C# 中&#xff0c;使用struct關鍵字來創建結構體。它就像是一個模板&#xff0c;能定義出符合特定需求的數據結構。比如&#xff0c;若要跟蹤圖書館中書的信息…

圖像噪聲處理技術:讓圖像更清晰的藝術

在這個數字化時代&#xff0c;圖像作為信息傳遞的重要載體&#xff0c;其質量直接影響著我們的視覺體驗和信息解讀。然而&#xff0c;在圖像采集、傳輸或處理過程中&#xff0c;難免會遇到各種噪聲干擾&#xff0c;如高斯噪聲、椒鹽噪聲等&#xff0c;這些噪聲會降低圖像的清晰…

追逐低空經濟,無人機研學技術詳解

追逐低空經濟&#xff0c;無人機研學技術成為了一個備受關注的領域。以下是對無人機研學技術的詳細解析&#xff1a; 一、無人機研學技術概述 無人機研學技術是以無人機為核心&#xff0c;結合航空科技、電子技術、機械原理等多領域知識的一種教育實踐活動。它旨在通過理論學習…

(done) MIT6.S081 2023 學習筆記 (Day7: LAB6 Multithreading)

網頁&#xff1a;https://pdos.csail.mit.edu/6.S081/2023/labs/thread.html (任務1教會了你如何用 C 語言調用匯編&#xff0c;編譯后鏈接即可) 任務1&#xff1a;Uthread: switching between threads (完成) 在這個練習中&#xff0c;你將設計一個用戶級線程系統中的上下文切…

Kubernetes學習之通過Service訪問Pod

一、基礎概述 1.當通過deployment等controller動態創建和銷毀pod使得每個pod都有自己的ip地址&#xff0c;當controller用新的pod替代發生故障的pod時&#xff0c;新的pod會分配到新的ip地址&#xff0c;那么客戶端如何穩定的找到并訪問pod提供的服務。 2.創建service service從…

【優先算法】專題——前綴和

目錄 一、【模版】前綴和 參考代碼&#xff1a; 二、【模版】 二維前綴和 參考代碼&#xff1a; 三、尋找數組的中心下標 參考代碼&#xff1a; 四、除自身以外數組的乘積 參考代碼&#xff1a; 五、和為K的子數組 參考代碼&#xff1a; 六、和可被K整除的子數組 參…

CDDIS從2025年2月開始數據遷移

CDDIS 將從 2025 年 2 月開始將我們的網站從 cddis.nasa.gov 遷移到 earthdata.nasa.gov&#xff0c;并于 2025 年 6 月結束。 期間可能對GAMIT聯網數據下載造成影響。

谷歌Titans模型論文解析,Transformer迎來變革拐點——DeepSeek能否“接招”?

一、引入 Titans 模型 我們將深入探討谷歌研究院的一篇新論文《Titans: Learning to Memorize at Test Time》&#xff0c;該論文介紹了一種名為 Titans 的新模型架構。 Titans 在緩解 Transformer 二次方成本問題的同時&#xff0c;展現出了令人期待的成果。Titans 模型的設…

新春賀歲,共赴AGI之旅

點擊藍字 關注我們 AI TIME歡迎每一位AI愛好者的加入&#xff01; 往期精彩文章推薦 季姮教授獨家文字版干貨 | 面向知識淵博的大語言模型 關于AI TIME AI TIME源起于2019年&#xff0c;旨在發揚科學思辨精神&#xff0c;邀請各界人士對人工智能理論、算法和場景應用的本質問題…

Baklib推動數字化內容管理解決方案助力企業數字化轉型

內容概要 在當今信息爆炸的時代&#xff0c;數字化內容管理成為企業提升效率和競爭力的關鍵。企業在面對大量數據時&#xff0c;如何高效地存儲、分類與檢索信息&#xff0c;直接關系到其經營的成敗。數字化內容管理不僅限于簡單的文檔存儲&#xff0c;更是整合了文檔、圖像、…

【memgpt】letta 課程4:基于latta框架構建MemGpt代理并與之交互

Lab 3: Building Agents with memory 基于latta框架構建MemGpt代理并與之交互理解代理狀態,例如作為系統提示符、工具和agent的內存查看和編輯代理存檔內存MemGPT 代理是有狀態的 agents的設計思路 每個步驟都要定義代理行為 Letta agents persist information over time and…

測試方案和測試計劃相同點和不同點

在軟件測試領域&#xff0c;測試方案與測試計劃皆為舉足輕重的關鍵文檔&#xff0c;盡管它們有著緊密的關聯&#xff0c;但在目的與內容層面存在著顯著的差異。相同點&#xff1a; 1.共同目標&#xff1a;測試方案和測試計劃的核心目標高度一致&#xff0c;均致力于保障軟件的…

詳細介紹:網站背景更換功能

目錄 1. HTML 部分 2. JavaScript 部分 3. 完整流程 4. 總結 5. 適用場景 本文將介紹如何通過文件上傳實現網站背景圖片的更換。通過使用 JavaScript 和 Axios&#xff0c;我們可以允許用戶上傳圖片文件并將其作為網站的背景圖片。上傳的圖片 URL 會保存在瀏覽器的 localSt…

嵌入原則:數據特征如何 融入 模型的 損失地形

嵌入原則&#xff1a;數據特征如何 融入 模型的 損失地形 第一節&#xff1a;嵌入原則的基本概念與公式解釋 機器學習中的嵌入原則&#xff0c;就像 “雕刻師” 將 “石塊的紋理” 逐漸融入到 “雕塑的造型” 中。數據特征不再是獨立的輸入&#xff0c;而是被模型 “吸收” 和…

FPGA|例化生成的PLL功能IP核

1、例化上一篇文章中調用的IP核&#xff0c;新建文件PLL_test.v 2、代碼如圖 timescale 1ns / 1ps module PLL_test(input clk,input rst_n,output clkout0,output clkout1,output clkout2,output clkout3,output clkout4);wire locked;PLL pll_inst(.inclk0(clk),.c0(clkout0)…

【C++】P5734 【深基6.例6】文字處理軟件

博客主頁&#xff1a; [小????????] 本文專欄: C 文章目錄 &#x1f4af;前言&#x1f4af;題目描述&#x1f4af;題目描述輸入格式輸出格式示例輸入與輸出輸入&#xff1a;輸出&#xff1a; &#x1f4af;我的做法操作1&#xff1a;在文檔末尾插入字符串操作2&…

后盾人JS -- 原型

沒有原型的對象 也有沒有原型的對象 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document<…

洛谷 P1130 紅牌 C語言

題目描述 某地臨時居民想獲得長期居住權就必須申請拿到紅牌。獲得紅牌的過程是相當復雜&#xff0c;一共包括 N 個步驟。每一步驟都由政府的某個工作人員負責檢查你所提交的材料是否符合條件。為了加快進程&#xff0c;每一步政府都派了 M 個工作人員來檢查材料。不幸的是&…

【線程】基于環形隊列的生產者消費者模型

1 環形隊列 環形隊列采用數組來模擬&#xff0c;用取模運算來模擬環狀特性。 1.如何判斷環形隊列為空或者為滿? 當環形隊列為空時&#xff0c;頭和尾都指向同一個位置。當環形隊列為滿時&#xff0c;頭和尾也都指向同一個位置。 因此&#xff0c; 可以通過加計數器或者標記…