【数据结构】哈希应用-STL-位图
目录
1、位图的概念
2、位图的设计与实现
2.1 set
2.2 reset
2.3 test
3、C++库中的位图
4、位图的优缺点
5、位图相关题目
1、位图的概念
面试题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
法一:遍历,时间复杂度是O(N),太慢
法二:排序 + 二分查找。时间复杂度是O(N * logN) + O(logN)。只是第一次比较慢,后面就快了。使用这个方法有一个致命的缺陷是存放40亿个数据需要的内存太过庞大。
1GB = 1024MB = 1024 * 1024KB = 1024 * 1024 * 1024Byte
所以40亿个数据约等于16GB,说明40亿个数据是无法直接放到内存中的,只能放到硬盘文件中。而二分查找只能对内存数组中的有序数据就行查找。这里使用数组是最节省空间的,因为每个位置只存放数据,如果使用红黑树或哈希表需要的空间还要更大
法三:使用位图
数据是否在给定的整型数据中,结果是在或不在,刚好是两种状态,那么可以用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,如果二进制比特位为0,代表不存在。那么我们就可以设计一个用位表示数据是否存在的数据结构,这个数据结构就是位图。
2、位图的设计与实现
实现中要注意的是,C/C++中没有对应位的类型,只能看char/int这样的整型类型,我们再通过位运算去控制对应的比特位。比如我们数据存到vector<int>中,相当于每个Int映射对应的32个值,比如第一个整型映射0~31对应的位,第二个整型映射32~63对应的位,后面依次类推。那么来一个无符号整型x,i = x / 32,j = x % 32,x映射的位置就是vector第i个整型数据的第j位。

我的机器是小端存储,所以一个整型中,低位是在右边
对于上面40亿个无符号整型,我们开空间需要开2^32个,因为无符号整型有2^32个,不是根据数据个数来开空间
namespace cxf
{template<size_t N> // 开N个位的位图class bitset{public:bitset(){_bs.resize(N / 32 + 1); // 因为N除32可能会除不尽,所以多开一个整型,保证位够}private:std::vector<int> _bs;};
}
2.1 set
向位图中插入数据,也就是将插入数据映射到的位标记成1
假设要向位图中插入数据77,要如何操作呢?
首先计算出位为77的地方位于第几个整型数据的第几个位。会发现位于第3个整型数据的第13个位,然后将1左移13个位的结果与第3个整型数据按位或,就可以将插入数据映射到的位标记成1
void set(size_t x)
{size_t i = x / 32;size_t j = x % 32;_bs[i] |= (1 << j);
}
2.2 reset
向位图中删除数据,也就是将传入数据映射到的位标记成0
假设要向位图中删除数据77,要如何操作呢?
首先计算出位为77的地方位于第几个整型数据的第几个位。会发现位于第3个整型数据的第13个位,然后将1左移13个位再按位取反的结果与第3个整型数据按位与,就可以将插入数据映射到的位标记成0
void reset(size_t x)
{size_t i = x / 32;size_t j = x % 32;_bs[i] &= (~(1 << j));
}
2.3 test
若传入数据映射到的位是1就返回真,是0就返回假
bool test(size_t x)
{size_t i = x / 32;size_t j = x % 32;return _bs[i] & (1 << j);
}
可以测试一下
void test_bitset()
{cxf::bitset<100> bs; // 开一个100个位的位图bs.set(77);bs.set(66);cout << bs.test(77) << endl;cout << bs.test(66) << endl;bs.reset(66);cout << bs.test(77) << endl;cout << bs.test(66) << endl;
}
结果是1 1 1 0,是正确的
那要如何开2^32个空间呢?有3种方法
cxf::bitset<-1> bs1;
cxf::bitset<0xffffffff> bs2;
cxf::bitset<UINT_MAX> bs3;
namespace cxf
{template<size_t N> // 开N个位的位图class bitset{public:bitset(){_bs.resize(N / 32 + 1); // 因为N除32可能会除不尽,所以多开一个整型,保证位够}void set(size_t x){size_t i = x / 32;size_t j = x % 32;_bs[i] |= (1 << j);}void reset(size_t x){size_t i = x / 32;size_t j = x % 32;_bs[i] &= (~(1 << j));}bool test(size_t x){size_t i = x / 32;size_t j = x % 32;return _bs[i] & (1 << j);}private:std::vector<int> _bs;};
}
3、C++库中的位图

