【数据结构】海量数据处理

news2025/1/14 0:51:08

【数据结构】海量数据处理

前言

海量数据处理是指基于海量数据的存储和处理,正因为数据量太大,所以导致要么无法在短时间内迅速处理,要么无法一次性装入内存。

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

位图相关

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

我们标记整数时可以将其分为三种状态:

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

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

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

为了方便演示,下面我们直接从vector中读取若干整数进行模拟处理:

#include <assert.h>
#include <bitset>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    //此处应该从文件中读取100亿个整数
    vector<int> v{12, 33, 4, 2, 7, 3, 32, 3, 3, 12, 21};
    //在堆上申请空间
    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(理论上不会出现该情况)
            assert(false);
        }
    }

    for (size_t i = 0; i < 4294967295; i++) {
        if (!bs1->test(i) && bs2->test(i)) {
            //01
            cout << i << endl;
        }
    }
    return 0;
}

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

方案一:(一个位图需要512M内存)

  1. 依次读取第一个文件中的所有整数,将其映射到一个位图。
  2. 再读取另一个文件中的所有整数,判断在不在位图中,在就是交集,不在就不是交集。

方案二:(两个位图刚好需要1G内存,满足要求)

  1. 依次读取第一个文件中的所有整数,将其映射到位图1。
  2. 依次读取另一个文件中的所有整数,将其映射到位图2。
  3. 将位图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 <bitset>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v{12, 33, 4, 2, 7, 3, 32, 3, 3, 12, 21};
    //在堆上申请空间
    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->11
            bs2->set(e);
        } else {//11->11
            //不做处理
        }
    }

    for (size_t i = 0; i < 4294967295; i++) {
        if ((!bs1->test(i) && bs2->test(i)) || (bs1->test(i) && !bs2->test(i))) {
            //01或10
            cout << i << endl;
        }
    }
    return 0;
}

布隆过滤器相关

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

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

  • 先读取其中一个文件当中的query,将其全部映射到一个布隆过滤器当中。
  • 然后读取另一个文件当中的query,依次判断每个query是否在布隆过滤器当中,如果在则是交集,不在则不是交集。

哈希切割相关

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

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

  • 首先需要估算一下这里一个文件的大小,便于确定将一个文件切分为多少个小文件。

  • 假设平均每个query为20字节,那么100亿个query就是200G,由于我们只有1G内存,这里可以考虑将一个文件切分成400个小文件。

  • 这里我们将这两个文件分别叫做A文件和B文件,此时我们将A文件切分成了A0A399共400个小文件,将B文件切分成了B0B399共400个小文件。

在切分时需要选择一个哈希函数进行哈希切分,以切分A文件为例,切分时依次遍历A文件当中的每个query,通过哈希函数将每个query转换成一个整型 i (0 ≤ i ≤ 399),然后将这个query写入到小文件Ai当中。对于B文件也是同样的道理,但切分A文件和B文件时必须采用的是同一个哈希函数。
在这里插入图片描述

由于切分A文件和B文件时采用的是同一个哈希函数,因此A文件与B文件中相同的query计算出的 i ii 值都是相同的,最终就会分别进入到Ai和Bi文件中,这也是哈希切分的意义。

因此我们就只需要分别找出A0与B0的交集、A1与B1的交集、…、A399与B399的交集,最终将这些交集和起来就是A文件和B文件的交集。

在这里插入图片描述

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

  • 经过切分后理论上每个小文件的平均大小是512M,因此我们可以将其中一个小文件加载到内存,并放到一个set容器中,再遍历另一个小文件当中的query,依次判断每个query是否在set容器中,如果在则是交集,不在则不是交集。
  • 当哈希切分并不是平均切分,有可能切出来的小文件中有一些小文件的大小仍然大于1G,此时如果与之对应的另一个小文件可以加载到内存,则可以选择将另一个小文件中的query加载到内存,因为我们只需要将两个小文件中的一个加载到内存中就行了。
  • 但如果两个小文件的大小都大于1G,那我们可以考虑将这两个小文件再进行一次切分,将其切成更小的文件,方法与之前切分A文件和B文件的方法类似。
  • 本质这里在进行哈希切分时,就是将这些小文件看作一个个的哈希桶,将大文件中的query通过哈希函数映射到这些哈希桶中,如果是相同的query,则会产生哈希冲突进入到同一个小文件中。

给一个超过100G大小的log file,log中存着IP地址,设计算法找到出现次数最多的IP地址?如何找到top K的IP?如何直接用Linux系统命令实现?

该题目同样需要用到哈希切分,切分步骤如下:

  • 我们将这个log file叫做A文件,由于A文件的大小超过100G,这里可以考虑将A文件切分成200个小文件。

  • 在切分时选择一个哈希函数进行哈希切分,通过哈希函数将A文件中的每个IP地址转换成一个整型 i (0 ≤ i ≤ 199),然后将这个IP地址写入到小文件Ai当中。

  • 由于哈希切分时使用的是同一个哈希函数,因此相同的IP地址计算出的i值是相同的,最终这些相同的IP地址就会进入到同一个Ai小文件当中。

