位图原理及实现

news2025/2/23 11:55:56

位图原理及实现

  • 位图概念
  • 位图实现
    • 构造函数
    • set成员函数
    • reset成员函数
    • test成员函数
  • 位图的应用

位图概念

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

对于上面这道题大多数人都会想到用遍历和二分查找的方法去解决,但是会存在一个问题,40亿个unsigned int类型的整数,所占内存空间大约在16G左右了,这样大的空间内存当中是放不下的,那么应该怎么办呢?

我们可以用位图来解决这个问题:

我们会发现无符号整数有2^ 32 个,而我们如果以bit位来计量的话,就只需要 2^32个bit位,也就是512MB的空间,内存当中是可以进行存储的,那么我们该如何进行操作呢?

我们需要判断的是一个数在不在,我们就假设存在bit位就是1,不存在bit位就是0,我们以char类型来进行划分,一个char类型数据就占8个bit位,如下图所示:
在这里插入图片描述

位图实现

构造函数

一个char类型型有8个比特位,因此N个位的位图就需要用到N/8个,但是实际我们所需的整型个数是N/8+1,因为所给非类型模板参数N的值可能并不是8的整数倍。

例如:N=27,N/8+1 = 3+1 = 4;
在这里插入图片描述

template<size_t N>
class bitset
{
public:
	//构造函数
	bitset()
	{
		_bits.resize(N / 8 + 1, 0);
	}

private:
	vector<char> _bits;
};

set成员函数

set成员函数用于设置位,设置位的方法如下:

  1. 计算 x 位所在的第 i 个位置所占的第 j 个bit位;
  2. 将1左移 j 位后与第 i 个位置进行 | 运算即可;
    在这里插入图片描述
void set(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;
	//计算x位所在的第i个位置所占的第j个bit位

	_bits[i] |= (1 << j);
	//将该设置为1 
}

reset成员函数

reset成员函数用于清空位,清空位方法如下:

  1. 计算 x 位所在的第 i 个位置所占的第 j 个bit位;
  2. 将1左移 j 位再按位取反后与第 i 个位置进行 & 运算即可。
    在这里插入图片描述
void reset(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;
	//计算x位所在的第i个位置所占的第j个bit位

	_bits[i] &= ~(1 << j);
	//将该设置为0
}

test成员函数

test成员函数用于获取位的状态,方法如下:

  1. 计算x位所在的第 i 个位置所占的第 j 个bit位;
  2. 将1左移 j 位后与第 i 个位置进行 & 运算得出结果。
  3. 若结果非0,则该位被设置,否则该位未被设置。
    在这里插入图片描述
bool test(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;
	//计算x位所在的第i个位置所占的第j个bit位

	return _bits[i] = (1 << j);
}

位图的应用

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

我们来看几道题目:

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

我们可以将整数标记为3种状态:

  • 出现0次;
  • 出现1次;
  • 出现2次或者2次以上。

一个位只能表示两种状态,而要表示三种状态我们至少需要用两个位,因此我们可以开辟两个位图,这两个位图的对应位置分别表示该位置整数的第一个位和第二个位。

我们可以将着三种状态分别定义为00、01、10,此时当我们读取到重复的整数时,就可以让其对应的两个位按照00→01→10的顺序进行变化,最后状态是01的整数就是只出现一次的整数。

template<size_t N>
class twobitset
{
public:
	void set(size_t x)
	{
		bool insert1 = bt1.test(x);
		bool insert2 = bt2.test(x);
		
		//00
		if (insert1 == false && insert2 == false)
		{
			//->01
			bt2.set(x);
		}
		else if (insert1 == false && insert2 == true)
		{
			//->10
			bt1.set(x);
			bt2.reset(x);
		}
	}

	void print_once_num()
	{
		for (size_t i = 0; i < N; i++)
		{
			if (bt1.test(i) == false && bt2.test(i) == true)
			{
				cout << i << endl;
			}
		}
	}
private:
	bitset<N> bt1;
	bitset<N> bt2;
};
  1. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件的交集?

方案一:(一个位图需要512M内存)

  • 依次读取第一个文件中的所有整数,将其映射到一个位图。
  • 再读取另一个文件中的所有整数,判断在不在位图中,在就是交集,不在就不是交集。

方案二:(两个位图刚好需要1G内存,满足要求)

  • 依次读取第一个文件中的所有整数,将其映射到位图1。
  • 依次读取另一个文件中的所有整数,将其映射到位图2。
  • 将位图1和位图2进行与操作,结果存储在位图1中,此时位图1当中映射的整数就是两个文件的交集。
  1. 一个文件有100亿个整数,1G内存,设计算法找到出现次数不超过2次的所有整数。

