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

这篇具有很好参考价值的文章主要介绍了【C++】哈希位图和布隆过滤器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

哈希位图和布隆过滤器都是常用的概率数据结构,用于高效地判断一个元素是否存在于一个集合当中,但它们在实现方法和各自的优缺点上有所区别。

哈希位图

哈希位图(Hash Bitmap)是由一个位数组构成,每个元素(通常是一个整数)被映射到位数组中的某个位置。对于集合中的每个元素,通过哈希函数将其映射到位数组的对应位置,并将该位置标记为已经存在。判断一个元素是否存在时,只需检查位数组中对应的位置是否被标记,若被标记则表示元素存在,否则表示元素不存在

哈希位图(Hash Bitmap)是由一个位数组构成,每个元素(通常是一个整数)被映射到位数组中的某个位置。对于集合中的每个元素,通过哈希函数将其映射到位数组的对应位置,并将该位置标记为已经存在。判断一个元素是否存在时,只需检查位数组中对应的位置是否被标记,若被标记则表示元素存在,否则表示元素不存在。
【C++】哈希位图和布隆过滤器,c++,哈希算法,c++,算法

当我们存储整数时,因为一个整数为四个bit位,一个比特位八个字节,这样算下来占存的空间极大,我们可以使用char类型进行存储,因为char只占一个字节。
我们可以将数组按字节来进行归类,就如上图来说
当我们要进行存储X的时候,我们先用 X / 8 来算出它在哪个比特位,然后再进行X % 8 来计算出他在这个bit位的第几个字节,计算出后将此位置设置为1,标记此数字

优缺点

优点

  • 简单高效:哈希位图通过位运算可以在常量时间内完成元素的插入和查询操作。
  • 空间效率高:相对于其他数据结构,哈希位图在空间使用上非常紧凑,只需要存储每个元素的标记位即可。

缺点

  • 无法删除元素:哈希位图只能进行插入和查询操作,无法删除已经插入的元素。
  • 内存占用:如果集合中的元素较多,哈希位图会占用较大的内存空间。
位图应用
  1. 快速查找某个数据是否在一个集合中
  2. 排序 + 去重
  3. 求两个集合的交集、并集等
  4. 操作系统中磁盘块标记

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

分析:首先不要受到题目的迷惑,100亿整数中包括很多重复数据,实际范围是0到0xffffffff。

512M左右就可以表示数据是否存在了。

代码逻辑分析:

用两个位图来放两文件中的数据,用两个位图中的对应位置表示不同的状态:

00表示两文件中都没有某个数据,10表示在一个位图中出现过,01表示在两个位图中都出现了,这种状态也就是交集数据的状态。

模拟实现代码
using namespace std;
//普通类型模板
template<size_t N>
class bitset
{
public:
	bitset()
	{
		_bits.resize((N / 8) + 1, 0);
	}

	//将对应的值按照位图存放
	void set(size_t x)
	{
		size_t i = x / 8;//计算x映射的位在第i个char数组位置
		size_t j = x % 8;//计算x映射的位在这个char的第j个比特位
		_bits[i] |= (1 << j);
	}

	void reset(size_t x)
	{
		size_t i = x / 8;//计算x映射的位在第i个char数组位置
		size_t j = x % 8;//计算x映射的位在这个char的第j个比特位
		_bits[i] &= ~(1 << j);
	}

	//检查是否将位图修改
	bool test(size_t x)
	{
		size_t i = x / 8;//计算x映射的位在第i个char数组位置
		size_t j = x % 8;//计算x映射的位在这个char的第j个比特位

		return _bits[i] & (1 << j);
	}


private:
	vector<char> _bits;
};

template<size_t N>
class twobitset
{
public:

	//查找唯一出现一次的数
	void set(size_t x)
	{
		// 00 -> 01
		if (_bs1.test(x) == false
			&& _bs2.test(x) == false)
		{
			_bs2.set(x);
		}
		else
		{
			//01 -> 10
			_bs1.set(x);
			_bs2.reset(x);
		}
	}void Print()
	{
		for (size_t i = 0; i < N; ++i)
		{
			if (_bs2.test(i))
			{
				cout << i << endl;
			}
		}
	}
	void Print_more()
	{
		for (size_t i = 0; i < N; ++i)
		{
			if (_bs1.test(i))
			{
				cout << i << endl;
			}
		}
	}


private:
	bitset<N> _bs1;
	bitset<N> _bs2;
};


