上一篇博客中讲到的位图只能判断数据是否存在,但并不能判断该数据是只存在1个还是存在多个,这就是一个小小的缺陷!没事,稍改代码就可以弥补这一缺陷。
方便实现代码,我们假设数组的数据类型为int,则位图所实现的接口如下:
0.初始化数组
设数据的范围为range,开辟一个大小为(range>>4)+1的数组,并使其初始化为0。
BitSet(size_t range)
{
_set.resize((range >> 4) + 1, 0);
}
1.确定数据应存入的位置
设要存入的数据为num,index表示的是存入数组的哪个数据中,pos表示的是存入数据的哪位二进制位中。
size_t index = num >> 5;
size_t pos = (num % 16) * 2;
2.设置数据
用2位二进制位表示一个数据,其中00表示数据不存在,01表示只存在1个,11表示数据存在多个。
void set(size_t num)
{
size_t index = num >> 5;
size_t pos = (num % 16) * 2;
if((_set[index] & (1 << pos)) == 0)
{
_set[index] |= (1 << pos);
}
else
{
_set[index] |= (1 << pos);
++pos;
_set[index] |= (1 << pos);
}
}
3.清除数据
该自定义类不能设计清除数据这一接口,因为在清除数据时,若数据存在时无法判断数据是存在1个还是多个。
4.判断数据是否存在
若输出为0表示数据不存在,输出为1表示数据存在1个,输出为2表示数据存在多个。
int Test(size_t num)
{
size_t index = num >> 5;
size_t pos = (num % 16) * 2;
if((_set[index] & (1 << pos)) == 0)
{
return 0;
}
else if((_set[index] & (1 << pos)) && (_set[index] & (1 << (++pos))) == 0)
{
return 1;
}
else
{
return 2;
}
}
完整的源代码及测试用例如下:
#include <vector>
class BitSet
{
public:
BitSet(size_t range)
{
_set.resize((range >> 4) + 1, 0);
}
void set(size_t num)
{
size_t index = num >> 5;
size_t pos = (num % 16) * 2;
if((_set[index] & (1 << pos)) == 0)
{
_set[index] |= (1 << pos);
}
else
{
_set[index] |= (1 << pos);
++pos;
_set[index] |= (1 << pos);
}
}
int Test(size_t num)
{
size_t index = num >> 5;
size_t pos = (num % 16) * 2;
if((_set[index] & (1 << pos)) == 0)
{
return 0;
}
else if((_set[index] & (1 << pos)) && (_set[index] & (1 << (++pos))) == 0)
{
return 1;
}
else
{
return 2;
}
}
protected:
vector<int> _set;
};
void TestBitSet()
{
BitSet s(1000);
s.set(1);
s.set(1);
s.set(8);
cout<<s.Test(1)<<endl;
cout<<s.Test(8)<<endl;
cout<<s.Test(33)<<endl;
}