最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ 數(shù)據(jù)結(jié)構(gòu)之布隆過濾器

 更新時間:2017年06月06日 14:21:17   投稿:lqh  
這篇文章主要介紹了C++ 數(shù)據(jù)結(jié)構(gòu)之布隆過濾器的相關(guān)資料,需要的朋友可以參考下

布隆過濾器

一、歷史背景知識

   布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實(shí)際上是一個很長的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優(yōu)點(diǎn)是空間效率和查詢時間都遠(yuǎn)超過一般的算法,缺點(diǎn)是有一定的誤識別率和刪除錯誤。而這個缺點(diǎn)是不可避免的。但是絕對不會出現(xiàn)識別錯誤的情況出現(xiàn)(即假反例False negatives,如果某個元素確實(shí)沒有在該集合中,那么Bloom Filter 是不會報告該元素存在集合中的,所以不會漏報)

在 FBI,一個嫌疑人的名字是否已經(jīng)在嫌疑名單上;在網(wǎng)絡(luò)爬蟲里,一個網(wǎng)址是否被訪問過等等。最直接的方法就是將集合中全部的元素存在計算機(jī)中,遇到一個新 元素時,將它和集合中的元素直接比較即可。一般來講,計算機(jī)中的集合是用哈希表(hash table)來存儲的。它的好處是快速準(zhǔn)確,缺點(diǎn)是費(fèi)存儲空間。當(dāng)集合比較小時,這個問題不顯著,但是當(dāng)集合巨大時,哈希表存儲效率低的問題就顯現(xiàn)出來 了。

比如說,一個象 Yahoo,Hotmail 和 Gmai 那樣的公眾電子郵件(email)提供商,總是需要過濾來自發(fā)送垃圾郵件的人(spamer)的垃圾郵件。一個辦法就是記錄下那些發(fā)垃圾郵件的 email 地址。由于那些發(fā)送者不停地在注冊新的地址,全世界少說也有幾十億個發(fā)垃圾郵件的地址,將他們都存起來則需要大量的網(wǎng)絡(luò)服務(wù)器。如果用哈希表,每存儲一億 個 email 地址, 就需要 1.6GB 的內(nèi)存(用哈希表實(shí)現(xiàn)的具體辦法是將每一個 email 地址對應(yīng)成一個八字節(jié)的信息指紋,然后將這些信息指紋存入哈希表,由于哈希表的存儲效率一般只有 50%,因此一個 email 地址需要占用十六個字節(jié)。一億個地址大約要 1.6GB, 即十六億字節(jié)的內(nèi)存)。因此存貯幾十億個郵件地址可能需要上百 GB 的內(nèi)存。除非是超級計算機(jī),一般服務(wù)器是無法存儲的[2]。

二、布隆過濾器原理以及優(yōu)缺點(diǎn)

如果想判斷一個元素是不是在一個集合里,一般想到的是將集合中所有元素保存起來,然后通過比較確定。鏈表、樹、散列表(哈希表,Hash table)等數(shù)據(jù)結(jié)構(gòu)都是這種思想。但是隨著集合中元素的增加,我們需要的存儲空間越來越大。同時檢索速度也會越來越慢。

Bloom Filter 是一種空間效率很高的隨機(jī)數(shù)據(jù)結(jié)構(gòu),Bloom Filter 可以看做是對bit-map的擴(kuò)展,它的原理是:

當(dāng)一個元素被加入集合中時,通過K個hash函數(shù)將這個元素映射成一個位陣列(Bit array)中的K個點(diǎn),將它們置成1. 檢索時,我們只需要看這些點(diǎn)是不是都是1就能(大約)知道集合中有沒有它:

如果這些點(diǎn)中有任何一個0,則被檢索元素一定不在;

如果都是1,則被檢索元素很可能在。

優(yōu)點(diǎn):

它的優(yōu)點(diǎn)是空間效率和查詢時間都遠(yuǎn)遠(yuǎn)超過一般的算法,布隆過濾器存儲空間和插入\查詢時間都是O(K),另外,散列函數(shù)相互之間沒有關(guān)系,方便硬件并行實(shí)現(xiàn),布隆過濾器不需要存儲元素本身,在某些對保密要求非常嚴(yán)格的場合有優(yōu)勢。

缺點(diǎn):

1、布隆過濾器的缺點(diǎn)和優(yōu)點(diǎn)同樣明顯。誤算率是其中之一。隨著存入元素的增加,誤算率隨之增加。但是元素數(shù)量太少,則使用散列就可以了。

2、一般情況下不能從布隆過濾器中刪除元素,我們很容易想到把位數(shù)組變成整數(shù)數(shù)組,每插入一個元素相應(yīng)的計數(shù)器加1,這樣刪除元素時將計數(shù)器減掉就可以了。然而要保證安全地刪除元素并非這么簡單。首先我們必須保證刪除的元素的確存在布隆過濾器里面,另外計數(shù)器回繞也會造成問題。

三、example

