C++——位图与布隆过滤器

目录

一,位图

1.1 关于大量数据的问题

1.2 位图概念

1.3 位图模拟实现

 1.4 位图的应用

 1.5 位图优缺点

二,布隆过滤器

2.1 一些场景

2.2 布隆过滤器概念

2.3 布隆过滤器模拟实现和测试

2.4 布隆过滤器查找

2.5 布隆过滤器删除

2.6 布隆过滤器优缺点


一,位图

1.1 关于大量数据的问题

先看一个面试题:

给40亿个不重复的未排序的无符号整数,然后如何快速判断一个数是否在这40亿个数中

 以我们前面的知识,最先想到的有两种方法:1,排序+二分查找  2,存到哈希表和红黑树中再查

但是题目中给的是40亿个整数,我们先算下需要的内存:1G就是1024MB,是1024*1024KB,是1024*1024*1024Byte,相当于10亿Byte,所以,40亿个数需要4*40Byte大概就是16G的空间,所以由于空间的限制,上面两种方法就都可以去掉了。

所以我们需要一种更好的方法去存储这40亿个整数

1.2 位图概念

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

比如上面的题目,判断数据在不在,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位位1,代表存在,为0表示不存在,如下图:

1.3 位图模拟实现

namespace bit
{template<size_t N>class bitset{public:bitset(){_bits.resize(N / 8 + 1, 0);//8+1,多开一个//这样开空间的 {(0       7)(8       15)(16       23)(24       31)...}}                    //  char      char         char//插入void set(size_t x){size_t i = x / 8; //一个数组里面有很多个char,每个char有8个比特位,先算x需要被映射到哪个8比特位上size_t j = x % 8; //再算在该8比特位里面的位置,整个过程可以理解为看电影时,先找在哪一排,再找具体的位置_bits[i] |= (1 << j);//假如x是10,10/8=1,找到第一个char,再模8就是2,然后将1往左移两格,向高位移,比如00000001,往左移就是00000010//这样的话,我们就用非常小的空间代价把大量数据存起来了}//删除void erset(size_t x){size_t i = x / 8;size_t j = x % 8;_bits[i] &= ~(1 << j);//按位取反,1与0为0完成删除,0与0还是0,不变}//判断在不在bool test(size_t x){size_t i = x / 8;size_t j = x % 8;return _bits[i] & (1 << j); //如果存在,那1与1就是1,返回1;如果不在,0与1就是0,返回0//return( _bit[i] >> j) & 1;}private:vector<char> _bits;};void test_bit_set1(){bitset<100> bs1;bs1.set(10);bs1.set(11);bs1.set(15);cout << bs1.test(10) << endl;cout << bs1.test(11) << endl;cout << bs1.test(15) << endl;bs1.erset(10);bs1.erset(11);bs1.erset(15);cout << bs1.test(10) << endl;cout << bs1.test(11) << endl;cout << bs1.test(15) << endl;}void test_bit_set2(){bitset<-1> bs1; //给的是整形的最大值bitset<0xFFFFFFFF> bs2;}
}

 1.4 位图的应用

先看下下面几个题目:

①给100亿个整数,设计算法找到只出现一次的整数

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

③一个文件有100亿个整数,给1G内存,请设计算法找到出现次数不超过2的所有整数

上面的题目都有个共同点,就是和1,2和大于2的数字有关,换成位就是01,10和11,所以我们可以用一个封装了两个位图的类来解决,对于问题一,在类插入时,如果是00则表示第一次出现,01表示出现过一次,10出现两次,10后的不考虑;后面的两个问题也是同样的解决逻辑

namespace bit
{	template<size_t N>class twobitset{public:void set(size_t x){bool inset1 = _bs1.test(x);bool inset2 = _bs2.test(x);//00if (inset1 == false && inset2 == false) //还未出现{// -> 01_bs2.set(x);}else if (inset1 == false && inset2 == true) //第一次出现{// -> 10_bs1.set(x);_bs2.erset(x);}else if (inset1 == true && inset2 == false) //第二及以上次出现{// -> 11_bs1.set(x);_bs2.set(x);}}void print_onse_num(){for (size_t i = 0; i < N; ++i){if (_bs1.test(i) == false && _bs2.test(i) == true){cout << i << endl;}}}private:bitset<N> _bs1;bitset<N> _bs2;};void test_bit_set3(){int a[] = { 3, 4, 5, 2, 3, 4, 4, 4, 4, 12, 77, 65, 44, 4, 44, 99, 33, 33, 33, 6, 5, 34, 12 };twobitset<100> bs;for (auto e : a){bs.set(e);}bs.print_onse_num();}

 1.5 位图优缺点

优点:位图的存储和查找效率非常快,而且可以节省很多空间

缺点:可以看出,位图只能存储可以转化成位的整数,如果是其他类型的数就不能使用位图,比如浮点数,string等自定义类型

所以为了使位图的设计能够支持其他类型的数据,就有了下面要介绍的布隆过滤器

二,布隆过滤器

2.1 一些场景

直接看图:

 又比如我们生活中的场景:

我们在注册账号时:

2.2 布隆过滤器概念

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

2.3 布隆过滤器模拟实现和测试

struct HashBKDR
{//BKDR字符串转intsize_t operator()(const string& key){size_t val = 0;for (auto ch : key){val *= 131;val += ch;}return val;}
};
struct HashAP
{// APsize_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
{// DJBsize_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);_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; // 可能存在误判}private:const static size_t _ratio = 5;bit::bitset<_ratio* N>* _bits = new bit::bitset<_ratio * N>;//由于std库中这个东东是用静态数组实现的,一旦数据过大就会栈溢出,所以使用new的方式将数据转移到堆上,就可以解决了
};

测试一

void TestBloomFilter1()
{BloomFilter<10> bf;string arr1[] = { "苹果", "西瓜", "阿里", "美团", "苹果", "字节", "西瓜", "苹果", "香蕉", "苹果", "腾讯" };for (auto& str : arr1){bf.Set(str);}for (auto& str : arr1){cout << bf.Test(str) << “ ”;}cout << endl << endl;string arr2[] = { "苹果111", "西瓜", "阿里2222", "美团", "苹果dadcaddxadx", "字节", "西瓜sSSSX", "苹果 ", "香蕉", "苹果$", "腾讯" };for (auto& str : arr2){cout << str << ":" << bf.Test(str) << endl;}
}

 测试二

void TestBloomFilter2()
{srand(time(0));const size_t N = 100000;BloomFilter<N> bf;cout << sizeof(bf) << endl;//因为报栈溢出,查看bf的大小std::vector<std::string> v1;std::string url = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";for (size_t i = 0; i < N; ++i){v1.push_back(url + std::to_string(1234 + i)); //让每个字符不一样}for (auto& str : v1){bf.Set(str);}// 相似std::vector<std::string> v2;for (size_t i = 0; i < N; ++i){std::string url = "http://www.cnblogs.com/-clq/archive/2021/05/31/2528153.html";url += std::to_string(rand() + i);v2.push_back(url);}size_t n2 = 0;for (auto& str : v2){if (bf.Test(str)){++n2;}}cout << "相似字符串误判率:" << (double)n2 / (double)N << endl;std::vector<std::string> v3;for (size_t i = 0; i < N; ++i){string url = "zhihu.com";url += std::to_string(rand() + i);v3.push_back(url);}size_t n3 = 0;for (auto& str : v3){if (bf.Test(str)){++n3;}}cout << "不相似字符串误判率:" << (double)n3 / (double)N << endl;
}

2.4 布隆过滤器查找

布隆过滤器不是为了解决冲突,而是为了降低冲突!

将一个元素用多个哈希函数映射到一个位图中,因此被映射到位置的比特位一定为1,所以在查找时,分别计算每个哈希值对应的比特位置存储的是否为0,只要有一个为0,表面该元素一定不在哈希表中,如果都不为0,那么可能存在,因此存在误判

2.5 布隆过滤器删除

布隆过滤器不能直接支持删除,因为在删除一个元素时会影响其他元素

2.6 布隆过滤器优缺点

优点:

①增加和查询的时间复杂度为O(K),K为哈希函数个数,一般都是一位数,因此和数据量大小无关

②哈希函数相互之间没有关系,方便硬件运算

③布隆过滤器不存储元素本身,所以在某些保密要求较高的场合有很大优势

④在能承受一定误判时,布隆过滤器比其他数据结构有很大的空间与时间优势

⑤数据量很大时,布隆过滤器可以表示全集,其他数据结构不能

缺点:

①有误判,即存在假阳性,不能准确判断元素是否在集合中,但也有补救方法

②不能获取元素本身

③大多数情况不能删除元素

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/454090.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C#][opencvsharp]winform实现自定义卷积核锐化和USM锐化

【锐化介绍】 图像锐化(image sharpening)是补偿图像的轮廓&#xff0c;增强图像的边缘及灰度跳变的部分&#xff0c;使图像变得清晰&#xff0c;分为空间域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓&#xff0c;或某些线性目标要素的特征。这种滤波方法…

C语言—自定义函数的传值调用和传址调用

不多废话&#xff0c;先说函数定义&#xff0c;分为两种&#xff1a; 库函数&#xff1a;C语言内部提供的函数&#xff1b;自定义函数&#xff1a;自己写的函数。 本文主要讲自定义函数&#xff0c;也就是如何自己实现函数的编写。 自定义函数&#xff0c;包括&#xff1a;函…

Python基础知识:Python流程控制语句

流程控制就是控制程序如何执行的方法&#xff0c;适用于任何一门编程语言&#xff0c;其作用在于&#xff0c;可以根据用户的需求决定程序执行的顺序。计算机在运行程序时&#xff0c;有3种执行方法&#xff0c;第一种是顺序执行&#xff0c;自上而下顺序执行所有的语句&#x…

Codeforces Round 651 (Div. 2)C. Number Game 博弈 奇偶数 偶数的表示

Submission #244500083 - Codeforces 题目&#xff1a; 思路&#xff1a; 此题要从奇偶性上入手。&#xff08;注意除的是奇因数&#xff0c;即一个奇数。我想成质数了&#xff09; 1.当A选手开局是1时&#xff0c;A败。 2.当A选手开局是2和奇数时&#xff0c;A必胜。&…

###C语言程序设计-----C语言学习(9)#函数基础

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 一. 基础知识的学习 1.函数的定义 函数是一个完成特定工作的独立程序模块&…

VR全景技术可以应用在哪些行业,VR全景技术有哪些优势

引言&#xff1a; VR全景技术&#xff08;Virtual Reality Panorama Technology&#xff09;是一种以虚拟现实技术为基础&#xff0c;通过360度全景影像、立体声音、交互元素等手段&#xff0c;创造出沉浸式的虚拟现实环境。该技术不仅在娱乐领域有着广泛应用&#xff0c;还可…

java企业办公自动化OA

技术架构&#xff1a; sshjbpm 有需要该项目的小伙伴可以私信我你的Q。 功能描述&#xff1a; 用户管理&#xff0c;岗位管理&#xff0c;部门管理&#xff0c;权限管理&#xff0c;网上交流&#xff0c;贴吧&#xff0c;审批流转。权限管理是树状结构人性化操作&#xff0…

「Mybatis实战二」:Mybatis实现数据新增详析

一、前言 ​ 本文将在 Mybatis初体验&#xff1a;一小时从入门到运行你的第一个应用 所构建的基础代码结构之上&#xff0c;并实现利用Mybatis进行数据新增的操作。 二、代码演示 1、修改映射文件UserMapper.xml <?xml version"1.0" encoding"UTF-8&quo…

微服务—RabbitMQ

目录 初识MQ 同步和异步通讯 同步通讯的优缺点 异步调用方案 异步通信优缺点 常见MQ技术对比 RabbitMQ快速入门 安装RabbitMQ RabbitMQ整体架构与相关概念 常见消息模型​编辑 入门案例 SpringAMQP 基本介绍 SpringAMQP案例——模拟HelloWorld消息模型 Sprin…

c语言实现greedy snake(贪吃蛇)

##第一个小项目 大一学生寒假项目 最终实现效果如图 一.以C语言实现个人小项目 在我们快速学完了一个高级编程语言&#xff0c;就应该写一个小项目来加以巩固自己的学习成果。 所以今天&#xff0c;我们来尝试写一写greedy snake&#xff0c;对于大学生来说也是可以加强能…

在线视频格式转换,就是这么简单!(免费)

随着数字化时代的发展&#xff0c;我们在日常生活中越来越频繁地与各种视频文件打交道。然而&#xff0c;不同设备和平台对于视频格式的支持可能存在差异&#xff0c;这就导致了我们有时需要进行视频格式的转换&#xff0c;以确保视频在各种环境中流畅播放。而幸运的是&#xf…

【目标跟踪】3D点云跟踪

文章目录 一、前言二、代码目录三、代码解读3.1、文件描述3.2、代码框架 四、关联矩阵计算4.1、ComputeLocationDistance4.2、ComputeDirectionDistance4.3、ComputeBboxSizeDistance4.4、ComputePointNumDistance4.5、ComputePointNumDistance4.6、result_distance 五、结果 一…