8.7.外部排序
1.为什么外部排序只能使用归并策略实现
外部排序:外部排序是指对超出内存容量的大规模数据进行排序的技术,由于数据量太大,无法一次性加载到内存中因此需要借助外部存储进行排序,如硬盘。
外部排序的核心目标是在内存有限的情况下,高效处理大规模数据,而归并排序能成为外部排序的首选策略,是因为它具有以下优势:
-
分阶段处理(适合大规模数据)
将大数据集分成多个小块,每个小块可以加载到内存中排序,然后将排序后的小块逐步合并。 -
低内存需求(适合内存有限的环境)
只需要少量的内存来存储当前正在处理的数据块,而不需要一次性加载所有数据。 -
可扩展性(多路归并可以提高排序效率)
归并排序可以扩展为多路归并,即同时合并多个有序子序列,进一步提高排序效率,多步归并可以显著减少归并次数,从而减少外部存储的读写操作。 -
顺序访问外部存储(减少硬盘随机访问的开销)
减少了随机访问,归并排序主要依赖顺序访问外部存储,而硬盘的顺序读写速度远高于随机读写速度,如果采用其他排序算法可能频繁的进行随机访问,导致性能下降。 -
稳定性(适合需要保持数据顺序的场景:数据库排序)
归并排序是稳定的排序算法。
总结:归并排序的分治策略和顺序合并特性完美匹配外部排序的分块读写需求,使其成为外部排序的标准算法。
拓展:为什么其他排序算法不适合外部排序
快速排序:需要频繁的随机访问数据,而硬盘的随机访问速度较慢,性能较差,递归深度较大时,可能导致栈溢出。
堆排序:需要将整个数据集加载到内存中,无法处理超出内存容量的数据。
插入排序:时间复杂度过高。
2.置换选择排序生成初始归并段
为什么要使用置换选择排序生成初始归并段:主要目的是在内存有限的情况下,生成尽可能长的有序子序列,从而减少归并阶段的次数和外部存储的读写操作,提高排序效率。
优点:相比简单分段排序,置换选择排序可以生成更长的有序子序列,减少归并次数。生成的归并段越长,归并阶段的读写操作越少,排序效率越高。
缺点:需要维护一个最小堆或有限队列,并处理临时缓冲区。需要足够的内存缓冲区来存储堆和临时数据。
3.多路平衡归并排序的优缺点和原理
多路平衡归并排序的优点:
-
减少归并次数
多路平衡归并可以同时合并多个有序序列,从而减少归并次数,提升排序效率。 -
降低了I/O开销
归并次数减少,对外部存储的读写操作也相应减少,提高了整体性能。 -
内存利用率高
多路归并可以更有效的利用内存缓冲区,减少内存浪费。 -
支持动态数据流
适用于流式数据,不需要等待所有数据加载完毕即可开始归并,并在数据持续生成的场景中表现优异
多路平衡归并排序的缺点:
-
实现难度高
多路平衡归并需要结合置换选择排序、多叉哈夫曼树等算法来优化归并段的生成和分配。 -
内存需求高
多路平衡归并需要维护多个内存缓冲区,用于存储归并段的当前元素,若归并路数增加,则内存需求会显著增加。 -
生成归并段和构建哈夫曼树的开销较大
生成归并段时,使用置换选择排序,其本身需要额外的计算和内存开销,在生成归并段时,可能需要频繁地从外部存储读取数据,增加I/O操作。
构建多叉哈夫曼树需要额外的计算资源,尤其是在归并段数量较多的时候哈夫曼树的构建和更新可能会成为性能瓶颈。 -
不适合小规模数据
对于小规模数据,多路平衡归并的优化效果有限,而其实现复杂度和额外开销可能得不偿失,简单归并策略(如二路归并)可能更适合小规模数据。 -
外部存储的随机访问性能要求高
尽管多路平衡归并减少了归并次数,但在归并过程中仍然需要频繁的从外部存储中读取数据。
如果外部存储的随机访问性能较差,可能会影响整体性能。 -
对硬件性能要求较高
多路平衡归并排序的原理:
多路平衡归并排序的原理是通过同时合并多个有序归并段,并优化归并段的长度和合并顺序,以最小化归并次数和外部存储的读写操作。
-
归并段的生成
通过选择置换排序生成,使得归并段长度尽可能长(平均长度大约为内存容量的两倍),减少归并段总数m。 -
多路归并
将K个有序归并段按照最佳归并树顺序合并,并使用败者树优化内部归并的比较次数。
4.多叉哈夫曼树
多叉哈夫曼树即为哈夫曼树的推广,它允许每个节点最多有d个子节点(d >= 2)。
多叉哈夫曼树长用于:数据压缩,网络传输协议,数据库索引结构,上面的最佳归并树就是多叉哈夫曼树在外部排序中的实现。
5.败者树(
败者树是完全二叉树的一种变体,用于高效处理多路归并排序中的最小值选择问题。可以从k个有序序列中快速选出当前的最小值,时间复杂度\(O(\log_{2}^{k})\),优于普通最小堆的\(O(k)\)。
败者树的构建:
-
初始化:从k个归并段各读一个元素到叶子节点,然后兄弟节点互相比较,败者(较大值)的归并段编号存入父节点,胜者继续向上比较,最终根节点记录全局最小值的归并段编号。
-
调整流程(输出最小值之后):
- 从最小值所在的归并段读取洗一个元素,更新对应叶子节点。
- 从被更新的叶子节点开始,逐个往上比较兄弟节点,败者的归并段编号存入父节点,胜者继续向上比较,直到根节点。
败者树的性能:建树时间复杂度为\(O(k)\),每次调整的时间复杂度为\(\log_{2}k\)。

浙公网安备 33010602011771号