位图的详解

目录

位图

位图的概念

位图的实现

位图常见三道面试题

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

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

3. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数.


位图

位图的概念

先来看一下位图的概念

位图 (Bitmap) 是一种基于位操作的数据结构,用于表示一组元素的集合信息。它通常是一个仅包含0和1的数组,其中每个元素对应集合中的一个元素。位图中的每个位(或者可以理解为数组的元素)代表一个元素是否存在于集合中。当元素存在时,对应位的值为1不存在时,对应位的值为0。位图常用于判断某个元素是否属于某个集合,或者对多个集合做交集、并集或差集等集合运算。

可能这么多听起来很复杂,其实总结下来就这个意思:

位图本质是个数组,用来存放0和1。

位图通过自身数组中的每个来代表集合(我们要处理的数据)中的元素,每个是0或1,代表元素的存在与否(0,不存在;1,存在)。

我们先看一下下面的例子:

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

1.首先当然可以遍历这40亿个数,这样效率会太低了,肯定直接pass掉.

2.也可以考虑搜索树或者哈希表,操作之前一定要把数据先存下来构建树或表。但是仔细一想,40亿个数,占多少空间?

40亿个无符号整数,每个大小4个字节,则一共占用160亿字节。

1GB = 1024 MB, 1MB  = 1024KB, 1KB = 1024Byte(字节).

所以一共占用16000000000/1024/1024/1024≈14.9G.

所以要用这些方法的话一上来就占用14.9G的系统内存,大多数电脑是吃不消的,更别说搜索树结点还存其他属性信息,现在内存16G的电脑也不算很多。这肯定不行的.

3.当然还可以存在磁盘上,进行外排序+二分查找。但是想一下,这一切是在磁盘上进行,磁盘的速度可是非常慢的,而且要对这么多数据排序,以及在磁盘上进行二分查找,无论代码还是时间都是复杂和比较慢的.

下一个方法,就是我们大名鼎鼎的位图来解决了,具体是怎么样的呢?

首先,我们要给数组开辟一块空间,这片空间我们开多少呢,要根据数据范围开空间,而不是数据个数。

这个我相信大家都能理解,毕竟如果只有两个数,一个是1,一个数是40亿,按数据个数开两个空间的话只能存下1和2,40亿肯定是存不下的。

所以无符号整型的数据范围是0~2^32-1,所以我们要开这么大的空间.那么一共多大呢?

由于我们是使用比特位进行表示每一个数是否存在的,所以相当于是2^32-1个比特位。由于1byte=8bit.根据上面所说,一共占用(2^32-1)/8/1024/1024/1024=0.5GB=512MB. 

所以我们开好空间以后,我们只需要将数对应的位置为1即可.

比如数据{1,4,9,15,17,23},在位图中是什么样的?

 这样到时候直接判断对应位置是不是1即可判断某个数是否存在.

具体怎么设置,取消,判断看下面。

位图的实现

主要包含三个核心接口:设置(设为1)、重置(设为0)、判断(是0还是1)

对于每一步可以看注释.

#include<iostream>
#include<vector>
using namespace std;namespace hyx
{//N代表数据范围template<size_t N>class bit_set{public:bit_set(){_bits.resize(N / 8 + 1, 0);}void set(size_t x){//由于一个组是char,所以x/8是计算在哪个char组里size_t i = x / 8;//一个char里有8位,x%8是计算出在char组里面的具体哪一位size_t j = x % 8;//这个建议大家画图理解,首先_bits[i]是对应的char组,然后1<<j,其实是将1向左移动了j位,然后再或等,这样就把对应位置上的数置为1了,可以画图理解._bits[i] |= (1 << j);}void reset(size_t x){size_t i = x / 8;size_t j = x % 8;//也是先1向左移动j位,然后再按位取反,此时除了目标位是0,别的位都是1.然后再&上这个数,任何数&1都是它本身,&0都是0.所以此时将目标位设置为0了_bits[i] &= ~(1 << j);}bool test(size_t x){size_t i = x / 8;size_t j = x % 8;//任何数&1都是它本身,因为我们可以利用这一点来判断目标位是0还是1.//注意此时不再需要加等于号了,因为这是判断,不是修改。return _bits[i] & (1 << j);}private:vector<char> _bits;};
}

 接下来你可以测试一些数据,比如set一些或reset一些.

