位图|布隆过滤器

位图概念  

位图本质上是一个数组,每个位置上存储的是0和1。

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。

首先我们首先想到的是遍历数组,但是这里会遇到一个问题,40亿个整数会开多大的空间?

1个整数4个字节,也就是需要内存160亿字节,大约14.9GB

1GB = 1024 MB, 1MB  = 1024KB, 1KB = 1024Byte

现如今电脑16GB内存就很不错了,所以这里就需要位图来解决

无符号整数范围是(0,2^32-1),每个数对应一个位置,如果那个位置存在就是1,不存在就是0

需要40亿个比特位,也就是512MB就可以存下

vector中每个值的有32个比特位

位图实现 

template<size_t N>
class bitset
{
public:
	bitset()
	{
		_a.resize(N / 32 + 1);
	}
    
    //把这个数对应比特位标记位0
	void set(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;
		_a[i] |= (1 << j);
	}

//标记为1
	void reset(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;
		_a[i] &= (~(1 << j));
	}

	bool test(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;

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

private:
	vector<int> _a;
};

给定100亿个整数,设计算法找到只出现一次的整数? 

整数最大值就是42亿左右,所以不会出现空间不足的问题,会有数据重复出现。

出现0次: 00

出现1次: 01

出现两次及以上: 10

template<size_t N>
class twobitset
{
public:
	void set(size_t x)
	{
		//00->01
		if (!_bs1.test(x) && !_bs2.test(x))
		{
			_bs2.set(x);
		}
		else if (!_bs1.test(x) && _bs2.test(x))//01->10
		{
			_bs1.set(x);
			_bs2.reset(x);
		}
	}

	bool is_once(size_t x)
	{
		return _bs1.test(x) && !_bs2.test(x);
	}

private:
	bitset<N> _bs1;
	bitset<N> _bs2;

};

布隆过滤器

是二进制向量和一系列随机映射函数组成。

一个值映射到几个位置,这几个映射值为1,表示这个元素存在,但是这会出现一个新的问题,当有几个元素映射到了相同几个位置就会出现误判。

使用不同的哈希函数将一个数映射到不同的位置

布隆过滤器的缺点:

删除元素,当有几个元素在同一个位置有映射值,如果删除的话,会影响其他元素。

struct BKDRHash
    {
        size_t operator()(const string& str)
        {
            size_t hash = 0;
            for (auto ch : str)
            {
                hash = hash * 131 + ch;
            }

            //cout <<"BKDRHash:" << hash << endl;
            return hash;
        }
    };

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

            //cout << "APHash:" << hash << endl;
            return hash;
        }
    };

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

            //cout << "DJBHash:" << hash << endl;
            return hash;
        }
    };

    template<size_t N,
        class K = string,
        class Hash1 = BKDRHash,
        class Hash2 = APHash,
        class Hash3 = DJBHash>
        class BloomFilter
    {
    public:
        void set(const K& key)
        {
            size_t hash1 = Hash1()(key) % N;
            size_t hash2 = Hash2()(key) % N;
            size_t hash3 = Hash3()(key) % N;

            _bs.set(hash1);
            _bs.set(hash2);
            _bs.set(hash3);
        }

        bool test(const K& key)
        {
            size_t hash1 = Hash1()(key) % N;
            if (!_bs.test(hash1))
                return false;

            size_t hash2 = Hash2()(key) % N;
            if (!_bs.test(hash2))
                return false;

            size_t hash3 = Hash3()(key) % N;
            if (!_bs.test(hash3))
                return false;

            return true;
        }
    private:
        bitset<N> _bs;
    };

位图(Bitmap)和布隆过滤器(Bloom Filter)都是常用的数据结构,用于处理大规模数据集合,但它们有着不同的应用场景和用途。 位图是一种压缩数据结构,用于快速地判断某个元素是否在集合中。位图的实现方式是将每个元素映射到一个二进制位上,如果该元素存在于集合中,则将对应的二进制位标记为1,否则标记为0。这样,当需要查询某个元素是否在集合中时,只需要查找对应的二进制位即可。由于位图的实现方式非常简单,因此可以快速地进行插入和查询操作,而且占用的空间也非常小,适合处理大规模数据集合。 布隆过滤器也是一种快速判断元素是否存在于集合中的数据结构,但其实现方式与位图略有不同。布隆过滤器使用一组哈希函数将元素映射到多个二进制位上,并将对应的二进制位标记为1。当查询某个元素是否在集合中时,将该元素进行哈希映射,并查找对应的二进制位,如果所有的二进制位都被标记为1,则说明该元素可能存在于集合中,否则可以确定该元素不存在于集合中。布隆过滤器的优点是可以快速地判断一个元素不存在于集合中,而且占用的空间也比较小,但存在误判率的问题。 因此,位图布隆过滤器虽然都可以用来处理大规模数据集合,但它们的实现方式和应用场景有所不同。位图适用于需要快速地判断某个元素是否在集合中的场景,而布隆过滤器适用于需要快速地判断一个元素不存在于集合中的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值