数据结构:位图、布隆过滤器以及海量数据面试题

位图、布隆过滤器以及海量数据面试题

    • 1.位图
      • 1.1概念
      • 1.2实现
      • 1.3位图应用
    • 2.布隆过滤器
      • 2.1布隆过滤器的提出
      • 2.2布隆过滤器的概念
      • 2.3布隆过滤器的查找
      • 2.4布隆过滤器的实现
      • 2.5布隆过滤器的删除
      • 2.6布隆过滤器的优点
      • 2.7布隆过滤器的缺点
    • 3.海量数据面试题
      • 3.1哈希切分
      • 3.2位图应用
      • 3.3布隆过滤器

1.位图

1.1概念

  1. 引入
    给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
    (1)遍历: 时间复杂度O(N)
    (2)排序加二分:时间复杂度O(N*logN)
    其中 方法(2)是行不通的,因为内存很难装下这么多数据(40亿整数大概为16G)。
    方法(1)可行,但如果需要多次查询很耗时。

    (3)位图:数据是否在给定的整形数据中,结果是在或者不在,刚好是
    两种状态
    ,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:
    在这里插入图片描述
    方法(3)的优势的建立起这个位图后,查找任一数据在不在时间复杂度均为O(1),而且只需要 16G / 32 = 0.5G(存储整形需要16G,现在一个比特位就可代表,一个整形有32个比特位),空间占用很小。
  2. 概念
    所谓位图,就是用比特位来存放某种状态(哈希思想的体现),适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。

1.2实现

namespace mystd
{//叫bitset只是单纯和库里面统一而已,接口命名也是//库里面bitset使用基本也是这几个接口template<size_t N>  //N表示要表示整数的范围,即比特位个数class bitset  {public:bitset() {//初始化这里,可能存在浪费,但几个比特位而已_bits.resize(N / 32 + 1, 0);}void set(size_t x)  //设置标记,表示x存在{//给你x,计算出x属于第几个整数,整数中的第几个比特位int i = x / 32;  //第几个int j = x % 32;  //第几个比特位//把对应的_bits[i]的第[j]位修改为1即可,方法是将1左移j位,或运算即可_bits[i] |= (1 << j);}void reset(size_t x)  //去标记,表示x不存在{int i = x / 32;int j = x % 32;//把对应的_bits[i]的第[j]位修改为0即可,方法(1)是将1左移j位 (2)取反(j位置为0,其它位置为1) (3)进行与运算_bits[i] &= ~(1 << j);}bool test(size_t x)  //看x在不在{int i = x / 32;int j = x % 32;//取到_bits[i]的第j位即可return _bits[i] & (1 << j);  //非0即真,0即假}private:vector<int> _bits;};
}

1.3位图应用

  1. 快速查找某个数据是否在一个集合中
  2. 排序 + 去重
  3. 求两个集合的交集、并集等

代码:

#include<iostream>
#include<bitset>
using namespace std;
//位图的应用
//快速查找某个数据是否在一个集合中
void test1()
{vector<int> a = { 0, 1, 2, 3, 4, 8, 99, 100, 150 };bitset<151> bit_set;for (auto e : a){bit_set.set(e);}int x = 0;while (cin >> x){if (bit_set.test(x)){cout << x << "存在" << endl;}else{cout << x << "不存在" << endl;}}
}//排序 + 去重
void test2()
{int a[] = {0, 1, 2, 3, 4, 8, 99, 99, 100, 100, 150};bitset<151> bit_set;vector<int> result;for (auto e : a){bit_set.set(e);}//实际中应该在建立位图的过程中找出最大最小值,这里就不写了//min = 0, max = 150;for (int i = 0; i <= 150; i++)   {if (bit_set.test(i)){result.push_back(i);}}for (auto e : result)  cout << e << " ";cout << endl;
}//求两个集合的交集、并集等
void test3()
{int a1[] = { 0, 1, 2, 3 };int a2[] = { 0, 2, 2, 4, 5, 6 };//交集bitset<7> bit_set1;bitset<7> bit_set2;for (auto e : a1)  bit_set1.set(e);cout << "交集为:";for (auto e : a2){if (bit_set1.test(e) && bit_set2.test(e) == false){bit_set2.set(e);  //过滤掉多次出现的数据cout << e << " ";}}cout << endl;//并集cout << "并集为:";bitset<7> bit_set3;  //去掉a1中重复的部分for (auto e : a1){if (bit_set3.test(e) == false){cout << e << " ";bit_set3.set(e);}}for (auto e : a2){if (bit_set3.test(e) == false)  //把a2特有的提取出来{cout << e << " ";}}cout << endl;
}



