海量数据处理(位图和布隆过滤器)

本文探讨了哈希算法在处理大数据集时的应用,包括如何找到最频繁出现的IP地址和topK元素,以及位图在快速数据查找和集合操作中的高效使用。还介绍了布隆过滤器的工作原理和优缺点,以及其在近似算法中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

哈希切割

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?如何直接用Linux系统命令实现

解决思路

找到出现次数最多的IP地址

要找到前TopK的IP地址,就是要统计每个IP地址出现多少次
分割大文件:如果能将相同IP地址放到同一个文件中
哈希分割: 从源文件中获取一个IP地址---->IP%文件份数

  1. 每拿到一个IP地址后,用函数把IP地址转化为整型数据,再%上文件分数,就知道把IP地址放到哪个文件中去
  2. 这样,就可以统计每个IP地址出现多少次
//构建键值对
<IP地址的整型数据,次数>
  1. 统计哪个IP地址出现的次数比较多,用unordered_map,m[ip]++;每拿到一个IP地址的++。每个IP地址出现的次数,已经在unordered_map中保存起来
  2. 按类似的方法,统计每个文件中的IP地址的次数,最后用一个for()---->找出出现最多的IP地址
top K的IP

堆---->最多前K个IP地址—><次数,IP地址>

位图

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

  1. 遍历,时间复杂度O(N)
  2. 排序(O(NlogN)),利用二分查找: logN

位图解决

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比
特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:
40亿的整型数据大概是16G的数据
用位图来映射的话 大概就是232-23=512M
在这里插入图片描述

解决

C++中提供了位图的类,bitset
在这里插入图片描述

位图的实现

#pragma once
#include<vector>
#include<iostream>
using namespace std;
namespace LXY
{
	class bitset
	{
	public:
		bitset(size_t bitCount)
			:_set(bitCount/8 + 1)
			, _bitCount(bitCount)
		{}
		//置1操作
		void set(size_t which)
		{
			//如果位集合给出100个比特位,那么你给100,就表示不了,范围为0~99
			if(which >= _bitCount)
				return;
			//计算对应的字节
			size_t index = (which >> 3);//除以8
			size_t pos = which % 8;

			//先将1移到对应的比特位上,再或上对应位上的数字
			_set[index] |= (1 << pos);
		}
		//置0操作
		void reset(size_t which)
		{
			if (which >= _bitCount)
				return;
			//计算对应的字节
			size_t index = (which >> 3);//除以8
			size_t pos = which % 8;

			//先将1的取反0移到对应的比特位上,再与上对应位上的数字
			_set[index] &= ~(1 << pos);
		}

		//检测which比特位是否为1
		bool test(size_t which)
		{
			if (which >= _bitCount)
				return false;
			//计算对应的字节
			size_t index = (which >> 3);//除以8
			size_t pos = which % 8;

			//与上1不等于0就代表存在
			return 0 != (_set[index] & (1 << pos));
		}
		//返回比特位总的个数
		size_t size()
		{
			return _bitCount;
		}

		//返回为1的比特位的总数
		size_t count()
		{
			//查表
			int bitCnttable[256] = {
				0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2,
				3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,
				3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
				4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,
				3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,
				6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
				4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
				6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,
				3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3,
				4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6,
				6, 7, 6, 7, 7, 8 };
			size_t szcount = 0;
			for (size_t i = 0; i < _set.size(); ++i)
				szcount += bitCnttable[_set[i]];
			return szcount;
		}
	public:
		std::vector<unsigned char> _set;
		size_t _bitCount;
	};
}

void TestBitSet()
{
	LXY::bitset bt(100);
	bt.set(10);
	bt.set(20);
	bt.set(30);
	bt.set(40);
	bt.set(41);
	cout << bt.size() << endl;
	cout << bt.count() << endl;

	if (bt.test(40))
		cout << "40bite is 1" << endl;
	else
		cout << "40bite is not 1" << endl;

	bt.reset(40);
	cout << bt.count() << endl;

	if (bt.test(40))
		cout << "40bite is 1" << endl;
	else
		cout << "40bite is not 1" << endl;
}

int main()
{
	TestBitSet();
	system("pause");
	return 0;
}
位图的应用
  1. 快速查找某个数据是否在一个集合中
  2. 排序 (数据不能有重复)
  3. 求两个集合的交集、并集等
  4. 操作系统中磁盘块标记

