海量数据面试题

目录

前言

什么是海量数据

 一、利用位图解决

二、利用布隆过滤器解决

三、利用哈希切割解决


前言

在大数据时代,海量数据处理已成为技术领域中的一项重要课题。无论是企业级应用、互联网平台,还是人工智能和机器学习的实现,都离不开对大规模数据的高效处理。而对于C++开发者来说,如何在面对海量数据时保证系统的高效性和可扩展性,已经成为面试中常见的考察内容。

C++作为一种高性能的编程语言,凭借其接近硬件的操作和精细的内存管理,常常被用于构建对性能要求极高的系统。在海量数据的处理过程中,C++开发者需要不仅具备扎实的基础知识,还需掌握一些特殊的算法和数据结构,以应对各种挑战性的问题。

本篇文章将围绕海量数据处理相关的C++面试题展开,涵盖常见的数据结构、算法优化、内存管理等方面。通过深入分析和解答这些面试题,希望能够帮助读者提升在大规模数据处理中的应对能力,进而在面试中脱颖而出。

什么是海量数据

所谓海量数据,通常指的是超出传统数据库和计算系统处理能力的数据量。这些数据集通常规模庞大,数据类型复杂,可能包含结构化、半结构化和非结构化数据。根据不同的场景,海量数据的规模可以从几GB到几TB,甚至达到PB级别。

面对如此庞大的数据量,传统的单机计算和存储方式往往力不从心,因此需要采用分布式处理框架、数据压缩技术、数据流处理等方法来有效应对。

就比如说,我们熟知一个int类型占4字节空间大小,通过计算4G,内存大概可以存储10亿个int类型的数据,但是如果有人问你,怎么存储100亿呢?现在的电脑是以16G,32G运行内存为主,对于处理100亿个int类型数据,那么就不可以处理。

这不仅仅是空间上的问题,还伴随着时间上的问题。

所以就对于此问题就有了相应的解决方法:

  • 对于时间问题,就可以采用位图、布隆过滤器等数据结构来解决。
  • 对于空间问题,就可以采用哈希切割等方法,将大规模的数据转换成小规模的数据逐个击破。

 一、利用位图解决

简单介绍一下位图

对于传统的存储方式,一般是对于整数i,相关信息会存放到容器第i个位置,但是位图不一样,他是对于整数i,相关信息存放到第i个比特位上。所以这就大大减少了时间与空间的消耗。

题目一:给定100亿个整数,设计算法找到只出现一次的整数。

刚才我们也举例了,真要处理起来还真就是不行的,个人的电脑对空间,时间都无法对应解决问题。

但是int的范围是: -2^31到2^32 - 1。所以我们就可以创建一个”大小“(单位为比特)为2^32大小的空间,以可以存储int的所有相关数据。所以我们标记整数时可以将其分为三种状态

  1. 出现0次。
  2. 出现1次。
  3. 出现2次及以上。

一个比特位只能表示两种状态,而要表示三种状态我们至少需要用两个比特位,因此我们可以开辟两个位图,这两个位图的对应位置分别表示该位置整数的第一个位和第二个位。

我们可以将着三种状态分别定义为00、01、10,此时当我们读取到重复的整数时,就可以让其对应的两个位按照00→01→10的顺序进行变化,最后状态是01的整数就是只出现一次的整数。

#include <iostream>
#include <vector>
#include <assert.h>
#include <bitset>
using namespace std;int main()
{//此处应该从文件中读取100亿个整数,但是为了方便演示,就假设已经读取了vector<int> v{ 12, 33, 4, 2, 7, 3, 32, 3, 3, 12, 21 };// 假设v里面有100亿个整形数据//在堆上申请空间bitset<4294967295>* bs1 = new bitset<4294967295>;bitset<4294967295>* bs2 = new bitset<4294967295>;for (auto e : v){if (!bs1->test(e) && !bs2->test(e)) //00->01{bs2->set(e);}else if (!bs1->test(e) && bs2->test(e)) //01->10{bs1->set(e);bs2->reset(e);}else if (bs1->test(e) && !bs2->test(e)) //10->10{//不做处理}else //11(不会出现这种,因为我们设定上就是最大为10){assert(false);}}// 统计那个整数出现了一次for (size_t i = 0; i < 4294967295; i++){if (!bs1->test(i) && bs2->test(i)) //01cout << i << endl;}return 0;
}

