处理大文件排序的方式--外部排序

引言

  一般来说,对一个数组的排序,我们常用冒泡排序、快速排序、堆排序等算法进行排序。这样的数组能够一次性加载到内存中,使用上述的排序算法就能轻而易举进行排序,所以上述的排序算法可以称之为堆内排序
  然而有些场景下,一个待排序的文件可能超过甚至远远大于应用程序的运行内存。这种情况,一次性将文件加载到内存中,明显是不可行的,需要使用其他的排序手段进行排序。外部排序就是一种可行的方案。

基本思想

  • 1、将原文件拆分成一个个能一次性加载到内存的小文件
  • 2、依次将小文件排序
  • 3、将排好序的小文件归并成一个有序的大文件

归并的方法

二路归并

在这里插入图片描述
  各片段均已采用内排序算法进行排序,每次读入2路有序片段的前m个元素进行归并;若输出缓冲区已满,则将已归并好的元素写入文件;若其中一路m个元素归并完成,读入该路剩下的前m个元素。重复交替执行,直到所有元素都归并完成为止
  缺点:元素需要反复比较,比较次数过多,导致归并的效率很低。

k路归并

  基于二路归并多次比较的缺点,有人提出了改进算法,采用多路归并来提高效率。
  k路归并可以使用堆进行排序,利用完全二叉树的性质,可以很快更新,保持堆的性质。但是,操作次数不够精简。

胜者树

在这里插入图片描述
  归并过程:

  • 1、在拆分成k个文件并排序后,取每个文件的首个元素作为叶子节点,构建一颗胜者树
  • 2、输出一个最值到缓冲区;如果缓冲区已满,则将数据写入文件
  • 3、从输出的值对应的来源文件取元素,加入到胜者树中,同时调整树
  • 4、重复第2、3步骤,直到所有数据都读取并归并,最终得到排序的文件

  胜者树父节点记录的的值为兄弟节点比较胜利的元素。所以在新值添加到树中,需要与父节点和子节点比较。

败者树

在这里插入图片描述
  归并过程:

  • 1、在拆分成k个文件并排序后,取每个文件的首个元素作为叶子节点,构建一颗败者树
  • 2、输出一个最值到缓冲区;如果缓冲区已满,则将数据写入文件
  • 3、从输出的值对应的来源文件取元素,加入到胜者树中,同时调整树
  • 4、重复第2、3步骤,直到所有数据都读取并归并,最终得到排序的文件

  败者树将败者存放在父结点中,而胜者再与上一级的父结点比较。败者树的更新只需将子节点与父节点比较。

总结

1、大文件过大,不能一次加载,所以需要拆分成k个小文件
2、k个小文件各自排序,为下一步文件归并打好铺垫
3、二路归并元素比较次数过多,效率低
4、k路归并中,堆排序可以很快更新,但操作数不够精简;胜者树父节点记录胜利的一方,更新时需要比较父节点和兄弟节点;败者树是胜者树的一种变体,父节点记录失败的一方,同时胜利一方与上一级的父节点比较,更新只需要比较父节点。因此在实际应用中采用败者树更好。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
外部排序是一种用于处理大型文件排序算法,由于文件太大无法全部读入内存,因此需要将文件分割成多个部分,分别进行排序后再合并。下面是一种基于归并排序外部排序实现: 1. 首先将大文件分割成多个小文件,每个小文件的大小可以根据内存的大小来决定,一般选择小于内存容量的值。 2. 对每个小文件进行排序,可以使用内置的sort函数或其他快速排序算法。 3. 将排序后的小文件依次读入内存,进行归并排序,生成一个有序的大文件。 4. 重复步骤1-3,直到所有小文件都已经排序并合并成一个大文件。 下面是一个简单的Python实现: ```python import heapq import os def external_sort(input_file, output_file, chunk_size=1000000): """外部排序""" chunks = [] with open(input_file, 'rb') as f: while True: chunk = f.read(chunk_size) if not chunk: break chunk = list(map(int, chunk.split())) chunk.sort() chunks.append(chunk) with open(output_file, 'wb') as f: for item in heapq.merge(*chunks): f.write('{} '.format(item).encode()) # 删除临时文件 for chunk_file in chunks: os.remove(chunk_file) if __name__ == '__main__': external_sort('big_file.txt', 'sorted_file.txt') ``` 这个实现中,我们将大文件分割成大小为`chunk_size`的小文件,每个小文件进行排序后,再将它们依次读入内存,使用heapq.merge函数进行归并排序,最后生成一个有序的大文件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值