2.布隆过滤器

2.1布隆过滤器的提出

想要判断某个数据在不在:

  1. 哈希表,空间消耗大。
  2. 位图,空间消耗小,只适用于整形。
  3. 哈希位图相结合,即布隆过滤器。可适用各种复杂数据,只要能通过哈希函数转化出关键值即可。

2.2布隆过滤器的概念

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

图解:
在这里插入图片描述


2.3布隆过滤器的查找

结合前面可知,布隆过滤器的查找需要对多个位置进行判断,都为1才认为存在,有一个为0认为不存在。

  1. 布隆过滤器判断存在,判断不准确

    在这里插入图片描述
  2. 布隆过滤器判断不在,结果准确

布隆过滤器存在误判,为什么还要使用?

以用户注册为例,用户名等信息存储在服务器数据库,每次注册新用户都要遍历所有数据,消耗太大。这个时候可以考虑使用布隆过滤器,对于判断不在的情况,是准确的,可以允许注册;对于判断在的情况就需要去遍历数据。实际当中可以过滤掉大量的请求,提高效率


2.4布隆过滤器的实现

//三个字符串哈希函数
struct BKDRHash
{size_t operator()(const string& key){// BKDRsize_t hash = 0;for (auto e : key){hash *= 31;hash += e;}return hash;}
};struct APHash
{size_t operator()(const string& key){size_t hash = 0;for (size_t i = 0; i < key.size(); i++){char ch = key[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};struct DJBHash
{size_t operator()(const string& key){size_t hash = 5381;for (auto ch : key){hash += (hash << 5) + ch;}return hash;}
};//布隆过滤器一般都是解决字符串
//关于布隆过滤器的长度,len = N * x,一般x取三以上,至于具体大小依据场景进行衡量
//(1)x过大,空间浪费
//(2)x过小,误判较多(不在判断为在),过滤效果不好
template<size_t N, size_t x = 5, class K = string, class HashFun1 = BKDRHash, class HashFun2 = APHash, class HashFun3 = DJBHash>
class BloomFilter
{void set(const K& key){//一次标记3个位置,要让数值落在范围内部size_t len = N * x;size_t hash1 = HashFun1()(key) % len;size_t hash2 = HashFun2()(key) % len;size_t hash3 = HashFun3()(key) % len;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);}bool test(const K& key){//看三个位置,有一个为0就返回falsesize_t len = N * x;size_t hash1 = HashFun1()(key) % len;if (_bs.test(hash1) == false)  return false;size_t hash2 = HashFun2()(key) % len;if (_bs.test(hash2) == false)  return false;size_t hash3 = HashFun3()(key) % len;if (_bs.test(hash3) == false)  return false;return true;}
private:bitset<N * x> _bs;
};

2.5布隆过滤器的删除

布隆过滤器一般不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。
在这里插入图片描述
比如:删除上图中"腾讯"元素,如果直接将该元素所对应的二进制比特位置0,“百度”元素也被删除了,因为这两个元素在多个哈希函数计算出的比特位上刚好有重叠。


(了解)一定要支持删除的话,可以采用引用计数的方法:
将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。


2.6布隆过滤器的优点

  1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关
  2. 哈希函数相互之间没有关系,方便硬件并行运算
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  4. 能够承受一定的误判时,布隆过滤器比其他数据结构相比有很大的空间优势
  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

2.7布隆过滤器的缺点

  1. 有误判率,即存在假阳性(False Position),即判断元素在集合中不准确(补救方法:再建立一个白名单,存储可能会误判的数据)
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕(溢出了回滚到0)问题



3.海量数据面试题

3.1哈希切分


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

  1. 100G过大,无法直接在内存中处理,可以先切割成100个小文件。先将IP转化为整形key,然后key %= 100,相同IP会分到一样的小文件。
  2. 依此读取这100个文件,找每个文件中出现次数最多,然后找出最大的那个。
  3. 利用哈希切分可能存在冲突,如果某个小文件极大,可以更换哈希函数,对这个小文件再进行切分。

3.2位图应用

  1. 给定100亿个整数,设计算法找到只出现一次的整数?
    解法一:整形范围为40多亿,位图需要的空间为0.5G,存在出现多次的情况,即三种状态,故一个比特位不够,可以增加一位,即用两个位图实现。当结果为00时代表没有出现、为01时代表出现了一次、为11时代表出现了多次
    解法二:哈希切分,相同的数字一定会分到同个文件,对每个文件做统计即可。
  2. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
    (1)先哈希切分,key %= 500,文件一分出A0、A1、A2……A499,文件二分出B0、B1、B2……B499。其中相同的部分(交集)会被分到相同标号的文件,只需要A0对B0、A1对B1……A499对B499的两两找交集就行。
    (2)小文件过大的情况,更换哈希,再次切分即可。
  3. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
    (1)分析状态:一、出现0次。二、出现1次。三、出现2次。四、出现2次以上。
    (2)有四种状态,用两个比特位即可表示,即使用两个位图。当结果为00、01、10时都属于没超过2次,当结果为11时代表结果超过了两次

3.3布隆过滤器

  1. 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
    (1)近似算法,先读取文件一,建立布隆过滤器。然后读取文件二,依次判断是否在布隆过滤器中,近似算法存在误判。
    (2)精确算法,对两个大文件进行哈希切分,两两小文件找交集即可。
  2. 如何扩展BloomFilter使得它支持删除元素的操作
    (1)数据量不大,可以用几个位图实现。
    (2)数据量大,一个哈希值对应的就不是一比特位了,而是一个整形。

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

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

相关文章

如何成为前1%的程序员

如果你想成为前1%的程序员&#xff0c;你必须遵循1%的程序员做什么&#xff0c;了解其他99%的人不做什么。在现代&#xff0c;我们有各种学习平台&#xff0c;里面充满了与编程相关的视频、图文以及其他资料。 举例来说&#xff0c;我作为编程的初学者&#xff0c;去寻找路线图…

IDEA2023找不到add framework support怎么解决

问题: 我的idea版本是2023.01&#xff0c;新版idea右键项目没有Add Framework Support&#xff0c;help里面也找不到相关的。 从project structue的facets里面添加就行了&#xff0c;都是一样的。 1.依旧是新建一个项目 2.file-->project structure--->facets 左上角加…

Android studio如何安装ai辅助工具

引言 在没有翻墙的情况下&#xff0c;即单纯在公司打工&#xff0c;经测试&#xff0c;大部分ai工具都是使用不了的&#xff08;比如各种gpt,codeium,copilot&#xff09;&#xff0c;根本登录不了账号&#xff0c;但有一个国内的codegeex是可以使用的&#xff0c;在这里不对各…

Android app性能优化指南

Android应用性能优化指南 提高应用程序的性能以实现更流畅的用户体验和更高的可见度。 性能在任何应用程序的成功中发挥着重要的作用。为用户提供流畅无缝的体验应该是开发人员的重点。 应用程序大小 在用户开始使用我们的应用程序之前&#xff0c;他们需要下载应用程序并将…

DTCC2023大会-DBdoctor-基于eBPF观测数据库-附所有PPT下载链接

DTCC2023大会-DBdoctor-基于eBPF观测数据库-附所有PPT下载链接 8月16日—18日,第14届中国数据库技术大会(DTCC-2023)在北京国际会议中心举行。聚好看在大会上首次发布基于eBPF观测数据库性能的产品DBdoctor&#xff0c;受到了业界广泛的关注。近期几位业内同仁过来要大会的PPT…

2024考研数学二备考历程

GoodNotesGoodNotes apphttps://share.goodnotes.com/s/bhsraJMZ6OJwuYJb3OWnzP

C/C++之输入输出

文章目录 一.C语言的输入输出1.printfi. 输出整数ii. 浮点数iii.字符 & 字符串 2.scanfi.整数ii.浮点数iii. 字符 & 字符串 3.特殊用法i. * 的应用ii. %n 的应用iii. %[] 的应用 二.C中的输入输出1.couti. 缓冲区&#xff08;buffer&#xff09;ii. cout之格式化输出 2…

Proteus仿真--串口发送数据到2片8×8点阵屏滚动显示

本文介绍2片88点阵屏滚动显示设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 仿真运行视频 Proteus仿真--1602LCD显示电话拨号键盘按键实验&#xff08;仿真文件程序&#xff09; 附完整Proteus仿真资料代码资料 链接&#xff1a;https://pan.baidu…

使用C语言操作kafka ---- librdkafka

1 安装librdkafka git clone https://github.com/edenhill/librdkafka.git cd librdkafka git checkout v1.7.0 ./configure make sudo make install sudo ldconfig 在librdkafka的examples目录下会有示例程序。比如consumer的启动需要下列参数 ./consumer <broker> &…

一对一聊天程序

package untitled1.src;import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.*;public class MyServer extends JFrame{private ServerSocket server; // 服务器套接字pri…

【漏洞复现】华脉智联指挥调度平台/xml_edit/fileread.php文件读取漏洞

Nx01 产品简介 深圳市华脉智联科技有限公司&#xff0c;融合通信系统将公网集群系统、专网宽带集群系统、不同制式、不同频段的短波/超短波对讲、模拟/数字集群系统、办公电话系统、广播系统、集群单兵视频、视频监控系统、视频会议系统等融为一体&#xff0c;集成了专业的有线…

第一课【习题】HarmonyOS应用/元服务上架

元服务发布的国家与地区仅限于“中国大陆” 编译打包的软件包存放在项目目录build > outputs > default下 创建应用时&#xff0c;应用包名需要和app.json5或者config.json文件中哪个字段保持一致&#xff1f; 发布应用时需要创建证书&#xff0c;证书类型选择什么…

web前端实现LED功能、液晶显示时间、数字

MENU 效果演示html部分JavaScript部分css部分 效果演示 html部分 <div id"app"><!-- 页面 --><div class"time-box"><!-- 时 --><div class"house-box"><bit-component :num"houseTem"></bit…

使用cmake构建Qt6.6的qt quick项目,添加应用程序图标的方法

最近&#xff0c;在学习qt的过程中&#xff0c;遇到了一个难题&#xff0c;不知道如何给应用程序添加图标&#xff0c;按照网上的方法也没有成功&#xff0c;后来终于自己摸索出了一个方法。 1、准备一张图片作为图标&#xff0c;保存到工程目录下面&#xff0c;如logo.ico。 …

mybatis的快速入门以及spring boot整合mybatis(二)

需要用到的SQL脚本&#xff1a; CREATE TABLE dept (id int unsigned PRIMARY KEY AUTO_INCREMENT COMMENT ID, 主键,name varchar(10) NOT NULL UNIQUE COMMENT 部门名称,create_time datetime DEFAULT NULL COMMENT 创建时间,update_time datetime DEFAULT NULL COMMENT 修改…

低多边形建筑3D模型纹理贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时&#xff0c;有几种不同的风格&#xf…

树莓派CSI摄像头在新系统(23年12月)中的不用设置了,没有开关,也没有raspistill

网上都是老信息&#xff0c;用的raspistill命令&#xff0c;至少新系统没有这个东西了&#xff0c;也不会在sudo raspi-config里面也没有摄像头的开关了。 ls /dev/video* 能看到摄像头video0&#xff0c;但是vcgencmd get_camera supported0&#xff0c; detected0&#xff0…

CPU的三大调度

计算机系统中的调度可以分为不同层次&#xff0c;包括作业调度、内存调度和进程调度。这三种调度分别负责管理和优化计算机系统中不同层次的资源分配和执行顺序。 高级调度&#xff1a;作业调度&#xff08;Job Scheduling&#xff09;&#xff1a; 作业调度是指对提交到计算…

了解c++11中的新增

一&#xff0c;统一的初始化列表 在引入c11后&#xff0c;我们得出计划都可以用初始化列表进行初始化。 C11 扩大了用大括号括起的列表 ( 初始化列表 ) 的使用范围&#xff0c;使其可用于所有的内置类型和用户自 定义的类型&#xff0c; 使用初始化列表时&#xff0c;可添加等…

Vue学习计划-Vue2--VueCLi(二)vuecli脚手架创建的项目内部主要文件分析

1. 文件分析 1. 补充&#xff1a; 什么叫单文件组件&#xff1f; 一个文件中只有一个组件 vue-cli创建的项目中&#xff0c;.vue的文件都是单文件组件&#xff0c;例如App.vue 2. 进入分析 1. package.json: 项目依赖配置文件&#xff1a; 如图&#xff0c;我们说主要的属性…