参考:
https://blog.csdn.net/v_july_v/article/details/6685962
位图
https://blog.csdn.net/ArchyLi/article/details/78573362
位图BitMap:位图是一个数组,数组中的每一个数据元素的每一个二进制位表示一个数据,0表示数据不存在,1表示数据存在。
如上所示,当我们需要存放一个数据的时候,我们需要安装以下方法:
- 首先确定这个数字在整个数据的哪一个数据(区间)。
- 确定这个数据(区间)的哪一个Bit位上。
- 在这个位上置1即可。
- 举例
假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采用Bit-map的方法来达到排序的目的。要表示8个数,我们就只需要8个Bit(1Bytes),首先我们开辟1Byte的空间,将这些空间的所有Bit位都置为0(如下图:)
然后遍历这5个元素,首先第一个元素是4,那么就把4对应的位置为1(可以这样操作 p+(i/8)|(0×01<<(i%8)) 当然了这里的操作涉及到Big-ending和Little-ending的情况,这里默认为Big-ending),因为是从零开始的,所以要把第五位置为一(如下图):
然后再处理第二个元素7,将第八位置为1,,接着再处理第三个元素,一直到最后处理完所有的元素,将相应的位置为1,这时候的内存的Bit位的状态如下:
然后我们现在遍历一遍Bit区域,将该位是一的位的编号输出(2,3,4,5,7),这样就达到了排序的目的。下面的代码给出了一个BitMap的用法:排序。
//定义每个Byte中有8个Bit位
#include <memory.h>
#define BYTESIZE 8
void SetBit(char *p, int posi)
{
for(int i=0; i < (posi/BYTESIZE); i++)
{
p++;
}
*p = *p|(0x01<<(posi%BYTESIZE));//将该Bit位赋值1
return;
}
void BitMapSortDemo()
{
//为了简单起见,我们不考虑负数
int num[] = {3,5,2,10,6,12,8,14,9};
//BufferLen这个值是根据待排序的数据中最大值确定的
//待排序中的最大值是14,因此只需要2个Bytes(16个Bit)
//就可以了。
const int BufferLen = 2;
char *pBuffer = new char[BufferLen];
//要将所有的Bit位置为0,否则结果不可预知。
memset(pBuffer,0,BufferLen);
for(int i=0;i<9;i++)
{
//首先将相应Bit位上置为1
SetBit(pBuffer,num[i]);
}
//输出排序结果
for(int i=0;i<BufferLen;i++)//每次处理一个字节(Byte)
{
for(int j=0;j<BYTESIZE;j++)//处理该字节中的每个Bit位
{
//判断该位上是否是1,进行输出,这里的判断比较笨。
//首先得到该第j位的掩码(0x01<<j),将内存区中的
//位和此掩码作与操作。最后判断掩码是否和处理后的
//结果相同
if((*pBuffer&(0x01<<j)) == (0x01<<j))
{
printf("%d ",i*BYTESIZE + j);
}
}
pBuffer++;
}
}
int main(int argc, _TCHAR* argv[])
{
BitMapSortDemo();
return 0;
}
位图实现
参考:https://blog.csdn.net/ArchyLi/article/details/78573362
#include <iostream>
#include <vector>
using namespace std;
class BitMap
{
public:
BitMap(size_t range)
{
//此时多开辟一个空间
_bits.resize(range / 32 + 1);
}
void Set(size_t x)
{
int index = x / 32;//确定哪个数据(区间)
int temp = x % 32;//确定哪个Bit位
_bits[index] |= (1 << temp);//位操作即可
}
void Reset(size_t x)
{
int index = x / 32;
int temp = x % 32;
_bits[index] &= ~(1 << temp);//取反
}
bool Test(size_t x)
{
int index = x / 32;
int temp = x % 32;
if (_bits[index]&(1<<temp))
return 1;
else
return 0;
}
private:
vector<int> _bits;
};
void TestBitMap()
{
BitMap am(-1);
BitMap bm(200);
bm.Set(136);
bm.Set(1);
cout << bm.Test(136) << endl;
bm.Reset(136);
cout << bm.Test(136) << endl;
}
int main()
{
TestBitMap();
return 0;
}
bitset和vector< bool >
-
bitset就像一个bool类型的数组一样,但是有空间优化——bitset中的一个元素只占1 bit。
bitset有一个特性:整数类型和布尔数组都能转化成bitset。
在定义bitset时,要明确bitset含有多少位,须在尖括号内给出它的长度值:给出的长度值必须是常量表达式。 -
如果想用动态的bit数组,可以试试vector<bool>,vector<bool>是vector的一个模板特化,注意bool类型是8 bits,但是vector<bool>内部也会进行空间优化,vector< bool>里面不是一个Byte一个Byte储存的,而是一个bit一个bit储存的。
因为它不是容器,不容纳bool类型,因为vector 打包 bool 以节省空间,每个保存在“vector”中的“bool”占用一个单独的bit。
同时禁止有指向单个比特的指针
vector c{ false, true, false, true, false };
bool *p = &c[0]; //错误,不能编译,因为无法将一个临时量地址给绑定到指针
关于bitset和vector<bool>的内存占用大小这里有篇文章
c++中bool数组与bitset,vector的使用与占用空间大小对比
在某些简单的情况下,不想自定义位图的实现时,也可以考虑下用vector<bool>和bitset来实现。
示例:
#include <iostream> // std::cout
#include<vector>
using namespace std;
int main ()
{
vector<int> nums{0,-2,1,-3,9,42,10,4,34,33,6,13,5,-12,11,-8,57,15,74};
//先找出nums中的最大值和最小值
int minNums=INT_MAX,maxNums=INT_MIN;
for(auto &i:nums){
if(i<minNums) minNums=i;
if(i>maxNums) maxNums=i;
}
//将[minNums,maxNums]区间转换到[0,newMaxNums]
//将nums中每个元素减minNums即可实现
//注意bool是8 bits
//但是vector<bool>是vector的一个模板特化,内部会进行空间优化,保证bool类型在里面是1bit存储的。
vector<bool> temp(maxNums-minNums+1,false);
for(auto &i:nums){
temp[i-minNums]=true;//区间start前移到0
}
//看看temp的内存占用大小
//注意sizeof用于vector时,结果跟vector中的元素无关,只是返回这个vector<>类型的大小。
//cout<<"sizeof(temp)="<<sizeof(temp)<<endl;
//这里用temp.capacity()来输出vector<bool>类型的容量,单位为bit
cout<<"temp.capacity()="<<temp.capacity()<<"bits"<<endl;//此处的大小单位为bit
for(int i=0;i<temp.size();i++)
{
if(temp[i]==true)
cout<<i+minNums<<" ";//区间start恢复
}
system("pause");
return 0;
}