数据结构 - 位图 | 布隆过滤器

news2024/12/23 15:31:53

文章目录

    • 一、位图
      • 1、位图概念
      • 2、实现一个简略的位
      • 3、位图的优缺点
      • 4、位图的应用场景
    • 二、布隆过滤器
      • 1、提出
      • 2、概念
      • 3、布隆过滤器的实现
    • 三、海量数据处理
      • 1、哈希切割
      • 2、面试题


一、位图

1、位图概念

位图(Bitmap)是一种非常高效的数据结构,主要用于快速查找、去重、排序等操作,特别是在处理大数据集时非常有用。它通过将数据集合中的每个元素映射到一个二进制位(bit)上来工作,每个位表示集合中是否存在该元素。

2、实现一个简略的位


(1)准备
在这里插入图片描述
(2)将pos值映射的位置置为1
在这里插入图片描述

(3)将pos值映射的位置置为0
在这里插入图片描述
(4)判断pos是否存在
在这里插入图片描述
(5)代码实现

template <size_t N = 10>
class bitset
{
	
public:
	bitset()
	{
		_set.resize((N/32+1), 0);
	}

	//pos位置的值是否存在
	bool test(size_t pos) const
	{
		int x = pos / 32;
		int y = pos % 32;

		return (_set[x] & (1 << y));
	}
	
	//将pos位置置1
	bitset& set(size_t pos)
	{
		int x = pos / 32;
		int y = pos % 32;

		_set[x] |= (1 << y);

		return *this;
	}

	//将pos位置置0
	bitset& reset(size_t pos)
	{
		int x = pos / 32;
		int y = pos % 32;

		_set[x] &= (~(1 << y));

		return *this;
	}

private:
	vector<int> _set;
};

(6)测试

void test_bitste()
{
	bitset<100000> bs;
	
	//储存一万个元素
	int arr[10000] = { 0 };
	for (int i = 1; i < 10000; i++)
	{
		arr[i] = rand() % 10000 + i;
	}

	//将一万个元素置为1
	for (auto& e : arr)
	{
		bs.set(e);
	}

	//判断这些元素是否都存在
	for (auto& e : arr)
	{
		if (bs.test(e))	cout << "OK" << endl;
		//出错直接终止程序
		else assert(false);
	}

	//将元素全部删除
	for (auto& e : arr)
	{
		bs.reset(e);

		//如果还存在直接终止程序
		if (!bs.test(e))	cout << "OK" << endl;
		else	assert(false);
	}
}

在这里插入图片描述

3、位图的优缺点

(1)优点

空间效率高:由于每个元素只需要一个bit来表示,因此空间占用非常小。
查询速度快:由于是直接通过索引访问位数组,所以查询某个元素是否存在的时间复杂度为O(1)。

(2)缺点

内存占用:虽然位图的空间效率很高,但当数据集非常大时,位向量可能会占用大量的内存。
元素范围:位图通常适用于元素值为连续整数的情况。如果元素值范围很大但实际值很稀疏,那么位图可能会浪费大量的空间。
扩展性:当元素值范围超出预期时,可能需要重新分配位向量,这可能会导致性能下降。

4、位图的应用场景

快速去重:处理大量数据时,可以快速判断一个数据是否已经出现过。
数据排序:通过位图可以快速统计出每个元素的频率,然后据此进行排序。
数据压缩:对于只有两种状态的数据(如布尔值),使用位图可以极大地减少存储空间。
数据库索引:在数据库中,位图索引用于提高查询效率,特别是当查询条件为“是否包含”时。

二、布隆过滤器

1、提出

我们在使用新闻客户端看新闻时,它会给我们不停地推荐新的内容,它每次推荐时要去重,去掉
那些已经看过的内容。问题来了,新闻客户端推荐系统如何实现推送去重的? 用服务器记录了用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录里进行筛选,过滤掉那 些已经存在的记录。 如何快速查找呢?

  1. 用哈希表存储用户记录,缺点:浪费空间
  2. 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理 了。
  3. 将哈希与位图结合,即布隆过滤器

2、概念

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

在这里插入图片描述

3、布隆过滤器的实现

(1)位图设置多大?
布隆过滤器(Bloom Filter)设计中位图(BitMap)的大小设计并不是固定不变的,而是根据具体的应用场景和需求来决定的。

这里假设:插入的元素个数n,哈希函数个数k, 那么我们可以设置位图大小为n*k。

(1)插入
在这里插入图片描述

(2)查找

布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中。
注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可 能存在,因为有些哈希函数存在一定的误判。
比如:在布隆过滤器中查找"alibaba"时,假设3个哈希函数计算的哈希值为:1、7,10刚好和其他元素的比特位重叠,此时布隆过滤器告诉该元素存在,但实该元素是不存在的。

