【C++篇】哈希扩展:位图和布隆过滤器+哈希切割

C++——哈希练习题 输出结果中的每个元素一定是 唯一 的。A:依次读取文件A中的query,i = Hash(query)%1000,这个query就进去Ai小文件。B:依次读取文件B中的query,i = Hash(query)%1000,这个query就进去Bi小文件。输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]输入:nums1 = [1,2,2,1], nums2 = [2,2]输入:nums = [5,1,5,2,5,3,5,4]输入:nums = [2,1,2,5,3,2] 阅读详情


位图

所谓位图,就是用内存的每个比特位来存放某种状态, 适用于海量的整数数据,通常是用
来判断某个数据存不存在。

我们库中是有这个容器的:bitset文档介绍

使用需包头文件:include<bitset>

常用接口:
在这里插入图片描述

接口功能
size返回容器大小(单位:比特)
test返回给定数据对应比特位的状态(为1返回true,为0返回false)
set将给定数据映射的的比特位设为1
reset将给定数据映射的的比特位设为0

面试题

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

常规查找方法可以吗?
比如:

  1. 用set解决?
  2. 排序+二分查找?

答案是不行!
我们来算算如果用常规的整数去处理,需要多少空间?

40亿个整数大概占160亿比特位,也就是16个G左右,非常的夸张。

位图解决

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0则代表不存在。

将数据集{1, 3, 7,4,12, 16, 19, 13, 22, 18}映射到位图(本质上是一个vector<char>的一个对象)中:
在这里插入图片描述
最后判断一个数在不在,看其映射的byte位的值即可。

模拟实现位图

对于比特位数据的操作,无非就是0和1直接修改或判断。因此,位图的实现的核心思想是位运算。

本文我们用vector<int>,作为载体,实现位图:
在这里插入图片描述

template<size_t N>
class Bitset
{
public:
	Bitset()
	{
		_a.resize(N / 32 + 1);//开好空间,默认初始空间位32位
	}
	//…………
private:
	vector<int> _a;
};
1. set

具体逻辑:

  1. 查找该比特位在哪个整数中i = x%32
  2. 查找该比特位在整数的第几位j = x/32
  3. 将该整数与对应比特位为1且其余为0的整数按位或_a[i] |= 1<<j

在这里插入图片描述

	void set(size_t x)
	{
		int i = x / 32;
		int j = x % 32;
		_a[i] |= (1 << j);
	}
2. reset

具体逻辑:

  1. 查找该比特位在哪个整数中i = x%32
  2. 查找该比特位在整数的第几位j = x/32
  3. 将该整数与对应比特位为0且其余为1的整数按位与_a[i] &= (~(1<<j))
    在这里插入图片描述
void reset(size_t x)
{
	int i = x / 32;
	int j = x % 32;
	_a[i] &= (~(1 << j));
}
3. test
  1. 查找该比特位在哪个整数中i = x%32
  2. 查找该比特位在整数的第几位j = x/32
  3. 返回将该整数与对应比特位为1且其余为0的整数按位与的结果return _a[i] & 1<<j

在这里插入图片描述

bool test(size_t x)
{
	int i = x / 32;
	int j = x % 32;
	//非零则为真
	return _a[i] & (1 << j);
}

海量数据面试题(位图应用)

位图的功能:

  • 快速查找某个数据是否在一个集合中
  • 排序 + 去重
  • 求两个集合的交集、并集等
  • 操作系统中磁盘块标记
  1. 给定100亿个整数,设计算法找到只出现一次的整数?
    具体逻辑:
    用两个比特位:遍历标记,每出现一次就+1,当为10(3)时,就无需+1了。最后遍历找01(1)即可。

用双位图实现:

void Test2()
{
	int a[] = { 1,2,3,3,4,4,4,4,4,2,3,6,3,1,5,5,8,9 };

	Bitset<10> bs1;
	Bitset<10> bs2;

	//遍历标记,每出现一次就+1,当为10(3)时,就无需+1了。最后遍历找01(1)即可
	for (auto e : a)
	{
		//00->01
		if (!bs1.test(e) && !bs2.test(e))
		{
			bs2.set(e);
		}
		//01->10
		else if (!bs1.test(e) && bs2.test(e))
		{
			bs1.set(e);
			bs2.reset(e);
		}
	}

	//遍历找01
	for (auto e : a)
	{
		if (!bs1.test(e) && bs2.test(e))
		{
			cout << e << " ";
		}
	}
	cout << endl;

}
  1. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
    具体逻辑:
    应用位图功能之一:去重
    双位图解决问题:
    1. 将两文件的数据分别映射到两个位图中
    2. 若两位图对应的byte皆为1,则该对应的数是交集的
void Test3()
{
	int a1[] = { 1,2,3,3,4,4,4,4,4,2,3,6,3,1,5,5,8,9 };
	int a2[] = { 8,4,8,4,1,1,1,1 };

	Bitset<10> bs1;
	Bitset<10> bs2;

	// 去重
	for (auto e : a1)
	{
		bs1.set(e);
	}

	// 去重
	for (auto e : a2)
	{
		bs2.set(e);
	}

	for (int i = 0; i < 10; i++)
	{
		if (bs1.test(i) && bs2.test(i))
		{
			cout << i << " ";
		}
	}
	cout << endl;

}


布隆过滤器

位图虽然强大,但却只能用于整数数据,那对于字符串数据呢?

其实,我们可以用一些字符串哈希函数将字符串其转换为整数数据,然后再用位图解决问题。

字符串哈希算法

但还是存在很大的问题:

假设经过字符串哈希算法计算后,“百度”对应20,“腾讯”对应59,“阿里”对应38,映射结果如下:
在这里插入图片描述
问查找“字节”(假设对应59)的结果如何?
查找结果:“字节”是存在的,因为腾讯也是59。

但实际上,“字节”是不存在的。
由此我们可以得出结论:

  • 判断数据存在是不准确的:可能因为冲突而导致误判。
  • 判断数据不存在是准确的

那能否降低误判率呢?

布隆过滤器正是解决此问题的!

布隆过滤器原理:它是用多个字符串哈希算法,将一个数据映射到位图结构中。

比如,我们用三个字符串哈希算法,将一个数据对应3个整数,查找时,需要对应的3个整数在位图中映射都为1,才能判定该数据存在。
在这里插入图片描述
【注意】

  1. 布隆过滤器只是降低误判的概率(可以做到大幅度降低),但误判是无可避免的。
  2. 一般情况下不能从布隆过滤器中删除元素,因为可能会影响其他数据。
  3. 误判率与哈希函数个数和所给空间大小有关
    在这里插入图片描述
    参考文献:详解布隆过滤器的原理,使用场景和注意事项

布隆过滤器实现

我选用了三个评分最高的哈希函数来实现hhh
在这里插入图片描述
实现逻辑非常简单,对bitset进行封装即可

将哈希函数写为仿函数。

set:
用3个哈希函数来计算数据对应的整数,然后用set到位图中即可

test:
用3个哈希函数来计算数据对应的整数,然后判断各个整数在位图中是否为1

//BKDR哈希算法
struct BKDRHash
{
    size_t operator()(const string& str)
    {
        size_t hash = 0;
        for (auto ch : str)
        {
            hash = hash * 131 + ch;
        }

        return hash;
    }
};

//AP哈希算法
struct APHash
{
    size_t operator()(const string& str)
    {
        size_t hash = 0;
        for (size_t i = 0; i < str.size(); i++)
        {
            size_t ch = str[i];
            if ((i & 1) == 0)
            {
                hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
            }
            else
            {
                hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
            }
        }

        return hash;
    }
};

//DJB哈希算法
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 = BKDRHash
    , class Hash2 = APHash
    , class Hash3 = DJBHash>
