布隆过滤器是用于检查元素是否存在于大集合中的高效且性能很好的数据结构,缺点是集合中元素越多误报可能性越大,并且不容易删除,好处是判断不存在的一定不存在,判断存在的大概率存在
布隆过滤器的原理
加入一个元素到集合时
1、使用布隆过滤器中的哈希函数对元素值进行计算,得到哈希值(有几个哈希函数得到几个哈希值)。
2、根据得到的哈希值,在位数组中把对应下标的值置为 1。
判断元素是否存在
1、给定元素进行计算;
2、如果都为1那么值存在,如果有一个值不为1,那么不存在;
布隆过滤器的代码实现
#include <iostream>
#include <vector>
#include <bitset>
#include <functional>
#include <cmath>
// 定义布隆过滤器类
class BloomFilter {
public:
// 构造函数,初始化参数
BloomFilter(size_t size, size_t hashFunctionsCount)
: m_size(size), m_hashFunctionsCount(hashFunctionsCount), m_bitset(size) {}
// 插入元素到过滤器中
void insert(const std::string& key) {
for (size_t i = 0; i < m_hashFunctionsCount; ++i) {
// 计算哈希值
size_t hashValue = hash(key, i);
// 将哈希值对应的位设置为1
m_bitset.set(hashValue % m_size);
}
}
// 判断元素是否可能在过滤器中
bool contains(const std::string& key) const {
for (size_t i = 0; i < m_hashFunctionsCount; ++i) {
// 计算哈希值
size_t hashValue = hash(key, i);
// 如果对应的位为0,则说明该元素不在过滤器中
if (!m_bitset.test(hashValue % m_size)) {
return false;
}
}
// 如果所有位都为1,则说明该元素可能在过滤器中
return true;
}
private:
// 计算哈希值的函数
size_t hash(const std::string& key, size_t index) const {
std::hash<std::string> hasher;
size_t hash1 = hasher(key);
size_t hash2 = hasher(std::to_string(index));
return hash1 ^ hash2;
}
size_t m_size; // 过滤器大小
size_t m_hashFunctionsCount; // 哈希函数数量
std::bitset<1000> m_bitset; // 位数组
};
int main() {
BloomFilter bloomFilter(1000, 3); // 创建一个大小为1000,使用3个哈希函数的布隆过滤器
bloomFilter.insert("hello"); // 将"hello"插入到过滤器中
bloomFilter.insert("world"); // 将"world"插入到过滤器中
std::cout << "hello: " << bloomFilter.contains("hello") << std::endl; // 输出"hello"是否可能在过滤器中
std::cout << "world: " << bloomFilter.contains("world") << std::endl; // 输出"world"是否可能在过滤器中
std::cout << "test: " << bloomFilter.contains("test") << std::endl; // 输出"test"是否可能在过滤器中
return 0;
}
布隆过滤器的使用场景
- 给定数据是否存在
- 防止缓存穿透
- 垃圾邮件过滤
- 黑名单
- 去重
- 爬取过的网址不重复爬取
- 海量qq号去重
体验 Redis 中的布隆过滤器(需提前一键安装docker)
1、搜索 docker redis bloomfilter找到具体地址一键拉取镜像:https://hub.docker.com/r/redislabs/rebloom/
2、运行容器 :docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest
3、进入容器 :docker exec -it redis-redisbloom bash