【C++】哈希的应用

位图

腾讯面试题:给40亿个不重复的无符号整数,没排过序,给一个无符号整数,如何快速判断一个数是否在40亿个数中。

  • 遍历??时间复杂度为O(N)
  • set使用红黑树??

40亿个整数等于160亿byte,1G等于1024MB等于1024*1024kb等于1024*1024*1024byte,换算过来1G等于10亿byte,那么160亿byte大约等于16G。这种情况也仅仅只是使用顺序表来存储,如果使用容器(红黑树),那么内存消耗会更大。

可以利用哈希的直接定址法,如果需要确定的值有42亿个值,可以通过2^32bit位置来确定对应值是否存在,1个字节有8个bit位也就是可以确定2^3,此时42亿个数据需要2^29字节,即500MB的内存空间即可。

通过在顺序表中保存int的值,一个int有4个字节也就是代表32个值,如果需要存储例如80,只需要用80 / 32 = 2,也就是80在下标为2的int值中的第80%32的bit位置。

【科普】计算机底层存储可能是按照大端机,也可能是小端机存储方式。

cpp 复制代码
#pragma once
#include <vector>
#include <iostream>

using namespace std;

template<size_t N>
class BitSet
{
public:
	BitSet()
	{
		_a.resize(N / 32 + 1);
	}

	// 将x映射的值标记成1
	void set(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;
		_a[i] |= (1 << j);
	}

	// 将x映射的值标记成0
	void reset(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;
		_a[i] &= ~(1 << j);
	}
	
	// 检查一个值在不在
	bool Test(size_t x)
	{
		size_t i = x / 32;
		size_t j = x % 32;
		return _a[i] & (1 << j);
	}

private:
	vector<int> _a;
};

库里面实现的位图bitset

位图相关问题:

(1)给定100亿个整数,设计算法找到只出现一次的整数

【解释】

方法1:改造位图,将两个bit位表示,00表示没有出现,01表示出现一次,10表示出现2次及2次以上。

方法2:使用库中位图结构,设计两个位图,表示一个整数。

(2)给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

【解释】设计两个位图结构,对应的位置进行&。对应位置都为1,那么这个值就是交集。

(3)位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数。

【解释】设计两个位图结构,00表示没有出现,01表示出现一次,10表示出现2次,11表示2次以上。

布隆过滤器

引入布隆过滤器

在使用抖音、新闻等客户端看内容时,会不停地推荐新的内容,而在每次推荐时都会进行去重,去掉已经看过的内容。此时的问题是,这些客户端推荐系统是如何实现推送去重的?

【解释】使用服务器记录用户看过的所有历史记录,当推荐系统推荐新闻时会从每个用户的历史记录中进行筛选,过滤掉那些已经存在的记录。

++问题:那么如何快速查找?++

【目前已知的方式】

  1. 用哈希表存储用户记录,缺点:浪费空间
  2. 用位图存储用户记录,缺点:位图一般只能处理整形,如果内容编号是字符串,就无法处理了。
  3. 将位图与哈希结合使用,即布隆过滤器。

布隆过滤器的概念

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的一种紧凑的、比较巧妙地概率型数据结构,特点是高效地插入和查询,可以用来说明"某样东西一定不存在或者可能存在",他就是用多个哈希函数,将一个数据映射到位图结构中,此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

将一个字符串使用多种方式映射到不同的位置上,只有当一个字符串进行查询时,每一个方式都可以对应上即说明这个字符串是对应的字符串,但是也会出现误判的情况,但是此时的误判率大大降低。

  • 此时字符串存在:误判率较低
  • 此时字符串不存在:准确
cpp 复制代码
#pragma once
#include <iostream>
#include <bitset>

using namespace std;

struct BKDPHash
{
	size_t operator()(const string& str)
	{
		size_t hash = 0;
		for (auto ch : str)
		{
			hash = hash * 131 + ch;
		}
		return hash;
	}
};

struct APHash
{
	size_t operator()(const string& str)
	{
		size_t hash = 0;
		for (int i = 0; i < str.size(); ++i)
		{
			size_t ch = str[i];
			if ((i & i) == 0)
			{
				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
			}
		}
		return hash;
	}
};

struct DJBHash
{
	size_t operator()(const string& str)
	{
		size_t hash = 5381;
		for (auto ch : str)
		{
			hash += (hash << 5) + ch;
		}

		return hash;
	}
};

template<size_t N, 
	class K = string, 
	class Hash1 = BKDPHash, 
	class Hash2 = APHash, 
	class Hash3 = DJBHash>
class BloomFilter
{
public:
	void Set(const K& key)
	{
		size_t hash1 = Hash1()(key) % N;
		size_t hash2 = Hash2()(key) % N;
		size_t hash3 = Hash3()(key) % N;

		_bs.set(hash1);
		_bs.set(hash2);
		_bs.set(hash3);
	}

	// 布隆过滤器一般不支持reset

	bool Test(const K& key)
	{
		size_t hash1 = Hash1()(key) % N;
		size_t hash2 = Hash2()(key) % N;
		size_t hash3 = Hash3()(key) % N;

		if (_bs.test(hash1) == false) return false;
		if (_bs.test(hash2) == false) return false;
		if (_bs.test(hash3) == false) return false;

		return true; // 存在误判
	}


private:
	bitset<N> _bs;
};

应用场景:

1.不需要精确的场景,例如快速判断昵称是否注册过(容忍误判)。如果需要精确的场景,使用布隆过滤器当作筛板,如果不在直接返回,如果存在进一步到数据库查找并精准判断。

布隆过滤器的场景问题:

1.给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法?

【答】近似算法使用布隆过滤器,精确算法使用哈希切分。

2.如何扩展BlookFilter使得其支持删除元素的操作?

【答】多个位标识一个值,使用引用计数。

相关推荐
AI成长日志32 分钟前
【笔面试算法学习专栏】哈希表基础:两数之和与字母异位词分组
学习·算法·面试
abant243 分钟前
leetcode 239 单调队列 需要一些记忆
算法·leetcode·职场和发展
漫霂1 小时前
二叉树的统一迭代遍历
java·算法
炽烈小老头1 小时前
【每天学习一点算法 2026/04/08】阶乘后的零
学习·算法
Mr_Xuhhh1 小时前
算法刷题笔记:从滑动窗口到哈夫曼编码,我的算法进阶之路
开发语言·算法
MicroTech20251 小时前
突破虚时演化非酉限制:MLGO微算法科技发布可在现有量子计算机运行的变分量子模拟技术
科技·算法·量子计算
hssfscv1 小时前
软件设计师下午题六——Java的各种设计模式
java·算法·设计模式
珂朵莉MM1 小时前
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--多策略混合算法
人工智能·算法
罗西的思考1 小时前
【OpenClaw】通过 Nanobot 源码学习架构---(6)Skills
人工智能·深度学习·算法
枫叶林FYL2 小时前
【自然语言处理 NLP】7.2 红队测试与对抗鲁棒性(Red Teaming & Adversarial Robustness)
人工智能·算法·机器学习