void test_twobitset()
{
	int a[] = { 1,1,2,2,3,3,4,4,5,5,6,6,7 };
	twobitset<20> t;
	for (auto e : a)
	{
		t.set(e);
	}
	t.Print();
	t.Print_more();
}

【C++】哈希位图和布隆过滤器,c++,哈希算法,c++,算法

哈希布隆过滤器

布隆过滤器(Bloom Filter)是一种概率型数据结构,基于位数组和多个哈希函数实现。对于集合中的每个元素,通过多个哈希函数将其映射到位数组的多个位置,并将对应位置标记为已经存在。判断一个元素是否存在时,需要对该元素进行多次哈希,并检查所有对应位置是否都被标记,若有任何一个位置未被标记,则表示元素不存在。

哈希布隆过滤器的提出

在注册账号设置昵称的时候,为了保证每个用户昵称的唯一性,系统必须检测你输入的昵称是否被使用过,这本质就是一个key的模型,我们只需要判断这个昵称被用过,还是没被用过。

  • 方法一:用红黑树或哈希表将所有使用过的昵称存储起来,当需要判断一个昵称是否被用过时,直接判断该昵称是否在红黑树或哈希表中即可。但红黑树和哈希表最大的问题就是浪费空间,当昵称数量非常多的时候内存当中根本无法存储这些昵称
  • 方法二:用位图将所有使用过的昵称存储起来,虽然位图只能存储整型数据,但我们可以通过一些哈希算法将字符串转换成整型,比如BKDR哈希算法。当需要判断一个昵称是否被用过时,直接判断位图中该昵称对应的比特位是否被设置即可。

位图虽然能够大大节省内存空间,但由于字符串的组合形式太多了,一个字符的取值有256种,而一个数字的取值只有10种,因此无论通过何种哈希算法将字符串转换成整型都不可避免会存在哈希冲突。

这里的哈希冲突就是不同的昵称最终被转换成了相同的整型,此时就可能会引发误判,即某个昵称明明没有被使用过,却被系统判定为已经使用过了,于是就出现了布隆过滤器。

哈希布隆过滤器概念

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询。

  • 布隆过滤器其实就是位图的一个变形和延申,虽然无法避免存在哈希冲突,但我们可以想办法降低误判的概率。
  • 当一个数据映射到位图中时,布隆过滤器会用多个哈希函数将其映射到多个比特位,当判断一个数据是否在位图当中时,需要分别根据这些哈希函数计算出对应的比特位,如果这些比特位都被设置为1则判定为该数据存在,否则则判定为该数据不存在。
  • 布隆过滤器使用多个哈希函数进行映射,目的就在于降低哈希冲突的概率,一个哈希函数产生冲突的概率可能比较大,但多个哈希函数同时产生冲突的概率可就没那么大了。

假设布隆过滤器使用三个哈希函数进行映射,那么“张三”这个昵称被使用后位图中会有三个比特位会被置1,当有人要使用“李四”这个昵称时,就算前两个哈希函数计算出来的位置都产生了冲突,但由于第三个哈希函数计算出的比特位的值为0,此时系统就会判定“李四”这个昵称没有被使用过。

【C++】哈希位图和布隆过滤器,c++,哈希算法,c++,算法
但随着位图中添加的数据不断增多,位图中1的个数也在不断增多,此时就会导致误判的概率增加。

比如“张三”和“李四”都添加到位图中后,当有人要使用“王五”这个昵称时,虽然“王五”计算出来的三个位置既不和“张三”完全一样,也不和“李四”完全一样,但“王五”计算出来的三个位置分别被“张三”和“李四”占用了,此时系统也会误判为“王五”这个昵称已经被使用过了。
【C++】哈希位图和布隆过滤器,c++,哈希算法,c++,算法

布隆过滤器的特点

  • 当布隆过滤器判断一个数据存在可能是不准确的,因为这个数据对应的比特位可能被其他一个数据或多个数据占用了。
  • 当布隆过滤器判断一个数据不存在是准确的,因为如果该数据存在那么该数据对应的比特位都应该已经被设置为1了。

