【C++】位图

news2025/1/12 12:30:54

文章目录

    • 位图概念
    • 位图操作
    • 位图代码
    • 位图应用

位图概念

boss直接登场:

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

40亿个整数,大概就是16GB。40亿个字节大概就是4GB。

1Byte=8bit
1KB=1024Byte
1MB=1024KB=1024*1024=1048576字节
1GB=1024MB=1024*1048576≈10亿字节,所以4GB约等于40亿字节

1TB=1024GB

如果采用排序+二分的做法来查找:排序要用到数组,要开出16GB大的数组,排在数组里才能进行二分查找,但是这些数组在内存里放不下,所以排序都排不了。那只能放到磁盘上,那数据在磁盘上就不能用二分了,不支持下标,效率也慢

如果用红黑树和哈希表:数组都存放不下,红黑树和哈希表更不用说了,红黑树三叉链结构+颜色,消耗更大,哈希表也有消耗:存放_next指针,负载因子等问题,内存放不下。

下面,我们解决这个问题的方法是位图

这个问题是在不在的问题,是key的模型,那我们可以标记在还是不在,我们只需要一个比特位就可以标记在还是不在

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在

image-20230301231054082

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

image-20230301232501497


位图操作

位图核心的三个操作是setresettest

set是将x对应的比特位置设为1,reset是将x对应的比特位置设为0,test用来查看x在不在

set将对应的比特位置设为1:_bits[i]|=(1<<j)

reset将对应的比特位置设为0:_bits[i]&=(~(1<<j))

test查看x在或不在:_bits[i]&(1<<j)

image-20230302075736347

        void set(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_bits[i] |= (1 << j);
		}

		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_bits[i] &= (~(1 << j));
		}

		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			return _bits[i] & (1 << j);
		}

位图代码

#pragma once
#include <iostream>
#include <vector>
using namespace std;

namespace hwc
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_bits.resize(N/8+1, 0);
		}
		void set(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_bits[i] |= (1 << j);
		}

		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_bits[i] &= (~(1 << j));
		}

		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			return _bits[i] & (1 << j);
		}
	private:
		vector<char> _bits;
	};

	void test_bitset()
	{
		//bitset<100> bs1;
		//bitset<-1> bs2;//
		bitset<0xffffffff> bs2;
		bs2.set(10);
		bs2.set(20);
		bs2.set(3000);
		cout << bs2.test(10) << endl;
		cout << bs2.test(20) << endl;
		cout << bs2.test(3000) << endl;
		cout << bs2.test(666) << endl;
		cout << bs2.test(777) << endl << endl;
		bs2.reset(20);
		bs2.set(666);
		cout << bs2.test(10) << endl;
		cout << bs2.test(20) << endl;
		cout << bs2.test(3000) << endl;
		cout << bs2.test(666) << endl;
		cout << bs2.test(777) << endl;
	}
}

image-20230302112710583

小细节:(-1)的size_t类型

实际上,库里面也有位图:

image-20230302112316139


位图应用

\1. 快速查找某个数据是否在一个集合中
\2. 排序
\3. 求两个集合的交集、并集等
\4. 操作系统中磁盘块标记

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

100亿个数字找到只出现一次的整数,这是KV模型的统计次数,数字有三种状态:0次、1次、1次以上,。这三种状态需要用两个比特位就可以表示,分别位00代表0次,01代表1次,10代表1次以上既可以。我们可以采用两个位图来实现,复用上面所实现的位图即可解决问题

image-20230302120058914

template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			if (!_bs1.test(x) && !_bs2.test(x))//00
			{
				_bs2.set(x);//01
			}
			else if (!_bs1.test(x) && _bs2.test(x))//01
			{
				_bs1.set(x);
				_bs2.reset(x);//10
			}
			//10不变
		}
		void PrintOnce()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if (!_bs1.test(i) && _bs2.test(i))
				{
					cout << i << endl;
				}
			}
			cout << endl;
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

	void test_twobitset()
	{
		twobitset<100> tbs;
		int a[] = { 2,3,4,56,99,55,3,3,2,2,10 };
		for (auto e : a)
		{
			tbs.set(e);
		}
		tbs.PrintOnce();
	}

image-20230302122230391

给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

image-20230302171724233

1 个文件有 100 亿个 int,1G内存,设计算法找到出现次数不超过2次的所有整数

这与上面的类似,多判断一次把10->11,最后找不超过两次的整数

image-20230302173221304

