C++——位图的介绍和使用

news2024/12/29 9:54:31

位图的介绍

位图的引入

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

要判断一个数是否在某一堆数中,我们可能会想到如下方法:

· 将这一堆数进行排序,然后通过二分查找的方法判断该数是否在这一堆数中。
· 将这一堆数插入到unordered_set容器中,然后调用find函数判断该数是否在这一堆数中。
单从方法上来看,这两种方法都是可以,而且效率也不错,第一种方法的时间复杂度是O ( N l o g N ) O(NlogN)O(NlogN),第二种方法的时间复杂度是O ( N ) O(N)O(N)。

但问题是这里有40亿个数,若是我们要将这些数全部加载到内存当中,那么将会占用16G的空间,空间消耗是很大的。因此从空间消耗来看,上面这两种方法实际都是不可行的。

位图解决

实际在这个问题当中,我们只需要判断一个数在或是不在,即只有两种状态,那么我们可以用一个比特位来表示数据是否存在,如果比特位为1则表示存在,比特位为0则表示不存在。比如:

无符号整数总共有232个,因此记录这些数字就需要232个比特位,也就是512M的内存空间,内存消耗大大减少。

位图的概念

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

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

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

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

位图的实现

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

对于每一步可以看注释

#include<iostream>
#include<vector>
using namespace std;
 
namespace yxh
{
    //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;
	};
}

位图的使用

位图的应用

在实际应用中,位图可以用于各种用途,例如:

  1. 存在性检测:使用位图快速检测某个元素是否存在。
  2. 权限管理:用位图表示用户的权限,每个位代表一种权限。
  3. 内存管理:操作系统使用位图来管理内存分配,跟踪内存块的使用情况。
  4. 集合操作:用位图表示集合,实现集合的并、交、差运算。

位图的高级应用

位图可以进行更高级的操作,如按位与、按位或、按位异或等。以下示例展示了如何实现这些操作: 

#include <iostream>
#include <vector>
#include <cstdint>

class Bitmap {
public:
    Bitmap(size_t size) : bits((size + 7) / 8, 0) {}

    void set(size_t pos) {
        bits[pos / 8] |= (1 << (pos % 8));
    }

    void reset(size_t pos) {
        bits[pos / 8] &= ~(1 << (pos % 8));
    }

    bool test(size_t pos) const {
        return bits[pos / 8] & (1 << (pos % 8));
    }

    Bitmap operator&(const Bitmap& other) const {
        Bitmap result(bits.size() * 8);
        for (size_t i = 0; i < bits.size(); ++i) {
            result.bits[i] = bits[i] & other.bits[i];
        }
        return result;
    }

    Bitmap operator|(const Bitmap& other) const {
        Bitmap result(bits.size() * 8);
        for (size_t i = 0; i < bits.size(); ++i) {
            result.bits[i] = bits[i] | other.bits[i];
        }
        return result;
    }

    Bitmap operator^(const Bitmap& other) const {
        Bitmap result(bits.size() * 8);
        for (size_t i = 0; i < bits.size(); ++i) {
            result.bits[i] = bits[i] ^ other.bits[i];
        }
        return result;
    }

    void print() const {
        for (size_t i = 0; i < bits.size(); ++i) {
            for (int j = 0; j < 8; ++j) {
                std::cout << ((bits[i] & (1 << j)) ? '1' : '0');
            }
        }
        std::cout << std::endl;
    }

private:
    std::vector<uint8_t> bits;
};

int main() {
    Bitmap bitmap1(16);
    Bitmap bitmap2(16);

    bitmap1.set(1);
    bitmap1.set(5);
    bitmap1.set(8);

    bitmap2.set(1);
    bitmap2.set(4);
    bitmap2.set(8);

    Bitmap and_result = bitmap1 & bitmap2;
    Bitmap or_result = bitmap1 | bitmap2;
    Bitmap xor_result = bitmap1 ^ bitmap2;

    std::cout << "Bitmap 1: ";
    bitmap1.print(); // 0100010010000000

    std::cout << "Bitmap 2: ";
    bitmap2.print(); // 0100100010000000

    std::cout << "AND result: ";
    and_result.print(); // 0100000010000000

    std::cout << "OR result: ";
    or_result.print(); // 0100110010000000

    std::cout << "XOR result: ";
    xor_result.print(); // 0000110000000000

    return 0;
}

bitset

位图(Bitmap)和 bitset 有许多相似之处,但它们并不完全相同。以下是两者的比较和具体区别:

bitset(C++标准库中的位集)

bitset 是C++标准模板库中的一种容器,用于处理固定长度的二进制序列(位集)。它提供了高效的位操作,并且在编译时确定大小。