位图的题

  1. 给定100亿个整数,设计算法找到只出现一次的整数?
    用两个比特位表示一个数据,8/2=4;那么位图中一个字节只能表示4个数据,232/22=1G。
    取一个数据:哪个字节 哪两个比特位
	if(00) //出现过0次
	01
	else if(01) //出现过多次
	10
  1. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

布隆过滤器

位图+哈希函数
特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。多个比特位代表数据的状态信息

布隆过滤器插入

如果向布隆过滤器中插入baidu,我们用三个哈希函数将三个位置置为1
在这里插入图片描述
在这里插入图片描述
“baidu”---->1 4 7
“tecent”---->3 4 8
hash1,hash2,hash3----->三个位置
检测三个位置的状态
如果三个位置只要有一个为0,说明数据一定不存在

布隆过滤器的查找

布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中
布隆过滤器如果告诉你数据不存在,那么一定不存在,如果告诉你存在,则有可能存在。

布隆过滤器的插入和查找的实现

#pragma once
#include"biteset.hpp"
#include<iostream>
#include"Common.hpp"
using namespace std;

//BloomFilter:位图+多个哈希
template<class T,class HF1 = Str2INT ,class HF2 = Str2INT2,class HF3 = Str2INT3,
				class HF4 =Str2INT4,class HF5 = Str2INT5>
//哈希函数给的越多,将来产生误报的概率就也就越小
class BloomFilter
{
public:
	BloomFilter(size_t size = 10)
		:_bt(10 * size)
		, _size(0)
	{}
	bool Insert(const T& data)
	{
		//HF1()(data)可能回越界,要%上位图的比特位数
		size_t index1 = HF1()(data) % _bt.size();
		size_t index2 = HF2()(data) % _bt.size();
		size_t index3 = HF3()(data) % _bt.size();
		size_t index4 = HF4()(data) % _bt.size();
		size_t index5 = HF5()(data) % _bt.size();

		_bt.set(index1);
		_bt.set(index2);
		_bt.set(index3);
		_bt.set(index4);
		_bt.set(index5);
		_size++;
		return true;
	}

	//检测是否存在,每个哈希函数都得检测
	bool IsIn(const T&data)
	{
		size_t index = HF1()(data) % _bt.size();
		if (!_bt.test(index))
			return false;

		index = HF2()(data) % _bt.size();
		if (!_bt.test(index))
			return false;

		index = HF3()(data) % _bt.size();
		if (!_bt.test(index))
			return false;

		index = HF4()(data) % _bt.size();
		if (!_bt.test(index))
			return false;

		index = HF5()(data) % _bt.size();
		if (!_bt.test(index))
			return false;

		//元素可能存在
		return true;
	}

	//存储多少个元素
	size_t count()const
	{
		return _size;
	}
private:
	LXY::bitset _bt;
	size_t _size;
};

布隆过滤器的删除

布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素
一种支持删除的方法:将布隆过滤器中的每个比特位扩展成一个小的计数器(整型数组),插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。

缺陷:
  1. 无法确认元素是否真正在布隆过滤器中
  2. 存在计数回绕

布隆过滤器优点

  1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关
  2. 哈希函数相互之间没有关系,方便硬件并行运算
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

布隆过滤器缺陷

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕问题
布隆过滤器
  1. 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
    答:给一个布隆过滤器,将一个文件的数据映射里面去。如果整体映射不完,先映射一部分。从另外一个文件拿一个数据在布隆过滤器里面找,如果有,数据存在就算是两个文件的交集。

倒排索引

给上千个文件,每个文件大小为1K—100M。给n个词,设计算法对每个词找到所有包含它的文件,你只有100K内存

哈希加密

