【经典问题】给两个文件,分别有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')
相关文章
|
2月前
|
存储
数据在内存中的存储之整数存储
数据在内存中的存储之整数存储
26 0
|
17天前
|
Python
python3获取内存和cpu利用率记录日志文件psutil
python3获取内存和cpu利用率记录日志文件psutil
17 1
|
2天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
10 0
有 3 个进程 P1、P2、P3 协作解决文件打印问题。P1 将文件记录从磁盘读入内存的缓冲区 1,每执行一次读一个记录 ;P2 将缓冲区 1 中的内容复制到缓冲区 2 中,每执行一次复制一个记录 ;
有 3 个进程 P1、P2、P3 协作解决文件打印问题。P1 将文件记录从磁盘读入内存的缓冲区 1,每执行一次读一个记录 ;P2 将缓冲区 1 中的内容复制到缓冲区 2 中,每执行一次复制一个记录 ;
|
5天前
|
存储 C语言
【C语言进阶篇】整数在内存的存储——原码、反码、补码
【C语言进阶篇】整数在内存的存储——原码、反码、补码
|
9天前
|
存储 C语言
C语言---求一个整数存储在内存中的二进制中1的个数--3种方法
C语言---求一个整数存储在内存中的二进制中1的个数--3种方法
|
2月前
|
Windows
虚拟机内存越用越少,即使文件都永久删除了!!!
虚拟机内存越用越少,即使文件都永久删除了!!!
|
2月前
|
存储
整数和浮点数在内存中存储
整数的2进制表⽰⽅法有三种,即原码、反码和补码。
24 0
|
2月前
|
存储 算法
【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题
【三种方法】求一个整数存储在内存中二进制中的1的个数附两道课外练习题
18 0
|
2月前
|
存储 编译器 C语言
C语言基础知识:数据在内存中的存储解析(整数,浮点数)
C语言基础知识:数据在内存中的存储解析(整数,浮点数)