class BloomFilter
{
public:
    void set(const K& key)
    {
        size_t hash1 = Hash1()(key) % N;
        _bt.set(hash1);
        
        size_t hash2 = Hash2()(key) % N;
        _bt.set(hash2);

        size_t hash3 = Hash3()(key) % N;
        _bt.set(hash3);

    }

    bool test(const K& key)
    {
        size_t hash1 = Hash1()(key) % N;
        if (!_bt.test(hash1))
            return false;

        size_t hash2 = Hash2()(key) % N;
        if (!_bt.test(hash2))
            return false;

        size_t hash3 = Hash3()(key) % N;
        if (!_bt.test(hash3))
            return false;
        return true;
    }
private:
	bitset<N> _bt;
};

哈希切割

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

此处近似算法可以用布隆过滤器解决,但精确算法得用哈希切割。

何为哈希切割?

用哈希函数将一组数据进行分类,就是哈希切割。

本题我们可以分别将两个海量数据文件分割为1000份:
假设两文件分别为A和B
A被分为(A0,A1,A2,……,A998,A999)
B被分为(B0,B1,B2,……,B998,B999)

i = Hash(query) % 1000
i是多少,query就进入第i个小文件

最后依次找Ai和Bi的交集即可。

💡:切割后的每个小文件就像哈希表的桶
图解:
在这里插入图片描述

找交集方法:将Ai读出来放到一个set,然后再用这个set去查找Bi的query在不在,在就是交集。

如果是平均切割为1000份,每份的大小约为300MB,但是哈希切分并非平均切分,在冲突较为极端的情况下,会导致其中某个Ai文件太大,超过1G,那就不符合题意了。

那怎么办呢?

哈希冲突太多有两个情况:

  1. 大半部分都是相同的query
  2. 大多数的query都是冲突

解决方案:

先把Ai的query读到一个set,

  1. 如果set的insert报错抛异常(bad_alloc),说明是大多数的query都是冲突,在换一个哈希函数,再次进行哈希切割。
  2. 如果Ai能够全部被读取insert到set中,那就锁门ai中有大量重复的query。

面试题2
给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?

与上题同样的方式进行哈希切割,相同的IP地址一定在一个小文件中,用map去分别统计每个小文件中IP出现的次数即可。

BSD盲区检测系统性能要求及试验方法 盲区监测系统BSD通过安装在车辆后方的两颗毫米波雷达实时监测驾驶员视野盲区,当发现视野盲区内出现其它道路使用者时,通过左右后视镜上的警示灯向驾驶员发出报警。 阅读详情

相关推荐

Twincat Scopeview录波中的Ringbuffer设置技巧与常见问题解决

本文深入解析了倍福Twincat Scopeview录波功能中Ringbuffer(环形缓冲区)的核心设置技巧与常见问题解决方案。针对数据丢失、触发时机不准等痛点,详细阐述了缓冲区大小、预触发样本、采样率等关键参数的优化配置,并提供了多通道同步、自动诊断等实战应用指南,帮助工程师高效捕捉和分析PLC数据。

rainy的博客 846

C++寻位映射的究极密码:哈希扩展

位图和布隆过滤器是基于哈希的一种常见应用,通常用来处理大体量数据,提升查找数据的效率

Zero_VPN的博客 3039

Linux服务器上后台运行jupyter notebook/Lab

1 安装配置教程2 后台运行jupyter3 更改运行环境kernel4 SSH端口转发 1 安装配置教程 可以参考:https://www.cnblogs.com/thousfeet/p/10647102.html 2 后台运行jupyter screen -S jupyter # 新建一个名为jupyter的后台screen # 在base环境下,先 cd 到指定文件目录 jupyter notebook # or jupyter lab 3 更改运行环境kernel 需要手动为每个环境添加内.

strivequeen的博客 1835

