遇到大数据文件,你会怎么处理?快来看一看位图和布隆过滤器吧(上)

目录

前文

一,为什么会出现位图和布隆过滤器

二,位图/BitSet

2.1 什么是位图

2.2 位图实现

三,位图的优缺点

3.1 位图的优点

3.2 位图的缺点

总结


前文

在我们的日常生活中大数据的处理必不可少,比如注册游戏起名字,都需要向数据库比对确认是否存在,JAVA有分页处理和数据库缓存机制等,而我们C++交的答卷则是以哈希理念为基础的用来处理大数据搜寻的位图和布隆过滤器,当然这只是其中一种,也是我们本次主要讲解一下位图的概念以及实现,后续我们会再讲布隆过滤器。

一,为什么会出现位图和布隆过滤器

在现实的生活中,大数据的处理是不可避免的,在我们的数据结构中,以哈希表为基础的unordered_set/unordered_map是一种查找极其高效的数据结构,但是当面对大文件例如几个g,十几个g无法加载到内存的时候就有写捉襟见肘了,为了处理这种情况,继承哈希思想的位图和布隆过滤器就诞生了。

二,位图/BitSet

2.1 什么是位图

在正式介绍位图之前,我们先来看一道腾讯的经典面试题

 

 如上图所示,同学们看到会怎么做呢,常见的有以下两个思路

1.遍历,时间复杂度O(N)

2.排序,然后利用二分查找,时间复杂度O(NlogN+logN)

 上面两种方法在处理正常的判断是否存在问题很有效,但是本题有40亿个整数,160亿字节,约等于16G,一般来说根本加载不到内存中,那么要怎么处理呢?这里我们可以这样解决

3.位图解决

一个整数数据是否存在我们可以用0,1来表示,因此一个整数就可以映射到一个比特位上面,如下图所示

 因此我们位图的概念就如下所示

所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用
来判断某个数据存不存在的

2.2 位图实现

这里我们来实现一个有set(插入),reset(删除),test(查找)三大基本功能的位图结构

首先我们的位图是一个比特位对应一个数据,因此我们在开空间时,假如有N个数据,就需要开N个bit的空间,这样就极大的节省了空间,我们原本读取40亿的整数需要16G的内存,现在开辟40亿bit的空间,我们只需要500M,这样就极大的节省了空间

其次,我们的内置类型有char——1字节——8比特位,int——4字节——12比特位,这里我们选择以char为基本的单位,这样我们定位数据的时候比较方便

最后找数据所映射的位置我们可以用下面公式

//定位到第i个char
int i = N / 8
//定位到第i个char的第j个位
int j = n % 8

当定位完位置,我们用按位&(比较补码对应二进制位有0则为0,都为1则为1),按位|(比较补码,对应的二进制只要有1就为1,都是0才是0)等位运算完成数据的插入,删除,查找

我们根据上面的思路画了一个如下的图

实现代码如下

	template <size_t N>//N为要数据量
	class BitSet
	{
	public:
		//构造函数
		BitSet()
		{
			_bs.resize(N / 8 + 1, 0);//这里多开一个char的原因是
			//因为/号可能省去了余数,因此需要多开一个
			//如10/8=1,但实际上还有2个数据,因此需要多开一个
		}

		//插入
		void set(size_t number)
		{
			size_t i = number / 8;
			size_t j = number % 8;
			//插入
			_bs[i] |= (1 << j);
		}

		//删除
		void reset(size_t number)
		{
			size_t i = number / 8;
			size_t j = number % 8;
			//删除
			_bs[i] &= ~(1 << j);
		}

		//查找
		bool test(size_t number)
		{
			size_t i = number / 8;
			size_t j = number % 8;
			return _bs[i] & (1 << j);
		}

	private:
		vector<char> _bs;
	};

我们可以用测试例子来测试一下

void test_bitset1()
	{
		BitSet<100> bs;
		bs.set(10);
		bs.set(11);
		bs.set(15);
		cout << bs.test(10) << endl;
		cout << bs.test(15) << endl;

		bs.reset(10);

		cout << bs.test(10) << endl;
		cout << bs.test(15) << endl;

		bs.reset(10);
		bs.reset(15);

		cout << bs.test(10) << endl;
		cout << bs.test(15) << endl;
	}

完美运行

三,位图的优缺点

3.1 位图的优点

1.根据映射关系查找,时间复杂度位(O(1)),效率高

2.相较于直接载入整数数据所用的空间,位图极大的节省了空间

3.2 位图的缺点

1.只能映射整数数据,对于其他的string等无能为力

总结

如上就是本节位图的所有内容,位图的优点很给力,但是缺点也很明显,无法应用于字符等其他方面,那么这是否有解决办法呢?自然是有的,这时我们的布隆过滤器就要登场了,老铁们尽请期待

猜你喜欢

转载自blog.csdn.net/zcxmjw/article/details/131002473