在这里插入图片描述

经过哈希切分后得到的这些小文件,理论上就能够加载到内存当中了,如果个别小文件仍然太大那可以对其再进行一次哈希切分,总之让最后切分出来的小文件能够加载到内存。

  • 现在要找到出现次数最多的IP地址,就可以分别将各个小文件加载到内存中, 然后用一个map<string, int>容器统计出每个小文件中各个IP地址出现的次数,然后比对各个小文件中出现次数最多的IP地址,最终就能够得到log file中出现次数最多的IP地址。
  • 如果要找到出现次数top K的IP地址,可以先将一个小文件加载到内存中,选出小文件中出现次数最多的K个IP地址建成一个小堆,然后再依次比对其他小文件中各个IP地址出现的次数,如果某个IP地址出现的次数大于堆顶IP地址出现的次数,则将该IP地址与堆顶的IP地址进行交换,然后再进行一次向下调整,使其仍为小堆,最终比对完所有小文件中的IP地址后,这个小堆当中的K个IP地址就是出现次数top K的IP地址。

件加载到内存中,选出小文件中出现次数最多的K个IP地址建成一个小堆,然后再依次比对其他小文件中各个IP地址出现的次数,如果某个IP地址出现的次数大于堆顶IP地址出现的次数,则将该IP地址与堆顶的IP地址进行交换,然后再进行一次向下调整,使其仍为小堆,最终比对完所有小文件中的IP地址后,这个小堆当中的K个IP地址就是出现次数top K的IP地址。

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

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

相关文章

摄影后期图像编辑软件Lightroom Classic 2023 mac中文特点介绍

Lightroom Classic 2023 mac是一款图像处理软件&#xff0c;是数字摄影后期制作的重要工具之一&#xff0c;lrc2023 mac适合数字摄影后期制作、摄影师、设计师等专业人士使用。 Lightroom Classic 2023 mac软件特点 高效的图像管理&#xff1a;Lightroom Classic提供了强大的图…

分布式应用程序协调服务 ZooKeeper 详解

目录 1、ZooKeeper简介 2、ZooKeeper的使用场景 3、ZooKeeper设计目的 4、ZooKeeper数据模型 5、ZooKeeper几个重要概念 5.1、ZooKeeper Session 5.2、ZooKeeper Watch 5.3、Consistency Guarantees 6、ZooKeeper的工作原理 6.1、Leader Election 6.2、Leader工作流…

Docker中MySql容器的数据挂载

1.查看是否有数据卷 docker inspect mysql 说明&#xff1a;Name的值是随机生成的不是命令的。因此没有数据卷。 2. 目录挂载 说明&#xff1a;本地目录不允许简写&#xff1b;在执行docker runi命令时&#xff0c;使用-v本地目录&#xff1a;容器内目录可以完成本地目录挂载…

Python之函数、模块、包库

函数、模块、包库基础概念和作用 A、函数 减少代码重复 将复杂问题代码分解成简单模块 提高代码可读性 复用老代码 """ 函数 """# 定义一个函数 def my_fuvtion():# 函数执行部分print(这是一个函数)# 定义带有参数的函数 def say_hello(n…

列表的增删改查和遍历

任务概念 什么是任务 任务是一个参数为指针&#xff0c;无法返回的函数&#xff0c;函数体为死循环不能返回任务的实现过程 每个任务是独立的&#xff0c;需要为任务分别分配栈称为任务栈&#xff0c;通常是预定义的全局数组&#xff0c;也可以是动态分配的一段内存空间&#…

农产品团购配送商城小程序的作用是什么

农产品覆盖稻麦油蛋等多种细分类目&#xff0c;各地区经营商家众多&#xff0c;随着人们生活品质提升&#xff0c;对食物的要求也在提升&#xff0c;绿色无污染无激素的农产品往往受到不少人喜爱&#xff0c;而在销售中&#xff0c;也有不少人选择自建商城线上经营。 通过【雨…

【软考】磁盘工作原理 计算最多最少读取时间

这个题目重复看了三四遍讲解&#xff0c;才完全搞懂计算过程&#xff0c;特此记录 解析 磁头不会停止旋转 单缓冲区&#xff1a;读取完一个物理块后&#xff0c;只有等该物理块处理完成&#xff0c;才能继续读取后面的物理块。 最长时间 摆放顺序如下&#xff1a; 从 R0 开始…

【JavaEE】JavaScript webAPI的基本知识

JavaScript Web API 文章目录 JavaScript Web APIwebAPI背景DOMDOM树 获取元素querySelectorquerySelectorAll 事件初识键盘事件onkeydownonkeypressonkeyup 操作元素获取/修改元素内容1.innerText2.innerHTML 获取/修改元素属性获取/修改表单元素属性获取/修改样式属性行内样式…

