Hash表(3):hash表的应用

位图的应用场景引出: 

位图概念: 

用每一个比特位来存放某种状态,适用于海量数据,数据无重复的场景。通常用于判断某个数据是否存在

位图的实现:

template<size_t N>
	class bitset
	{
	public:
		//构造函数
		bitset()
		{
			//开多少char 一个char大小为一个字节=8个比特位
            //为余的位数多开一个char
			_bits.resize(N/8+1, 0);
		}
        
        //标记的时候是从低位往高位存
		void set(size_t x)
		{
			//计算存在第几个char中
			size_t i = x / 8;
			//存在该char的第几个位里
			size_t j = x % 8;
			//当前char的每个位都是零,要将映射的位置置为1 
			// 原来的位置是1还是1 原来是0的位置还是零不变
			//采用位运算的方法  高 00000000 低
			//                     00000001
			//注意运算的优先级! 分不清就套括号
			_bits[i] = _bits[i]|(1 << j);
		}

		//将元素的值映射的位置置为0
		void reset(size_t x)
		{
			//计算存在第几个char中
			size_t i = x / 8;
			//存在该char的第几个位里
			size_t j = x % 8;

			//原来的0和1不变 所映射的位置置为0
			// 00001010
			
			// 00001000
			// 11110111

			//这里是按位取反 解决问题时可以运用逆向思维
			_bits[i] = _bits[i]& (~(1 << j));
		}

		bool test(size_t x)
		{
			//计算存在第几个char中
			size_t i = x / 8;
			//存在该char的第几个位里
			size_t j = x % 8;

			//00000101
			//00000100

			return _bits[i] & (1 << j);
		}
	private:
        //创建一个以char为存储元素的vector,一个char是8个bit位
		vector<char> _bits;
	};

测试用例:

void test_bit_set1()
	{
		bitset<100> bs1;
		bs1.set(8);
		bs1.set(9);
		bs1.set(20);

		cout << bs1.test(8) << endl;
		cout << bs1.test(9) << endl;
		cout << bs1.test(20) << endl;

		bs1.reset(8);
		bs1.reset(9);
		bs1.reset(20);

		cout << bs1.test(8) << endl;
		cout << bs1.test(9) << endl;
		cout << bs1.test(20) << endl;
	}

运行结果及画图解释:

以上监视窗口是以16进制展示的结果

图示:

在位图上的扩展:

在此基础上,我们可以用两个位图来记录元素的数量,这样就可以筛选出出现过0 1 2 3次的数据个数

template<size_t N>
	class twobitset
	{
	public:
        //通过在两个位图相同的映射位置上置数来表示当前存储个数
		void set(size_t x)
		{
			//高位
			bool inset1 = _bs1.test(x);
			//低位
			bool inset2 = _bs2.test(x);
            
            //插入之前要看该数据映射的位置原来的个数
			// 00
			if (inset1 == false && inset2 == false)
			{
				//原来是00 置为01
				_bs2.set(x);
			}
			//01
			else if (inset1 == false && inset2 == true)
			{
				_bs1.set(x);
				_bs2.reset(x);
			}
			//10
			else if (inset1 == true && inset2 == false)
			{
				_bs2.set(x);
			}
			//else if (inset1 == true && inset2 == false)
			//{
			//	// ->11
			//	_bs1.set(x);
			//	_bs2.set(x);
			//}
		}

		void print_once_num()
		{
			for (size_t i = 0;i < N;i++)
			{
				if (_bs1.test(i) == false && _bs2.test(i) == true)
				{
					cout << i << endl;
				}
			}
		}

		void print_twice_num()
		{
			for (size_t i = 0;i < N;i++)
			{
				if (_bs1.test(i) == true && _bs2.test(i) == false)
				{
					cout << i << endl;
				}
			}
		}

		void print_third_num()
		{
			for (size_t i = 0;i < N;i++)
			{
				if (_bs1.test(i) == true && _bs2.test(i) == true)
				{
					cout << i << endl;
				}
			}
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

布隆过滤器

即用多个哈希函数,将一个数据映射到多个哈希地址中,可以用来告诉你“某个数据一定不存在或者可能存在”,既提升了查询效率,也可以节省大量的空间。

布隆过滤器的实现:

struct HashBKDR
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t val = 0;
		for (auto ch : key)
		{
			val *= 131;
			val += ch;
		}

		return val;
	}
};

struct HashAP
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (size_t i = 0; i < key.size(); i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ key[i] ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ key[i] ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

struct HashDJB
{
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 5381;
		for (auto ch : key)
		{
			hash += (hash << 5) + ch;
		}

		return hash;
	}
};

//N表示要映射N个值
template<size_t N,
	class K = string, class Hash1 = HashBKDR, class Hash2 = HashAP, class Hash3 = HashDJB>
	class BloomFilter
{
public:
	void Set(const K& key)
	{
		// 要使用类的重载函数要先建立一个类的对象
        // 这里使用的是类的匿名对象
		size_t hash1 = Hash1()(key) % (_ratio * N);
		//cout << hash1 << endl;
		_bits->set(hash1);

		size_t hash2 = Hash2()(key) % (_ratio * N);
		//cout << hash2 << endl;
		_bits->set(hash2);

		size_t hash3 = Hash3()(key) % (_ratio * N);
		//cout << hash3 << endl;
		_bits->set(hash3);
	}

	bool Test(const K& key)
	{
		//三个位置只要有一个不在就肯定不在
		size_t hash1 = Hash1()(key) % (_ratio * N);
		//cout << hash1 << endl;
		if (_bits->test(hash1)==false)
		{
			return false;
		}

		size_t hash2 = Hash2()(key) % (_ratio * N);
		//cout << hash2 << endl;
		if (_bits->test(hash2) == false)
		{
			return false;
		}
		
		size_t hash3 = Hash3()(key) % (_ratio * N);
		//cout << hash3 << endl;
		if (_bits->test(hash3)==false)
		{
			return false;
		}

		return true;
	}
private:
	const static size_t _ratio = 5;
	//根据公式得出,开出的位数=4.2*N 这里把4.2给成5 即一个数据开5个位
    //这样开空间可以使误判率降低
	std::bitset<_ratio* N>* _bits = new std::bitset<_ratio* N>;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值