该题跟题目一的做法一样,我们将数据标记为4种状态:

  • 出现0次。
  • 出现1次。
  • 出现2次。
  • 出现2次以上。
template<size_t N>
class twobitset
{
public:
	void set(size_t x)
	{
		bool insert1 = bt1.test(x);
		bool insert2 = bt2.test(x);
		
		//00
		if (insert1 == false && insert2 == false)
		{
			//->01
			bt2.set(x);
		}
		else if (insert1 == false && insert2 == true)
		{
			//->10
			bt1.set(x);
			bt2.reset(x);
		}
		else if (insert1 == true && insert2 == true)
		{
			//->11
			bt1.set(x);
			bt2.set(x);
		}
	}
	void print_twice_num()
	{
		for (size_t i = 0; i < N; i++)
		{
			if ((bt1.test(i) == false && bt2.test(i) == true) || (bt1.test(i) ==true && bt2.test(i) == true))
			{
				cout << i << endl;
			}
		}
	}
private:
	bitset<N> bt1;
	bitset<N> bt2;
};

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

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

相关文章

什么是Webpack的Tree Shaking?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Webpack的Tree Shaking⭐ 作用和原理⭐ 使用 Tree Shaking⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感…

2023年免疫细胞治疗行业研究报告

第一章 行业概况 1.1 定义及分类 免疫细胞治疗是细胞治疗的一种重要分支&#xff0c;它涉及对免疫细胞进行体外操作&#xff0c;然后将其回输到人体内&#xff0c;以实现对肿瘤细胞的杀伤或清除病毒等功能。这种治疗方法的核心是利用免疫细胞的自然功能&#xff0c;通过体外技…

【构造函数和原型】

构造函数和原型 1 本节目标2 构造函数和原型2.1 概述2.2 构造函数2.3 构造函数的问题2.4 构造函数原型prototype2.5 对象原型__proto__2.6 constructor构造函数2.7 构造函数、实例、原型对象三者之间的关系2.8 原型链2.9 JavaScript的成员查找机制(规则)2.10 原型对象this指向2…

Qt UDP传送图片

Qt UDP传送图片&#xff0c;server发送&#xff0c;client接收。 server #include "mainwindow.h" #include "ui_mainwindow.h" #include <QTime> #include <QPainter>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new…

求解灰度直方图,如何绘制灰度直方图(数字图像处理大题复习 P1)

文章目录 1. 画 X 轴2. 画直方图3. Complete 视频原链接 数字图像处理期末考试大题 B站链接 1. 画 X 轴 2. 画直方图 有几个 0 就在图上画多高&#xff0c;同理有几个 1 &#xff0c;X1 的地方就画多高 3. Complete 这里的情况比较平均&#xff0c;一般来说不会这么平均&a…

element -ui table表格内容无限滚动 使用插件vue-seamless-scroll

使用插件 一、安装组件依赖 npm install vue-seamless-scroll 二、引入组件 import vueSeamlessScroll from "vue-seamless-scroll"; components: { vueSeamlessScroll }, <div class"table-list "><vue-seamless-scroll :class-option"…

JavaWeb概念视频笔记

学习地址&#xff1a;102.尚硅谷_Tomcat-Tomcat服务器和Servlet版本的对应关系_哔哩哔哩_bilibili 目录 1.JavaWeb的概念 2.Web资源的分类 3.常用的Web服务器 4.Tomcat服务器和Servlet版本的对应关系 5.Tomcat的使用 a.安装 b.目录介绍 c.如何启动 Tomcat 服务器 另一…

【C语言】指针和数组笔试题解析(1)

指针是C语言的灵魂&#xff0c;他的玩法多种多样&#xff0c;这篇文章带来指针的笔试题详解&#xff0c;可以帮助我们更好的理解与巩固指针的知识 目录 预备知识&#xff1a;题目&#xff1a;一维数组&#xff1a;二维数组&#xff1a; 题目比较多&#xff0c;但切记戒骄戒躁&a…

Selenium常用操作之单选复选框、下拉列表、键盘、截屏、断言、(显式隐式)等待