当然如果想创建无符号整数的测试集,范围是0~2^32-1,可以直接用-1替代,因为-1的二进制是全1.

转化为无符号整数就是最大的。或者0xffffffff。同样地道理。如下

hyx::bit_set<-1> bs1;

这样创建即可.

位图常见三道面试题

下面来几个位图的拓展题:

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

首先100亿个整数会不会有空间的问题?答案是肯定不会的,因为开空间和数据范围有关系,和数据个数没有关系,100亿个整数,每个数的范围都是42亿(2^32-1)之内,不会说有100亿个不重复的整数.

首先问题是找出现一次的整数,很明显是个key-value模型。那这至少需要两个位图了。所以就需要建立双位图解决.

既然求出现一次,那么肯定是以下三种情况:(左边次数,右边对应的位图状态)

0次                     00

1次                     01

2次及以上          10

所以上面可知,第二个位图是由两个位进行表示.这样又得需要各种控制,也是不太方便.

其实位图也是一个数据结构,STL库中也有对应的容器——bitset.

 那我们直接用两个位图分别表示这两个位不就可以了吗,当然!

所以我们要自己建立一个有两个位图的类,如下

整体思路是:依次判断两个位:

1.若为00,说明这个数一次也没出现过,将其改为01.即将第二个位图设为1.

2.若为01,说明这个数出现了一次,将其改为10,即第一个位图设为1,第二个位图设为0.

 后面可以写一个成员函数来输出符合条件的数:

template <size_t N>
class twobitset
{
public:void set(size_t x){bool inset1 = _bs1.test(x);bool inset2 = _bs2.test(x);//00if (inset1 == false && inset2 == false){//->01_bs2.set(x);}else if (inset1 == false && inset2 == true){//->10_bs1.set(x);_bs2.reset(x);}}void print_once_num(){for (int i = 0; i < N; i++){//筛选出两个位图为01的数if (_bs1[i] == false && _bs2[i] == true){cout << i << endl;}}}
private:bitset<N> _bs1;bitset<N> _bs2;
};
void test_oncenum()
{int a[] = { 1,1,2,3,4,5,5,5,6,6,6,6,7,9,22 };twobitset<100> bs;for (auto e : a){bs.set(e);}bs.print_once_num();
}

 然后我们调用测试函数,得到:

可以发现已经输出了出现个数只为1的数.

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

这道题比较简单,思路是建立两个位图,然后分别把两个文件里的数据set到位图里,然后最后将两个位图&一下,然后再从最后的结果中找位是1的即可(利用test).

3. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数.

这个题和1题类似,无非就是多了一种状态:3次及3次以上。最后对应的状态是以下这样:

0次                     00

1次                     01

2次                     10

3次及3次以上     11

然后要在twobitset的set中多加一个判断条件:当位图位10时,下一次改为11.