需要注意以下几点:

  1. 存储100亿个整数大概需要40G的内存空间,因此题目中的100亿个整数肯定是存储在文件当中的,代码中直接从vector中读取数据是为了方便演示,我也不能真正去读取100亿个数据,那时间也需要很长。
  2. 为了能映射所有整数,位图的大小必须开辟为2^32位,也就是代码中的4294967295,因此开辟一个位图大概需要512M的内存空间,两个位图就要占用1G的内存空间,所以代码中选择在堆区开辟空间,若是在栈区开辟则会导致栈溢出。
  3. 最后的检查中循环写的是:for (size_t i = 0; i < 4294967295; i++),而不是for (int i = INT_MIN; i < INT_MAX; i++),就是因为位图是无符号类型,不支持负数的表示。如果你想传递负数,需要处理负数的映射。

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

首先明确一点创建一个存整形的位图需要512M的内存。 

 方法一:仅使用512M

  • 第一个文件中的数据,我们将其转化为位图,并存储在内存中。
  • 第二个文件中的数据,我们读取其中的所有整数,然后判断在不在位图中,在就是交集,不在就不是交集。

方法二:刚好使用1G

  • 文件 1: 第一个文件中的数据,我们将其转化为位图,并存储在内存中。
  • 文件 2: 第二个文件中的数据,我们按照同样的方式逐块处理。

每次加载文件 1 的一个块并标记其位图后,我们可以将文件 2 的当前块与文件 1 的位图进行比较,计算交集。具体方法是,遍历文件 2 的当前块中的每个整数,并检查文件 1 中的位图对应位置是否为 1。如果是,说明该整数在两个文件中都出现了,这就是交集的一部分。

说明一下: 对于32位的整型,无论待处理的整数个数是多少,开辟的位图都必须有2^32个比特位,也就是512M,因为我们要保证每一个整数都能够映射到位图当中,因此这里位图的空间的消耗是不可避免的,即便位图在规定上不允许存负数。

题目三:一个文件有100亿个整数,1G内存,设计算法找到出现次数不超过2次的所有整数。

该题目和题目一的方法是一样的,在该题目中我们标记整数时可以将其分为四种状态:

  1. 出现0次。
  2. 出现1次。
  3. 出现2次。
  4. 出现2次以上。

一个整数要表示四种状态也是只需要两个位就够了,此时当我们读取到重复的整数时,就可以让其对应的两个位按照00→01→10→11的顺序进行变化,最后状态是01或10的整数就是出现次数不超过2次的整数。

#include <iostream>
#include <vector>
#include <assert.h>
#include <bitset>
using namespace std;int main()
{//此处应该从文件中读取100亿个整数,但是为了方便演示,就假设已经读取了vector<int> v{ -12, 33, 4, 2, 7, 3, 32, 3, 3, 12, 21 };// 假设v里面有100亿个整形数据//在堆上申请空间bitset<INT_MAX>* bs1 = new bitset<INT_MAX>;bitset<INT_MAX>* bs2 = new bitset<INT_MAX>;for (auto e : v){if (!bs1->test(e) && !bs2->test(e)) //00->01{bs2->set(e);}else if (!bs1->test(e) && bs2->test(e)) //01->10{bs1->set(e);bs2->reset(e);}else if (bs1->test(e) && !bs2->test(e)) //10->10{//不做处理}else //11(不会出现这种,因为我们设定上就是最大为10){assert(false);}}// 统计那个整数出现了一次for (size_t i = 0; i < 4294967295; i++){if ((!bs1->test(i) && bs2->test(i)) || (bs1->test(i) && !bs2->test(i))) //01或10cout << i << endl;}return 0;
}

二、利用布隆过滤器解决

简单介绍一下布隆过滤器