给一个超过100G大小的log file,log中存着IP地址,设计算法找到出现次数最多的IP地址

统计次数自然是要map的,map有附带消耗,三叉链。位图只能判断在不在。所以还是要用map统计的:

我们可以把整个文件通过哈希切分成小的文件,然后去进行统计次数,但是如果小的文件超过1G,说明了这个小文件有两种情况:

1.这个小文件冲突的ip很多,但都是不同的ip,map统计不下------->map的insert插入失败,没有内存,相当于new节点失败,new失败会抛出异常

2.这个肖文杰冲突的ip很多,大多都是相同的ip,map可以统计-------->直接用map统计,可以统计,不会报错

image-20230303073530302

位图特点:位图只能处理整形。采用位图标记字符串时,必须先将字符串转化为整形的数字,找到位图对应的比特位置

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

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

相关文章

sklearn中的降维算法PCA和SVD

目录 一.维度 二.sklearn中的降维算法 三.PCA与SVD 四.降维的实现 五.重要参数n_components 1.累积可解释方差贡献率曲线选择n_components 2.最大似然估计自选超参数 3.按信息量占比选超参数 六.PCA中的SVD 七.重要参数svd_solver 与 random_state 八.重要属性compon…

FormData同时传输多个文件和其他数据

近日有个需求是&#xff1a;在web的对话框中&#xff0c;用户可以输入文本内容和上传附件&#xff0c;附件的数量不限&#xff0c;所有附件总和大小不超过20M。 这个实现的方法不止一种&#xff0c;比如之前的后端同事是要求&#xff1a;文件和文本分开传输&#xff0c;文件用…

程序员的上帝视角(2)——我所体悟的思维方式

心外无物仍然记得在高中阶段&#xff0c;总是为了没有解题思路而苦恼。现在回想起来&#xff0c;总算有点感悟——执着于做题、刷题&#xff0c;却忽视了最本质的思考&#xff0c;为什么可以有这样的解题思路&#xff0c;别人是如何想到这种解题思路的。这正是心学所提倡的&…

189、【动态规划】leetcode ——312. 戳气球(C++版本)

题目描述 原题链接&#xff1a;312. 戳气球 解题思路 &#xff08;1&#xff09;回溯法 很多求最值实际上就是穷举所有情况&#xff0c;对比找出最值。因为不同的戳气球顺序会产生不一样的结果&#xff0c;所以实际上这就是一个全排列问题。 class Solution { public:int r…

linux shell 入门学习笔记18 函数开发

概念 函数就是将你需要执行的shell命令组合起来&#xff0c;组成一个函数体。一个完整的函数包括函数头和函数体&#xff0c;其中函数名就是函数的名字。 优点 将相同的程序&#xff0c;定义&#xff0c;封装为一个函数&#xff0c;能减少程序的代码数量&#xff0c;提高开发…

新:DlhSoft Gantt Chart for WPF Crack

用于 Silverlight/WPF 4.3.48 的 DlhSoft 甘特图灯光库 改进甘特图、网络图和 PERT 图表组件的 PERT 关键路径算法。2023 年 3 月 2 日 - 17:09新版本特征 改进了甘特图、网络图和 PERT 图表组件的 PERT 关键路径算法。Silverlight/WPF 标准版的 DlhSoft 甘特图灯光库 DlhSoft …

精选博客系列|面向公共安全的SD-WAN Edge:刷新VMware边缘计算栈

在巴塞罗那举行的 2023 世界移动通信大会上&#xff0c;VMware 展台展示了配备小型加固 SD-WAN 设备、搭配用于自动车牌识别等应用的 Jenoptik 软件的特斯拉汽车。VMware SD-WAN 能够在车队中创建移动办公室&#xff0c;实现安全的移动通信和实时边缘计算。 萨里和苏塞克斯警方…

如何做好固定资产管理?易点易动高能解决方案来了

企业固定资产管理一直以来都是企业开源节流的重中之重。在当前的数字化时代中&#xff0c;固定资产需要数字化支撑&#xff0c;实现固定资产的有序、科学管理&#xff0c;以便尽可能实现物尽其用&#xff0c;让处于高速发展期中的企业节约在固定资产上的投入成本。 如何做好固…

B站的多个视频教程,怎样生成一个二维码?