Google Chrome瀏覽器使用Bloom filter識別惡意鏈接(能用較小的存儲空間表示較大的數(shù)據(jù)集合,簡單想就是把 每一個URL都可以映射成bit)的多,并且誤判率在萬分之一以下。

C++實(shí)現(xiàn)

bit_set.h

#pragma once 
#include<iostream> 
using namespace std; 
#include<vector> 
 
class Bitset 
{ 
public: 
  Bitset(size_t value) 
  { 
    _a.resize((value >> 5) + 1, 0); 
  } 
  bool set(size_t num) 
  { 
    size_t index = num>>5; 
    size_t pos = num % 32; 
    if (_a[index] & (1 << (31 - pos))) 
    { 
      return false; 
    } 
    else 
    { 
      _a[index] |= (1 << (31 - pos)); 
      _size++; 
      return true; 
    } 
     
  } 
  bool Reset(size_t num) 
  { 
    size_t index = num >> 5; 
    size_t pos = num % 32; 
    if (Text(num)) 
    { 
      _a[index] &= ~(1 << (31 - pos)); 
      _size--; 
      return true; 
    } 
    else 
    { 
      return false; 
    } 
  } 
  bool Text(size_t num) 
  { 
    size_t index = num >> 5; 
    size_t pos = num % 32; 
    return _a[index] & (1 << (31-pos)); 
  } 
private: 
  vector<int> _a; 
  size_t _size; 
}; 

Hash.h

#pragma once 
template<class T> //各類哈希字符串轉(zhuǎn)換函數(shù)  
size_t BKDRHash(const char *str) 
{ 
  register size_t hash = 0; 
  while (size_t ch = (size_t)*str++) 
  { 
    hash = hash * 131 + ch; 
  } 
  return hash; 
} 
 
template<class T> 
size_t SDBMHash(const char *str) 
{ 
  register size_t hash = 0; 
  while (size_t ch = (size_t)*str++) 
  { 
    hash = 65599 * hash + ch; 
  } 
  return hash; 
} 
 
template<class T> 
size_t RSHash(const char * str) 
{ 
  size_t hash = 0; 
  size_t magic = 63689; 
  while (size_t ch = (size_t)*str++) 
  { 
    hash = hash * magic + ch; 
    magic *= 378551; 
  } 
  return hash; 
} 
 
 
template<class T> 
size_t APHash(const char *str) 
{ 
  register size_t hash = 0; 
  size_t ch; 
  for (long i = 0; ch = (size_t)*str++; i++) 
  { 
    if ((i & 1) == 0) 
    { 
      hash ^= ((hash << 7) ^ ch ^ (hash >> 3)); 
    } 
    else 
    { 
      hash ^= (~((hash << 11) ^ ch ^ (hash >> 5))); 
    } 
  } 
  return hash; 
} 
 
 
template<class T> 
size_t JSHash(const char* str) 
{ 
  if (!*str) 
  { 
    return 0; 
  } 
  size_t hash = 1315423911; 
  while (size_t ch = (size_t)*str++) 
  { 
    hash ^= ((hash << 5) + ch + (hash >> 2)); 
  } 
  return hash; 
} 

Bloom_Filter.h

#pragma once 
 
#include"bite_set.h" 
#include"Hash.h" 
#include<string> 
 
template<class T> 
struct __HashFunk1 
{ 
  size_t operator()(const T& key) 
  { 
    return BKDRHash<T>(key.c_str()); 
  } 
}; 
 
template<class T> 
struct __HashFunk2 
{ 
  size_t operator()(const T& key) 
  { 
    return SDBMHash<T>(key.c_str()); 
  } 
};  
 
template<class T> 
struct __HashFunk3 
{ 
  size_t operator()(const T& key) 
  { 
    return RSHash<T>(key.c_str()); 
  } 
}; 
 
template<class T> 
struct __HashFunk4 
{ 
  size_t operator()(const T& key) 
  { 
    return APHash<T>(key.c_str()); 
  } 
}; 
 
template<class T> 
struct __HashFunk5 
{ 
  size_t operator()(const T& key) 
  { 
    return JSHash<T>(key.c_str()); 
  } 
}; 
 
 
template<class K = string, 
class HashFunk1 = __HashFunk1<K>, 
class HashFunk2 = __HashFunk2<K>, 
class HashFunk3 = __HashFunk3<K>, 
class HashFunk4 = __HashFunk4<K>, 
class HashFunk5 = __HashFunk5<K>> 
 
class BoolFilter 
{ 
public: 
  BoolFilter(size_t n) 
    :_a(n * 10) 
    , _range(n * 10) 
  {} 
 
  void set(const K& key) 
  { 
    _a.set(HashFunk1()(key) % _range); 
    _a.set(HashFunk2()(key) % _range); 
    _a.set(HashFunk3()(key) % _range); 
    _a.set(HashFunk4()(key) % _range); 
    _a.set(HashFunk5()(key) % _range); 
  } 
 
