目录
位图其实也是应用哈希思想的一种对数据进行快速查找的方法。位图将每个比特位的两种状态来表示数据的存在与否,0表示数据不存在1表示数据存在。实际应用中一般用来在特别大的数据量中查找元素是否存在。
1.位图的简单应用
我们先来看位图映射少量的元素:可以看到在一个数组中有1到22中个别元素如果如果我们每次查找数组中1~22中一个元素是否存在我们每次都需要遍历一遍数组那么是十分慢的,所以我们可以用位图的方式也就是用22个比特位来代表这22个数字的存在状态。那么我们每次判断一个数据是否存在于数组中就可以到位图中去查找。
2.位图海量数据查找
在实际的生活中我们要处理的数据是往往是十分巨大的,例如我们要处理40亿的数据。要求查找40亿的数据中某个元素是否存在那么我们就可以用位图的方式来表示。
首先我们来计算一下不用位图的方式来查询四十亿数据。那么我们首先大概计算一下40亿数据大概是占用多少内存。
我们可以看到40亿数据有大约16个G我们采用内部排序(这里查找的本质就是排序,就是在查找的过程中对每个元素进行排序对比)是很难进行的因为要一次性将16G的数据全部都加载到内存中才可以一一进行查找比对。但是实际中我们的内存可能只有8G或者16G要是将这16G的数据全部都加载到内存中肯定是不合理的。那么就需要外部排序,但是外部排序也需要对文件进行合并排序,排序复杂而且耗费时间。那么我们就可以用位图的方式来轻松解决。
我们可以看到用位图的方式我们只需要申请512M数据就可以实现40亿的数据的查找。
3.STL中位图的介绍和使用
3.1位图的介绍:
可以看到STL中的位图是一个特化的模板直接给出一个无符号的N来表示位图的比特个数。
3.2位图的使用:
- 位图中常见的用法:
- 可以看到这里最低位的位图中的元素在转化为字符串的时候被当作最低位的字符串
4. 位图的应用
4.1. 快速查找某个数据是否在一个集合中
- 我们上面查找数据就是应用位图来实现数的查找
4.2. 排序
- 在上面对于数据查找的过程中因为位图是按照顺序来进行标记数据的,那么在标记的过程中我们其实也就完成了对数据的排序过程。只要在位图中依次将置为1的位读出,那么就是集合中数据的次序。
4.3. 求两个集合的交集、并集等
- 交集:至于交集就更加容易实现了,我们只要将两个位图的每一位进行按位与操作那么得到的新的位图中标记的数据就是原本两个集合的交集。
- 并集:对两个位图进行按位或操作得到的新的位图就是原本两个集合的并集。
4.4. 操作系统中磁盘块标记
(1条消息) Linux下文件系统_月半木斤的博客-优快云博客
https://blog.youkuaiyun.com/weixin_45897952/article/details/123262685?spm=1001.2014.3001.5501
5.位图的模拟实现
#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
namespace wbx
{
template<size_t N>
class bitset
{
public:
bitset()
:_con(N/8+1),_count(0)
{}
bitset& set(size_t pos, bool val = true)
{
if (pos >= N)
{
assert(true);
}
if (val)
{
_con[pos / 8] |= (1 << (pos % 8));
_count++;
}
else
{
reset(pos);
}
return *this;
}
bitset& reset(size_t pos)
{
_con[pos / 8] &= (~(1 << (pos % 8)));//将其置0
_count--;
return *this;
}
size_t count()
{
//这里也可以用我们实现给好的每个数字对应的位图中数字的个数来计算count的值
//int bitCnttable[256] = {
// 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2,
// 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,
// 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
// 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,
// 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,
// 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
// 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
// 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,
// 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3,
// 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6,
// 6, 7, 6, 7, 7, 8 };
//_count = 0;
//for (int i = 0; i <_con.size(); i++)
//{
// _count += bitCnttable[_con[i]];
//}
return _count;
}
size_t size()
{
return N;
}
bool test(size_t pos)
{
int temp = _con[pos / 8] & (1 << (pos % 8));
return bool(temp > 0 ? true : false);
}
//?????????????没写出来
unsigned char& operator[](size_t pos)
{//不知道怎样返回一个位置的引用
return _con[pos / 8];
}
string to_string()const
{
string ret;
bool flag = false;
for (int i = 0; i < _con.size(); i++)
{
if (i == _con.size())
{
flag = true;
}
ret += char_tostring(_con[i], flag);
}
return ret;
}
unsigned long to_ulong()const
{
unsigned long ret=0;
string temp = to_string();
int base = 0;
for (int i = temp.size() - 1; i >= 0; i--)
{
ret += (temp[i] - '0')*Nsquare(base);
base++;
}
return ret;
}
private:
long Nsquare(int N)const
{
long ret = 1;
for (int i = 0; i < N; i++)
{
ret *= 2;
}
return ret;
}
string char_tostring(unsigned char num,bool flag)const
//flag用于表示当前是否是最后一位
{
string rets;
while (num)
{
unsigned long temp = num % 2;
num /= 2;
rets.push_back((char)(temp + '0'));
}
if (!flag)
{
while (rets.size() < 8)
{
rets.push_back('0');
}
}
reverse(rets.begin(), rets.end());
return rets;
}
vector<unsigned char> _con;
size_t _count;
};
}
int main()
{
wbx::bitset<23> b;//这里我们因为要表示0-22之间的元素存在情况所以我们要构造23个空间因为还包括0
int array[] = { 1, 3, 7, 4, 16, 12, 13, 19, 22, 18 };
for (int e : array)
{
b.set(e);//将数组中每一个数据都在位图中置为1
}
if (b.test(1))
{
cout << "1 is in bitset" << endl;
}
else
{
cout << "1 is not in bitset" << endl;
}
b.reset(1);//将1位置置为0
if (b.test(1))
{
cout << "1 is in bitset" << endl;
}
else
{
cout << "1 is not in bitset" << endl;
}
cout << b.size() << endl;//位图的个数
cout << b.count() << endl;//位图中被置为1的个数
if (b.test(4))
{
cout << "4 位置在位图中被置为1" << endl;
}
else
{
cout << "4 位置在位图中没有被置为1" << endl;
}
if (b.test(10))
{
cout << "10 位置在位图中被置为1" << endl;
}
else
{
cout << "10 位置在位图中没有被置为1" << endl;
}
cout << b.to_string() << endl;//将位图中每位的设置情况转化为字符串
cout << b.to_ulong() << endl;//将位图中每位的设置情况转化为无符号long型
return 0;
}
测试结果:
看到这里如果觉得有用不如点个赞再走吧!!!