与前面我们自己实现的位图是差不多的,operator[]可以像数组一样控制某个位
要注意,库中的位图是不能直接开2^32个空间的
void test_bitset2()
{std::bitset<UINT_MAX> bs;
}
像这样程序会崩溃的,因为我们自己实现的位图底层是使用vector,是去堆上开空间,而库中的位图是用一个静态数组实现的,没办法开太大。我们可以对其就行测试
void test_bitset2()
{cxf::bitset<100> bs1;cxf::bitset<10000> bs2;std::bitset<100> bs3;std::bitset<10000> bs4;cout << sizeof(bs1) << " ";cout << sizeof(bs2) << " ";cout << sizeof(bs3) << " ";cout << sizeof(bs4) << " ";
}
结果是16 16 16 1256
当然,是可以通过指针来解决的
std::bitset<-1>* ptr = new std::bitset<-1>();
4、位图的优缺点
优点:增删查改快,时间复杂度均为O(1),节省空间
缺点:只适用于整型
5、位图相关题目
位图的应用:
题目一:给定100亿个整数,设计算法找到只出现一次的整数。
注意:此时虽然是100亿个整数,但是还是按范围开空间,所以还是开2^32个位,与前面一样
法一:可以用两个位来标记一个数,00表示没出现过,01表示出现了1次,10表示出现了2次及以上法二:用两个位图,一个数在每个位图中各占一个位,规则与法一相同
题目二:一个文件有100亿个整数,1G内存,设计算法找到出现次数不超过2次的所有整数
与上面类似,只不过这里是00表示没出现过,01表示出现了1次,10表示出现了2次,11表示出现3次及以上
我们来复用前面实现的位图来对这两个问题就行实现
namespace cxf
{template<size_t N> // 开N个位的位图class bitset{public:bitset(){_bs.resize(N / 32 + 1); // 因为N除32可能会除不尽,所以多开一个整型,保证位够}void set(size_t x){size_t i = x / 32;size_t j = x % 32;_bs[i] |= (1 << j);}void reset(size_t x){size_t i = x / 32;size_t j = x % 32;_bs[i] &= (~(1 << j));}bool test(size_t x){size_t i = x / 32;size_t j = x % 32;return _bs[i] & (1 << j);}private:std::vector<int> _bs;};template<size_t N>class twobitset{public:void set(size_t x){bool bit1 = _bs1.test(x);bool bit2 = _bs2.test(x);if (!bit1 && !bit2) // 00->01{_bs2.set(x);}else if (!bit1 && bit2) // 01->10{_bs1.set(x);_bs2.reset(x);}else if (bit1 && !bit2) // 10->11{_bs2.ser(x);}}int get_count(size_t x) // 返回x出现的次数{bool bit1 = _bs1.test(x);bool bit2 = _bs2.test(x);if (!bit1 && !bit2) return 0;else if (!bit1 && bit2) return 1;else if (bit1 && !bit2) return 2;else return 3;}private:bitset<N> _bs1;bitset<N> _bs2;};
}
题目三:给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件的交集?
把数据读出来,分别放到两个位图,依次遍历,同时在两个位图的值就是交集
相关文章:
【数据结构】哈希应用-STL-位图
目录 1、位图的概念 2、位图的设计与实现 2.1 set 2.2 reset 2.3 test 3、C库中的位图 4、位图的优缺点 5、位图相关题目 1、位图的概念 面试题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这4…...
Unbuntu 服务器- Anaconda安装激活 + GPU配置
一、Anaconda安装激活 1.更新 sudo apt-get update 2.安装wget、vim sudo apt-get install wget sudo apt-get install vim 3.安装Anaconda 进入这个网址:Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 点这里&#x…...
python 装饰器记录函数用时
装饰器 # 用于记录函数平均用时的装饰器 def average_time_decorator(func):times []def wrapper(*args, **kwargs):start_time time.time()result func(*args, **kwargs)end_time time.time()t end_time - start_timetimes.append(t) # 记录用时print(f"{func.__n…...
实验10 任何一个非0自然数m的立方均可写成m个连续奇数之和。
实验10 题目描述 任何一个非0自然数m的立方均可写成m个连续奇数之和。 例如: 1^3 1 2^3 35 3^3 7911 4^3 13151719 编程实现:输入一自然数n,求组成心的n个连续奇数。 【实验要求】 1、不允许用等差数列的方法求首项 2、要求使用双重循环&a…...
Jenkins的安装方式
一、Jenkins是什么 Jenkins是一款开源CI&CD软件,用于自动化构建、测试和部署软件等各种任务,以实现持续集成。 Jenkins支持各种运行方式,可通过系统包、Docker或者通过一个独立的Java程序。 二、安装方式 2.1禅道智能应用平台一键安装…...
网络之华为S5700S-52P-LI交换机系统恢复
一、需求说明 盒式交换机flash存储空间一般比较小,只有几百兆,部分比较可能不到100M。当然一般情况下也是够用的,只有在日志文件等占用较多,或者ios系统升级较多,bin文件占用较多的情况下可能出现不够用的情况。什么情…...
蜂窝网络架构
2G/3G 4G eNB RF-RRU eCPRI RRU-BBU 光纤 5G From 38.300 AMF处理信令等,UPF 用户面,后面还有SMF...
培训第二十二天(mysql数据库主从搭建)
上午 1、为mysql添加开机启动chkconfig [rootmysql1 ~]# chkconfig --list //列出系统服务在不同运行级别下的启动状态注:该输出结果只显示 SysV 服务,并不包含原生 systemd 服务。SysV 配置数据可能被原生 systemd 配置覆盖。 要列出 systemd 服务…...
速盾:CDN回源失败都有什么原因?
CDN(内容分发网络)是一种通过将内容分发到全球各个边缘节点来提高网站访问速度和用户体验的网络技术。CDN回源失败是指CDN节点无法正常获取源站(原始服务器)上的内容。下面是一些可能导致CDN回源失败的常见原因: 网络故…...
C语言 | Leetcode C语言题解之第328题奇偶链表
题目: 题解: struct ListNode* oddEvenList(struct ListNode* head) {if (head NULL) {return head;}struct ListNode* evenHead head->next;struct ListNode* odd head;struct ListNode* even evenHead;while (even ! NULL && even->…...
8月6日笔记
8月6日 红日靶场打靶继续 SHOW VARIABLES #用于显示服务器运行时的各种系统变量的当前设置。这些变量可以控制服务器的行为在 MySQL 中,general_log 和 general_log_file 是两个与“general”相关的系统变量,它们控制着服务器是否启用一般查询日志以及…...
爱可声助听器:在全球听力市场中破冰前行
早在2021年,全球助听器市场规模就已经达到了101亿美元,Grand View Research数据显示,这一规模会持续增大,在未来的6年间,该数据将以4.9%的复合年增长率(CAGR)增长。 作为发展中国家,…...
华为OD面试 - 最佳升级时间窗(Java JS Python C C++)
题目描述 有一套系统需升级,为减小系统升级期间的影响,需根据系统过去一段时间内的每小时平均访问数据,来预测最佳升级时间窗。 现给长度为168(7 * 24)的整数数组,表示一个周期(假设从周一00:00到周日24:00)的每小时历史数据,最佳升级时间窗选择规则如下: 时间窗内…...
LE-50821F/FA激光扫描传感器|360°避障雷达之性能参数与配置清单说明
LE系列激光扫描传感器|360避障雷达涵盖LE-50711、LE-50711F、 LE-50621、LE-50821F、LE-50621F、LE-50821FA、LE-50711FA、LE-50621FA等型号,广泛应用于自动化工厂、物流与仓储、汽车制造与物流、机械设备、能源与环境等领域的环境感知、高精度定位(…...
精准洞察农田生态,智慧农业物联网环境监测与数据采集系统来袭
随着智慧农业的快速发展,利用物联网技术实现对农田种植状态的精准监测变得愈发重要。为了确保监测的准确性、一致性和有效性,规范农田物联网监测设备的技术参数、部署安装以及数据对接等技术指标势在必行。 本文技术说明旨在为相关设备的选择、安装和集…...
sql注入复现(1-14关)
目录 第一关(字符型注入) 第二关(数字型注入) 第三关(闭合方式不同) 第四关(用双引号闭合) 第五关(不会数据回显) 第六关(闭合方式不同双引…...
Spring Boot-12
JavaConfig 是一种通过 Java 代码来配置 Spring 应用程序的方式,取代了传统的 XML 配置文件。这 什么是 JavaConfig JavaConfig 是 Spring Framework 的一部分,它允许你使用纯 Java 代码来定义 Spring Beans 和配置应用程序,而不需要 XML 配…...
【Linux】进程详解
1、定义 使用编译器将代码编译成的可执行文件称为程序,程序存储在磁盘上; 将程序从磁盘装载到内存中,并通过指令调用、各级缓存、寄存器运行起来的实例,称为进程; 一个程序可以同时运行多个进程;每个进程具有自己的内存空间、寄存器和文件描述符等资源。 进程ID:…...
python的多线程
python的threading模块,它提供了丰富的接口来创建和管理线程。 定义一个函数print_numbers,这个函数将由线程执行。在这个函数中,我们使用一个循环来打印数字,并使用time.sleep(1)来模拟每个数字打印之间有1秒的延迟。 在 if __…...
在Kylin服务器安装PostgreSQL16数据库
1、下载PostgreSQL16安装包 下载地址https://www.postgresql.org/ftp/source/v16.3/ 2、安装依赖和ICU库 查看服务器版本 yum install -y perl-ExtUtils-Embed readline-devel zlib-devel pam-devel libxml2-devel libxslt-devel openldap-devel python-devel gcc-c opens…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