(3)删除
布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。
在这里插入图片描述
但是也可以通过一些办法来实现删除操作:

计数器布隆过滤器(Counting Bloom Filter):
计数器布隆过滤器是对传统布隆过滤器的一种扩展,它将位数组中的每个位扩展为一个小的计数器。当插入元素时,对应的k个计数器(k为哈希函数的数量)增加1;当删除元素时,对应的计数器减少1。这样,即使某个位置被多个元素共享,也能通过减少计数器的值来模拟删除操作。然而,这种方法需要更多的存储空间,并且存在计数回绕(counter overflow)的风险。
使用额外的数据结构:
如果删除操作不是非常频繁,且可以接受一定的性能开销,可以考虑在布隆过滤器之外维护一个额外的数据结构(如哈希表)来记录需要删除的元素。在查询元素时,先检查这个额外的数据结构,如果元素在其中,则认为元素不存在于布隆过滤器中,即使布隆过滤器可能误判其存在。这种方法虽然可以模拟删除操作,但会增加额外的存储和查询开销,并且需要定期清理或同步这两个数据结构以保持一致性。
重新构建布隆过滤器:
对于需要频繁删除操作的应用场景,如果元素的数量不是非常大,可以考虑在删除操作较多时重新构建布隆过滤器。即,将当前所有需要保留的元素重新插入到一个新的布隆过滤器中,并丢弃旧的布隆过滤器。这种方法可以彻底清除不再需要的元素,但需要重新计算哈希值和构建位数组,可能会带来较大的性能开销。

(4)简略实现

//哈希函数
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;
	}
};

template<size_t N,
	size_t K = 3,
	class V = string,
	class HashFunc1 = BKDRHash,
	class HashFunc2 = APHash,
	class HashFunc3 = DJBHash>
class BloomFilter
{
public:
	//置为1
	void set(const V& s)
	{
		//求出哈希值
		int hash1 = HashFunc1()(s) % (N * K);
		int hash2 = HashFunc2()(s) % (N * K);
		int hash3 = HashFunc3()(s) % (N * K);

		//将哈希值的映射位置置为1
		_set.set(hash1);
		_set.set(hash2);
		_set.set(hash3);
	}

	//是否存在
	bool test(const  V& s)
	{
		//求出哈希值
		int hash1 = HashFunc1()(s) % (N * K);
		int hash2 = HashFunc2()(s) % (N * K);
		int hash3 = HashFunc3()(s) % (N * K);

		//只要有一个不存在就判断为不存在  -- 可能存在误判
		return _set.test(hash1) && _set.test(hash2) && _set.test(hash3);
	}

private:
	//位图
	bitset<N* K> _set;
};

(5)优缺点

优点

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

缺点

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再 建立一个白名单,存储可能会误判的数据)
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕问题

(6)使用场景

  1. 缓存穿透保护 在使用Redis等缓存系统时,用户可能查询大量不在缓存中的数据,导致这些请求直接穿透到数据库,给数据库造成巨大压力。布隆过滤器可以用于提前判断一个元素是否存在于缓存中,如果不存在,则直接返回,避免了对数据库的无效查询。这种方式可以显著降低数据库的访问压力,保护系统免受缓存穿透的影响。

  2. 网页爬虫URL去重 在爬虫系统中,为了避免重复爬取相同的URL地址,通常会使用集合(如HashSet)来存储已经爬取过的URL。然而,当URL数量非常庞大时,集合会占用大量的内存空间。布隆过滤器提供了一种更为节省空间的方法,它允许爬虫系统以较低的误判率快速判断一个URL是否已经被爬取过,从而避免了不必要的重复爬取。

  3. 反垃圾邮件 在反垃圾邮件系统中,布隆过滤器可以用于判断一个邮箱地址是否存在于垃圾邮件列表中。由于垃圾邮件列表可能包含数亿个邮箱地址,使用传统的数据结构会占用大量的内存和存储空间。而布隆过滤器通过其高效的插入和查询性能,可以在较低误判率的前提下,实现对垃圾邮件列表的快速检索。

  4. 数据库查询优化 在数据库查询中,布隆过滤器可以用于过滤掉大量不存在的数据行,从而减少对磁盘的访问次数,提高查询效率。例如,在NoSQL数据库中,可以使用布隆过滤器在内存中快速判断某个row是否存在于数据库中,如果不存在,则无需进一步访问磁盘进行查询。

  5. 网络安全 在网络安全领域,布隆过滤器可以用于识别恶意IP地址、URL等。通过将已知的恶意实体加入到布隆过滤器中,系统可以快速判断一个请求是否来自恶意实体,从而采取相应的安全措施。

  6. 推荐系统 在推荐系统中,布隆过滤器可以用于过滤掉用户已经阅读或观看过的内容,确保推荐的内容是新颖的。虽然布隆过滤器存在一定的误判率,但在大多数情况下,这种误判是可以接受的,因为它能够显著降低系统的计算复杂度和存储需求。

  7. 消息队列去重 在消息队列中,为了防止消息重复消费,可以使用布隆过滤器对消息的key进行去重。当消息发送时,将消息的key加入到布隆过滤器中;当消息消费时,先检查消息的key是否存在于布隆过滤器中,如果存在,则认为是重复消息,进行相应处理。

