【C++】位图的简单实现与布隆过滤器

位图与布隆过滤器

一、简单实现位图

1.什么是位图

2.位图的实现

二、 布隆过滤器

1.什么是布隆过滤器

2.布隆过滤器的实现

3.布隆过滤器的优点

4.布隆过滤器的缺点


一、简单实现位图

1.什么是位图

        位图,就是利用比特位0和1的特性,用来映射数据的状态表示,适用于海量数据,以及无重复数据的处理。一般用于表示数据的存在与否。

2.位图的实现

        表示数据是整型类型的情况

#pragma once

#include <vector>

namespace bit
{
	// 使用无符号整型防止模板参数为负数
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_n.resize(N / 32 + 1);
		}

		// 映射指定值到位图中
		void set(size_t x)
		{
			int i = x / 32;
			int j = x % 32;
			_n[i] |= (1 << j);
		}

		// 取消映射值
		void reset(size_t x)
		{
			int i = x / 32;
			int j = x % 32;
			_n[i] &= (~(1 << j));
		}

		// 判断是否存在
		bool test(size_t n)
		{
			int i = n / 32;
			int j = n % 32;

			return _n[i] & (1 << j);
		}

	private:
		vector<int> _n;
	};
}

        测试用例与效果:

#include <iostream>
using namespace std;

#include "BitSet.h"

int main()
{
	bit::bitset<1000> bs;
	bs.set(1);
	bs.set(10);
	bs.set(100);

	cout << bs.test(1) << endl;
	cout << bs.test(10) << endl;
	cout << bs.test(100) << endl;
	cout << bs.test(999) << endl<<endl;

	bs.set(999);
	bs.reset(10);

	cout << bs.test(1) << endl;
	cout << bs.test(10) << endl;
	cout << bs.test(100) << endl;
	cout << bs.test(999) << endl << endl;


	//bit::bitset<-1> bs1;
	//bit::bitset<0xffffffff> bs2;

	return 0;
}

二、 布隆过滤器

1.什么是布隆过滤器

        布隆过滤器是布隆在1970年提出的一种紧凑的、比较巧妙地概率型数据结构,有着高效的插入、查询,以及快速获取数据存在与否的特点。它是由多个哈希函数,将一个数据映射到多个位图结构中,相比与寻常的数据结构,它可以节省大量对内存的负担。

        其中,最好理解的就是字符串的状态表示了。比如一个游戏中,玩家游玩需要注册名字且与其他玩家不能重复,当然公司中肯定会存储各位玩家的数据,但如果玩家特别特别多,这将导致取名字时响应时间过长影响玩家的游戏体验。此时我们就需要使用布隆过滤器了,将字符串(名字)映射到多个位图上,如果都存在,那么再去海量数据中去查找;不存在,直接返回结果即可。这无疑是一个对数据查找大大的优化。

2.布隆过滤器的实现

        通过布隆过滤器实现对大量字符串类型的映射,其中对于字符串的映射参考于多位算法大佬(本文只引用了三种算法)。

// 布隆过滤器
struct BKDRHash
{
	size_t operator()(const string& s)
	{
		// BKDR
		size_t value = 0;
		for (auto ch : s)
		{
			value *= 31;
			value += ch;
		}
		return value;
	}
};

struct APHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (long i = 0; i < s.size(); i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

struct DJBHash
{
	size_t operator()(const string& s)
	{
		size_t hash = 5381;
		for (auto ch : s)
		{
			hash += (hash << 5) + ch;
		}
		return hash;
	}
};

// 使N个数据乘以X倍有利于布隆过滤器中数据重复情况的减少(X倍数越大重复越少)
template<size_t N, size_t X = 5, class K = string,
	class HashFunc1 = BKDRHash,
	class HashFunc2 = APHash,
	class HashFunc3 = DJBHash>
	class BloomFilter
{
public:
	void Set(const K& key)
	{
		size_t len = X * N;
		size_t index1 = HashFunc1(key) % len;
		size_t index2 = HashFunc2(key) % len;
		size_t index3 = HashFunc3(key) % len;
		/* 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 len = X * N;

		size_t index1 = HashFunc1(key) % len;
		if (_bs.test(index1) == false)
			return false;
		size_t index2 = HashFunc2(key) % len;
		if (_bs.test(index2) == false)
			return false;
		size_t index3 = HashFunc3(key) % len;
		if (_bs.test(index3) == false)
			return false;

		return true;
	}

	// 不支持删除,删除可能会影响其他值。
	void Reset(const K& key);

private:
	bitset<X* N> _bs;
};

3.布隆过滤器的优点

1.查询速度极快,为O(k),其中的k为哈希函数的个数;

2.在允许误差的范围内,可以节省大量的内存消耗;

3.布隆过滤器没有存储元素本身,有一定的保密性。

4.布隆过滤器的缺点

1.一般不能删除映射的元素,相当于一次性用品;

2.不能查找到元素本身,只能获取其一定的状态表示;

3.仍然存在误判的可能性。

猜你喜欢

转载自blog.csdn.net/qq_74641564/article/details/133586425