  bool Text(const K& key) 
  { 
    if (!_a.Text(HashFunk1()(key)% _range)) 
      return false; 
    if (!_a.Text(HashFunk2()(key) % _range)) 
      return false; 
    if (!_a.Text(HashFunk3()(key) % _range)) 
      return false; 
    if (!_a.Text(HashFunk4()(key) % _range)) 
      return false; 
    if (!_a.Text(HashFunk5()(key) % _range)) 
      return false; 
    return true; 
  } 
private: 
  Bitset _a; 
  size_t _range; 
}; 


相關(guān)文章

  • C語言編程中對目錄進(jìn)行基本的打開關(guān)閉和讀取操作詳解

    C語言編程中對目錄進(jìn)行基本的打開關(guān)閉和讀取操作詳解

    這篇文章主要介紹了C語言編程中對目錄進(jìn)行基本的打開關(guān)閉和讀取操作,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • C++四種cast使用詳細(xì)介紹

    C++四種cast使用詳細(xì)介紹

    本文主要介紹了C++四種cast使用詳細(xì)介紹,今天我們要來講的是顯式類型轉(zhuǎn)換,C++提供了四種顯式類型轉(zhuǎn)換,分別是:static_cast、dynamic_cast、const_cast、reinterpret_cast,感興趣的可以了解一下
    2022-07-07
  • STL  priority_queue(優(yōu)先隊列)詳解

    STL priority_queue(優(yōu)先隊列)詳解

    這篇文章主要介紹了 STL priority_queue(優(yōu)先隊列)詳解的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • 一文帶你了解C++中queue的使用

    一文帶你了解C++中queue的使用

    C++中的queue是一種容器,用于在FIFO(先進(jìn)先出)原則下存儲和管理元素。本篇文章將深入探討C++中的queue,包括它的定義、使用、原理和示例,感興趣的可以了解一下
    2023-04-04
  • 淺談C++中的構(gòu)造函數(shù)分類及調(diào)用規(guī)則

    淺談C++中的構(gòu)造函數(shù)分類及調(diào)用規(guī)則

    這篇文章主要介紹了C++中的構(gòu)造函數(shù)分類及調(diào)用規(guī)則,文中根據(jù)參數(shù)寫出了幾種不同類型的構(gòu)造函數(shù)并解釋了如何調(diào)用,需要的朋友可以參考下
    2016-03-03
  • 如何使用C++結(jié)合OpenCV進(jìn)行圖像處理與分類

    如何使用C++結(jié)合OpenCV進(jìn)行圖像處理與分類

    在計算機(jī)視覺領(lǐng)域,OpenCV與C++結(jié)合能高效處理和分類圖像,C++的高執(zhí)行效率適合大規(guī)模數(shù)據(jù)處理,OpenCV提供豐富的功能,如圖像預(yù)處理和機(jī)器學(xué)習(xí)算法,安裝OpenCV需要配置環(huán)境和添加庫文件,本文詳細(xì)介紹了使用C++和OpenCV進(jìn)行圖像分類的過程,包括使用SVM和深度學(xué)習(xí)模型
    2024-09-09
  • Linux下實(shí)現(xiàn)C++操作Mysql數(shù)據(jù)庫

    Linux下實(shí)現(xiàn)C++操作Mysql數(shù)據(jù)庫

    由于工作需要抽出一周的時間來研究C/C++訪問各種數(shù)據(jù)庫的方法,并打算封裝一套數(shù)據(jù)庫操作類,現(xiàn)在奉上最簡單的一部分:在Linux下訪問MySQL數(shù)據(jù)庫。
    2017-05-05
  • C++學(xué)習(xí)之多態(tài)的使用詳解

    C++學(xué)習(xí)之多態(tài)的使用詳解

    這篇文章主要為大家詳細(xì)介紹了C++中多態(tài)的機(jī)制以及使用,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C++有一定的幫助,感興趣的可以了解一下
    2022-06-06
  • C++求最大公約數(shù)四種方法解析

    C++求最大公約數(shù)四種方法解析

    這篇文章主要為大家詳細(xì)介紹了C++求最大公約數(shù)四種方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C語言數(shù)據(jù)結(jié)構(gòu)順序表中的增刪改(頭插頭刪)教程示例詳解

    C語言數(shù)據(jù)結(jié)構(gòu)順序表中的增刪改(頭插頭刪)教程示例詳解

    這篇文章主要為大家介紹了C語言數(shù)據(jù)結(jié)構(gòu)順序表中增刪改關(guān)于頭插頭刪的教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02

最新評論

富宁县| 沂南县| 贵港市| 阳信县| 鸡泽县| 法库县| 长白| 峨边| 正定县| 北碚区| 鹤山市| 平湖市| 马山县| 托克托县| 乌拉特后旗| 伊宁县| 花莲县| 资阳市| 广丰县| 定日县| 闵行区| 渝北区| 津南区| 绩溪县| 凉山| 南汇区| 竹山县| 郁南县| 平定县| 平湖市| 响水县| 灵宝市| 龙山县| 富民县| 太保市| 舒兰市| 滨州市| 德兴市| 凤台县| 宝清县| 张家口市|