【数据结构】盘点那些经典的 [哈希面试题]【哈希切割】【位图应用】【布隆过滤器】(10)

一.哈希切割 【1】给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 二.位图应用 【1】给定100亿个整数,设计算法找到只出现一次的整数? 【2】位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数 【3】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集? 三.布隆过滤器 【1】给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法——

YYDsis的博客 1758

NACA0012的O型网格求解

本篇文章采用偏微分方程数值解法生成NACA0012翼型O型网格,并采用速度势方程求解绕NACA0012翼型迎角为0度时的低速不可压无粘流场。 文章目录一、求解网格1.翼型2.远场3.网格4.迭代5.求解二、求解流场1.偏微分方程2.迭代求解流场三、求解参数1.偏微分方程2.迭代求解四、导出数据 一、求解网格 1.翼型 本次求解网格和流场等采用的是NACA0012(修形)对称翼型,在NACA四位翼型中,第一位数字代表的是弯度,第二位数字代表的是弯度位置,后两位数字代表的是厚度,由于本次翼型的前两位数字都为0,

m0_50746433的博客 6677

雷达信号处理DDC数字下变频

由于接收到的雷达信号频率较高,不能对其进行直接采样并数据处理,所以需要对雷达信号进行预处理,在降低其采样率的同时,将其由中频降低到低频,然后对输出的基带信号进行后续的解析,以便于获取雷达信号的特征参数。 本文采用数字正交下变频,将单通道信号转化为正交双通道信号,数字下变频(DDC)的原型为模拟下变频,通过对窄带雷达信号或单频信号进行数字混频,然后对信号进行正交采样,提取 I、Q 两路正交分量,最后通过滤波去除信号中的高频分量,将信号由中高频搬移至低频。 模拟下变频的系统框图如下: 其数学推导.

qq_44033461的博客 5229

一文学会《C++》进阶系列之哈希(包括位图布隆过滤器)

文章摘要:C++11引入了unordered系列关联容器(unordered_map、unordered_set等),其底层采用哈希结构实现,查询效率可达O(1)。与红黑树实现的map/set相比,unordered系列容器通过哈希值直接定位元素,但遍历效率较低。文章重点介绍了unordered_map的特性(键值唯一、无序存储、哈希桶机制)和常用接口(构造、容量查询、元素访问[]操作符等),并对比了哈希结构与顺序结构/平衡树的性能差异,指出哈希结构通过减少关键码比较次数实现高效查询。(149字)

2403_87165176的博客 1958

专栏丨华为HN8145XR光猫获取超级管理员密码

摘要:本文详细介绍了华为HN8145xr光猫获取超级管理员权限的完整步骤。首先通过ONT使能工具补全shell,然后利用Telnet登录光猫后台进行操作。文章提供了多种获取超级密码的方法,包括配置文件解密、一键查询工具等,并针对联通光猫特别说明了默认密码格式(CUAdmin+后八位数字)。此外,还介绍了恢复出厂设置、修改SSID等实用操作,帮助用户完全掌控光猫设备。文末附有详细的命令行操作指南,适合有一定技术基础的用户参考。

8276

【C++】位图和布隆过滤器

这篇文章详细的介绍了位图与布隆过滤器,位图与布隆过滤器是C++开发者在处理大数据集时常用的优化工具。位图通过每一位表示集合中某元素的存在性,实现空间与查询效率的双赢,特别适用于快速去重和查找。而布隆过滤器则是一种概率型数据结构,利用多个哈希函数降低误判率,适用于判断元素是否“可能”存在于集合中,适合处理大规模数据过滤。尽管布隆过滤器存在删除困难和一定误判率的缺点,但其高效的空间利用率和查询速度,使其成为处理海量数据时的优选方案。掌握位图与布隆过滤器的实现与应用,对于提升C++程序性能至关重要。

是阿建吖! 1534

302.QoS实现工具之MQC

