使用C++实现位图处理

 更新时间:2023年04月19日 08:47:50   作者:芒果再努力  
本文介绍了如何使用C++语言处理位图图像,包括读取、修改、保存等操作。通过具体的代码示例,读者可以学习到如何利用C++中的位运算、数组和文件操作等知识点完成位图处理任务。同时,本文也提供了一些常用的图像处理算法供读者参考,帮助读者更好地理解位图处理过程

位图的引入

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

方法1:遍历, 时间复杂度O(N)

方法2:排序—O(N*logN) + 二分查找----O(logN)

方法3:可以将所有数放到unordered_set中,然后调用find函数查找

上述的方法存在的问题:

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

方法4:利用位图解决

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

问:40亿个整数需要占用多少空间

1G =1024*1024*1024 Byte = 10亿字节,刚才存放一个整形4个字节,32个比特位,需要16G的空间,现在用一个比特位存,只需要16/32 = 0.5G即可

注意我们需要开辟42亿9千多万个比特位,而不是40亿个比特位,因为要映射,要按照整数的最大范围去开,而不是按个数去开 开辟内存的最小单位->字节->用char/int都可以

如何正确开辟42亿9前多万个比特位呢?

共有两种方式: bitset: template<size_t N> class bitset;

bitset<0xffffffff> bs;//#define UINT_MAX      0xffffffff
bitset<-1> bs; //-1的补码是全1 0xffffffff,而非类型模板参数的N的参数是size_t类型

什么是位图

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

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

例子:

位图的应用

  • 快速查找某个数据是否在一个集合中
  • 排序
  • 求两个集合的交集、并集等
  • 操作系统中磁盘块标记
  • 内核中信号标志位(信号屏蔽字和未决信号集)

bitset的使用

定义方式

bitset ---> template <size_t N> class bitset; 位图的大小在编译时是固定的(由其模板参数确定)

  • 构造一个N位的位图,所有位都初始化为0
  • 构造一个N位的位图,根据所给值初始化位图的前n位
  • 构造一个N位的位图,根据字符串中的0/1序列初始化位图的前n位
#include<bitset>
int main()
{
	//方式1:构造一个N位的位图,所有位都初始化为0
	bitset<16> bs1;//0000 0000 0000 0000
	//方式2:构造一个N位的位图,根据所给值初始化位图的前n位
	bitset<16> bs2(0xabc);//0011 1101 0101 0000
	//方式3:构造一个N位的位图,根据字符串中的0/1序列初始化位图的前n位
	bitset<16> bs3(string("10110001"));//1000 1101 0000 0000
	return 0;
}

成员函数

成员函数功能
set设置指定位或所有位为1
reset清空指定位或所有位为0
flip反转指定位或所有位
test获取指定位的状态 0或者1
count获取被设置位的个数
size获取可以容纳的位的个数
any判断是否有位被设置–>如果有任何一个位被设置则返回true
none判断是否所有位都没有被设置->如果没有位被设置则返回true
all判断是否所有位都设置->如果所有位都被设置则返回true

使用实例:

#include<iostream>
#include<bitset>
int main()
{
	//从右到左算起, 最右边为第0位
	bitset<8> bs;//构造一个8位的位图,所有位都初始化为0
	bs.set(1);//设置第1位为1
	bs.set(5);//设置第5位为1
	cout << bs << endl; //00100010
	bs.flip();//反转bs的所有位
	cout << bs << endl;//11011101
	cout << "共有"<<bs.count()<<"位被设置成1" << endl;//共有6位被设置成1
	cout << bs.test(3) << endl;//输出第3位的状态 - 1
	bs.reset(1);//将第1位设置为0
	cout << bs << endl;//11011101
	bs.flip(7);//将第7位反转
	cout << bs << endl;//01011101
	cout << bs.size() << endl;//输出位图可以容纳的位的个数 ---8
	cout << bs.any() << endl;//判断是否有位被设置 ---1
	bs.reset();//清空所有位
	cout << bs << endl;//00000000
	bs.set();//将所有位设置为1
	cout << bs << endl;//11111111
	cout << bs.all() << endl;//判断是否所有位都设置 ----1
	return 0;
}

注意如何区分成员函数set,reset,flip是对所有位操作还是对某一个位操作呢?

如果成员函数带了参数,就是对该指定的位操作如果没有指定,就是对所有位操作

bitset的运算符重载

>> 及 << 运算符

我们可以直接使用>><<运算符对biset容器对应的所有位进行输入输出操作

