【经典问题】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

简介: 【1月更文挑战第26天】【经典问题】给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

【方案一】使用Hash函数 + 分文件的方式

使用hash函数将第一个文件的所有整数映射到1000个文件中,每个文件有1000万个整数,大约40M内存, 内存可以放下,把1000个文件记为 a1,a2,a3.....a1000,用同样的hash函数映射第二个文件到1000个文件中,这1000个文件记为b1,b2,b3......b1000,由于使用的是相同的hash函数,所以两个文件中一样的数字会被分配到文件下标一致的文件中,分别对a1和b1求交集,a2和b2求交集,ai和bi求交集,最后将结果汇总,即为两个文件的交集。

【方案二】BitMap

桶分+组内bitmap。如果这里的整数是32bit的话,直接使用bitmap的方法就能实现了。所有整数共2^32种可能,每个数用2bit来表示,“00”表示两个文件均没出现,“10”表示文件1出现过,“01”表示文件2出现过,“11”表示两个文件均出现过,共需(2^32)*2/8=1GB内存,遍历两个文件中的所有整数,然后寻找bitmap中“11”对应的整数即是两个文件的交集,这样即可线性时间复杂度完成。  



使用外部排序(External Sort)和归并(Merge)的技术,结合哈希算法。


下面是一个基本的步骤:

  1. 分块排序: 首先,将两个文件分成适当大小的块,然后在内存中加载并对每个块进行排序。这是外部排序的第一步。
  2. 归并: 对于每个文件,创建一个指向排序后块的指针。然后,从两个文件中读取每个块中的第一个元素,将它们进行比较,并找到两个文件中相等的元素。如果找到相等的元素,就将其输出为交集元素。如果不相等,将较小的元素的文件的指针向前移动。
  3. 迭代: 重复执行归并步骤,直到两个文件的所有块都被处理。这样可以找到两个文件的交集元素。

这个方法的核心思想是在排序的基础上使用指针进行归并,以便逐块处理文件而不是一次性加载整个文件。

请注意,这里的关键在于如何在内存有限的情况下处理大文件。在实际实现中,可能需要根据实际情况进行调整,并考虑使用哈希算法来进一步优化处理过程。


def find_intersection(file1, file2, output_file):
    block_size =1000000# 块大小,根据实际情况调整    buffer_size =100000# 缓冲区大小,根据实际情况调整    with open(file1, 'r') as f1, open(file2, 'r') as f2, open(output_file, 'w') as output:
while True:
            block1 = read_and_sort_block(f1, block_size, buffer_size)
            block2 = read_and_sort_block(f2, block_size, buffer_size)
if not block1 or not block2:
                break  # 文件已处理完毕            intersection = merge_blocks(block1, block2)
            write_intersection(output, intersection)
def read_and_sort_block(file, block_size, buffer_size):
    block = []
    buffer = []
for i in range(block_size):
        line = file.readline()
if not line:
            break  # 文件已处理完毕        buffer.append(int(line))
if i % buffer_size ==0:
            block += sorted(buffer)
            buffer = []
if buffer:
        block += sorted(buffer)
    return block
def merge_blocks(block1, block2):
    intersection = []
    i, j =0, 0while i < len(block1) and j < len(block2):
if block1[i] == block2[j]:
            intersection.append(block1[i])
            i +=1            j +=1elif block1[i] < block2[j]:
            i +=1else:
            j +=1    return intersection
def write_intersection(output, intersection):
for num in intersection:
        output.write(str(num) +'\n')
相关文章
|
1月前
|
Linux C++
Linux c/c++文件虚拟内存映射
这篇文章介绍了在Linux环境下,如何使用虚拟内存映射技术来提高文件读写的速度,并通过C/C++代码示例展示了文件映射的整个流程。
46 0
|
1月前
|
程序员 Windows
程序员必备文件搜索工具 Everything 带安装包!!! 比windows自带的文件搜索快几百倍!!! 超级好用的文件搜索工具,仅几兆,不占内存,打开即用
文章推荐了程序员必备的文件搜索工具Everything,并提供了安装包下载链接,强调其比Windows自带搜索快且占用内存少。
43 0
|
2月前
|
存储 安全 Linux
将文件映射到内存,像数组一样访问
将文件映射到内存,像数组一样访问
29 0
|
4月前
|
Java
jmap 查看jvm内存大小并进行dump文件内存分析
jmap 查看jvm内存大小并进行dump文件内存分析
92 3
|
4月前
|
移动开发 监控 Serverless
函数计算操作报错合集之机器配置显示为1G内存,但报错显示0.12G,是什么原因
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
|
5月前
|
Python
python3获取内存和cpu利用率记录日志文件psutil
python3获取内存和cpu利用率记录日志文件psutil
68 1
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0
有 3 个进程 P1、P2、P3 协作解决文件打印问题。P1 将文件记录从磁盘读入内存的缓冲区 1,每执行一次读一个记录 ;P2 将缓冲区 1 中的内容复制到缓冲区 2 中,每执行一次复制一个记录 ;
有 3 个进程 P1、P2、P3 协作解决文件打印问题。P1 将文件记录从磁盘读入内存的缓冲区 1,每执行一次读一个记录 ;P2 将缓冲区 1 中的内容复制到缓冲区 2 中,每执行一次复制一个记录 ;
|
5月前
|
存储 C语言
【C语言进阶篇】整数在内存的存储——原码、反码、补码
【C语言进阶篇】整数在内存的存储——原码、反码、补码
|
5月前
|
存储 C语言
C语言---求一个整数存储在内存中的二进制中1的个数--3种方法
C语言---求一个整数存储在内存中的二进制中1的个数--3种方法