<think>好的,用户想了解C++中位图布隆过滤器的相关知识及总结,我需要结合提供的引用资料来组织回答。首先,我应该先明确位图布隆过滤器的基本概念,然后讨论它们的实现应用,最后总结它们的优缺点应用场景。 首先看位图部分。根据引用[3],位图用于处理海量数据的存在性判断,比如40亿个整数去重。位图通过每个bit位表示一个数据是否存在,节省空间。需要提到位图的数据结构设计,比如用vector<bool>或直接操作比特位。实现部分可能需要给出C++的代码示例,比如设置某位为1,清除为0,检查存在性。应用方面包括快速查找、去重、排序等,引用[2][3]都有提到这些应用。 然后是布隆过滤器。根据引用[4],布隆过滤器是概率型数据结构,用于判断元素可能存在或一定不存在。它使用多个哈希函数映射到不同的位,引用[3][4]都提到了这一点。实现部分需要说明插入查找的过程,以及为什么不能删除,或者如何支持删除(可能需要引用计数)。应用方面,引用[5]提到了缓存穿透的解决方案,防止数据库被无效查询压垮。此外,分布式系统爬虫中的URL去重也是常见应用。 需要注意布隆过滤器的优缺点,比如空间效率高但存在误判率,无法删除元素等。引用[4][5]都有相关描述。可能需要比较位图布隆过滤器的适用场景,比如位图适合精确判断且数据范围小的情况,而布隆过滤器适合大数据量且允许一定误判的情况。 代码实现部分,位图可以用bitset或手动操作位,布隆过滤器则需要多个哈希函数位图的组合。需要确保示例代码正确,比如展示如何设置位,检查存在性,以及布隆过滤器的插入查询步骤。 最后总结部分,需要将位图布隆过滤器的核心点对比,强调它们在海量数据处理中的重要性,并结合引用中的内容,如引用[1]提到的结合位图布隆过滤器的方案,可能可以提到这种混合结构在优化空间查询速度上的优势。 现在需要检查是否有遗漏的引用内容,比如引用[1]提到结合位图布隆过滤器的优点,这可能是在实际应用中的优化策略,需要在总结部分提到。同时,用户要求生成相关问题,需要根据内容设计相关问题,比如应用场景、实现细节、优缺点比较等。 需要注意回答的结构,先讲位图,再讲布隆过滤器,每个部分包括概念、实现、应用,最后总结对比。确保引用标识正确添加,例如在提到布隆过滤器概念时加上[^4],在缓存穿透时引用[^5]等。</think>### C++位图布隆过滤器总结 #### 一、位图(Bitmap) **1. 概念与实现** 位图通过每个比特位(bit)表示一个数据的存在性(0/1),适用于海量数据的快速存在性判断[^3]。例如,40亿个整数(约16GB)用位图仅需约500MB内存。 **C++实现示例**: ```cpp class Bitmap { private: std::vector<uint32_t> bits; // 使用uint32_t数组存储位 public: Bitmap(size_t range) : bits((range >> 5) + 1, 0) {} // 计算需要多少32位块 void set(size_t x) { size_t index = x >> 5; // 确定数组下标 size_t offset = x % 32; // 确定比特位偏移 bits[index] |= (1 << offset); } bool test(size_t x) { size_t index = x >> 5; size_t offset = x % 32; return (bits[index] & (1 << offset)) != 0; } }; ``` **2. 应用场景** - **数据去重**:如统计40亿整数中不重复的数字。 - **快速查询**:判断IP是否在黑名单中。 - **排序**:对有限范围的整数进行非比较排序[^2]。 --- #### 二、布隆过滤器(Bloom Filter) **1. 概念与实现** 布隆过滤器通过$k$个哈希函数将元素映射到多个位,若所有对应位为1则“可能存在”,否则“一定不存在”[^4]。牺牲一定准确性换取极高的空间效率。 **C++实现核心逻辑**: ```cpp class BloomFilter { private: Bitmap bitmap; size_t k; // 哈希函数数量 public: BloomFilter(size_t size, size_t k) : bitmap(size), k(k) {} void add(const std::string& key) { for (size_t i = 0; i < k; ++i) { size_t hash = std::hash<std::string>{}(key + std::to_string(i)); bitmap.set(hash % bitmap.size()); } } bool contains(const std::string& key) { for (size_t i = 0; i < k; ++i) { size_t hash = std::hash<std::string>{}(key + std::to_string(i)); if (!bitmap.test(hash % bitmap.size())) return false; } return true; // 可能存在(有一定误判率) } }; ``` **2. 应用场景** - **缓存穿透防护**:拦截不存在的数据请求,保护数据库。 - **分布式系统**:减少节点间冗余数据传输。 - **爬虫URL去重**:避免重复抓取已处理的页面[^3]。 **3. 优缺点** - **优点**:空间效率高,查询时间$O(k)$,适合海量数据[^4]。 - **缺点**:误判率随元素增加而上升,且不支持删除(除非引入计数布隆过滤器)。 --- #### 三、对比与总结 | **特性** | **位图** | **布隆过滤器** | |------------------|------------------------------|------------------------------| | **数据范围** | 适用于整数且范围较小 | 支持任意数据类型 | | **误判率** | 无 | 有(可调整哈希函数数量优化) | | **删除支持** | 直接修改位即可 | 需额外结构(如计数位图) | | **典型场景** | 精确存在性判断 | 允许误判的存在性预筛 | **混合优化方案**:结合位图布隆过滤器,例如用位图处理高频数据,布隆过滤器处理低频数据,提升整体性能[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值