【C++】哈希的應用:位圖和布隆過濾器

目錄

一、位圖

1.1 位圖的概念

1.2 位圖的實現

1.3 位圖的應用

二、布隆過濾器

2.1 布隆過濾器的提出

2.2 布隆過濾器的概念

2.3 布隆過濾器的插入和查找

2.4?布隆過濾器的刪除

2.5?布隆過濾器的優點

2.6?布隆過濾器的缺點


一、位圖

1.1 位圖的概念

1. 面試題

給40億個不重復的無符號整數,沒排過序。給一個無符號整數,如何快速判斷一個數是否在這40億個數中。【騰訊】

  1. 遍歷,時間復雜度(O(N))
  2. 排序(O(N*logN)),利用二分查找(O(logN))
  3. 位圖解決:數據是否在給定的整形數據中,結果是在或者不在,剛好是兩種狀態,那么可以使用一個二進制比特位來代表數據是否存在的信息,如果二進制比特位為1,代表存在,為0代表不存在。比如:

2. 位圖概念

所謂位圖,就是用每一位來存儲某種狀態,適用于海量數據,數據無重復的場景。通常是用來判斷某個數據存不存在。

1.2 位圖的實現

template<size_t N>
class Bitset
{
public:Bitset(){_bs.resize(N / 32 + 1);}void set(size_t x) // 將該位置置為1{size_t i = x / 32;size_t j = x % 32;_bs[i] |= (1 << j);}void reset(size_t x) // 將該位置置為0{size_t i = x / 32;size_t j = x % 32;_bs[i] &= (~(1 << j));}bool test(size_t x) // 判斷該數是否存在{size_t i = x / 32;size_t j = x % 32;return _bs[i] & (1 << j);}
private:vector<int> _bs;
};

測試代碼:

void test_bitset1()
{int a1[] = { 5,7,9,2,5,99,5,5,7,5,3,9,2,55,1,5,6 };int a2[] = { 5,3,5,99,6,99,33,66 };Bitset<100> bs1;Bitset<100> bs2;for (auto e : a1){bs1.set(e);}for (auto e : a2){bs2.set(e);}for (size_t i = 0; i < 100; i++){if (bs1.test(i) && bs2.test(i)){cout << i << endl;}}
}

1.3 位圖的應用

  1. 快速查找某個數據是否在一個集合中
  2. 排序 + 去重
  3. 求兩個集合的交集,并集等
  4. 操作系統中磁盤塊標記