JUC——并发编程—第四部分

理解JMM Volatile是Java虚拟机提供的轻量级的同步机制。有三大特性。 1.保证可见性 2.不保证原子性 3.禁止指令重排 定义:Java内存模型&#xff0c;是一个概念。 关于JMM的一些同步的约定: 1、线程解锁前&#xff0c;必须把共享变量立刻刷回主存. 2、线程加锁前&#x…

华为鸿蒙手表开发之动态生成二维码

华为鸿蒙手表开发之动态生成二维码 前言&#xff1a; 最近入职新公司&#xff0c;由于之前的哥们临时离职&#xff0c;走得很突然&#xff0c;所以没有任何交接和文档&#xff0c;临时顶上公司手表应用的上架&#xff0c;更换了新的密钥和key之后重新测试功能和流程&#xff…

FFmpeg 基础模块:下载编译与安装、常用命令、处理流程

FFmpeg源码下载 我们会逐步分析作为 API 用户我们需要了解的 FFmpeg 中的重要模块&#xff0c;比如 AVFormat 模块、AVcodec 模块、AVfilter 模块、swscale 模块、swresample 模块。 在具体讲解如何使用 FFmpeg 的 API 之前&#xff0c;为了方便你查看 API 对应的代码&#x…

图像处理初学者导引---OpenCV 方法演示项目

OpenCV 方法演示项目 项目地址&#xff1a;https://github.com/WangQvQ/opencv-tutorial 项目简介 这个开源项目是一个用于演示 OpenCV 方法的工具&#xff0c;旨在帮助初学者快速理解和掌握 OpenCV 图像处理技术。通过这个项目&#xff0c;你可以轻松地对图像进行各种处理&a…

Transformer学习-self-attention

这里写自定义目录标题 Self-attentionMulti-head self-attention用self-attention解决其他问题 Self-attention 用Wq、Wk、Wv分别乘输入向量得到q、k、v向量 用每个q向量乘所有的k向量得到对应项的attention&#xff0c;即用每项的query向量去匹配所有的key向量&#xff0c;得…

由于找不到d3dx9_43.dll无法继续执行此代码怎么解决?全面解析d3dx9_43.dll

在使用计算机过程中&#xff0c;我们可能会遇到各种各样的问题。其中之一就是d3dx9_43.dll文件丢失的问题。这个问题通常会出现在运行某些应用程序或游戏时&#xff0c;导致程序无法正常启动或运行。那么&#xff0c;如何解决这个问题呢&#xff1f;小编将为您提供一些解决方案…

Leetcode字符串题目

1 sslist(s) ttlist(t) ss.sort() tt.sort() return sstt 时间复杂度更低的代码 2 dict1{} dict2{} for ch in s:dict1[ch]dict1.get(ch,0)1 # 如果有ch&#xff0c;则原有位置加一&#xff0c;没有的话就创建了(01) for ch in t:dict2[ch]dict2.get(ch,0)1 return dict1…

苹果双系统和虚拟机哪个好用?

苹果不能直接使用windows系统中的软件&#xff0c;但windows系统较为全面&#xff0c;为了解决苹果电脑不能使用windows系统软件的问题&#xff0c;使用双系统和类虚拟机是非常不错的解决方案。那么&#xff0c;苹果双系统和虚拟机哪个好&#xff1f;这两种解决方案各有千秋。苹…

105.从前序与中序遍历序列构造二叉树

力扣题目链接(opens new window) 根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如&#xff0c;给出 前序遍历 preorder [3,9,20,15,7] 中序遍历 inorder [9,3,15,20,7] 返回如下的二叉树&#xff1a; class Solution { public:Tr…

Android学习之路(19) ListView详解

一.ListView简介 在Android开发中&#xff0c;ListView是一个比较常用的控件。它以列表的形式 展示具体数据内容&#xff0c;并且能够根据数据的长度自适应屏幕显示。 二.ListView简单用法 代码部分 1.布局界面 activity_main.xml 代码&#xff1a; <?xml version"…

106.从中序与后序遍历序列构造二叉树

力扣题目链接(opens new window) 根据一棵树的中序遍历与后序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如&#xff0c;给出 中序遍历 inorder [9,3,15,20,7]后序遍历 postorder [9,15,7,20,3] 返回如下的二叉树&#xff1a; class Solution { public:Tr…

堆排序算法---C语言实现(超详细解析!!!!)

目录 一、前言 二、堆排序 &#x1f34e;方法一&#xff08;自己写一个堆&#xff0c;在进行排序&#xff09; &#x1f4a6;时间复杂度分析 &#x1f350;方法二&#xff08;直接在数组上建堆&#xff09; &#x1f4a6;向上调整建堆 &#x1f4a6;向下调整建堆 &a…