目录 1. 窗口最大化 2.单选框操作 3. 复选框操作 4. 下拉列表 5. selenium 三种等待 6. 键盘操作 7.截屏 8.断言 9. Selenium操作JS弹窗控件 10.鼠标悬停与释放 1. 窗口最大化 driver.maximize_window() 2.单选框操作 driver.find_element_by_xpath("//input[…

Hdoop伪分布式集群搭建

文章目录 Hadoop安装部署前言1.环境2.步骤3.效果图 具体步骤&#xff08;一&#xff09;前期准备&#xff08;1&#xff09;ping外网&#xff08;2&#xff09;配置主机名&#xff08;3&#xff09;配置时钟同步&#xff08;4&#xff09;关闭防火墙 &#xff08;二&#xff09…

Linux学习第13天:嵌入式LinuxLED驱动开发:一字一符总见情

在正式写这篇笔记前&#xff0c;有一个事情必须要说一下。昨天更新的基于API函数的字符设备驱动开发按照正常的教程来说应该在本笔记后一天更新才对。但是由于我一时的疏忽&#xff0c;跳过了本笔记。在昨天学习基于API函数的时候造成了一定程度的困扰。今天重翻教程的时候才发…

burp+IE 微信小程序抓包教程

文章目录 一、BURP里新增监听端口二、BURP导出证书三、导入证书四、IE代理设置五、小程序抓包实际测试 一、BURP里新增监听端口 找一个没用的端口&#xff0c;使用以下方式新增 二、BURP导出证书 选择刚才新增的监听端口&#xff0c;点击证书导入导出 将其存出来即可&…

Maven知识点总结

Maven 基础课程第一天 第1章 Maven 介绍 1.1什么是 Maven 1.1.1什么是 Maven Maven 的正确发音是[ˈmevən]&#xff0c;而不是“马瘟”以及其他什么瘟。Maven 在美国是一个口语化的词语&#xff0c;代表专家、内行的意思。 一个对Maven 比较正式的定义是这么说的&#xff1…

notepad++ 配置 python 以及Anaconda中的python(已解决)

说明&#xff0c;无论是自己的电脑单独安装的python 还是Anaconda虚拟环境安装的python都是一样的。区别就是 独立安装的python 的exe文件路径添加的环境变量了&#xff0c;不需要制定它的路径直接运行下面的命令就可以&#xff0c;而Anaconda中的python.exe的文件夹并没有在虚…

endnotes插入文献突然变得格式不对,而且也不是按照正常的顺序来插入解决办法

今天插入文献突然变成了endnotes里面的文献序号&#xff0c;而且也不导入了&#xff0c;多了作者和序号信息 解决办法&#xff1a; 更新一下&#xff0c;然后在进行的导入就ok了&#xff0c;能够按照以前的格式插入了&#xff0c;序号也能自动排开&#xff0c;而且也能导入文献…

从CNN(卷积神经网络),又名CAM获取热图

一、说明 卷积神经网络&#xff08;CNN&#xff09;令人难以置信。如果你想知道它如何看待世界&#xff08;图像&#xff09;&#xff0c;有一种方法是可视化它。 这个想法是&#xff0c;我们从最后的密集层中得到权重&#xff0c;然后乘以最终的CNN层。这需要全局平均…

想要精通算法和SQL的成长之路 - 戳气球

想要精通算法和SQL的成长之路 - 戳气球 前言一. 戳气球1.1 记忆化搜索 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 戳气球 原题链接 首先我们看一下题干&#xff1a;对于超出了数组边界的&#xff0c;就当做它是一个数字为1的气球。遇到这种的&#xff0c;我们可以考…

论文解读-DeepEdit:使用纳米孔直接RNA测序对A - to - I RNA编辑事件进行单分子检测和阶段划分

DOI&#xff1a; 10.1186/s13059-023-02921-0 期刊 &#xff1a;Genome Biology 中科院分区&#xff1a;1Q 影像因子&#xff1a;12.3 作者 Longxian Chen; Liang Ou; Xinyun Jing; Yawei Kong; Bingran Xie; et al 出版日期 2023-04-17 网址&#xff1a; https://genome…

Jetpack系列 -- LiveData源码原理解析(解决黏性问题)

一、LiveData是什么&#xff1f; 注意&#xff1a;一般情况下&#xff0c;LiveData要配合ViewModel一起使用的&#xff0c;但是今天是单独使用LiveData&#xff0c;作为学习的话&#xff0c;我们可以只关注LiveData了。 LiveData是一种可观察的数据存储器类。与常规的可观察类…

python-保留小数位数的3种方法

在python实际运用中&#xff0c;需要对小数位数进行截取保留。 以下是&#xff0c;python保留小数点位数的3种方法。 方法一 方法&#xff1a;’%.nf’ % num n代表保留的小数位数&#xff0c;num表示需要截取的目标数 用法如下&#xff1a; old_num 1.23456 new_num %.2f…