前言
在学习到位图的高效后,我们又会思考一个问题,就是位图只能处理整数,那如果数据是字符串呢?我们又该如何解决?
例子:我们在刷短视频时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉那些已经看过的内容。问题来了,推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当推荐系统推荐视频时会从每个用户的历史记录里进行筛选,过滤掉那些已经存在的记录。 如何快速查找呢?
- 用哈希表存储用户记录,缺点:浪费空间
- 用位图存储用户记录,缺点:不能处理字符串
- 将哈希与位图结合,即布隆过滤器
一、布隆过滤器是什么?
可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。
二、布隆过滤器实现
1.代码
#pragma once
#include "bitset.h"
#include <string>
namespace hdh
{
struct HashStr1
{
// BKDR
size_t operator()(const std::string& str)
{
size_t hash = 0;
for (size_t i = 0; i < str.size(); ++i)
{
hash *= 131;
hash += str[i];
}
return hash;
}
};
struct HashStr2
{
// RSHash
size_t operator()(const std::string& str)
{
size_t hash = 0;
size_t magic = 63689; // 魔数
for (size_t i = 0; i < str.size(); ++i)
{
hash *= magic;
hash += str[i];
magic *= 378551;
}
return hash;
}
};
struct HashStr3
{
// SDBMHash
size_t operator()(const std::string& str)
{
size_t hash = 0;
for (size_t i = 0; i < str.size(); ++i)
{
hash *= 65599;
hash += str[i];
}
return hash;
}
};
template <class K = string,
class Hash1 = HashStr1,
class Hash2 = HashStr2,
class Hash3 = HashStr3>
class bloomfilter
{
public:
bloomfilter(size_t num)
:_bs(5*num)
, _N(5*num)
{}
void set(const K& key)
{
size_t index1 = Hash1()(key) % _N;
size_t index2 = Hash2()(key) % _N;
size_t index3 = Hash3()(key) % _N;
cout << index1 << endl;
cout << index2 << endl;
cout << index3 << endl << endl;
_bs.set(index1);
_bs.set(index2);
_bs.set(index3);
}
bool test(const K& key)
{
size_t index1 = Hash1()(key) % _N;
if (_bs.test(index1) == false)
return false;
size_t index2 = Hash2()(key) % _N;
if (_bs.test(index2) == false)
return false;
size_t index3 = Hash3()(key) % _N;
if (_bs.test(index3) == false)
return false;
return true; // 但是这里也不一定是真的在,还是可能存在误判
// 判断在,是不准确的,可能存在误判
// 判断不在,是准确
}
void reset(const K& key)
{
// 将映射的位置给置0就可以?
// 不支持删除,可能会存在误删。一般布隆过滤器不支持删除
}
private:
bitset _bs; // 位图
size_t _N;
};
void test_bloomfilter()
{
bloomfilter<std::string> bf(100);
bf.set("abcd");
bf.set("aadd");
bf.set("bcad");
cout << bf.test("abcd") << endl;
cout << bf.test("aadd") << endl;
cout << bf.test("bcad") << endl;
cout << bf.test("cbad") << endl;
}
}
2.布隆过滤器优缺点
优点:节省空间,高效,可以标记存储任意类型
缺点:存在误判,不支持删除
总结
布隆过滤器是数据在的测试是不准确的,测试数据不在的时候是准确的