位图及布隆过滤器的模拟实现与面试题
位图
模拟实现
namespace yyq
{template<size_t N>class bitset{public:bitset(){_bits.resize(N / 8 + 1, 0);//_bits.resize((N >> 3) + 1, 0);}void set(size_t x)//将某位做标记{size_t i = x / 8; //第几个char对象size_t j = x % 8; //这个char对象的第几个比特位_bits[i] |= (1 << j); //标记}void reset(size_t x)//将某位去掉标记{size_t i = x / 8;size_t j = x % 8;_bits[i] &= (~(1 << j));}//测试值是否在bool test(size_t x){size_t i = x / 8;size_t j = x % 8;return _bits[i] & (1 << j);//整型提升,bool是4字节,char是1字节,按符号位来补}private:std::vector<char> _bits;};
}
当然位图也有缺点,它只能处理整型数据。
应用
- 快速查找某个数据是否在一个集合中
- 排序 + 去重
- 求两个集合的交集、并集等
- 操作系统中磁盘块标记
位图,是利用一个比特位来标识数据在不在(哈希的直接地址法),优点是节省空间,效率高,缺点是只能处理整型数据且要求数据相对集中。将哈希与位图结合,即布隆过滤器。
位图是要把一个数据通过一个哈希函数映射到一个位置,判断在不在;布隆过滤器是要把一个数据通过多个哈希函数映射到多个位置,降低误判率,判断一定不在或可能在
布隆过滤器
布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。
模拟实现
哈希函数个数的选择
哈希函数个数越多,布隆过滤器要开的bit位就越多,内存占用更大,则布隆过滤器bit位置为1的速度越快,但是效率变低;个数过少的话,误报率会变高。
k 为哈希函数个数,m 为布隆过滤器长度,n 为插入的元素个数,p 为误报率
计算公式为k=m/n∗ln(2)k = m / n * ln(2)k=m/n∗ln(2)以及m=−n∗ln(p)/ln2/ln2m = -n*ln(p) / ln2 / ln2m=−n∗ln(p)/ln2/ln2
第一个公式可以得出m=k∗n/ln2m = k * n / ln2m=k∗n/ln2,当我们用3个哈希函数时,布隆过滤器的长度为3∗n/ln2≈4.33n3*n/ln2 ≈ 4.33n3∗n/ln2≈4.33n。
在代码中,我们直接取5n,代码中为X == 5,可以更改。
struct BKDRHashFunc
{size_t operator()(const std::string& key){size_t hash = 0;for (auto ch : key){hash *= 131;hash += ch;}return hash;}
};struct APHashFunc
{size_t operator()(const std::string& key){size_t hash = 0;const char* str = key.c_str();for (int i = 0; *str; i++){if ((i & 1) == 0){hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));}else{hash ^= (~(hash << 11) ^ (*str++) ^ (hash >> 5));}}return hash;}
};struct DJBHashFunc
{size_t operator()(const std::string& key){size_t hash = 5381;const char* str = key.c_str();while (*str){hash += (hash << 5) + (*str++);}return hash;}
};// N是最多存储的数据个数
// 平均存储一个值,开辟X个位
template<size_t N, size_t X = 5, class K = std::string, class HashFunc1 = BKDRHashFunc, class HashFunc2 = APHashFunc, class HashFunc3 = DJBHashFunc>
class BloomFilter
{public:void set(const K& key){//3个哈希函数映射size_t hashi1 = HashFunc1()(key) % (X * N);size_t hashi2 = HashFunc2()(key) % (X * N);size_t hashi3 = HashFunc3()(key) % (X * N);_bs.set(hashi1);_bs.set(hashi2);_bs.set(hashi3);}bool test(const K& key){//3个哈希函数映射size_t hashi1 = HashFunc1()(key) % (X * N);if (!_bs.test(hashi1)){//如果通过一个映射值不在,那肯定不在return false;}size_t hashi2 = HashFunc2()(key) % (X * N);if (!_bs.test(hashi1)){//如果通过一个映射值不在,那肯定不在return false;}size_t hashi3 = HashFunc3()(key) % (X * N);if (!_bs.test(hashi1)){//如果通过一个映射值不在,那肯定不在return false;}//前三个映射值都存在,那么key可能在(有可能三个位置都冲突)return true;}private:std::bitset<N * X> _bs;
};
测试误判率
void test_bloomfilter2()
{srand(time(0));const size_t N = 100000;BloomFilter<N> 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(i));}for (auto& str : v1){bf.set(str);}// v2跟v1是相似字符串集,但是不一样std::vector<std::string> v2;for (size_t i = 0; i < N; ++i){std::string url = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";url += std::to_string(999999 + i);v2.push_back(url);}size_t n2 = 0;for (auto& str : v2){if (bf.test(str)){++n2;}}std::cout << "相似字符串误判率:" << (double)n2 / (double)N << std::endl;// 不相似字符串集std::vector<std::string> v3;for (size_t i = 0; i < N; ++i){std::string url = "zhihu.com";url += std::to_string(i + rand());v3.push_back(url);}size_t n3 = 0;for (auto& str : v3){if (bf.test(str)){++n3;}}std::cout << "不相似字符串误判率:" << (double)n3 / (double)N << std::endl;
}
不支持reset
因为某一位可能被多个值映射,有冲突。把这个位reset掉,可能导致真的在的key就变成不在了。
面试题
1、给定100亿个整数,设计算法找到只出现一次的整数
位图要完成的事情是在不在,只需要2种状态==>1个比特位,char的8个比特位可以表示8个数的状态。而这道题需要3种状态(0:00
、1:01
、n:10
)==>2个比特位,char的8个比特位可以表示4个数的状态。
开两个位图,两个位图的相同的位置可以用0和1表示,当这个数出现第1次,第一个位图对应位置置1;第2次及以上次出现,第2个位图对应位置置1。
要筛选出现1次的整数,就用2个位图;要筛选出现2次的整数,就用3个位图,以此类推。
template<size_t N>class twobitset{public:void set(size_t x)//将某位做标记{ if (!_bits1.test(x) && !_bits2.test(x))//00{_bits2.set(x);}else if (!_bits1.test(x) && _bits2.test(x))//01{_bits2.reset(x);_bits1.set(x); //10}else//10{//啥也不做}}private:std::bitset<N> _bits1;std::bitset<N> _bits2;};
}
2、给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集
两个文件的话,每个文件分别使用一个位图,此时位图对应的功能就包括去重+交集。两个位图位置都为1,就是两个文件的交集。
3、位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数。
int的最大值为24亿多,找不超过两次的,要用到2个位图4种状态(00\01\10\11),然后要过滤掉00和11这两个状态对应的数据
4、给一个超过100G大小的log文件, log中存着IP地址, 设计算法找到出现次数最多的IP地址?
ip是这样的127.0.0.1一个字符串。位图只能解决K问题(在不在),不能解决KV问题(多少次)。这里要求出现次数最多的,只能采用map来解决问题,100G大小肯定放不进去内存,我们利用哈希切割,先将文件分为100个小文件(注意不是平均分割),将每个小文件当作一个哈希桶,用函数将ip转成整型,i = HashFunc(ip) % 100
,i冲突的ip就会进入对应i号文件,那同一类ip就会进入同一个文件(相同的值一定会进入同一个文件,当然也会有哈希冲突的值),再对每个文件进行map统计出现次数。
如果:单个小文件超过1G,说明这个小文件里冲突的ip很多,a.大多是不同的ip/b.大多是相同的ip,该如何处理?
a.大多是不同的ip的情况,用map肯定无法完全统计,换个字符串哈希转换函数,递归再切分。
b.大多是相同的ip的情况,用map可以统计,大不了再用外排序。
如果map的insert失败,就表示没有内存了,相当于new节点失败,new失败会抛异常,就按a来处理。
5、给两个文件(A、B),分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法。
query是查询指令,比如可能是一个网页请求或者是一个数据库sql语句。
精确算法:假设每个query指令是50字节,那100亿个query大小约为500GB。将这些数据分到1000个小文件(Axx、Bxx),每个文件约0.5GB。每个小文件是通过同一个哈希函数,对应编号的文件里的数据大多是差不多的,把数据去个重,然后A01和B01分别用哈希表求交集,…A99和B99分别求交集。若小文件超过1GB,就再换个哈希函数再切分。
近似算法:用布隆过滤器,先把一个文件过一遍布隆过滤器,另一个文件来判断一下有哪些在。
6、如何扩展BloomFilter使得它支持删除元素的操作
计数器,有几个值映射到这个位,这个位就是几,当要求reset时,这个位置的值–。但是要实现计数的功能,映射位置就不能再使用一个位标记,而是需要多个位存储计数值,空间消耗成倍增加。故此方案在实际中不会被使用,还不如用哈希表。
相关文章:
位图及布隆过滤器的模拟实现与面试题
位图 模拟实现 namespace yyq {template<size_t N>class bitset{public:bitset(){_bits.resize(N / 8 1, 0);//_bits.resize((N >> 3) 1, 0);}void set(size_t x)//将某位做标记{size_t i x / 8; //第几个char对象size_t j x % 8; //这个char对象的第几个比特…...
在 Python 中将天数添加到日期
使用 datetime 模块中的 timedelta() 方法将天数添加到日期中,例如 result_1 date_1 timedelta(days3)。 timedelta 方法可以传递天数参数并将指定的天数添加到日期。 from datetime import datetime, date, timedelta# ✅ 将天数添加到日期 my_str 09-24-2023 …...
vue3知识点
一、vue3带来了什么? 1.性能的提升 打包大小减少41% 初次渲染快55%,更新渲染快133% 内存减少54% 2.源码的升级 使用Proxy代替defineProperty实现响应式 重写虚拟DOM的实现和Tree-shaking 3.拥抱TypeScript Vue3可以更好的支持TypeScript 4.新的特性 4.1.…...
一行代码生成Tableau可视化图表
今天给大家介绍一个十分好用的Python模块,用来给数据集做一个初步的探索性数据分析(EDA),有着类似Tableau的可视化界面,我们通过对于字段的拖拽就可以实现想要的可视化图表,使用起来十分的简单且容易上手,学习成本低&a…...
链表——删除元素或插入元素(头插法及尾插法)
目录 链表的结点由一个结构体构成 判断链表是否为空 键盘输入链表中的数据 输出链表中的数据 返回链表的元素个数 清空链表 返回指定位置的元素值 查找数据所在位置 删除链表的元素 插入元素 建立无头结点的单链表 建立有头结点的单链表(头插法ÿ…...
oracle容器的使用
oracle容器的使用 1.下载oracle容器 1.1拉取容器 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g拉取国内镜像,该镜像大小为2.99G,已经集成了oracle环境,拉取完可以直接用,推荐使用这款oracle镜像 1.2查看…...
基于springboot会员制医疗预约服务管理信息系统演示【附项目源码】
基于springboot会员制医疗预约服务管理信息系统演示开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea M…...
GoogleAdsense国内加载慢怎么解决?
一淘模板 56admin.com 发现GoogleAdsense(谷歌广告联盟)国内加载慢拖网站速度怎么解决?GoogleAdsense是谷歌旗下的站长广告联盟系统,如果站长没有好的变现渠道,挂谷歌联盟是最好的选择(日积月累)…...
【MySQL专题】03、性能优化之读写分离(MaxScale)
在我们了解了MySQL的主从复制的性能优化之后,紧接着《【MySQL专题】02、性能优化之主从复制》中,我们提及的读写分离,来进行读操作和写操作分散到不同的服务器结构中,同时希望对多个从服务器能提供负载均衡,读写分离和…...
Redis7高级之BigKey(二)
1.MoreKey案例 往redis里面插入大量测试数据key 生成100W条redis批量设置kv的语句保存在redisTest.txt for((i1;i<100*10000;i)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done; # 生成100W条redis批量设置kv的语句(keykn,valuevn)写入到/tmp目录下的…...
flex弹性盒子
概念 弹性盒子是一种用于按行或者按列布局的一维布局方法,元素可以膨胀以填充额外的空间,缩小以适应更小的空间 以下属性是给父元素添加的 1.flex-direction --改变轴的方向 row 默认值 默认沿着x轴排版(横向从左到右排列(左对齐ÿ…...
[Java Web]Cookie | 一文详细介绍会话跟踪技术中的Cookie
⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐作者主页:逐梦苍穹 ⭐所属专栏:Java Web 目录Cookie1、工作原理2、如何使用2.1、发送Cookie2.2、获取Cookie3、Cookie的存活时间4、中文错误Coo…...
这可能是2023最全的Java面试八股文,共计1658页,Java技术手册的天花板
前两天有个小伙伴在后台留言,最近的面试越来越难了,尤其是技术面,考察得越来越细,越来越底层,庆幸的是最终顺利找到了工作。 一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识 比如果这样的问题…...
字节流及存放本地文件上传和下载文件
前言 之前的文章有写过 vuespringboot使用文件流实现文件下载 实现如何通过 D:\file\文件名.文件格式的形式进行下载文件 但是它对于很多业务场景相对适用性不是很广泛。 以及 elementUI加springboot实现上传excel文件给后端并读取excel 也只能是通过elementui的元素类型进行…...
【翻译】下一步:Go 泛型
原文地址: The Next Step for Generics - The Go Blog https://blog.golang.org/generics-next-step 介绍 自从我们上次写下关于在Go中加入泛型的可能性的文章以来,已经快一年了。现在是该更新的时候了。 设计的更新 我们一直在继续完善泛型设计草案。…...
如何简单实现ELT?
在商业中,数据通常和业务、企业前景以及财务状况相关,有效的数据管理可以帮助决策者快速有效地从大量数据中分析出有价值的信息。数据集成(Data Integration)是整个数据管理流程中非常重要的一环,它是指将来自多个数据源的数据组合在一起&…...
细思极恐,第三方跟踪器正在获取你的数据,如何防范?
细思极恐,第三方跟踪器正在获取你的数据,如何防范? 当下,许多网站都存在一些Web表单,比如登录、注册、评论等操作需要表单。我们都知道,我们在冲浪时在网站上键入的数据会被第三方跟踪器收集。但是&#x…...
Java基础之==,equal的区别(温故而知新)-----点点滴滴的积累
1. 为运算符,equal 为String数据类型的比较方法;相同内容的对象地址不一定相同,但相相同地址的对象内容一定相同; 比较的是值是否相等,equal比较的是是否是同一个对象。 2.基本概念不同 1)对于,…...
SpringBoot项目使用切面编程实现数据权限管理
springBoot项目使用切面编程实现数据权限管理什么是数据权限管理如何实现数据权限管理什么是数据权限管理 不同用户在某页面看到数据不一致,实现每个用户之间数据隔离的效果。 如以下场景: ● 页面期望展示当前登录人所在部门的数据。 ● 页面期望展示当…...
亚马逊测评是做什么的,风险有哪些?
自养号测评顾名思义就是自己养国外的买家账号给自己店铺提升销量和评论,做过多年的跨境卖家都知道测评可以快速提高产品的排名、权重和销量,(国内某宝一样的逻辑)但随着测评需求日益增大,卖家在寻求真人测评时也很容易…...
安科瑞导轨式智能通讯管理机
安科瑞 李亚娜 一、概述 AWT200 数据通讯网关应用于各种终端设备的数据采集与数据分析。实现设备的监测、控制、计算,为系统与设备之间建立通讯纽带,实现双向的数据通讯。实时监测并及时发现异常数据,同时自身根据用户规则进行逻辑判断&…...
vs2010下 转换到 COFF 期间失败: 文件无效或损坏
因为同一个电脑上安装多个VS,有多个cvtres.exe。按照下面的操作如果还是不行就在C盘搜索cvtres.exe,然后挨个重命名,看看是调用的哪个,然后修改就可以了。 用VS2010编译C项目时出现这样的错误: LNK1123: 转换到 COFF …...
托福高频真词List19 // 附托福TPO阅读真题
目录 3.28单词 3.29真题 3.28单词 legitimately/properlyadv.正当地likewise/similarlyadv.同样地reveal/showv.揭示substantiate/confirmv.证实suppress/stop by forcev.镇压trend/tendencyn.趋势empirical/based on observationa.凭借经验的illuminate/li…...
Go语言项目标准结构应该如何组织的?
这里写自定义目录标题Go项目本身的目录结构Go语言项目典型目录结构GO语言项目最小标准目录结构可执行的Go语言项目目录结构库的Go语言项目目录结构关于internal目录总结参考文章每当我们写一个非hello world实用程序的Go程序或库时,我们都会在项目结构、代码风格和标…...
设计模式简介
设计模式简介 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错…...
#详细介绍!!! 线程池的拒绝策略(经典面试题)
本篇单独讲解线程池的拒绝策略,介绍了当线程池任务满了之后,线程池会以什么样的方式来响应添加进来的任务 目录 一:理解线程池拒绝策略的触发情况代码理解 二:线程池的四种常见的拒绝策略 1.ThreadPoolExecutor.AbortPolicy 2…...
正则表达式作业
利用正则表达式完成下面的操作: 一、不定项选择题 能够完全匹配字符串"(010)-62661617"和字符串"01062661617"的正则表达式包括(A ) A. r"\(?\d{3}\)?-?\d{8}" B. r"[0-9()-]" C. r"[0-9(-)]*\d*&qu…...
《扬帆优配》交易拥挤度达历史极值 当前A股TMT板块性价比几何?
上周,A股商场企稳,但盘面风格分歧再度加深:很多资金涌入以ChatGPT、数字经济为代表的TMT板块,而新能源以及前期强势的“中字头”种类都呈现了回调。兴业证券计算显现,3月24日,TMT及电子板块的商场成交金额占…...
C/C++开发,无可避免的IO输入/输出(篇三).字符串流(内存流)IO处理
目录 一、字符串流 1.1 字符串流继承体系 1.2 字符串流本质-类模板std::basic_stringstream 1.3 字符串流缓冲-std::stringbuf 1.4 stringbuf与序列缓冲 1.5 字符串流的打开模式 二、字符串流的运用 2.1 格式转换是其拿手好戏 2.2 字符串流仅提供移动赋值 2.3 std::basic_str…...
什么是HTTP请求?【JavaWeb技术】
HTTP请求是指从客户端到服务器的请求消息,建立HTTP请求需要经历以下7个步骤才能请求成功。 (1)建立TCP连接 在HTTP开始工作前,Web浏览器需先通过网络和Web服务器连接,连接过程主要使用TCP/IP完成。 (2)Web浏览器向Web服务器发送请求命令 一旦…...
郑州的网站建设/关键词搜索方法
1.Comparable 接口的定义:public interface Comparable{public int compareTo(T o)}接口中只有一个 compareTo 方法,该方法返回一个 int 类型的数据,但是 int 的值只能是3种:*1:表示大于*-1:表示小于*0&…...
用easyui做的网站/四川游戏seo整站优化
一、作用 用来判断海量数据中是否存在指定值。 二、原理 将容器中的所有值求hashcode然后根据hashcode找,类似于hashmap,但不同的是这里只比较hash值,没有hash值相同之后的进一步精确匹配。 所以出现hash碰撞时,不能确定是否真…...
有没有必要为B2B网站做外链/百度竞价推广技巧
备考第6周总结这个星期最大的收获就是看了何凯文老师的长难句基础课,一共有8节,这个星期学了4节。我感觉他讲的非常好,思路非常清晰,讲课时也不会忘记和大家开开玩笑,课堂气氛很好。我听了以后,受益匪浅&am…...
知名高端网站建设企业/深圳网站优化排名
pygame 图像的基本使用笛卡尔坐标系实际效果代码代码说明碰撞原理方法说明载入图片surface对象和Rect对象Rect对象属性移动我们会用到各种图片。来通过碰撞滑稽(小球实验)来了解一下吧 笛卡尔坐标系 游戏离不开坐标,我们来康康pygame中坐标…...
b2b电子商务网站的主要类型/百度推广怎么优化排名
import cv2 import numpy as npcap cv2.VideoCapture(0)# set blue thresh 设置HSV中蓝色、天蓝色范围 lower_blue np.array([78,43,46]) upper_blue np.array([110,255,255])while(1):# get a frame and show 获取视频帧并转成HSV格式, 利用cvtColor()将BGR格式转成HSV格式…...
wordpress网易音乐播放器/软文的目的是什么
1、故障现象 客服同事反馈平台系统运行缓慢,网页卡顿严重,多次重启系统后问题依然存在,使用top命令查看服务器情况,发现CPU占用率过高。 2、CPU占用过高问题定位 2.1、定位问题进程 使用top命令查看资源占用情况,发…...