bitset 的特点:

  1. 固定长度bitset 的大小在编译时就确定,不能在运行时改变。
  2. 类型安全:作为STL的一部分,bitset 提供类型安全和标准化的接口。
  3. 高效操作bitset 提供丰富的成员函数和操作符,使位操作更为简洁和安全。

bitset 的使用示例:

#include <bitset>
#include <iostream>

int main() {
    std::bitset<16> bs;

    bs.set(1);
    bs.set(5);
    bs.set(8);

    std::cout << bs << std::endl; // 输出位集状态

    bs.reset(5);
    std::cout << bs << std::endl; // 输出位集状态

    std::cout << "Bit at position 8: " << bs.test(8) << std::endl; // 检查位状态

    return 0;
}

比较和总结

  1. 长度:位图的长度可以动态调整,而 bitset 的长度在编译时确定,不可改变。
  2. 存储方式:位图通常使用字节数组实现,可以直接操作内存中的比特位; bitset 是一个模板类,封装了位操作,提供更高层次的接口。
  3. 效率:两者在位操作上效率相似,但 bitset 提供了更多的成员函数和操作符,使代码更简洁和安全。
  4. 应用场景:位图适用于需要动态调整长度或直接操作内存的场景,如操作系统内存管理、网络位图等。 bitset 适用于固定长度的位操作场景,如标志集合、布尔数组等。

综上所述,位图是一种通用的低级数据结构,可以灵活地适应各种长度和应用需求。而 bitset 是C++标准库中的一种固定长度位集容器,适用于需要固定长度和标准接口的场景。两者在概念上相似,但在具体实现和应用上有所不同。 

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

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

相关文章

VBA学习(16):工作表事件示例:输入数据后锁定单元格

在工作表单元格中输入数据后&#xff0c;该单元格就被锁定&#xff0c;不能再编辑。 打开VBE&#xff0c;在工程资源管理器中双击该工作表名称打开其代码模块&#xff0c;在其中输入下面的代码&#xff1a; 假设整个工作表的LockedFalse Private Sub Worksheet_Change(ByVal …

【文献及模型、制图分享】1985-2015年美国坦帕湾流域土地开发利用强度时空变化分析

公众号新功能 目前公众号新增以下等功能 1、处理GIS出图、Python制图、区位图、土地利用现状图、土地利用动态度和重心迁移图等等 2、核密度分析、网络od分析、地形分析、空间分析等等 3、地理加权回归、地理探测器、生态环境质量指数、地理加权回归模型影响因素分析、计算…

顶顶通呼叫中心中间件-机器人测试流程(mod_cti基于FreeSWITCH)

感兴趣的话可以点后面链接添加联系方式顶顶通小孙 一、打开ccadmin-web并且创建分机 1、登录ccadmin-web 登录地址&#xff1a;http://ddcti.com:88 登录之后根据下图去登录ccadmin-web系统。 2、创建分机 点击呼叫中心 -> 点击分机设置 -> 点击新增&#xff0c;点击…

超级管道,品质非凡——钢塑复合管

钢塑复合管&#xff0c;是一种新型的复合管材&#xff0c;又叫涂塑钢管&#xff0c;涂塑钢管有内涂塑钢管&#xff0c;外涂塑钢管&#xff0c;内外涂塑钢管&#xff0c;外镀锌内涂塑钢管&#xff0c;外3pe防腐内涂塑钢管等。 它结合了钢管和塑料管的优点&#xff0c;具有高强度…

LATR 算法解读