QoS 技术可以对网络中报文进行分类处理,根据优先级提供不同的差分服务,如何实现这种差分服务呢?我们有一种强大的配置方法 - 模块化 QoS 命令行 MQC(Modular QoS Command-Line)。下面就来介绍一下 MQC。

迷逝 1393

OpenClaw用户必看:每天0成本使用OpenClaw!NVIDIA NIM免费大模型接入教程

🚀 OpenClaw接入NVIDIA NIM免费API!glm5、minimax-m2.5等大量模型任选,0成本升级AI助手!💰

XiaoqiangClub的博客 5579

【重走C++学习之路】21、位图和布隆过滤器

位图和布隆过滤器的基本概念、模拟实现,海量数据处理问题

MeiYu_123的博客 1100

YOLOv12创新改进 | 全网独家创新篇、小目标检测改进 | AAAI 2025 | 引入HS-FPN中的HFP和SDP创新点,从频域增强小目标特征,淘汰FPN进行升级,助力YOLOv12有效涨点

本文提出了HS-FPN(高频和空间感知特征金字塔网络),通过HFP(高频感知)模块增强小目标特征,SDP(空间依赖感知)模块捕获像素间空间依赖关系。实验在AI-TOD等小目标数据集上验证了该方法的有效性,相比FPN显著提升检测性能。文章详细介绍了HS-FPN的网络结构、核心代码实现及在YOLOv12中的应用方法,并提供多种改进版本的yaml配置文件,为小目标检测任务提供了有效的解决方案。

Ai缝合怪、助力小伙伴高效发论文 338

[C++][数据结构][哈希表的应用][位图][布隆过滤器]详细讲解

[C++][数据结构][哈希表的应用][位图][布隆过滤器]详细讲解

SnowK博客 4585

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

数据结构——哈希的应用之位图,布隆过滤器与哈希切割

本篇博客主要讲述的是应用哈希的一些数据结构_位图和布隆过滤器,讲解了这两个数据结构的性质和意义所在,还有一个使用哈希的数据处理方法——哈希切割,最后给出了一些具体的使用场景。

weixin_72883322的博客 399

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

详解C++位图/布隆过滤器+海量数据处理

当删除一个元素时,将其加入到B中。近似算法:可以使用布隆过滤器的方法,先将一个文件中的所有query插入到一个布隆过滤器中,然后遍历另一个文件中的query,用布隆过滤器检查是否可能存在于第一个文件中。1.我们常规的方法,直接遍历,时间复杂度O(N),但是40亿个数中寻找一个数,无异于大海捞针,直接遍历所消耗的时间还是很多,更别说我们用什么来存储这40亿个数❌。,这样其他比特位都是0,如果测试的比特位是1,则结果是非0,那就是true,如果测试的比特位是0,则结果是0,那就是false。

weixin_55582891的博客 1205

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++海量数据处理:位图和布隆过滤器

前言 有一道非常经典的题目:给40亿个不重复的无序的无符号整数,再给一个无符号整数,如何快速判断这个数是否在这40亿个数中。 关于这道题目我们首先想到的解法就是排序二分查找,或者借助关联式容器进行求解,但是40亿个数据的数据量是非常巨大的(16G),没有办法放入内存中,所以在面对这种海量数据处理的时候,我们今天来学习位图和布隆过滤器的相关知识,用来解决海量数据处理的问题。 一:位图 位图其实就是哈希结构的变形,同样通过映射来处理数据,采用直接定址法存储数据,只不过位图本身并不存储数据,而是通过存储一个比特位

Outtch_的博客 541

【高阶数据结构】海量数据如何处理? (位图 & 布隆过滤器)

新年快乐

qq_42996461的博客 1797
上一篇: 【C++篇】STL的关联容器:unordered_map和unordered_set(下篇):用一个哈希表同时封装unordered_map和unordered_set
下一篇: 【C++篇】C++11入门:踏入C++新世界的大门
我想吃余
博客等级 码龄3年 1144粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值