位图
#pragma once
//位图其实 是利用物理位置来映射实际的数,来进行查找;优点是节省内存,不用插入数据结构中再进行查找;
//非类型模板参数
template<size_t N>
class bitset
{
public:
//构造函数
bitset()
{
_bits.resize(N/8+1,0);
}
//设置x映射的比特位为1
void set(size_t x)
{
//计算x在数组第i个char(其实是第i+1个位置)
size_t i = x / 8;
//计算x在第i个位置的第j个比特位(其实是第j+1个比特位,因为这里是左移j位);
size_t j = x % 8;
_bits[i] |= (1 << j);
}
//设置x映射的比特位为0
void reset(size_t x)
{
//计算x在数组第i个char(其实是第i+1个位置)
size_t i = x / 8;
//计算x在第i个位置的第j个比特位(其实是第j+1个比特位,因为这里是左移j位);
size_t j = x % 8;
_bits[i] &= ~(1 << j);//注意优先级(位运算符号优先级较低)
}
//检查这个数在不在;
bool test(size_t x)
{
//计算x在数组第i个char(其实是第i+1个位置)
size_t i = x / 8;
//计算x在第i个位置的第j个比特位(其实是第j+1个比特位,因为这里是左移j位);
size_t j = x % 8;
size_t ret = (1 << j) & _bits[i];
if (ret==0)
return false;
//1的位置不一样,结果也不一样,但是只要不为0,那么就一定存在;
else
return true;
}
private:
vector<char> _bits;
};
void test_bitset1()
{
bitset<100> s1;
s1.set(10);
s1.set(12);
s1.reset(12);
}
template<size_t N>
class twobitset
{
public:
//搞成进制型的 用来计算该数出现了几次;
void set(size_t x)
{
//00->01,从 出现0次 到 出现一次;
if ( _bs1.test(x)==false && _bs2.test(x)==false )
{
_bs2.set(x);
}
//01->10,从出现1次到出现两次
else if (_bs1.test(x) == false && _bs2.test(x) == true)
{
_bs1.set(x);
_bs2.reset(x);
}
//10->11,11->11,出现两次及两次以上;
else
{
_bs1.set(x);
_bs2.set(x);
}
}
//找出范围0--N中 只出现一次的数;
void Print()
{
for (int i=0;i<N;++i)
{
if (_bs1.test(i) == false && _bs2.test(i) == true)
{
cout << i << " ";
}
}
}
private:
bitset<N> _bs1;//用来进位;
bitset<N> _bs2;
};
void test_bitset2()
{
//bitset<0XFFFFFFFF> s1;//-1转化成无符号整数就是无符号整数的最大值 42亿9千万;
int arr[] = {3,6,7,8,5,7,3,11,16,28,39,42,28};
twobitset<100> b1;
for (auto& e : arr)
{
b1.set(e);
}
b1.Print();
}
布隆过滤器
//三个仿函数,用来计算哈希位置的;
struct BKDRHash
{
size_t operator()(const string& str)
{
size_t hashi = 0;
for (auto& ch:str)
{
hashi += ch;
hashi *= 31;
}
return hashi;
}
};
struct APHash
{
size_t operator()(const string& s)
{
size_t hash = 0;
for (long i = 0; i < s.size(); i++)
{
if ((i & 1) == 0)//最后一个比特位是0
{
hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
}
else//最后一个比特位是1;
{
hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
}
}
return hash;
}
};
struct DJBHash
{
size_t operator()(const string& str)
{
size_t hashi = 5381;
for (auto& ch : str)
{
hashi += (hashi << 5)+ch;
}
return hashi;
}
};
//布隆过滤器(建立多映射,降低冲突率)
//应用场景大多是字符串,所以可以给默认缺省;
template <size_t N,class K = string,class Hash1=BKDRHash,class Hash2=APHash,class Hash3=DJBHash>
class BloomFilter
{
public:
void set(const K& key)
{
size_t len = N * _X;
//找多个映射位置,降低冲突率;
size_t hash1 = Hash1()(key) % len;//算出哈希映射位置;
_bs1.set(hash1);
size_t hash2 = Hash2()(key) % len;
_bs1.set(hash2);
size_t hash3 = Hash3()(key) % len;
_bs1.set(hash3);
//用来查看映射的位置是否冲突;
cout << hash1 << " " << hash2 << " " << hash3 << endl;
}
//不在一定准确,在不一定准确;因为映射的几个比特位中只要有0一定是不在;
bool test(const K& key)
{
size_t len = N * _X;
size_t hash1 = Hash1()(key) % len;
if (!_bs1.test(hash1))
{
return false;
}
size_t hash2 = Hash2()(key) % len;
if (!_bs1.test(hash2))
{
return false;
}
size_t hash3= Hash3()(key) % len;
if (!_bs1.test(hash3))
{
return false;
}
//说明这三块比特位都为1;
return true;
}
private:
static const size_t _X=4;//需要开辟的空间大小,越大冲突率越低;
bitset<N*_X> _bs1;//成员变量 :位图
};
void test_bloomfilter()
{
BloomFilter<100> bf;
bf.set("sort");
bf.set("bloom");
bf.set("hello");
bf.set("test");
bf.set("stet");
}