python3利用归并算法对超过内存限制的超大文件进行排序

上一篇文章《python3实现归并排序算法图文详解》中,我们了解了归并排序算法的基本使用逻辑。这一篇文章我们对这个逻辑进行一个延伸,从内存延伸到对硬盘上的文件进行排序,也就是所谓的外部排序。

操作场景

所谓的大文件就是无法一次性全部读到内存中的文件。

为了操作不真的把我机器的内存都榨干,这里假设机器的内存是300MB,刨除一些系统占用,规定每次读到内存的文件大小不能超过200MB

我又用下面的程序创建了一个1GB大小的文件

with open('bigfile.txt','a') as f:
    for i in range(100000000):
        f.write(str(random.randint(100000000,999999999))+'\r\n')

这个文件一共有1亿行,每一行以字符串格式存储着一位9位数,并在末尾加上了换行符,所以每行占据10B,算下来一共有10亿B也就是1GB。

下面要实现的就是在内存占用每次不超过200MB的情况下将这个1GB的文件进行排序。硬盘空间很大,随意使用。

思路分析

大家应该还记得《python3实现归并排序算法图文详解》中的两张图

1-cursor.png

针对一个长列表,我们先分割为两个小列表,并将小列表排好序。利用两个游标从左到右移动,我们对两个已经各自排好序的列表合并成了一个新的有序列表。

2-finish.png

这里的小技巧就是利用了递归的思路,对每一个小的列表都进行了归并排序。

但是我们这个问题不需要这么麻烦。首先将1GB的大文件分解为5个200MB的小文件,这里的小文件就是可以直接读进内存一次性排序。

然后直接对这5个小文件读进内存进行排序

最后再利用归并的思路,通过5个游标分别在5个文件中逐行从左往右移动,将每次最小的一行读到新文件中,达到排序的效果,如下图

3-files.png

代码实现

文件分割

首先来对文件进行分割,每次从原文件读200MB的整行数,然后保存到一个新文件。

这里要补充下python中读取文件的几个方法。f.readlines(n)可以接一个参数n,注意这里的n并不是行数,而是以字节为单位的大小,表示当读到某行时总大小超过了n就不再读下一行。同理,f.readline(n)也可以传递n,表示读取下一行的前n个字节,如果下一行总大小少过n就读取整行。而在某些没有换行符的文件中就不能用这两种读取的方法了,因为无论如何都是直接读取所有内容,只能采用f.read(n)的方式,这里的n也同样是字节数

def splitFile(path
Python中的归并排序是一种分治策略的经典例子,它将一个大的数组分成两个较小的子数组,分别对这两个子数组进行排序,然后合并它们。以下是基本步骤: 1. **分割**:函数首先检查输入数组是否只包含一个元素,如果是,那么它已经有序了,可以直接返回。如果数组长度大于1,就将其一分为二。 2. **递归**:对每个子数组继续进行归并排序,直到达到基本情况。 3. **合并**:当子数组排序完成后,将它们合并成一个有序的大数组。这是通过创建一个新的空数组,然后依次比较子数组的元素,并将较小的元素添加到新数组中,直到一个子数组完全添加完毕,再将另一个子数组剩余的部分复制过去。 4. **回溯**:最后,返回合并后的有序数组作为整个过程的结果。 下面是一个简单的Python归并排序函数实现示例: ```python def merge_sort(arr): if len(arr) <= 1: return arr # 分割数组 mid = len(arr) // 2 left_half = arr[:mid] right_half = arr[mid:] # 递归排序左右半部分 left_half = merge_sort(left_half) right_half = merge_sort(right_half) # 合并两个已排序的半部分 return merge(left_half, right_half) def merge(left, right): merged, i, j = [], 0, 0 while i < len(left) and j < len(right): if left[i] < right[j]: merged.append(left[i]) i += 1 else: merged.append(right[j]) j += 1 # 如果有剩余元素,添加到结果数组 merged.extend(left[i:]) merged.extend(right[j:]) return merged # 示例 arr = [9, 7, 5, 11, 12, 2, 14, 3] sorted_arr = merge_sort(arr) print(sorted_arr)
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值