數據結構:位圖、布隆過濾器以及海量數據面試題

位圖、布隆過濾器以及海量數據面試題

    • 1.位圖
      • 1.1概念
      • 1.2實現
      • 1.3位圖應用
    • 2.布隆過濾器
      • 2.1布隆過濾器的提出
      • 2.2布隆過濾器的概念
      • 2.3布隆過濾器的查找
      • 2.4布隆過濾器的實現
      • 2.5布隆過濾器的刪除
      • 2.6布隆過濾器的優點
      • 2.7布隆過濾器的缺點
    • 3.海量數據面試題
      • 3.1哈希切分
      • 3.2位圖應用
      • 3.3布隆過濾器

1.位圖

1.1概念

  1. 引入
    給40億個不重復的無符號整數,沒排過序。給一個無符號整數,如何快速判斷一個數是否在這40億個數中。
    (1)遍歷: 時間復雜度O(N)
    (2)排序加二分:時間復雜度O(N*logN)
    其中 方法(2)是行不通的,因為內存很難裝下這么多數據(40億整數大概為16G)。
    方法(1)可行,但如果需要多次查詢很耗時。

    (3)位圖:數據是否在給定的整形數據中,結果是在或者不在,剛好是
    兩種狀態
    ,那么可以使用一個二進制比特位來代表數據是否存在的信息,如果二進制比特位為1,代表存在,為0代表不存在。比如:
    在這里插入圖片描述
    方法(3)的優勢的建立起這個位圖后,查找任一數據在不在時間復雜度均為O(1),而且只需要 16G / 32 = 0.5G(存儲整形需要16G,現在一個比特位就可代表,一個整形有32個比特位),空間占用很小。
  2. 概念
    所謂位圖,就是用比特位來存放某種狀態(哈希思想的體現),適用于海量數據,數據無重復的場景。通常是用來判斷某個數據存不存在的。

1.2實現

namespace mystd
{//叫bitset只是單純和庫里面統一而已,接口命名也是//庫里面bitset使用基本也是這幾個接口template<size_t N>  //N表示要表示整數的范圍,即比特位個數class bitset  {public:bitset() {//初始化這里,可能存在浪費,但幾個比特位而已_bits.resize(N / 32 + 1, 0);}void set(size_t x)  //設置標記,表示x存在{//給你x,計算出x屬于第幾個整數,整數中的第幾個比特位int i = x / 32;  //第幾個int j = x % 32;  //第幾個比特位//把對應的_bits[i]的第[j]位修改為1即可,方法是將1左移j位,或運算即可_bits[i] |= (1 << j);}void reset(size_t x)  //去標記,表示x不存在{int i = x / 32;int j = x % 32;//把對應的_bits[i]的第[j]位修改為0即可,方法(1)是將1左移j位 (2)取反(j位置為0,其它位置為1) (3)進行與運算_bits[i] &= ~(1 << j);}bool test(size_t x)  //看x在不在{int i = x / 32;int j = x % 32;//取到_bits[i]的第j位即可return _bits[i] & (1 << j);  //非0即真,0即假}private:vector<int> _bits;};
}

1.3位圖應用

  1. 快速查找某個數據是否在一個集合中
  2. 排序 + 去重
  3. 求兩個集合的交集、并集等

代碼:

#include<iostream>
#include<bitset>
using namespace std;
//位圖的應用
//快速查找某個數據是否在一個集合中
void test1()
{vector<int> a = { 0, 1, 2, 3, 4, 8, 99, 100, 150 };bitset<151> bit_set;for (auto e : a){bit_set.set(e);}int x = 0;while (cin >> x){if (bit_set.test(x)){cout << x << "存在" << endl;}else{cout << x << "不存在" << endl;}}
}//排序 + 去重
void test2()
{int a[] = {0, 1, 2, 3, 4, 8, 99, 99, 100, 100, 150};bitset<151> bit_set;vector<int> result;for (auto e : a){bit_set.set(e);}//實際中應該在建立位圖的過程中找出最大最小值,這里就不寫了//min = 0, max = 150;for (int i = 0; i <= 150; i++)   {if (bit_set.test(i)){result.push_back(i);}}for (auto e : result)  cout << e << " ";cout << endl;
}//求兩個集合的交集、并集等
void test3()
{int a1[] = { 0, 1, 2, 3 };int a2[] = { 0, 2, 2, 4, 5, 6 };//交集bitset<7> bit_set1;bitset<7> bit_set2;for (auto e : a1)  bit_set1.set(e);cout << "交集為:";for (auto e : a2){if (bit_set1.test(e) && bit_set2.test(e) == false){bit_set2.set(e);  //過濾掉多次出現的數據cout << e << " ";}}cout << endl;//并集cout << "并集為:";bitset<7> bit_set3;  //去掉a1中重復的部分for (auto e : a1){if (bit_set3.test(e) == false){cout << e << " ";bit_set3.set(e);}}for (auto e : a2){if (bit_set3.test(e) == false)  //把a2特有的提取出來{cout << e << " ";}}cout << endl;
}