商业插画视频教程、电商运营视频教程、在线网课视频、舞蹈视频教程、摄影视频教程、语言学习教程、纪录片视频…所有你发布在哔哩哔哩上的视频&#xff0c;都可以放在一个二维码里面。 任何人只要扫描这个二维码&#xff0c;就能在线观看你的这些视频教程&#xff01;分享起来…

渗透测试之地基服务篇:无线攻防之钓鱼无线攻击(上)

简介 渗透测试-地基篇 该篇章目的是重新牢固地基&#xff0c;加强每日训练操作的笔记&#xff0c;在记录地基笔记中会有很多跳跃性思维的操作和方式方法&#xff0c;望大家能共同加油学到东西。 请注意 &#xff1a; 本文仅用于技术讨论与研究&#xff0c;对于所有笔记中复现…

【Spring6】| Bean的作用域

目录 一&#xff1a;Bean的作用域 1. singleton&#xff08;单例&#xff09; 2. prototype&#xff08;多例&#xff09; 3. 其它scope 4. 自定义scop&#xff08;了解&#xff09; 一&#xff1a;Bean的作用域 1. singleton&#xff08;单例&#xff09; &#xff08;1…

【机器学习】TP TN FP FN及IoU的关系

TP&#xff08;True Positives&#xff09;&#xff1a; 真的正样本 【正样本 被正确分为 正样本】TN&#xff08;True Negatives&#xff09;&#xff1a; 真的负样本 【负样本 被正确分为 负样本】FP&#xff08;False Positives&#xff09;&#xff1a; 假的正样本 【负…

我做测试的3次能力飞跃,让我直接进了字节

回顾我从小公司到字节的成长路径&#xff0c;基本上是伴随着“3次能力飞跃”实现的。 第一家入职的时候是一家小公司&#xff0c;当然我也想直接去字节&#xff0c;可惜自己能力不足。 刚开始入行的时候&#xff0c;什么也不懂&#xff0c;就是从最简单的手工测试做起。每天做…

想开发IM集群?先搞懂什么是RPC!

即时通讯网官方技术群和社区里&#xff0c;经常有开发者在纠结怎么开发IM集群&#xff0c;虽然真正的使用人数&#xff0c;可能用个人电脑单机都能支撑。你也许会说&#xff0c;明明不需要用到IM集群&#xff0c;干吗要自找麻烦&#xff1f;答曰&#xff1a;“老板说这个得有&a…

I.MX6ULL内核开发0:linux内核模块

目录 简要 一、内核模块的概念 二、内核模块加载、卸载过程 简要 1、内核模块的概念 2、内核模块的原理&#xff1a;内核模块在内核的加载、卸载过程。 一、内核模块的概念 内核&#xff0c;是一个操作系统的核心。是基于硬件的第一层软件扩充&#xff0c;提供操作系统的最…

Prim和Kruskal的区别?哪个好?

Prim和Kruskal有啥区别&#xff1f;到底哪个好&#xff1f; 今天做了一道最小生成树的题&#xff0c;发现了一点猫腻&#xff01; 题目在这里 &#xff1a; 《修路问题1》 文章目录Prim和Kruskal有啥区别&#xff1f;到底哪个好&#xff1f;先说结论PrimKruskal修路问题1——…

EPICS Phoebus手册1

1、介绍 Phoebus是一个控制系统Stdio工具集的更新&#xff0c;它移除了对Eclipse RCP和SWT的依赖。 虽然Eclipse RCP快速启动了原先的CS-Studio的实现&#xff0c;并且为CS-Stdio也提供了大约十年的服务&#xff0c;因为RCP也增加了对控制系统用户接口开发的限制。 Phoebus项目…

【Spring源码】AOP的开端:核心对象创建的准备工作

AOP的核心成员是如何被被加载的&#xff1f;本篇我们主要分析使用xml的逻辑&#xff0c;如果使用注解&#xff0c;增加注解处理类即可&#xff08;ConfigurationClassPostProcessor&#xff09;拿之前分析循环的时候举的例子&#x1f330;&#xff0c;它的日志切面就是通过xml进…

119.(leaflet篇)文字碰撞

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

如何从 Android 手机上的 SD 卡恢复已删除的照片

为了扩展手机的存储空间&#xff0c;很多人都会在安卓手机上插入一张SD卡来存储一些大文件&#xff0c;比如电影、照片、视频等。虽然SD卡给我们带来了很大的方便&#xff0c;但我们还是避免不了数据丢失一些事故造成的。您是否正在为 SD 卡上的照片意外丢失而苦恼&#xff1f;…