如果输入的位数比位图所能容纳的位数N多,只会从前向后截取N位

#include<bitset>
int main()
{
	bitset<8> bs;
	cin >> bs;//输入:10101
	cout << bs << endl;//00010101
	return 0;
}

赋值-关系-复合赋值-单目运算符

bitset容器对一些复合赋值运算符和单目运算符也进行了重载

  • 赋值运算符:=
  • 关系运算符:== !=
  • 复合赋值运算符:&= |= ^= <<= >>=
  • 单目运算符:~
#include<bitset>
int main()
{
	bitset<8> bs1(string("11111111"));
	bitset<8> bs2(string("01010101"));
	cout << bs1 << endl;//11111111
	bs1 >>= 1;
	cout << bs1 << endl;//01111111
	bs2 &= bs1;
	cout << bs2 << endl;//01010101
	return 0;
}

其次我们可以使用& | ^ 对位图进行操作

#include<bitset>
int main()
{
	bitset<8> bs1(string("10101111"));
	bitset<8> bs2(string("01101101"));
	cout << (bs1 | bs2) << endl;//11101111
	cout << (bs1 & bs2) << endl;//00101101
	cout << (bs1 ^ bs2) << endl;//11000010
	return 0;
}

[]重载

bitset容器中对[ ]运算符进行了重载,我们可以直接使用[ ]对指定位进行访问或修改

int main()
{
	bitset<8> bs(string("11001010"));
	cout << bs[0] << endl; //0
	bs[0] = 1;
	cout << bs << endl; //11001011
	return 0;
}

到此这篇关于使用C++实现位图处理的文章就介绍到这了,更多相关C++位图处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言数组栈实现模板

    C语言数组栈实现模板

    这篇文章主要为大家详细介绍了C语言数组栈实现模板,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • Qt使用QChart实现静态显示温度变化曲线

    Qt使用QChart实现静态显示温度变化曲线

    QChart模块是Qt Charts库的基础,提供了用于创建和显示各种类型图表的类和接口,本文主要介绍了如何使用QChart实现动态显示3个设备的温度变化曲线,感兴趣的可以了解一下
    2023-06-06
  • C++连接mysql数据库的两种方法小结

    C++连接mysql数据库的两种方法小结

    这篇文章主要介绍了C++连接mysql数据库的两种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • C语言实现简单的五子棋游戏

    C语言实现简单的五子棋游戏

    这篇文章主要为大家详细介绍了c语言实现简单的五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C++中的类扩展之继承和组合详解

    C++中的类扩展之继承和组合详解

    在C++中,类扩展可以通过继承、组合和装饰模式实现。继承可以实现对已有类的修改和扩展,组合可以增加新的功能,装饰模式则能够在不改变原类的情况下为其添加新的功能。这些技术在C++程序设计中应用广泛,提高了程序的可扩展性和可维护性
    2023-04-04
  • C++ list常用接口和模拟实现实例代码

    C++ list常用接口和模拟实现实例代码

    C++中list容器底层实现是使用带头双向循环链表的结构,通过指针指向前一个和后一个节点,它也具有双向链表的优缺点,下面给大家介绍C++ list常用接口和模拟实现代码,感兴趣的朋友一起看看吧
    2025-04-04
  • C语言实现基于最大堆和最小堆的堆排序算法示例

    C语言实现基于最大堆和最小堆的堆排序算法示例

    这篇文章主要介绍了C语言实现基于最大堆和最小堆的堆排序算法示例,分别是基于最大堆的升序排序和基于最小堆的降序排序实例,需要的朋友可以参考下
    2016-06-06
  • Opencv基于CamShift算法实现目标跟踪

    Opencv基于CamShift算法实现目标跟踪

    这篇文章主要为大家详细介绍了Opencv基于CamShift算法实现目标跟踪,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • C语言中的逗号运算符详解

    C语言中的逗号运算符详解

    在C语言中逗号“,”也是一种运算符,称为逗号运算符,其功能是把两个表达式连接起来组成一个表达式, 称为逗号表达式,这篇文章主要介绍了C语言中的逗号运算符,需要的朋友可以参考下
    2022-11-11
  • C++内存模型和名称空间详解

    C++内存模型和名称空间详解

    这篇文章主要给大家介绍了关于C/C++中的内存模型和名称空间详解,文中通过示例代码介绍的非常详细,对大家学习或者使用c/c++具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧
    2021-09-09

最新评论