布隆过滤器底层其实是套用的位图,但是在此基础上对第i个位置的相关信息存放到第i个比特位的设定进行了修改,改为了:第i个位置的相关信息存放到第X,Y,Z......(X,Y,Z是通过多个哈希函数计算而得,越多其误差和错误越小)个比特位。

给两个文件,分别有100亿个string,我们只有1G内存,如何找到两个文件的交集?给出近似算法。

 题目要求给出近视算法,也就是允许存在一些误判,那么我们就可以用布隆过滤器。

  • 文件 1: 第一个文件中的数据,我们将其转化为布隆过滤器,并存储在内存中。
  • 文件 2: 第二个文件中的数据,我们按照同样的方式逐块处理。

每次加载文件 1 的一个块并标记其布隆过滤器后,我们可以将文件 2 的当前块与文件 1 的布隆过滤器进行比较,计算交集。具体方法是,遍历文件 2 的当前块中的每个string,并检查文件 1 中的布隆过滤器对应位置是否为 1。如果是,说明该string在两个文件中都出现了,这就是交集的一部分。

扩展:如何扩展BloomFilte使得它支持删除元素的操作

如果存放的基数大到一定程度时,那么错误是无法避免的。

所以一般不支持删除,删除一个值可能会影响其他值()原因如下:

  • 因为布隆过滤器判断一个元素存在时可能存在误判,因此无法保证要删除的元素确实在布隆过滤器当中,此时将位图中对应的比特位清0会影响其他元素。比方说,"qbs"(只出现一次存放在第20个比特位,"sss"(出现多次)也在此,如果删除"qbs",但是第20个比特位--后不为0,还是会判断"qbs"依旧存在,出现误判。
  • 此外,就算要删除的元素确实在布隆过滤器当中,也可能该元素映射的多个比特位当中有些比特位是与其他元素共用的,此时将这些比特位清0也会影响其他元素。

如果要让布隆过滤器支持删除,也可以,比方说:用多个位标记一个值,存引用计数,但是这样话,空间消耗的就变大了。得不偿失!!!

三、利用哈希切割解决

给两个文件,分别有100亿个string,我们只有1G内存,如何找到两个文件的交集?给出精确算法。

 还是刚才那道题目,但现在要求给出精确算法,那么就不能使用布隆过滤器了,此时需要用到哈希切分。

  • 首先需要估算一下这里一个文件的大小,便于确定将一个文件切分为多少个小文件。
  • 假设平均每个string为20字节,那么100亿个strng就是200G,由于我们只有1G内存,这里可以考虑将一个文件切分成400个小文件。
  • 我们决定要分割成400个小文件后,就需要创建400个文件,然后先访问前1G的数据,然后通过哈希函数,计算其应该被分到第几个文件。
  • 需要注意的是,对于两个文件的分割必须使用同一个哈希函数。

这里就拿其中一个文件举例 

 

切割完成后,每一个小文件都是512M的数据,那么我们就可以通过上面的思路求其交集

 

那各个小文件之间又应该如何找交集呢? 

  • 经过哈希切分后,理论上每个小文件的平均大小约为 512MB,因此我们可以将其中一个小文件加载到内存,并将其内容存入一个 set 容器中。然后,遍历另一个小文件中的查询(string),依次判断每个查询是否存在于 set 容器中。如果存在,则该查询为交集元素;如果不存在,则不是交集。
  • 然而,由于哈希切分并不一定会将文件平均切分,有些小文件的大小可能仍然超过 1GB。在这种情况下,如果与之对应的另一个小文件的大小小于 1GB,我们可以将该小文件加载到内存进行查询,因为我们只需要将其中一个小文件加载到内存。
  • 但如果两个小文件的大小都大于 1GB,我们可以考虑对这两个小文件再进行一次切分,将它们切成更小的文件。这一过程与之前对 A 文件和 B 文件的切分方法类似,具体就是通过哈希函数将其再次分割成多个更小的文件,然后分别加载其中的一个小文件到内存进行交集计算。

本质这里在进行哈希切分时,就是将这些小文件看作一个个的哈希桶,将大文件中的string通过哈希函数映射到这些哈希桶中,如果是相同的string,则会产生哈希冲突进入到同一个小文件中。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

复现论文-报错记录dream-ood

复现论文Dream the Impossible: Outlier Imagination with Diffusion Models 过程中出现的问题记录 服务器&#xff1a;NIVIDA2080ti github: 论文&#xff1a; arxiv.org/pdf/2309.13415 1.pytorch使用出现"RuntimeError: An attempt has been made to start a new proc…

LinkedList与链表

目录 一、链表 链表相关练习题 二、LikedList 1、构造方法 2、常用方法 3、LinkedList的遍历 4、ArrayList与LinkedList的区别 一、链表 链表是一种物理存储结构上非连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的 链式结构在逻辑上是连…

vulnhub靶机hackxor提示(部分写出)

靶机地址&#xff1a;Hackxor: 1 ~ VulnHub 主机发现 130是靶机 端口扫描 服务扫描 漏洞扫描 Hosts配置&#xff08;这个是需要在网上找的&#xff0c;这个是靶机的缘故搭建不完全所以需要自己写hosts&#xff09; 访问wraithmail:8080 数据包 GET http://utrack/cat.jsp?id1…

录的视频怎么消除杂音?从录制到后期的杂音消除攻略

在录制视频时&#xff0c;杂音往往是一个令人头疼的问题。无论是环境噪音、设备噪音还是电磁干扰&#xff0c;杂音的存在都会极大地影响视频的听觉体验。录的视频怎么消除杂音&#xff1f;通过一些前期准备和后期处理技巧&#xff0c;我们可以有效地消除这些杂音&#xff0c;提…

C++内存模型与并发支持

本文是CppCon23演讲&#xff1a;C Memory Model&#xff1a;from C11 to C 23的笔记&#xff0c;掺杂个人见解以及扩展 内存模型 操作系统的四个特性&#xff1a;虚拟&#xff0c;并发&#xff0c;持久 抽象中很重要的一部分就是内存虚拟。从编程的角度来看&#xff0c;编程就…

机器学习day5-随机森林和线性代数1

十 集成学习方法之随机森林 集成学习的基本思想就是将多个分类器组合&#xff0c;从而实现一个预测效果更好的集成分类器。大致可以分为&#xff1a;Bagging&#xff0c;Boosting 和 Stacking 三大类型。 &#xff08;1&#xff09;每次有放回地从训练集中取出 n 个训练样本&…

jdk1.7的hashmap为什么会出现死循环问题

原因在于链表结构出现了环状。为什么会出现环状的链表&#xff1f; 原因在于多个线程同时进行扩容的时候。 由于一个线程使用的是头插法进行迁移数据到新开辟的数组中&#xff0c;使得链表中的数据是颠倒的顺序。 而当另一个线程扩容的时候就可能因为这个颠倒的顺序而出现指针…

微信小程序navigateTo:fail webview count limit exceed

theme: nico 你们好&#xff0c;我是金金金。 场景 uniapp编写微信小程序&#xff0c;使用uni.navigateTo跳转的过程中报错如下&#xff1a; 报错意思也非常明显了&#xff1a;errMsg":"navigateTo:fail webview 数量超出限制 排查 排查之前我先贴一下代码 代码非…

逆向攻防世界CTF系列33-流浪者

逆向攻防世界CTF系列33-流浪者 shiftf12看到pass&#xff0c;跟进 是个输入的处理&#xff0c;其实很简单&#xff0c;看不懂也没关系&#xff0c;先看看return 这里strcmp成功后return的就是成功 最后要为KanXueCTF2019JustForhappy while ( *(_DWORD *)(a1 4 * v4) < 0x…

算法--解决二叉树遍历问题

第一 实现树的结构 class Node(): # 构造函数&#xff0c;初始化节点对象&#xff0c;包含数据和左右子节点 def __init__(self, dataNone): self.data data # 节点存储的数据 self.left None # 左子节点&#xff0c;默认为None self.rig…

Ubuntu22.04.2 k8s部署

k8s介绍 简单介绍 通俗易懂的解释&#xff1a; Kubernetes&#xff08;也被称为 K8s&#xff09;就像是一个大管家&#xff0c;帮你管理你的云计算服务。想象一下&#xff0c;你有很多个小程序&#xff08;我们称之为“容器”&#xff09;&#xff0c;每个都在做不同的事情&…

游戏引擎学习第12天

视频参考:https://www.bilibili.com/video/BV1yom9YnEWY 这节没讲什么东西&#xff0c;主要是改了一下音频的代码 后面有介绍一些alloc 和malloc,VirtualAlloc 的东西 _alloca 函数&#xff08;或 alloca&#xff09;分配的是栈内存&#xff0c;它的特点是&#xff1a; 生命周…

Linux-软件管理-本地仓库和网络资源仓库配置(RHCSA)

该章节的目录如下&#xff1a; 认识rpm包 将设备挂载到/mnt上面 查看光驱上的相关信息 使用rpm包管理软件 仓库的配置(重要) 无相关文件 本地仓库配置&#xff08;书写相关的仓库文件&#xff09; 配置流程 效果测试&#xff08;安装卸载&#xff09; 查看仓库 清理…

【arxiv‘24】Vision-Language Navigation with Continual Learning

论文信息 题目&#xff1a;Vision-Language Navigation with Continual Learning 视觉-语言导航与持续学习 作者&#xff1a;Zhiyuan Li, Yanfeng Lv, Ziqin Tu, Di Shang, Hong Qiao 论文创新点 VLNCL范式&#xff1a;这是一个新颖的框架&#xff0c;它使得智能体能够在适…

数字化建设:指标如何驱动的企业KPI设计?

我们以KPI设定为例&#xff0c;简单说明在一套科学的经营分析体系的加持下&#xff0c;企业的经营KPI应该如何设定&#xff0c;如图所示。 指标驱动的企业KPI设计 每年年初企业做战略规划的同时&#xff0c;会启动年度业务KPI的设定。这个时候经营分析团队会主导整个过程。首先…

初级数据结构——栈题库(c++)

目录 前言1.杭电oj——Bitset2.杭电oj——进制转换[3.力扣——LCR 123. 图书整理 I](https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/description/)[4.力扣——LCR 027. 回文链表](https://leetcode.cn/problems/aMhZSa/)[5.力扣——1614. 括号的最大嵌…

数字化转型企业架构设计手册(交付版),企业数字化转型建设思路、本质、数字化架构、数字化规划蓝图(PPT原件获取)

1、企业架构现状分析 2、企业架构内容框架 3、企业架构设计方法 3.1 、业务架构设计方法 3.2 、数据架构设计方法 3.3 、应用架构设计方法 3.4 、技术架构设计方法 软件全套资料部分文档清单&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&…

⾃动化运维利器Ansible-基础

Ansible基础 一、工作原理二、快速入门2.1 测试所有资产的网络连通性2.2 发布文件到被管理节点(资产) 三、资产(被管理节点)3.1 静态资产3.1.1 自定义资产3.1.2 自定义资产的使用3.1.3 资产选择器 四、Ansible Ad-Hoc 命令4.1 模块类型4.1.1 command & shell 模块4.1.2 cop…

鸿蒙NEXT自定义组件:太极Loading

【引言】&#xff08;完整代码在最后面&#xff09; 本文将介绍如何在鸿蒙NEXT中创建一个自定义的“太极Loading”组件&#xff0c;为你的应用增添独特的视觉效果。 【环境准备】 电脑系统&#xff1a;windows 10 开发工具&#xff1a;DevEco Studio NEXT Beta1 Build Vers…

AVL树了解并简单实现

这篇文章默认知道二叉搜索树&#xff0c;如果了解并不多可以先看看二叉搜索树了解和实现-CSDN博客 目录 1.AVL树概念 2.AVL树节点定义 3.AVL树的插入&#xff08;重点&#xff09; 3.1AVL树 3.2AVL树的旋转 3.3AVL树插入代码 4.AVL树的验证 5.AVL树的删除 6.AVL树的性能…