如何控制误判率

  • 很显然,过小的布隆过滤器很快所有的比特位都会被设置为1,此时布隆过滤器的误判率就会变得很高,因此布隆过滤器的长度会直接影响误判率,布隆过滤器的长度越长其误判率越小。
  • 此外,哈希函数的个数也需要权衡,哈希函数的个数越多布隆过滤器中比特位被设置为1的速度越快,并且布隆过滤器的效率越低,但如果哈希函数的个数太少,也会导致误判率变高。

那应该如何选择哈希函数的个数和布隆过滤器的长度呢,有人通过计算后得出了以下关系式:
【C++】哈希位图和布隆过滤器,c++,哈希算法,c++,算法
其中k为哈希函数个数,m为布隆过滤器长度,n为插入的元素个数,p为误判率。

我们这里可以大概估算一下,如果使用3个哈希函数,即k的值为3,l n 2 的值我们取0.7,那么 m 和 n的关系大概是m = 4 × n ,也就是布隆过滤器的长度应该是插入元素个数的4倍。

模拟实现代码
//布隆过滤器
//N位最多插入的key个数据
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;
		_bs.set(hash1);

		size_t hash2 = Hash2()(key) % len;
		_bs.set(hash2);

		size_t hash3 = Hash3()(key) % len;
		_bs.set(hash3);
		cout << hash1 << " " << hash2 << " " << hash3 << endl;
	}

	bool test(const K& key)
	{
		size_t len = N * _x;
		size_t hash1 = Hash1()(key) % len;
		if (!_bs.test(hash1))
		{
			return false;
		}

		size_t hash2 = Hash2()(key) % len;
		if (!_bs.test(hash2))
		{
			return false;
		}

		size_t hash3 = Hash3()(key) % len;
		if (!_bs.test(hash3))
		{
			return false;
		}
		return true; //key对应的三个位都被设置,key存在(可能误判)
	}
private:

	static const size_t _x = 4;
	bitset<N * _x> _bs;//求布隆过滤器长度
};

_X代表布隆过滤器的长度,是通过以下公式计算得来的
【C++】哈希位图和布隆过滤器,c++,哈希算法,c++,算法

为什么哈希布隆图要比位图省空间

哈希布隆图相比于位图在空间使用上更加高效,这是因为哈希布隆图利用了多个哈希函数和位数组的重复利用,减少了所需的内存空间。

首先,让我们对比一下位图和哈希布隆图的实现方式:

  1. 位图:位图是一个固定大小的位数组,数组中的每个位置表示一个元素,当元素存在时,对应位置的位值为1;当元素不存在时,对应位置的位值为0。位图的大小与集合中元素的总数相一致,每个元素都需要一个位置来进行标记。

  2. 哈希布隆图:哈希布隆图也是一个位数组,但与位图不同的是,哈希布隆图的位数组长度通常会远远小于集合中元素的总数。它利用了多个哈希函数,每个元素通过这些哈希函数映射到位数组中的多个位置,将这些位置标记为1。判断一个元素是否存在时,需要对该元素进行多次哈希,并检查所有对应位置是否都被标记。

那么为什么哈希布隆图能够在空间上节省?

  1. 多个哈希函数:哈希布隆图使用多个哈希函数,将每个元素映射到位数组的多个位置上。通过这种方式,可以减少冲突的可能性,使得位数组中的每个位置都能够被更多元素共享,从而减少了位图中的重复位。

  2. 位数组的重复利用:由于每个元素都会被多次哈希并占用多个位置,在位数组中的某个位置可能被多个元素标记。利用这种重复标记的方式,哈希布隆图可以在相对较小的位数组中表示更多的元素。

举个例子来说明,假设我们要表示一个集合,其中包含100个元素。如果使用位图,我们需要一个大小为100的位数组,每个元素都占用一个位;而使用布隆过滤器,我们可以选择一个相对较小的位数组,比如大小为50,并使用多个哈希函数将元素映射到位数组的多个位置,每个元素可以占用多个位。通过合理的设计,可以在仅占用50个位的情况下,仍然能够高效地判断集合中的元素是否存在。

需要注意的是,哈希布隆图的节省空间是以牺牲一定的查询准确率为代价的。由于哈希冲突和位数组的重复利用,布隆过滤器可能存在一定的误判率,即判断元素不存在时,仍有一定概率判断为存在。因此,在使用哈希布隆图时需要权衡空间利用和查询准确率之间的关系。文章来源地址https://www.toymoban.com/news/detail-718960.html

