bit-map简介及其C/C++代码实现

        在本文中, 我们来介绍一下bit-map,你可别以为这是什么bitmap图像, 那本文要介绍的bit-map是什么呢? 且听我慢慢道来。


        坐过火车没? 当你在火车上, 想拉屎的时候, 你得去上厕所啊。 屁颠屁颠爬到厕所处, 发现上面亮了一个灯, 表示里面有人, 你郁闷至极, 但无可奈何。 过了很久, 那个人出来了, 那个灯也就熄灭了, 你就可以上厕所了。

        这个灯, 就是计算机中的一个bit, 有两种状态 , 1表示有人在厕所中, 0表示没有人在厕所中。 所以, 从这个意义上说, 一个bit可以标志某事物的一个状态, 当这个bit与某事物状态建立映射后, 我说们, 形成了一个bit到事物状态的map.

         

        我们知道, 一个unsign char有8bit, 也就是说, 一个无符号字符可以标志某个厕所的8个坑位的状态, 下面我们看看程序:

#include <iostream>
using namespace std;

int main(void) 
{
	unsigned char c;
	
	// 8个坑位都没有人
	c = 0;

	// 8个坑位都有人
	c = 255;

	// 第1个(也可以认为是第0个)坑位有人
	c = 128;

	// 最后两个坑位有人
	c = 3;

	return 0;
}
      看到没? 一个bit标志一个坑, 标志一个事物的状态, 那么一个unsigned char标志着8个事物的状态。 同理, 一个unsigned int标志着32个事物的状态, 其实一个int也可以标志着32个事物的状态。 (当然, 这里所说的状态都是二值状态)


       现在, 假设有N个事物状态, 那至少需要多少个int来表示呢? 很显然是 N/32 + 1. 假设有100个事物(N=100), 那至少需要4个int (总共128位). 说的有点多了, 直接看程序吧:

#include <iostream>
using namespace std;

#define BIT_INT 32   // 1个int可以标志32个坑
#define SHIFT 5
#define MASK 0x1f
#define N 100
int a[1 + N / BIT_INT]; // 需要1 + N / BIT_INT 个整数来标志N个事物

// 将所有位都初始化为0状态
void setAllZero()
{
	memset(a, 0, (1 + N / BIT_INT) * sizeof(int));
}

// 设置第i位为1, 表示有人在厕所里面
void setOne(int i)
{
	a[i >> SHIFT] |= (1 << (i & MASK));
}

// 设置第i位为1, 表示没有人在厕所里面
void setZero(int i)
{
	a[i >> SHIFT] &= ~(1 << (i & MASK));
}

// 检查第i位的值, 看看有没有人在厕所里面
int getState(int i)
{
	return (a[i >> SHIFT] & (1 << (i & MASK))) && 1;
}

int main(void) 
{
	int bitNumber = (1 + N / BIT_INT) * BIT_INT;
	cout << bitNumber << endl;
	
	setAllZero();
	int i = 0;
	for(i = 0; i < bitNumber; i++)
	{
		cout << getState(i);
	}
	cout << endl;


	setOne(0);
	setOne(1);
	setOne(2);
	setOne(3);
	setOne(4);
	for(i = 0; i < bitNumber; i++)
	{
		cout << getState(i);
	}
	cout << endl;


	setZero(0);
	setZero(1);
	setZero(2);
	for(i = 0; i < bitNumber; i++)
	{
		cout << getState(i);
	}
	cout << endl;

	return 0;
}
      看看结果吧:

128
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
11111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
   

     果然, 结果与预期符合。


     我们再看程序:

#include <iostream>
#include <set>
using namespace std;


#define BIT_INT 32   // 1个int可以标志32个坑
#define SHIFT 5
#define MASK 0x1f
#define N 100
int a[1 + N / BIT_INT]; // 需要1 + N / BIT_INT 个整数来标志N个事物


// 产生伪随机数
unsigned  int getRandom()
{
	return rand();
}

// 将所有位都初始化为0状态
void setAllZero()
{
	memset(a, 0, (1 + N / BIT_INT) * sizeof(int));
}

// 设置第i位为1, 表示有人在厕所里面
void setOne(int i)
{
	a[i >> SHIFT] |= (1 << (i & MASK));
}

// 设置第i位为1, 表示没有人在厕所里面
void setZero(int i)
{
	a[i >> SHIFT] &= ~(1 << (i & MASK));
}

// 检查第i位的值, 看看有没有人在厕所里面
int getState(int i)
{
	return (a[i >> SHIFT] & (1 << (i & MASK))) && 1;
}

int main(void) 
{
	int r = N;
	int size = 40; // 假设有40个事物(数字), 他们在[0, N-1]这个区间内

	// 构造40个互不相等的事物, 实际上, s中的元素是有序的, 但在该程序中, 我们不需要太关注这个
	set<int> s;
	while(size != s.size())
	{
		s.insert(getRandom() % r);
	}

	// 将所有坑位的人赶出来, 初始化
	setAllZero();

	set<int>::iterator it;
	for(it = s.begin(); it != s.end(); it++)
	{
		setOne(*it); // 将事物*it与其对应的坑位*it联系起来, 当*it这个事物存在时, 对应的坑位*it的状态为1
		cout << *it << " ";
	}
	cout << endl;

	int i = 0;
	int bitNumber = (1 + N / BIT_INT) * BIT_INT;
	for(i = 0; i < bitNumber; i++)
	{
		cout << i << "对应的坑位状态为:--->" << getState(i) << endl; // 获取坑位状态
	}
	cout << endl;

	return 0;
}

      结果为:

0 2 3 4 5 11 12 16 18 21 22 24 26 27 33 34 35 36 38 41 42 45 47 53 58 61 62 64 67 69 71 73 78 81 82 91 92 94 95 99
0对应的坑位状态为:--->1
1对应的坑位状态为:--->0
2对应的坑位状态为:--->1
3对应的坑位状态为:--->1
4对应的坑位状态为:--->1
5对应的坑位状态为:--->1
6对应的坑位状态为:--->0
7对应的坑位状态为:--->0
8对应的坑位状态为:--->0
9对应的坑位状态为:--->0
10对应的坑位状态为:--->0
11对应的坑位状态为:--->1
12对应的坑位状态为:--->1
13对应的坑位状态为:--->0
14对应的坑位状态为:--->0
15对应的坑位状态为:--->0
16对应的坑位状态为:--->1
17对应的坑位状态为:--->0
18对应的坑位状态为:--->1
19对应的坑位状态为:--->0
20对应的坑位状态为:--->0
21对应的坑位状态为:--->1
22对应的坑位状态为:--->1
23对应的坑位状态为:--->0
24对应的坑位状态为:--->1
25对应的坑位状态为:--->0
26对应的坑位状态为:--->1
27对应的坑位状态为:--->1
28对应的坑位状态为:--->0
29对应的坑位状态为:--->0
30对应的坑位状态为:--->0
31对应的坑位状态为:--->0
32对应的坑位状态为:--->0
33对应的坑位状态为:--->1
34对应的坑位状态为:--->1
35对应的坑位状态为:--->1
36对应的坑位状态为:--->1
37对应的坑位状态为:--->0
38对应的坑位状态为:--->1
39对应的坑位状态为:--->0
40对应的坑位状态为:--->0
41对应的坑位状态为:--->1
42对应的坑位状态为:--->1
43对应的坑位状态为:--->0
44对应的坑位状态为:--->0
45对应的坑位状态为:--->1
46对应的坑位状态为:--->0
47对应的坑位状态为:--->1
48对应的坑位状态为:--->0
49对应的坑位状态为:--->0
50对应的坑位状态为:--->0
51对应的坑位状态为:--->0
52对应的坑位状态为:--->0
53对应的坑位状态为:--->1
54对应的坑位状态为:--->0
55对应的坑位状态为:--->0
56对应的坑位状态为:--->0
57对应的坑位状态为:--->0
58对应的坑位状态为:--->1
59对应的坑位状态为:--->0
60对应的坑位状态为:--->0
61对应的坑位状态为:--->1
62对应的坑位状态为:--->1
63对应的坑位状态为:--->0
64对应的坑位状态为:--->1
65对应的坑位状态为:--->0
66对应的坑位状态为:--->0
67对应的坑位状态为:--->1
68对应的坑位状态为:--->0
69对应的坑位状态为:--->1
70对应的坑位状态为:--->0
71对应的坑位状态为:--->1
72对应的坑位状态为:--->0
73对应的坑位状态为:--->1
74对应的坑位状态为:--->0
75对应的坑位状态为:--->0
76对应的坑位状态为:--->0
77对应的坑位状态为:--->0
78对应的坑位状态为:--->1
79对应的坑位状态为:--->0
80对应的坑位状态为:--->0
81对应的坑位状态为:--->1
82对应的坑位状态为:--->1
83对应的坑位状态为:--->0
84对应的坑位状态为:--->0
85对应的坑位状态为:--->0
86对应的坑位状态为:--->0
87对应的坑位状态为:--->0
88对应的坑位状态为:--->0
89对应的坑位状态为:--->0
90对应的坑位状态为:--->0
91对应的坑位状态为:--->1
92对应的坑位状态为:--->1
93对应的坑位状态为:--->0
94对应的坑位状态为:--->1
95对应的坑位状态为:--->1
96对应的坑位状态为:--->0
97对应的坑位状态为:--->0
98对应的坑位状态为:--->0
99对应的坑位状态为:--->1
100对应的坑位状态为:--->0
101对应的坑位状态为:--->0
102对应的坑位状态为:--->0
103对应的坑位状态为:--->0
104对应的坑位状态为:--->0
105对应的坑位状态为:--->0
106对应的坑位状态为:--->0
107对应的坑位状态为:--->0
108对应的坑位状态为:--->0
109对应的坑位状态为:--->0
110对应的坑位状态为:--->0
111对应的坑位状态为:--->0
112对应的坑位状态为:--->0
113对应的坑位状态为:--->0
114对应的坑位状态为:--->0
115对应的坑位状态为:--->0
116对应的坑位状态为:--->0
117对应的坑位状态为:--->0
118对应的坑位状态为:--->0
119对应的坑位状态为:--->0
120对应的坑位状态为:--->0
121对应的坑位状态为:--->0
122对应的坑位状态为:--->0
123对应的坑位状态为:--->0
124对应的坑位状态为:--->0
125对应的坑位状态为:--->0
126对应的坑位状态为:--->0
127对应的坑位状态为:--->0

       现在应该完成清楚了bit-map吧, 所谓bit-map, 实际上就是用一个bit去map一个事物的状态(二值状态). bit-map的好处是: 节省空间


       实际上, bit-map在大数据处理中经常会用到, 一些笔试面试题经常考, 后续我们会陆续介绍到。







你可能感兴趣的:(bit-map简介及其C/C++代码实现)