0
点赞
收藏
分享

微信扫一扫

每天一点python——day84

金牛豆豆 2023-12-03 阅读 40

在这里插入图片描述

哈希的应用

1. 前言

哈希最常用的应用是unordered
系列的容器,但是当面对海量数据
如100亿个数据中找有没有100这
个数时,使用无序容器的话内存放不下
所以哈希思想还有别的更重要的应用!

本章重点:


2. 位图的概念以及定义

请先看一道海量数据的面试题:

在这里插入图片描述

而一个数在或不在可以用1/0来表示
也就是说其实只需要一个比特位就可
以知道一个数在不在其中.
于是位图横空出世!

位图概念:

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

举例说明:

在这里插入图片描述


3. 位图的模拟实现

先来看看库中实现的位图:
在这里插入图片描述

模板参数N代表位图的大小

位图有三个主要的接口函数:

  1. set: 将一个数据放入位图中
  2. reset:将一个数据从位图中删掉
  3. test:检测一个数据在不在位图中

位图本身就是一段连续的空间
所以用char类型数组来充当位图的
基本结构是很符合情况的!

先将位图框架写出来:

template<size_t N>//N是所有数中的最大值
class bit_set
{
public:
	bit_set()
	{
		_bit.resize(N / 8 + 1, 0);
	}
	void set(size_t x)//将第x位变成1
	{}
	void reset(size_t x)//将第x位由1变0
	{}
	bool test(size_t x)
	{}
private:
	vector<char> _bit;
};

在这里插入图片描述

template<size_t N>//N是所有数中的最大值
class bit_set
{
public:
	bit_set()
	{
		_bit.resize(N / 8 + 1, 0);
	}
	void set(size_t x)//将第x位变成1
	{
		//x/8->在第几个char
		//x%8->在这个char的第几个比特位
		size_t i = x / 8;
		size_t j = x % 8;
		_bit[i] |= (1 << j);//将x对应的比特位变成1
	}
	void reset(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;
		_bit[i] &= ~(1 << j);//将x对应的比特位变成0
	}
	bool test(size_t x)
	{
		size_t i = x / 8;
		size_t j = x % 8;
		return _bit[i] & (1 << j);
	}
private:
	vector<char> _bit;
};

关于代码的解释都在注释中,请耐心观看
必要时可以自己画图做做试验


4. 布隆过滤器的概念以及定义

位图有一个缺陷,那就是只能判断整型是否存在
遇见字符串等类型的数据就很难处理了

布隆过滤器的提出:

在这里插入图片描述
布隆过滤器的概念:

举例说明:

在这里插入图片描述
查找字符"美团"是否存在时,会找到
这三个绿色的位置,看看是否都为1

布隆过滤器的拓展阅读:

布隆过滤器原理


5. 布隆过滤器模拟实现(一)

首先,布隆过滤器的底层也是位图,所以
只需封装一层即可实现一个布隆过滤器!

//三个不同的字符串映射成整数的函数
struct HashBKDR
{
	size_t operator()(const string& key)
	{
		size_t val = 0;
		for (auto ch : key)
		{
			val *= 131;
			val += ch;
		}
		return val;
	}
};
struct HashAP
{
	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
{
	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 Bloom_Filter
{
public:
	void set(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		_bits->set(hash1);
		size_t hash2 = Hash2()(key) % (_ratio * N);
		_bits->set(hash2);
		size_t hash3 = Hash3()(key) % (_ratio * N);
		_bits->set(hash3);
	}

	bool test(const K& key)
	{
		size_t hash1 = Hash1()(key) % (_ratio * N);
		if (!_bits->test(hash1))
			return false; // 准确的
		size_t hash2 = Hash2()(key) % (_ratio * N);
		if (!_bits->test(hash2))
			return false; // 准确的
		size_t hash3 = Hash3()(key) % (_ratio * N);
		if (!_bits->test(hash3))
			return false;  // 准确的
		return true; // 可能存在误判
	}

	void reset(const K& key)//支持删除操作的话,可能会把其他数据对应的映射值删除
	{}
private:
	const static size_t _ratio = 5;//开的空间越大,误判率越小
	std::bitset<_ratio* N>* _bits = new std::bitset<_ratio * N>;//标准库中的位图是在栈上开辟的静态数组,过大会栈溢出
};

6. 布隆过滤器模拟实现(二)

布隆过滤器的查找是一个很玄幻的过程:

因为哈希函数可能存在冲突的原因,如下:

在这里插入图片描述
所以我们得出一个结论:

  • 布隆过滤器说一个元素存在,那它可能存在
  • 布隆过滤器说一个元素不在,那它一定不在

布隆过滤器的删除操作:

在这里插入图片描述


7. 处理海量数据的面试题

海量数据的处理,有对位图的应用
也有对布隆过滤器的应用一步一步解析

位图的应用:

  1. 给100亿个整数,设法找到只出现一次的整数?
  2. 给两个文件,分别有100亿个整数,只有1G内存,如何找到两个文件交集?
  3. 位图应用变形:一个文件有100亿个int,1G内存,设法找到出现次数不超过2次的所有整数

布隆过滤器的应用:

  1. 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
  2. 如何扩展BloomFilter使得它支持删除元素的操作

这些问题大家可以下来想一想,有什么问题欢迎私信


8. 总结

讲到这里,哈希的所有内容就已经
讲完了,所以无脑哈希无脑哈希,
但实际上要学好哈希还真得费点脑子

海量数据得处理问题在面试时也是
经常问的,希望同学们好好学扎实!


🔎 下期预告:C++11新改动🔍
举报

相关推荐

0 条评论