文章目录 1. 论文2. 环境安装3. 代码解读3. 1 初始化 lane query3.1.1 SparseInsDecoder3.1.2 loss 计算3.1.3 初始化instance query3.2 ref points 的生成3.3 lane query 和feats进行attention3.3.1 self attn3.3.1 cross attn4. 参考1. 论文 2. 环境安装 146 [2024-06-20 10…

用自己的数据集训练TimeSformer并转ONNX用c++推理

用自己的数据集训练TimeSformer并转ONNX用c++推理 文章目录 用自己的数据集训练TimeSformer并转ONNX用c++推理下载安装TimeSformer创建分类文件夹创建数据集修改训练配置运行脚本开始训练测试模型模型转为onnx测试一下生成的onnx模型转为用c++推理下载安装TimeSformer TimeSfo…

IDEA中Maven--下载安装自己适配的版本---理解

Maven解释&#xff1a; Maven是一个强大的项目管理工具和构建工具&#xff0c;主要用于Java项目。它能够帮助开发团队管理项目的依赖、构建项目、发布文档和报告&#xff0c;并能够自动化许多重复的任务。 Maven的主要作用包括&#xff1a; 依赖管理&#xff1a;Maven能够管理…

Google Earth Engine(GEE)——checkbox的使用

结果 函数: ui.Checkbox(label, value, onChange, disabled, style) A checkbox with a label. Arguments: label (String, optional): The checkboxs label. Defaults to an empty string. value (Boolean, optional): Whether the checkbox is checked. A nu

SpringBoot 实现RequestBodyAdvice封装统一接受类功能

一、相关往期文章 SpringBootVue实现AOP系统日志功能_aop的vue完整项目 Spring AOP (面向切面编程&#xff09;原理与代理模式—实例演示_面向切面aop原理详解 二、需求分析 按照一般情况&#xff0c;统一接受类可以像以下的方式进行处理&#xff1a; 如果不想使用 Request…

8路编码器脉冲计数器或16路DI高速计数器,Modbus RTU模块 YL69-485/232

特点&#xff1a; ● 编码器解码转换成标准Modbus RTU协议 ● 可用作编码器计数器或者转速测量 ● 支持8个编码器同时计数&#xff0c;可识别正反转 ● 也可以设置作为16路独立DI高速计数器 ● 编码器计数值支持断电自动保存 ● DI输入和电源之间3000V隔离 ● 通过RS-4…

在线二维码解码器:将二维码转换成网址链接

在当今数字化时代&#xff0c;二维码&#xff08;QR码&#xff09;已成为一种便捷的信息传递工具。它不仅可以存储大量数据&#xff0c;还能快速分享信息。然而&#xff0c;有时我们需要将二维码中的内容转换为网址链接&#xff0c;以便在浏览器中直接访问。小编将详细介绍如何…

【Java】已解决java.nio.channels.ClosedChannelException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.nio.channels.ClosedChannelException异常 在Java的NIO&#xff08;New I/O&#xff09;编程中&#xff0c;java.nio.channels.ClosedChannelException是一个常见的异常…

内容安全复习 5 - 深在线社交网络分析与舆情监测

文章目录 在线社交网络分析什么是在线社交网络什么是在线社交网络分析社交网络信息传播基本模型影响力模型传染模型影响力计算公式 网络舆情监测网络舆情概述网络舆情监测系统 在线社交网络分析 什么是在线社交网络 在线社交网络是一种在信息网络上由社会个体集合及个体之间的…

分布式锁(Redission)

分布式锁&#xff1a; 使用场景&#xff1a; 通常对于一些使用率高的服务&#xff0c;我们会进行多次部署&#xff0c;可能会部署在不同的服务器上&#xff0c;但是他们获取和操作的数据仍然是同一份。为了保证服务的强一致性&#xff0c;我们需要对线程进行加锁&#xff0c;…

This content is blocked. Contact the site owner to fix the issue.

chrome浏览器在网页邮箱预览PDF附件&#xff0c;报如下错误&#xff1a; This content is blocked. Contact the site owner to fix the issue. 无法预览。 原因&#xff1a; chrome设置了PDF默认下载。更改为在chrome中打开PDF即可。 chrome://settings/content/pdfDocuments…

iOS 18 为 iPhone 15 机型引入了更多充电限制选项

iOS 18 为 iPhone 15 机型引入了更多充电限制选项 所有四款iPhone 15型号都具备一项设置&#xff0c;可以限制设备充电至80%以内&#xff0c;这样能够缩短电池完全充电所需的时间&#xff0c;并有可能延长iPhone电池的使用寿命。随着iOS 18的推出&#xff0c;Apple进一步加入了…

Blazor的SSR服务端渲染是不是交互式的

从.NET8开始&#xff0c;Blazor引入了SSR服务端渲染&#xff0c;归功于MVC和RazePage的沉淀&#xff0c;虽然来得晚&#xff0c;但一经发布&#xff0c;就将Blazor推向了新的高度。从今年开始&#xff0c;Youtube上关于Blazor的优质教学视频&#xff0c;以肉眼可见的速度在增加…

xocde编辑器支持修改为中文吗?不支持

xocde编辑器支持修改为中文吗&#xff1f; 不支持

故障诊断 | SABO-VMD-SVM轴承故障诊断(Matlab)

效果一览 文章概述 故障诊断 | SABO-VMD-SVM轴承故障诊断(Matlab) 模型描述 减法平均的优化算法(Subtraction-Average-Based Optimizer (SABO)),是于2023年提出的一种基于数学行为的智能优化算法,该算法具有寻优能力强,收敛速度快等特点。以最小包络熵、最小样本熵、最…

Spring Boot 3 搭建

1、jdk 17 2、spring boot 3.1.7 3、pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xs…