三、海量数据处理

1、哈希切割

哈希切割通过哈希函数将大数据集中的每个元素映射到一个较小的、有限的值域范围内,通常是整数集合。这个映射过程可以使得具有相同哈希值的元素被分配到同一个集合或文件中,所以相同的元素一定会被分到一组,而不同哈希值的元素则被分配到不同的集合或文件中,。由于哈希函数的性质,不同的输入可能产生相同的输出(即哈希冲突),但在实际应用中,这种冲突可以通过合理设计哈希函数和分配策略来减少其影响。如:有100g储存ip地址的文件,我们只有1个g的内存,此时我们需要用哈希函数将大文件分割为500个小文件,再进行处理。

在这里插入图片描述

2、面试题

(1)给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?
与上题条件相同,如何找到top K的IP?
在这里插入图片描述
(2)1. 给定100亿个整数,设计算法找到只出现一次的整数?
在这里插入图片描述
(3)给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
在这里插入图片描述
(4) 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数。
在这里插入图片描述
(5) 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2036575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ocr识别003】flask+paddleocr+bootstrap搭建OCR文本推理WEB服务

1.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 2.了解、学习OCR相关技术知识领域&#xff0c;结合日常的场景进行测试、总结。如本文总结的flaskpaddleocrbootstrap搭建OCR文本推理WEB服务应用示例场景。 文章目录 1.代码结构2.效果演…

【算法】梯度下降

一、引言 梯度下降算法&#xff08;Gradient Descent&#xff09;是一种一阶迭代优化算法&#xff0c;用于求解最小化目标函数的问题&#xff0c;广泛应用于机器学习和人工智能中的参数优化。 用于优化问题的迭代算法&#xff0c;尤其在机器学习和深度学习中广泛用于最小化损失…

EMQX Platform Snowflake:构建可再生分布式能源的智慧未来

引言 可再生能源如风力和太阳能发电&#xff0c;具有低成本和环保的特性&#xff0c;是未来能源供应的主要方向。然而&#xff0c;这类发电方式存在供应分散、设备数量多、地区分布广等特点。再加上不同地区的季节和天气变化&#xff0c;不确定性极大。 随着社会用电需求的持…

11 Radiobutton组件

11 Radiobutton组件 Tkinter 是 Python 的标准图形用户界面库&#xff0c;它提供了一个 Radiobutton 控件&#xff0c;用于在一组选项中让用户选择一个选项。Radiobutton 通常用于提供一组互斥的选项&#xff0c;用户只能选择其中一个。 Radiobutton 组件基础 Radiobutton 控…

CMake详解-捡重要的讲

CMake 通常我们使用cmake构建C++项目,其实就是编写CMakeLists.txt文件,过程如下 首先在创建项目名称,我这里是CMake文件夹,在路径下创建CMakeLists.txt文件,也就是在工作空间的目录下创建,具体有几个要素要设置 CMake最低版本要求项目名称-自定义即可编译方法:Debug或…

html+css+js网页制作 自定义电商10个页面

htmlcssjs网页制作 自定义电商10个页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#…

前端面试题整理-Javascript

JS组成&#xff1a; JS是运行在浏览器的一门编程语言 函数类型&#xff1a; 1. 说说 js 都有哪些数据类型&#xff0c;他们在内存存储上有什么不同 基本数据类型&#xff1a;number、boolean、string、null&#xff08;null就是特殊的object&#xff09;、undefined、Symbo…

循环神经网络三

一.介绍 在普通的神经网络中&#xff0c;信息的传递是单向的&#xff0c;这种限制虽然使得网络变得更容易学习&#xff0c;单在一定程度上也减弱了神经网络模型的能力。特别是在现实生活中&#xff0c;网络的输出不仅和当前时刻的输入相关&#xff0c;也过去一段时间的输出相关…

keepalived搭建与基础配置