		//10else if (inset1 == true && inset2 == false){//->11_bs2.set(x);}

然后输出的时候变化条件为bs1[i]==true和bs2[i]==true(11)即可.

至此,位图的所有内容就结束了,若有不懂或疑问的地方,欢迎私信或评论~

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用随便测测平台-做接口测试

目录 接口数据的来源 导出har文件 导入har文件 转化为用例 提取数据进行替换 如何选择哪些数据需要替换呢&#xff1f; Url Params、Data ​编辑进行替换操作 断言-冒烟 断言-详细 测试报告 结束 接口数据的来源 1、可通过charles工具&#xff0c;录制好接口操作&…

IDEA恢复误删除的文件

idea将删除的文件放在idea文件缓存中&#xff0c;文件的更改等信息都放在这个缓存中&#xff0c;所以短时间内删除的文件可以尝试恢复。

蚂蚁金服面试题解析:为什么String是HashMap中的绝佳Key类型?

大家好&#xff0c;我是小米&#xff0c;在今天的文章中&#xff0c;我将与大家一起探讨在使用HashMap时&#xff0c;选择使用String作为Key所带来的诸多好处。作为一位热爱技术的小伙伴&#xff0c;相信你一定对HashMap这个数据结构有所了解&#xff0c;那么&#xff0c;我们就…

【flutter滑动拼图验证码】

Java后台使用aj_captcha插件&#xff0c;提供/captcha/get&#xff08;获取captcha底图和拼块图片&#xff09;、/captcha/check&#xff08;验证拼图偏移量&#xff09;这两个接口。并且这个插件在GitHub上有源码。 1.先准备好aj_captcha的工具类&#xff1a; import dart:co…

【Spring/Java项目】如何利用swagger-parser解析yaml中的api请求类型、注释、接口名等等(含示例代码)

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;https://zhangxiaofan.blog.csdn.net/article/details/129167371 目录 前言 官方文档 项目配置 示例代码 测试文件 解析代码 运行结果 前言 用到这个工具是因为项目需要&#xff0…

Java9集合类新增功能

前言 Java8及Java9在集合Collection类中新增了一些很好用的新方法&#xff0c;能方便程序员更便捷的处理集合数据&#xff0c;本文对其中的一些方法进行总结 一. List 1.创建 // 传统方法List<String> list1 new ArrayList<>();list1.add("item1");li…

FPGA实验一:层次法设计组合电路(加法器)

目录 一、实验目的 二、实验要求 三、实验代码 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 3、下载测试结果及分析 五、实验心得 一、实验目的 &#xff08;1&#xff09;掌握基本组合逻辑电路的 FPGA实现&#xff1b; &#xff08;2&#xff09;学习 Verilo…

烂sql导致clickhouse集群memory_tracking直线飙升触发熔断

版 本 v e r s i o n 1 9 . 1 7 . 4 . 1 1 c l i c k h o u s e 集 群 &#xff0c; 主 要 存 日 志 数 据 与 监 控 数 据 。 架 构 为 4 台 主 机 1 2 个 实 例 数 &#xff0c; 数 据 为 单 副 本 。 近 日 &#xff0c; 该 c l i c k h o u s e 集 群 有 一 台 物…

Leetcode 数据库刷题记录

https://leetcode-cn.com/problemset/database/ 题目都是leetcode 上的可以点击题目会有相应的链接 每道题后面都应相应的难度等级&#xff0c;如果没时间做的话 可以在leetcode 按出题频率刷题&#xff0c;答案仅供参考 175. 组合两个表 难度简单 SQL架构 表1: Person ---…

深入理解什么是端口(port)

每当看到有人的简历上写着熟悉 TCP/IP, HTTP 等协议时, 我就忍不住问问他们: 你给我说说, 端口是啥吧! 可惜, 很少有人能说得让人满意… 所以这次就来谈谈 端口(port) , 这个熟悉的陌生人. 在此过程中, 还会谈谈 间接层, naming service 等概念, IoC, 依赖倒置 等原则以及 TCP …

服务器配置静态IP

服务器配置静态IP 一、前期准备二、配置静态IP 将服务器配置为使用静态IP地址。这将使服务器拥有一个永久的IP地址&#xff0c;而不会在每次启动时更改。为此&#xff0c;您需要编辑网络配置文件并将服务器的IP地址添加到其中。详细步骤如下&#xff1a; 一、前期准备 请在配置…

一篇搞懂socket、websocket、http协议及其使用

socket 介绍socket之前先看小编的这篇文章报文、报文段、数据包、帧、比特、字符、字节&#xff0c;与编码 在网络传输中数据都是经过多层封装的&#xff0c;在协议簇中最低层次为传输层才可以传输数据。再往底层就是面向计算机硬件和网络的部分了。例如常使用的ping baidu.co…