位圖應用變形:1個文件有100億個int,1G內存,設計算法找到出現次數不超過2次的所有整數

	template<size_t N>class TwoBiteset{public:void set(size_t x){bool b1 = _bs1.test(x);bool b2 = _bs2.test(x);if (!b1 && !b2) // 第一次出現 00 -> 01_bs2.set(x);else if (b1 && !b2) // 第二次出現 01 -> 10{_bs2.reset(x);_bs1.set(x);}else if (!b1 && b2) // 第三次即以上 10 -> 11{_bs2.set(x);}}size_t count(size_t x){bool b1 = _bs1.test(x);bool b2 = _bs2.test(x);if (!b1 && !b2) // 出現次數0return 0;else if (!b1 && b2) // 出現次數1return 1;else if (b1 && !b2) // 出現次數2return 2;else // 出現次數大于2return 3;}private:Bitset<N> _bs1;Bitset<N> _bs2;};

測試代碼:

void test_twobitset()
{TwoBiteset<100> tbs;int a[] = { 5,7,9,2,5,99,5,5,7,5,3,9,2,55,1,5,6,6,6,6,7,9 };for (auto e : a){tbs.set(e);}for (size_t i = 0; i < 100; ++i){//cout << i << "->" << tbs.get_count(i) << endl;if (tbs.count(i) == 1 || tbs.count(i) == 2){cout << i << endl;}}
}

二、布隆過濾器

2.1 布隆過濾器的提出

我們在使用新聞客戶端看新聞時,它會給我們不停地推薦新的內容,它每次推薦時要去重,去掉那些已經看過的內容。問題來了,新聞客戶端推薦系統如何實現推送去重的? 用服務器記錄了用戶看過的所有歷史記錄,當推薦系統推薦新聞時會從每個用戶的歷史記錄里進行篩選,過濾掉那些已經存在的記錄。 如何快速查找呢?

  1. 用哈希表存儲用戶記錄,缺點:浪費空間。
  2. 用位圖存儲用戶記錄,缺點:位圖一般只能處理整形,如果內容編號是字符串,就無法處理了。
  3. 將哈希與位圖結合,即布隆過濾器。

2.2 布隆過濾器的概念

布隆過濾器是由布隆(Burton Howard Bloom)在1970年提出的 一種緊湊型的、比較巧妙的概率型數據結構,特點是高效地插入和查詢,可以用來告訴你 “某樣東西一定不存在或者可能存在”,它是用多個哈希函數,將一個數據映射到位圖結構中。此種方式不僅可以提升查詢效率,也可以節省大量的內存空間

2.3 布隆過濾器的插入和查找

1. 插入

向布隆過濾器中插入:world

向布隆過濾器中插入:hello

2. 查找

布隆過濾器的思想是將一個元素用多個哈希函數映射到一個位圖中,因此被映射到的位置的比特位一定為1。所以可以按照以下方式進行查找:分別計算每個哈希值對應的比特位置存儲的是否為零,只要有一個為零,代表該元素一定不在哈希表中,否則可能在哈希表中。
注意:布隆過濾器如果說某個元素不存在時,該元素一定不存在,如果該元素存在時,該元素可能存在,因為有些哈希函數存在一定的誤判。

#include <string>
#include "Bitset.h"struct HashFuncBKDR
{// 本算法由于在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;}
};template<size_t N, size_t X = 5, class K = string, // X跟誤判率有關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;_bf.set(hash1);_bf.set(hash2);_bf.set(hash3);}bool test(const K& key){size_t hash1 = Hash1()(key) % M;size_t hash2 = Hash2()(key) % M;size_t hash3 = Hash3()(key) % M;if (_bf.test(hash1) == false)return false;else if (_bf.test(hash2) == false)return false;else if (_bf.test(hash3) == false)return false;elsereturn true; // 可能存在誤判}// 獲取公式計算出的誤判率double getFalseProbability(){double p = pow((1.0 - pow(2.71, -3.0 / X)), 3.0);return p;}
private:static const size_t M = N * X;my::Bitset<M> _bf;
};

測試代碼:

void TestBloomFilter1()
{Bloomfilter<10> bf;bf.set("豬八戒");bf.set("孫悟空");bf.set("唐僧");cout << bf.test("豬八戒") << endl;cout << bf.test("孫悟空") << endl;cout << bf.test("唐僧") << endl;cout << bf.test("沙僧") << endl;cout << bf.test("豬八戒1") << endl;cout << bf.test("豬戒八") << endl;
}

2.4?布隆過濾器的刪除

布隆過濾器不能直接支持刪除工作,因為在刪除一個元素時,可能會影響其他元素。

比如:刪除上圖中"hello"元素,如果直接將該元素所對應的二進制比特位置0,“world”元素也被刪除了,因為這兩個元素在多個哈希函數計算出的比特位上剛好有重疊.

一種支持刪除的方法:將布隆過濾器中的每個比特位擴展成一個小的計數器,插入元素時給k個計數器(k個哈希函數計算出的哈希地址)加一,刪除元素時,給k個計數器減一,通過多占用幾倍存儲空間的代價來增加刪除操作。

缺陷:

  1. 無法確定元素是否真正在布隆過濾器中
  2. 存在計數回繞

2.5?布隆過濾器的優點

  1. 增加和查詢元素的時間復雜度為:O(K), (K為哈希函數的個數,一般比較小),與數據量大小無關
  2. 哈希函數相互之間沒有關系,方便硬件并行運算
  3. 布隆過濾器不需要存儲元素本身,在某些對保密要求比較嚴格的場合有很大優勢
  4. 在能夠承受一定的誤判時,布隆過濾器比其他數據結構有這很大的空間優勢
  5. 數據量很大時,布隆過濾器可以表示全集,其他數據結構不能
  6. 使用同一組散列函數的布隆過濾器可以進行交、并、差運算

2.6?布隆過濾器的缺點

  1. 有誤判率,即存在假陽性(False Position),即不能準確判斷元素是否在集合中(補救方法:再建立一個白名單,存儲可能會誤判的數據)
  2. 不能獲取元素本身
  3. 一般情況下不能從布隆過濾器中刪除元素
  4. 如果采用計數方式刪除,可能會存在計數回繞問題

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

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

相關文章

C語言:指針(4)

1. 回調函數回調函數就是指通過函數指針調用的函數。如果將函數指針作為參數傳遞給另一個函數&#xff0c;另一個函數根據指針來調這個函數&#xff0c;那么被調用的函數就是回調函數。回調函數不是由這個函數的實現方直接調用&#xff0c;而是在特定的條件下由另一方調用的。例…

vue--video使用動態src時,視頻不更新

問題描述 在 Vue項目中&#xff0c;嘗試動態更新 標簽的 元素 src 屬性來切換視頻時&#xff0c;遇到了一個問題&#xff1a;即使 src 已更改&#xff0c;瀏覽器仍不顯示視頻。 <template><video width"100%" height"100%" controlspause"…

計算機視覺--opencv(代碼詳細教程)(一)

在計算機視覺的廣袤領域中&#xff0c;OpenCV 是一座極為關鍵的里程碑。無論是在前沿的學術研究&#xff0c;還是在蓬勃發展的工業界&#xff0c;OpenCV 憑借其強大的功能與高效的性能&#xff0c;為開發者提供了豐富的圖像處理和計算機視覺算法&#xff0c;助力無數項目落地。…

物聯網通訊協議-MQTT、Modbus、OPC

引言在物聯網迅速發展的今天&#xff0c;設備間的通信協議扮演著至關重要的角色。它們是不同設備、系統之間實現數據交換的橋梁。本文將詳細介紹三種在物聯網領域廣泛應用的通訊協議——MQTT、Modbus和OPC&#xff0c;包括它們的基礎概念、特點及在C#中的實現方法。一、MQTT協議…

牛客周賽R104 小紅的矩陣不動點

D-小紅的矩陣不動點_牛客周賽 Round 104 賽時這道題卡了一段時間&#xff0c;賽時代碼如下&#xff1a; #include<bits/stdc.h> using namespace std; int ans,h; int a[505][505]; signed main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int n,m;cin>…

Rust面試題及詳細答案120道(19-26)-- 所有權與借用

《前后端面試題》專欄集合了前后端各個知識模塊的面試題&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

Jenkins + SonarQube 從原理到實戰三:SonarQube 打通 Windows AD(LDAP)認證與踩坑記錄

前言 在前兩篇文章中&#xff0c;已經介紹了 SonarQube 的部署 以及 通過 sonar-cxx 插件實現 C/C 代碼掃描。 本篇將重點講 如何讓 SonarQube 對接 Windows AD&#xff08;LDAP&#xff09;&#xff0c;實現域賬號登錄和基于 AD 組的權限管理。 一、背景與需求分析 需求分析…

[AI React Web] 包與依賴管理 | `axios`庫 | `framer-motion`庫

第七章&#xff1a;包與依賴管理 在我們使用open-lovable的旅程中&#xff0c;已經探索了它如何管理對話狀態&#xff08;第一章&#xff1a;對話狀態管理&#xff09;、將創意轉化為可運行代碼&#xff08;第二章&#xff1a;AI代碼生成管道&#xff09;、如何在安全的虛擬環…

PanSou 一款開源網盤搜索項目,集成前后端,一鍵部署,開箱即用

PanSou 網盤搜索API PanSou是一個高性能的網盤資源搜索API服務&#xff0c;支持TG搜索和自定義插件搜索。系統設計以性能和可擴展性為核心&#xff0c;支持并發搜索、結果智能排序和網盤類型分類。 項目地址&#xff1a;https://github.com/fish2018/pansou 特性&#xff08…

java爬蟲實戰

本人目前在做魚皮的《智能協同云圖庫》&#xff0c;涉及到了以圖搜圖圖片爬取&#xff0c;雖然以前有爬過圖片&#xff0c;但是用的都是別人現成的代碼&#xff0c;不怎么去理解為什么要這樣做&#xff0c;這次有在嘗試理解每一個步驟。本人基礎極差&#xff0c;屬于一點基礎也…

深入詳解C語言的循環結構:while循環、do-while循環、for循環,結合實例,講透C語言的循環結構

&#x1f525;個人主頁&#xff1a;艾莉絲努力練劍 ?專欄傳送門&#xff1a;《C語言》、《數據結構與算法》、C語言刷題12天IO強訓、LeetCode代碼強化刷題、C/C干貨分享&學習過程記錄 &#x1f349;學習方向&#xff1a;C/C方向 ??人生格言&#xff1a;為天地立心&#…

北京-4年功能測試2年空窗-報培訓班學測開-第七十四天-線下面試-聊的很滿意但可能有風險-等信吧

今天沒去教室&#xff0c;因為下午有個線下面試。其實是可以去教室的&#xff0c;但我實在太焦慮了&#xff0c;我覺得去了教室我心情會更不好&#xff0c;什么都干不下去&#xff0c;所以我選擇不去早上依舊是帶著滿滿焦慮起來的&#xff0c;會覺得自己的一切都不令自己滿意&a…

在ubuntu服務器下安裝cuda和cudnn(筆記)

目錄 0 引言 1 相關環境查詢 2 安裝cuda 2.1 下載并安裝 2.2 安裝選項配置 2.3 驗證安裝 3 安裝cudnn 3.1 下載 3.2 解壓 3.3 刪除舊版本 cuDNN 3.4 復制新文件到 CUDA 目錄 3.5 設置文件權限 3.6 創建軟鏈接 3.7 驗證安裝 0 引言 我在使用服務器的cuda11.8的時…

docker安裝centos

docker庫地址https://hub.docker.com/ 嘗試使用centos7試了幾次超時 換了個版本就可以了 docker pull centos:centos7.9.2009有時候需要更新資源地址 可以使用 vim /etc/docker/daemon.json配置其他資源地址 {"registry-mirrors": ["http://hub-mirror.c.163…

內容索引之word轉md工具 - markitdown

切分文檔構建RAG庫過程中&#xff0c;langchain、llamaindex更期望處理latex、md類帶有顯式結構文檔。 langchain、llamaindex切分word&#xff0c;有可能將段落中間截斷&#xff0c;導致切分后的塊語義不完整。 所以&#xff0c;需要先將word轉化為md格式&#xff0c;然后再…

MaxKB+合合信息TextIn:通過API實現PDF掃描件的文檔審核

上海合合信息科技股份有限公司&#xff08;以下簡稱為合合信息&#xff09;是一家深耕人工智能、OCR&#xff08;光學字符識別&#xff09;及商業大數據技術領域的科技企業。該公司擁有領先的智能文字識別技術&#xff0c;其名片全能王&#xff08;CamCard&#xff09;、掃描全…

MyBatis 核心入門:從概念到實戰,一篇掌握簡單增刪改查

目錄 一、什么是 MyBatis&#xff1f;為什么要用它&#xff1f; 二、MyBatis 核心概念&#xff08;通俗理解&#xff09; 1.SqlSessionFactory 2.SqlSession 3.Mapper接口 4.映射文件&#xff08;XML&#xff09; 三、手把手搭建第一個 MyBatis 項目 1. 準備工作 2. 核心配置文…

數據結構初階(12)排序算法—插入排序(插入、希爾)(動圖演示)

2. 常見排序算法的實現2.0 十大排序算法2.1 插入排序 2.1.1 基本思想直接插入排序是一種簡單的插入排序法&#xff1a;基本思想把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中。直到所有的記錄插入完為止&#xff0c;得到一個新的有序序列 。 比 挪 (…

MySQL優化常用的幾個方法

本實例是對慢sql從2萬優化到5千優化方法的匯總。 首先貼上優化效果&#xff1a;1、更新數據時使用ID更新&#xff1b;2、"分頁/輪詢"查詢時先獲取符合數據要求主鍵的最大和最小ID&#xff0c;然后WHERE條件增加ID步增查詢&#xff1b;3、檢查SQL是否命中WHERE條件&am…

深入解析 AUTOSAR:汽車軟件開發的革命性架構

引言在汽車智能化、網聯化、電動化浪潮席卷全球的今天&#xff0c;汽車電子系統的復雜性與日俱增。傳統“煙囪式”的 ECU 開發模式&#xff08;各供應商獨立開發軟硬件&#xff09;帶來了巨大的兼容性、復用性和維護成本挑戰。AUTOSAR&#xff08;AUTomotive Open System ARchi…