【C++】STL详解(十三)—— bitset(位图)的介绍与使用

在这里插入图片描述

​个人主页:@Sherry的成长之路
学习社区:Sherry的成长之路(个人社区)
专栏链接:C++学习
长路漫漫浩浩,万事皆有期待

上一篇博客:【C++】STL详解(十二)—— 用哈希表封装出unordered_map和unordered_set

文章目录

  • bitset的介绍
    • 位图的引入
    • 位图的概念
    • 位图的应用
  • bitset的使用
    • bitset的定义方式
    • bitset成员函数的使用
    • bitset运算符的使用
  • 总结:

bitset的介绍

位图的引入

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

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

将这一堆数进行排序,然后通过二分查找的方法判断该数是否在这一堆数中。
将这一堆数插入到unordered_set容器中,然后调用find函数判断该数是否在这一堆数中。

单从方法上来看,这两种方法都是可以,而且效率也不错,第一种方法的时间复杂度是O(N*logN),第二种方法的时间复杂度是O(N)。

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

位图解决

实际在这个问题当中,我们只需要判断一个数在或是不在,即只有两种状态,那么我们可以用一个比特位来表示数据是否存在,如果比特位为1则表示存在,比特位为0则表示不存在。比如:
【C++】STL详解(十三)—— bitset(位图)的介绍与使用_第1张图片

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

位图的概念

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

位图的应用

常见位图的应用如下:

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

bitset的使用

bitset的定义方式

方式一: 构造一个16位的位图,所有位都初始化为0。

bitset<16> bs1; //0000000000000000

方式二: 构造一个16位的位图,根据所给值初始化位图的前n位。

方式三: 构造一个16位的位图,根据字符串中的0/1序列初始化位图的前n位。

bitset<16> bs3(string("10111001")); //0000000010111001

bitset成员函数的使用

bitset中常用的成员函数如下:

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

使用示例:

#include 
#include 
using namespace std;

int main()
{
	bitset<8> bs;
	bs.set(2); //设置第2位
	bs.set(4); //设置第4位
	cout << bs << endl; //00010100
	
	bs.flip(); //反转所有位
	cout << bs << endl; //11101011
	cout << bs.count() << endl; //6

	cout << bs.test(3) << endl; //1

	bs.reset(0); //清空第0位
	cout << bs << endl; //11101010

	bs.flip(7); //反转第7位
	cout << bs << endl; //01101010

	cout << bs.size() << endl; //8

	cout << bs.any() << endl; //1

	bs.reset(); //清空所有位
	cout << bs.none() << endl; //1

	bs.set(); //设置所有位
	cout << bs.all() << endl; //1
	return 0;
}

注意: 使用成员函数set、reset、flip时,若指定了某一位则操作该位,若未指定位则操作所有位。

bitset运算符的使用

一、bitset中>>、<<运算符的使用。
bitset容器对>>、<<运算符进行了重载,我们可以直接使用>>、<<运算符对biset容器定义出来的对象进行输入输出操作。

#include 
#include 
using namespace std;

int main()
{
	bitset<8> bs;
	cin >> bs; //10110
	cout << bs << endl; //00010110
	return 0;
}

二、bitset中赋值运算符、关系运算符、复合赋值运算符、单目运算符的使用。
bitset容器中不仅对赋值运算符和一些关系运算符进行了重载,而且对一些复合赋值运算符和单目运算符也进行了重载,我们可以直接使用这些运算符对各个位图进行操作。

包括如下运算符:

赋值运算符:=。
关系运算符:==、!=。
复合赋值运算符:&=、|=、^=、<<=、>>=。
单目运算符:~。

#include 
#include 
#include 
using namespace std;

int main()
{
	bitset<8> bs1(string("10101010"));
	bitset<8> bs2(string("10101010"));
	bs1 >>= 1;
	cout << bs1 << endl; //01010101

	bs2 |= bs1;
	cout << bs2 << endl; //11111111
	return 0;
}

三、bitset中位运算符的使用。
bitset容器中同时也对三个位运算符进行了重载,我们可以直接使用&、|、^对各个位图进行操作。

#include 
#include 
#include 
using namespace std;

int main()
{
	bitset<8> bs1(string("10101010"));
	bitset<8> bs2(string("01010101"));
	
	cout << (bs1&bs2) << endl; //00000000
	cout << (bs1|bs2) << endl; //11111111
	cout << (bs1^bs2) << endl; //11111111
	return 0;
}

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

#include 
#include 
#include 
using namespace std;

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

总结:

今天我们比较详细地学习了bitset(位图)的介绍与使用,了解了一些有关的底层原理。接下来,我们将进行bitset(位图)的模拟实现。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

你可能感兴趣的:(C++学习,c++,redis)