2.布隆過濾器

2.1布隆過濾器的提出

想要判斷某個數據在不在:

  1. 哈希表,空間消耗大。
  2. 位圖,空間消耗小,只適用于整形。
  3. 哈希位圖相結合,即布隆過濾器。可適用各種復雜數據,只要能通過哈希函數轉化出關鍵值即可。

2.2布隆過濾器的概念

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

圖解:
在這里插入圖片描述


2.3布隆過濾器的查找

結合前面可知,布隆過濾器的查找需要對多個位置進行判斷,都為1才認為存在,有一個為0認為不存在。

  1. 布隆過濾器判斷存在,判斷不準確

    在這里插入圖片描述
  2. 布隆過濾器判斷不在,結果準確

布隆過濾器存在誤判,為什么還要使用?

以用戶注冊為例,用戶名等信息存儲在服務器數據庫,每次注冊新用戶都要遍歷所有數據,消耗太大。這個時候可以考慮使用布隆過濾器,對于判斷不在的情況,是準確的,可以允許注冊;對于判斷在的情況就需要去遍歷數據。實際當中可以過濾掉大量的請求,提高效率


2.4布隆過濾器的實現

//三個字符串哈希函數
struct BKDRHash
{size_t operator()(const string& key){// BKDRsize_t hash = 0;for (auto e : key){hash *= 31;hash += e;}return hash;}
};struct APHash
{size_t operator()(const string& key){size_t hash = 0;for (size_t i = 0; i < key.size(); i++){char ch = key[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};struct DJBHash
{size_t operator()(const string& key){size_t hash = 5381;for (auto ch : key){hash += (hash << 5) + ch;}return hash;}
};//布隆過濾器一般都是解決字符串
//關于布隆過濾器的長度,len = N * x,一般x取三以上,至于具體大小依據場景進行衡量
//(1)x過大,空間浪費
//(2)x過小,誤判較多(不在判斷為在),過濾效果不好
template<size_t N, size_t x = 5, class K = string, class HashFun1 = BKDRHash, class HashFun2 = APHash, class HashFun3 = DJBHash>
class BloomFilter
{void set(const K& key){//一次標記3個位置,要讓數值落在范圍內部size_t len = N * x;size_t hash1 = HashFun1()(key) % len;size_t hash2 = HashFun2()(key) % len;size_t hash3 = HashFun3()(key) % len;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);}bool test(const K& key){//看三個位置,有一個為0就返回falsesize_t len = N * x;size_t hash1 = HashFun1()(key) % len;if (_bs.test(hash1) == false)  return false;size_t hash2 = HashFun2()(key) % len;if (_bs.test(hash2) == false)  return false;size_t hash3 = HashFun3()(key) % len;if (_bs.test(hash3) == false)  return false;return true;}
private:bitset<N * x> _bs;
};

2.5布隆過濾器的刪除

布隆過濾器一般不能直接支持刪除工作,因為在刪除一個元素時,可能會影響其他元素。
在這里插入圖片描述
比如:刪除上圖中"騰訊"元素,如果直接將該元素所對應的二進制比特位置0,“百度”元素也被刪除了,因為這兩個元素在多個哈希函數計算出的比特位上剛好有重疊。


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


2.6布隆過濾器的優點

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

2.7布隆過濾器的缺點

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



3.海量數據面試題

3.1哈希切分


給一個超過100G大小的log file, log中存著IP地址, 設計算法找到出現次數最多的IP地址?

  1. 100G過大,無法直接在內存中處理,可以先切割成100個小文件。先將IP轉化為整形key,然后key %= 100,相同IP會分到一樣的小文件。
  2. 依此讀取這100個文件,找每個文件中出現次數最多,然后找出最大的那個。
  3. 利用哈希切分可能存在沖突,如果某個小文件極大,可以更換哈希函數,對這個小文件再進行切分。

3.2位圖應用

  1. 給定100億個整數,設計算法找到只出現一次的整數?
    解法一:整形范圍為40多億,位圖需要的空間為0.5G,存在出現多次的情況,即三種狀態,故一個比特位不夠,可以增加一位,即用兩個位圖實現。當結果為00時代表沒有出現、為01時代表出現了一次、為11時代表出現了多次
    解法二:哈希切分,相同的數字一定會分到同個文件,對每個文件做統計即可。
  2. 給兩個文件,分別有100億個整數,我們只有1G內存,如何找到兩個文件交集?
    (1)先哈希切分,key %= 500,文件一分出A0、A1、A2……A499,文件二分出B0、B1、B2……B499。其中相同的部分(交集)會被分到相同標號的文件,只需要A0對B0、A1對B1……A499對B499的兩兩找交集就行。
    (2)小文件過大的情況,更換哈希,再次切分即可。
  3. 位圖應用變形:1個文件有100億個int,1G內存,設計算法找到出現次數不超過2次的所有整數
    (1)分析狀態:一、出現0次。二、出現1次。三、出現2次。四、出現2次以上。
    (2)有四種狀態,用兩個比特位即可表示,即使用兩個位圖。當結果為00、01、10時都屬于沒超過2次,當結果為11時代表結果超過了兩次

3.3布隆過濾器

  1. 給兩個文件,分別有100億個query,我們只有1G內存,如何找到兩個文件交集?分別給出精確算法和近似算法
    (1)近似算法,先讀取文件一,建立布隆過濾器。然后讀取文件二,依次判斷是否在布隆過濾器中,近似算法存在誤判。
    (2)精確算法,對兩個大文件進行哈希切分,兩兩小文件找交集即可。
  2. 如何擴展BloomFilter使得它支持刪除元素的操作
    (1)數據量不大,可以用幾個位圖實現。
    (2)數據量大,一個哈希值對應的就不是一比特位了,而是一個整形。

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

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

相關文章

如何成為前1%的程序員

如果你想成為前1%的程序員&#xff0c;你必須遵循1%的程序員做什么&#xff0c;了解其他99%的人不做什么。在現代&#xff0c;我們有各種學習平臺&#xff0c;里面充滿了與編程相關的視頻、圖文以及其他資料。 舉例來說&#xff0c;我作為編程的初學者&#xff0c;去尋找路線圖…

IDEA2023找不到add framework support怎么解決

問題: 我的idea版本是2023.01&#xff0c;新版idea右鍵項目沒有Add Framework Support&#xff0c;help里面也找不到相關的。 從project structue的facets里面添加就行了&#xff0c;都是一樣的。 1.依舊是新建一個項目 2.file-->project structure--->facets 左上角加…

數據結構與程序的關系

在計算機科學中,數據結構和算法是兩個核心的概念。數據結構是程序的基礎,它組織和存儲數據的方式直接影響程序的設計、效率、可讀性以及程序的錯誤檢測和調試。本文將詳細討論數據結構如何影響程序,以及數據結構與算法的組合如何使程序更高效、可靠。 一、數據結構的選擇影…

Android studio如何安裝ai輔助工具

引言 在沒有翻墻的情況下&#xff0c;即單純在公司打工&#xff0c;經測試&#xff0c;大部分ai工具都是使用不了的&#xff08;比如各種gpt,codeium,copilot&#xff09;&#xff0c;根本登錄不了賬號&#xff0c;但有一個國內的codegeex是可以使用的&#xff0c;在這里不對各…

tensorflow中張量tensor

在 TensorFlow 中&#xff0c;主要操作的對象是張量&#xff08;tf.Tensor&#xff09;。張量表示一個多維數組&#xff0c;可以執行各種操作以構建和修改計算圖。以下是一些常見的 TensorFlow 張量操作&#xff1a; 1. 創建張量&#xff1a; 使用 tf.constant 創建常量張量。…

Android app性能優化指南

Android應用性能優化指南 提高應用程序的性能以實現更流暢的用戶體驗和更高的可見度。 性能在任何應用程序的成功中發揮著重要的作用。為用戶提供流暢無縫的體驗應該是開發人員的重點。 應用程序大小 在用戶開始使用我們的應用程序之前&#xff0c;他們需要下載應用程序并將…

DTCC2023大會-DBdoctor-基于eBPF觀測數據庫-附所有PPT下載鏈接

DTCC2023大會-DBdoctor-基于eBPF觀測數據庫-附所有PPT下載鏈接 8月16日—18日,第14屆中國數據庫技術大會(DTCC-2023)在北京國際會議中心舉行。聚好看在大會上首次發布基于eBPF觀測數據庫性能的產品DBdoctor&#xff0c;受到了業界廣泛的關注。近期幾位業內同仁過來要大會的PPT…

2024考研數學二備考歷程

GoodNotesGoodNotes apphttps://share.goodnotes.com/s/bhsraJMZ6OJwuYJb3OWnzP

Python點云處理(二十)點云輪廓邊界提取——基于鄰域三角形距離算法

目錄 0 簡述1 點云輪廓提取原理2 點云輪廓提取應用3 算法步驟4 代碼實現5 結果展示0 簡述 點云輪廓提取/邊界提取,對于掃描物信息化提取、矢量化等都具有很重要的意義。掃描物體輪廓不僅包含位置和形狀信息,而且可作為一種先驗形狀信息推斷其結構以輔助三維模型重建,因此輪…

C/C++之輸入輸出

文章目錄 一.C語言的輸入輸出1.printfi. 輸出整數ii. 浮點數iii.字符 & 字符串 2.scanfi.整數ii.浮點數iii. 字符 & 字符串 3.特殊用法i. * 的應用ii. %n 的應用iii. %[] 的應用 二.C中的輸入輸出1.couti. 緩沖區&#xff08;buffer&#xff09;ii. cout之格式化輸出 2…

Proteus仿真--串口發送數據到2片8×8點陣屏滾動顯示

本文介紹2片88點陣屏滾動顯示設計&#xff08;完整仿真源文件及代碼見文末鏈接&#xff09; 仿真圖如下 仿真運行視頻 Proteus仿真--1602LCD顯示電話撥號鍵盤按鍵實驗&#xff08;仿真文件程序&#xff09; 附完整Proteus仿真資料代碼資料 鏈接&#xff1a;https://pan.baidu…

【python】函數的參數(實參,形參,*args和**kwargs)

一、實參和形參 實參&#xff1a; 函數執行的時候給函數傳遞的具體的值 形參&#xff1a; 在函數聲明時編寫的變量 函數執行時每個形參都要有值 # a,b為形參 def add(a, b):print(a b) # 3,4為實參 add(3, 4)二、實參 1.位置參數 按位置給形參傳遞數據 def add(a, b)…

使用C語言操作kafka ---- librdkafka

1 安裝librdkafka git clone https://github.com/edenhill/librdkafka.git cd librdkafka git checkout v1.7.0 ./configure make sudo make install sudo ldconfig 在librdkafka的examples目錄下會有示例程序。比如consumer的啟動需要下列參數 ./consumer <broker> &…

一對一聊天程序

package untitled1.src;import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.*;public class MyServer extends JFrame{private ServerSocket server; // 服務器套接字pri…

【漏洞復現】華脈智聯指揮調度平臺/xml_edit/fileread.php文件讀取漏洞

Nx01 產品簡介 深圳市華脈智聯科技有限公司&#xff0c;融合通信系統將公網集群系統、專網寬帶集群系統、不同制式、不同頻段的短波/超短波對講、模擬/數字集群系統、辦公電話系統、廣播系統、集群單兵視頻、視頻監控系統、視頻會議系統等融為一體&#xff0c;集成了專業的有線…

第一課【習題】HarmonyOS應用/元服務上架

元服務發布的國家與地區僅限于“中國大陸” 編譯打包的軟件包存放在項目目錄build > outputs > default下 創建應用時&#xff0c;應用包名需要和app.json5或者config.json文件中哪個字段保持一致&#xff1f; 發布應用時需要創建證書&#xff0c;證書類型選擇什么…

web前端實現LED功能、液晶顯示時間、數字

MENU 效果演示html部分JavaScript部分css部分 效果演示 html部分 <div id"app"><!-- 頁面 --><div class"time-box"><!-- 時 --><div class"house-box"><bit-component :num"houseTem"></bit…

編譯器緩存

2023年12月6日&#xff0c;周三晚上 使用編譯器緩存有什么用 編譯器緩存是一種用于加速編譯過程的工具&#xff0c;它可以緩存已編譯的對象文件和依賴關系&#xff0c;以便在后續構建中重復使用。使用編譯器緩存可以帶來以下幾個好處&#xff1a; 加快編譯速度&#xff1a;編譯…

TS型變與對象類型進階

子類型&#xff1a;給定兩個類型A和B&#xff0c;假設B是A的子類型&#xff0c;那么在需要A的地方都可以放心使用B。計作 A <: B &#xff08;A是B的子類型&#xff09;。 超類型正好與子類型相反。A >: B &#xff08;A是B的超類型&#xff09;。 1 TS 類型 可賦值性…

使用cmake構建Qt6.6的qt quick項目,添加應用程序圖標的方法

最近&#xff0c;在學習qt的過程中&#xff0c;遇到了一個難題&#xff0c;不知道如何給應用程序添加圖標&#xff0c;按照網上的方法也沒有成功&#xff0c;后來終于自己摸索出了一個方法。 1、準備一張圖片作為圖標&#xff0c;保存到工程目錄下面&#xff0c;如logo.ico。 …