目录 1 keepalived部署与环境准备 1.1 Keepalived 实验环境准备 1.2 Keepalived 相关文件 1.3 Keepalived 安装 1.4 KeepAlived 配置说明 1.5 配置语法说明 2 企业应用示例与配置 2.1 主从架构 2.1.1 启用keepalived日志功能 2.1.2 vrrp_iptables 参数 2.1.3 实现独立子配置文件…

python实现模型训练期间定时查询解析GPU资源详细信息,根据实际显存占用量动态启动新模型训练任务

经常要做模型开发训练的人一定对于GPU的查询不会陌生&#xff0c;实例如下&#xff1a; 详情数据如下&#xff1a; Tue Aug 13 16:42:31 2024 ----------------------------------------------------------------------------- | NVIDIA-SMI 450.80.02 Driver Versi…

oracle普通导出导入

原始的普通导出导入工具&#xff0c;是一个客户端工具。使用导出工具&#xff08;export utility简称exp&#xff09;是将数据从oracle数据库以二进制形式写入操作系统文件&#xff0c;这个文件存储在数据库之外&#xff0c;并且可以被另一个数据库使用导入工具&#xff08;imp…

大数据系列之:Flink Doris Connector,实时同步数据到Doris数据库

大数据系列之&#xff1a;Flink Doris Connector&#xff0c;实时同步数据到Doris数据库 一、版本兼容性二、使用三、Flink SQL四、DataStream五、Lookup Join六、配置通用配置项接收器配置项查找Join配置项 七、Doris 和 Flink 列类型映射八、使用Flink CDC访问Doris的示例九、…

Unity协程WaitForSeconds在编辑器和WebGL表现不同问题的解决方法参考

最近做的一个效果让下面为了让下面这种图片生成一个翻页效果&#xff08;使用ShaderGraph中的FlipBook节点&#xff09;&#xff0c;我通过携程来实现连续翻页。 先是定义一个Coroutine coroutine null&#xff1b; 然后在一定情况下执行coroutine StartCoroutine(KeepPrevie…

Spring入门讲解

这里写目录标题 Spring基础概念关键重点主要特性主要优势Spring与Java EE的对比Spring生态系统概述总结 Spring 基础概念 Spring是一个开源的轻量级Java开发框架&#xff0c;它提供了全面的基础设施支持&#xff0c;简化了企业级应用的开发和部署。Spring的核心理念是依赖注入…

基于华为atlas下的yolov5+BoT-SORT/ByteTrack煤矿箕斗状态识别大探索

写在前面&#xff1a; 本项目的代码原型基于yolov5yolov8。其中检测模型使用的yolov5&#xff0c;跟踪模型使用的yolov8。 这里说明以下&#xff0c;为什么不整体都选择yolov8呢&#xff0c;v8无疑是比v5优秀的&#xff0c;但是atlas这块经过不断尝试没有过去&#xff0c;所以…

前端进行分页Vue3+Setup写法

当后端不方便提供数据分页查询接口时&#xff0c;就需要前端来自己分割进行分页操作 在有可能的情况下还是建议用分页查询接口&#xff0c;减少网络数据传输 首先el-table绑定数组 分页组件&#xff0c;变量自己定义防止报错 <el-paginationlayout"->, total, siz…

Springboot实现doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频在线预览功能,你学“废”了吗?

最近工作中&#xff0c;客户需要生成包含动态内容的word/pdf报告&#xff0c;并且需要在线预览。 刚开始使用后台直接生成word文档&#xff0c;返回文件流给前端&#xff0c;浏览器预览会发生格式错乱问题&#xff0c;特别是文档中的图片有些还不显示。 想到最简单的办法就是…

在原生未启用kdump的BCLinux 8系列服务器上启用kdump及报错处理

本文记录了在原生未启用kdump的BCLinux 8系列操作系统的服务器上手动启用kdump服务及报错处理的过程。 一、问题描述 BCLinux 8系列操作系统&#xff0c;系统初始化安装时未启用kdump服务&#xff0c;手动启动时报以下“No memory reserved for crash kernel”或“ConditionK…

数学建模——评价决策类算法(层次分析法、Topsis)

一、层次分析法 概念原理 通过相互比较确定各准则对于目标的权重, 及各方案对于每一准则的权重&#xff0c;这些权重在人的思维过程中通常是定性的, 而在层次分析法中则要给出得到权重的定量方法. 将方案层对准则层的权重及准则层对目标层的权重进行综合, 最终确定方案层对目标…

解读RPA自动化流程机器人

RPA全称Robotic Process Automation&#xff0c;即机器人流程自动化&#xff0c;基于人工智能和自动化技术&#xff0c;能够将大量重复、规则明确的日常事务操作实现自动化处理&#xff0c;通常被形象地称为“数字员工”。本文金智维将深入探讨RPA的主要价值和应用领域&#xf…