到了这里,关于【C++】哈希位图和布隆过滤器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 哈希思想应用:位图,布隆过滤器,哈希切分

    1.问题 给你40亿个不重复的无符号整数,没排过序.给一个无符号整数,如何快速判断一个数是否在这40亿个数中? 2.分析 1 Byte = 8 bit 1KB = 1024 Byte 1MB = 1024KB = 1024 1024 大约= 10的6次方Byte 1GB = 1024MB = 1024 10的6次方 大约= 10的9次方Byte = 10亿字节 因此4GB 约等于40亿字节 其实最快的方式就是

    2024年04月17日
    浏览(34)
  • [C++]哈希应用之位图&布隆过滤器

               主厨:邪王真眼 主厨的主页:Chef‘s blog   所属专栏:c++大冒险        我们之前学习了哈希表,哈希表通过映射关系,实现了O(1)的复杂度来查找数据,哈希在实践中是一个非常重要的思想,今天要学习的就是哈希思想的两大应用:位图与布隆过滤器 给 40 亿个

    2024年04月15日
    浏览(29)
  • 【C++】哈希的应用:位图、哈希切分与布隆过滤器

    需要云服务器等云产品来学习Linux的同学可以移步/--腾讯云--/--阿里云--/--华为云--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。   目录 一、位图 1、位图的概念 2、大厂面试题 2.1位图应用(腾讯) 2.2位图应用 3、位图的优缺点 二、哈希切分 三、布隆过滤

    2023年04月09日
    浏览(39)
  • 【数据结构与算法】哈希—— 位图 | 布隆过滤器 | 哈希切割

    🐱作者:一只大喵咪1201 🐱专栏:《数据结构与算法》 🔥格言: 你只管努力,剩下的交给时间! 哈希是一种映射思想,这里再讲解两种应用哈希思想的数据结构。 问题: 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数

    2024年02月02日
    浏览(44)
  • 【C++高阶(六)】哈希的应用--位图&布隆过滤器

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 哈希最常用的应用是unordered 系列的容器,但是当面对海量数据 如100亿个数据中找有没有100这 个数时,使用无序容器的话内存放不下 所以哈希

    2024年02月05日
    浏览(35)
  • 【C++学习】哈希的应用—位图与布隆过滤器

    文章简介 : 在这篇文章中,你会学习到关于哈希思想的最常见的两个应用,也就是 位图 与 布隆过滤器 , 文章会讲解位图和布隆过滤器的概念,底层实现,对应的适应的场景,以及相关经典 海量数据面试题 及解析。 所谓位图,就是用每一位来存放某种状态,适用于 海量

    2024年04月14日
    浏览(50)
  • C++进阶--哈希的应用之位图和布隆过滤器

    哈希是一种映射的思想。 先来看一道题:给40亿个不重复的无符号整数,没排序过。给一个无符号整数,如何 快速判断 一个数 是否在 这40亿个数中。 首先想到的解法可能有这几种: 解法1 :遍历40亿个数,O(N) 解法2 :先排序,快排O( N l o g 2 N Nlog_2N Nl o g 2 ​ N ),再利

    2024年02月22日
    浏览(39)
  • C++哈希hash:位图、布隆过滤器的实现及应用

    所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用 来判断某个数据存不存在的。 当我们想查找某一个数据是否存在或者是否处于某种状态时,相比于直接对存放数据的容器进行遍历查找,与原存放数据的容器所建立映射关系的位图来

    2024年04月11日
    浏览(37)
  • 哈希思想应用【C++】(位图,布隆过滤器,海量数据处理面试题)

       目录 一,位图 1. 位图概念 2.实现 3. 测试题 位图的优缺点 二,布隆过滤器 1). 布隆过滤器提出 2). 概念 3). 布隆过滤器的查找 4). 布隆过滤器删除(了解) 5). 布隆过滤器优点 6). 布隆过滤器缺陷 三,海量数据面试题 1)哈希切割 我们首先由一道面试题来理解位图 给40亿个不

    2024年02月04日
    浏览(35)
  • C++ 哈希+unordered_map+unordered_set+位图+布隆过滤器(深度剖析)

    想象一下,你有一个巨大的图书馆,里面摆满了成千上万本书。如果你想要找到其中一本特定的书,你会怎么做?如果你按照书的编号来有序地排列它们,找到特定的书本可能会很容易。但是,如果书籍是随机地摆放,你可能需要逐本地查找,这个过程会非常耗时。 而哈希函

    2024年02月21日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包