哈希应用、海量数据处理:布隆过滤器
1.布隆过滤器概念
布隆过滤器是有布隆(Burton Howard Bloom)在1970年提出的一种紧凑型的、比较巧妙的概率型数据结构,特点是高效的插入和查询,可以用来告诉你"某个数据一定不存在或可能存在“,它是多个哈希函数,将一个数据映射到位图结构中,这种方法不仅可以提高查询效率,也可以节省大量的内存空间。
2.布隆过滤器的操作
2.1插入
插入原理:
采用n个字符串哈希函数,分别计算字符串的哈希地址并映射到位图对应比特位上置1,即完成插入,相当于利用位图上的n个比特位同时为1,来表示一个数据。
可以看出,以上方法是存在哈希冲突的可能性的,但是可能性较小,且采用的比特位数越多,概率越小。
bool Insert(const K& data) {size_t index = K2INT1()(data) % _bst.size();_bst.set(index);index = K2INT2()(data) % _bst.size();_bst.set(index);index = K2INT3()(data) % _bst.size();_bst.set(index);index = K2INT4()(data) % _bst.size();_bst.set(index);index = K2INT5()(data) % _bst.size();_bst.set(index);++_size;return true;}
2.2查找
分别计算每个哈希值,判断对应的比特位是否为1,只要有一个位置是0,则说明该元素一定不在哈希表中。
注意:
即使每个位置都为1,只能说明可能存在哈希表中,不能一定说明存在。
bool Find(const K& data) {size_t index = K2INT1()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT2()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT3()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT4()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT5()(data) % _bst.size();if (!_bst.test(index)) return false;//只能说明可能存在return true;}
2.3删除
布隆过滤器不能直接支持删除工作,因为一个元素在比特位上可能与其他元素有重叠,在删除一个元素时,可能会影响其他元素。
如何支持删除操作:
若想支持删除操作,则底层不能再使用位图,因为比特位只能表示两种状态,可能会与其他元素形成重叠。所以可以通过底层采用整形数组的形式,在插入时,给对应位置+1,删除时给对应位置-1,这样在删除一个元素时,就不会影响其他元素。
缺陷:同样无法确定元素一定在布隆过滤器中;增加了几倍的空间;存在计算回绕问题。
3.布隆过滤器的优缺点
3.1优点
(1)增加和查询元素的时间复杂度为O(K),(K为哈希函数的个数,一般较小),与数据量大小无关。
(2)哈希函数互相之间没有关系,方便硬件并行计算。
(3)布隆过滤器不需要存储元素本身,在某些对数据保密性要求比较严格的场景有较大优势。
(4)在能够承受一定的误判时,布隆过滤器比其他数据结构有很大的空间优势。
(5)数据量很大时,布隆过滤器可以表示全集,而其他数据结构不能。
(6)使用同一组散列函数的布隆过滤器可以进行交、并、差集运算。
3.2缺点
(1)有误判率,即不能准确判断元素是否在集合中。
(2)不能获取元素本身。
(3)一般情况下,不能从布隆过滤器中删除元素。
(4)如果采用计算方式删除,可能存在计算回绕问题。
4.布隆过滤器实现
4.1字符串哈希算法Common.h
#pragma once
//将类型转换为整形
#include <string>
template<class T>
class T2INT {//int-->int
public:size_t operator()(const T& data) {return data;}
};class Str2INT {//string-->int
public:size_t operator()(const std::string& str) {return SDBMHash(str.c_str());}unsigned int SDBMHash(const char* str) {unsigned int hash = 0;unsigned int seed = 131;while (*str) {hash = hash * seed + (*str++);}return (hash & 0x7FFFFFFF);}
};//增容质数表
const int PRIMECOUNT = 31;
const size_t primeList[PRIMECOUNT] =
{5,11, 23,53ul, 97ul, 193ul, 389ul, 769ul,1543ul, 3079ul, 6151ul, 12289ul, 24593ul,49157ul, 98317ul, 196613ul, 393241ul, 786433ul,1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,1610612741ul, 3221225473ul, 4294967291ul
};size_t GetNextPrime(size_t prime) {for (size_t i = 0; i < PRIMECOUNT; ++i) {if (primeList[i] > prime) {return primeList[i];}}return primeList[PRIMECOUNT - 1];
}/*五种字符串转整形的哈希算法*/class Str2INT1 {
public:size_t operator()(const std::string& str) {return SDBMHash(str.c_str());}/// @brief SDBM Hash Function /// @detail 本算法是由于在开源项目SDBM(一种简单的数据库引擎)中被应用而得名,它与BKDRHash思想一致,只是种子不同而已。 size_t SDBMHash(const char* str){register size_t hash = 0;while (size_t ch = (size_t)*str++){hash = 65599 * hash + ch;//hash = (size_t)ch + (hash << 6) + (hash << 16) - hash; }return hash;}
};class Str2INT2 {
public:size_t operator()(const std::string& str) {return RSHash(str.c_str());}/// @brief RS Hash Function /// @detail 因Robert Sedgwicks在其《Algorithms in C》一书中展示而得名。 size_t RSHash(const char* str){register size_t hash = 0;size_t magic = 63689;while (size_t ch = (size_t)*str++){hash = hash * magic + ch;magic *= 378551;}return hash;}
};class Str2INT3 {
public:size_t operator()(const std::string& str) {return APHash(str.c_str());}/// @brief AP Hash Function /// @detail 由Arash Partow发明的一种hash算法。 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;}
};class Str2INT4 {
public:size_t operator()(const std::string& str) {return JSHash(str.c_str());}/// @brief JS Hash Function /// 由Justin Sobel发明的一种hash算法。 size_t JSHash(const char* str){if (!*str) // 这是由本人添加,以保证空字符串返回哈希值0 return 0;register size_t hash = 1315423911;while (size_t ch = (size_t)*str++){hash ^= ((hash << 5) + ch + (hash >> 2));}return hash;}
};class Str2INT5 {
public:size_t operator()(const std::string& str) {return DEKHash(str.c_str());}/// @brief DEK Function /// @detail 本算法是由于Donald E. Knuth在《Art Of Computer Programming Volume 3》中展示而得名。 size_t DEKHash(const char* str){if (!*str) // 这是由本人添加,以保证空字符串返回哈希值0 return 0;register size_t hash = 1315423911;while (size_t ch = (size_t)*str++){hash = ((hash << 5) ^ (hash >> 27)) ^ ch;}return hash;}
};
4.2位图实现BitSet.hpp
#pragma once
#include <vector>
#include <assert.h>
namespace MyBitSet {template<size_t N>class bitset {public:/*N是比特位数,右移3位,即除以8,转化为字节为单位+1防止传入的位数小于8,右移后为0*/bitset(): _bst((N >> 3) + 1), _count(0){}void set(size_t which) {//比特位置1assert(which < N);size_t whichByte = which / 8;//计算处于那个字节size_t whichBite = which % 8;//计算处于该字节的那一个比特位if (_bst[whichByte] & (1 << whichBite)) {//说明该元素已经存在return;}_bst[whichByte] |= 1 << whichBite;++_count;//比特位为1的个数增加}void reset(size_t which) {//比特位置0assert(which < N);size_t whichByte = which / 8;//计算处于那个字节size_t whichBite = which % 8;//计算处于该字节的那一个比特位if (test(which)) {//该比特位是1,才进行置0_bst[whichByte] ^= 1 << whichBite;--_count;//比特位为1的个数减少}}bool test(size_t which) const {//检测比特位是否为1assert(which < N);size_t whichByte = which / 8;//计算处于那个字节size_t whichBite = which % 8;//计算处于该字节的那一个比特位return 0 != (_bst[whichByte] & (1 << whichBite));}size_t size() const {//返回比特位位数return N;}size_t count() const {//返回比特位为1的个数/*size_t num = 0;for (size_t i = 0; i < N; ++i) {if (test(i)) ++num;}return num;若比特位数较多,遍历则效率太低*/return _count;}private:std::vector<unsigned char> _bst;size_t _count;//记录比特位为1的个数};
}
4.3布隆过滤器实现BloomFilter.hpp
#pragma once
#include "BitSet.hpp"
#include "Common.h"//采用五个比特位,来映射一个数据
template<class K, size_t N, class K2INT1 = Str2INT1, class K2INT2 = Str2INT2, class K2INT3 = Str2INT3, class K2INT4 = Str2INT4, class K2INT5 = Str2INT5
>
class BloomFilter {
public:BloomFilter(): _bst(), _size(0){}bool Insert(const K& data) {size_t index = K2INT1()(data) % _bst.size();_bst.set(index);index = K2INT2()(data) % _bst.size();_bst.set(index);index = K2INT3()(data) % _bst.size();_bst.set(index);index = K2INT4()(data) % _bst.size();_bst.set(index);index = K2INT5()(data) % _bst.size();_bst.set(index);++_size;return true;}bool Find(const K& data) {size_t index = K2INT1()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT2()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT3()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT4()(data) % _bst.size();if (!_bst.test(index)) return false;index = K2INT5()(data) % _bst.size();if (!_bst.test(index)) return false;//只能说明可能存在return true;}size_t Size() const {return _size;}private:MyBitSet::bitset<N * 5> _bst;size_t _size;
};
哈希应用、海量数据处理:布隆过滤器相关推荐
- 哈希的应用(2)——布隆过滤器
文章目录 布隆过滤器 布隆过滤器的概念 布隆过滤器的实现 哈希函数个数和布隆过滤器长度 模拟实现 布隆过滤器的删除 小结 海量数据处理相关题 5.1哈希切割 5.2位图应用 5.3布隆过滤器 扩展 布 ...
- 哈希(解决哈希冲突,封装map/set,哈希的应用{位图/布隆过滤器})
文章目录 如何解决哈希冲突: ①闭散列:也叫开放定址法,如果发送哈希冲突了,就去找下一个空位置 ②开散列 -- 拉链法/哈希桶 封装map和set 哈希表的代码 封装的unordered_set 封装 ...
- [大数据处理]——布隆过滤器
布隆过滤器 说到布隆这两个字大家可千万不要认为我们这里讲的是英雄联盟中的布隆大叔,今天我们所讲的布隆过滤器是一种大数据处理利器,他是由布隆算法Bloom Filter音译而来,是以Bitmap集合为基 ...
- 哈希的应用->布隆过滤器
为什么用布隆过滤器 这个是基于位图的一个超级牛皮的一个数据结构.举个例子,假设我们创建Steam账号,我们的账户名字是不允许重复的,所以我们需要找到一个没有人使用过的名字,但是我们得知道现在这个名字是 ...
- 海量数据处理(一) :位图与布隆过滤器的概念以及实现
目录 位图 位图概念 位图的应用 位图的实现思路 set reset test 完整代码 布隆过滤器 布隆过滤器概念 布隆过滤器的优缺点 优点 缺点 布隆过滤器的实现思路 哈希冲突的问题 如何选择哈希 ...
- 哈希切割+布隆过滤器
目录 布隆过滤器 布隆过滤器的提出 布隆过滤器的概念 布隆过滤器的实现 插入 set函数 布隆过滤器长度的设置 测试布隆误判率 布隆过滤器删除 布隆过滤器的实现场景 布隆过滤器的扩展以及哈希切分 布隆 ...
- 哈希表应用——布隆过滤器
注:布隆过滤是用来处理海量数据且允许存在误判 目录 布隆过滤器提出 布隆过滤器概念 布隆过滤器的理论知识 布隆过滤器的实现 布隆过滤器的删除 布隆过滤器优点 布隆过滤器缺陷 布隆过滤器的应用场景 哈希 ...
- 哈希的应用 —— 布隆过滤器
文章目录 布隆过滤器的提出 布隆过滤器的概念 布隆过滤器的实现 布隆过滤器的插入 布隆过滤器的查找 布隆过滤器的删除 布隆过滤器的优点 布隆过滤器的缺陷 布隆过滤器使用场景 布隆过滤器的提出 在注册账 ...
- 海量数据处理问题知识点复习手册
前言 本文快速回顾了常考的知识点,用作面试复习,事半功倍. 面试知识点复习手册 通过以下两种途径查看全复习手册文章导航 关注我的公众号:Rude3Knife 点击公众号下方:技术推文--面试冲刺 全复 ...
- 高级数据结构——海量数据(位图,布隆过滤器)
目录 位图 位图介绍 位图代码实现 布隆过滤器 布隆过滤器介绍 布隆过滤器代码实现 布隆过滤器的优缺点 海量数据相关题目 位图 位图介绍 位图(bitmap),适用于存储海量,非负整数,不重复的数据. ...
最新文章
- jmap -histo pid 输出的[C [B [I [S methodKlass的含义
- php 换行 \n \r\n br 简介
- 面试:说说Java中的 volatile 关键词?
- pycharm python 如何快速给代码块添加try/catch try/finally包裹?【ctrl+alt+T】
- 项目管理如何调动员工的积极性?
- Numpy-矩阵的分割
- Robot Application Builder
- vue 多页面多模块分模块打包 分插件安装_Vue渲染方式
- SAP-MM:发票、贷方凭证、事后借记、后续贷记
- 11-提升R语言程序性能gc()
- xml字符串转xml对象,xml对象转json对象
- db2判断字符为空_算法之字符串转换为数字
- 扫描仪twain驱动是什么_扫描仪无法显示怎么办 扫描仪无法显示解决方法【详解】...
- [Step By Step]SAP HANA PAL多项式回归预测分析Polynomial Regression编程实例FORECASTWITHPOLYNOMIALR(预测)...
- Linux教程+操作系统教程
- Mac快捷键大全-网络整理
- vuejs登陆页面_20个最佳Vuejs登陆页面模板
- 互金平台乘着东风股价反弹,小赢科技为何成上涨“急先锋”?
- 名帖234 俞和 行书《云锦帖》
- “猫爪杯”遭国人疯抢,“大白兔冰淇淋”在美国大火