外部排序 之 概念篇

外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。

简而言之:一般来说外排序分为两个步骤:预处理和合并排序。即首先根据内存的大小,将有n个记录的磁盘文件分批读入内存,采用有效的内存排序方法进行排序,将其预处理为若干个有序的子文件,这些有序子文件就是初始顺串,然后采用合并的方法将这些初始顺串逐趟合并成一个有序文件,当然这一步是:一边把合并好的串存储到外存上,把尚未存储的串从外存读入内存。

我们一般提到排序都是指内排序,比如快速排序,堆排序,归并排序等,所谓内排序就是可以在内存中完成的排序。RAM的访问速度大约是磁盘的25万倍,我们当然希望如果可以的话都是内排来完成。但对于大数据集来说,内存是远远不够的,这时候就涉及到外排序的知识了。
外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装入内存的部分,分别把每一部分调入内存完成排序。然后,对已经排序的子文件进行归并排序。
一般来说外排序分为两个步骤:预处理和合并排序。即首先根据内存的大小,将有n个记录的磁盘文件分批读入内存,采用有效的内存排序方法进行排序,将其预处理为若干个有序的子文件,这些有序子文件就是初始顺串,然后采用合并的方法将这些初始顺串逐趟合并成一个有序文件。
预处理阶段最重要的事情就是选择初始顺串。通常使用的方法为置换选择排序,它是堆排序的一种变形,实现思路同STL的partial_sort。步骤如下:
1.初始化堆
(1)从磁盘读入M个记录放到数组RAM中
(2)设置堆末尾标准LAST=M-1
(3)建立最小值堆
2.重复以下步骤直到堆为空
(1)把具有最小关键码值的记录Min也就是根节点送到输出缓冲区
(2)设R是输入缓冲区中的下一条记录,如果R的关键码大于刚刚输出的关键码值Min,则把R放到根节点,否则使用数组中LAST位置的记录代替根节点,并将刚才的R放入到LAST所在位置,LAST=LAST-1;
(3)重新排列堆,筛出根节点
如果堆的大小是M,一个顺串的最小长度就是M个记录,因为至少原来在堆中的那些记录将成为顺串的一部分,如果输入时逆序的,那么顺串的长度只能是M,最好情况输入是正序的,有可能一次性就能把整个文件生成一个顺串,由此可见生成顺串的长度是大小不一的,但是每个顺串却是有序的,利用扫雪机模型能够得到平均顺串的长度为2M。
得到顺串之后呢,就开始进行归并了。二路归并的缺点是扫描次数太多,因为如果顺串的个数为m个,那么二路归并的扫描次数就是log(2,m),采用多路归并可以减少扫描次数,一般情况下使用选择树来进行多路归并。选择树有赢者树和败者树2种,赢者树比较直观,但是每次调整需要改动比较大,所以一般情况下都用败者树,所谓败者树就是非叶子节点的值都是两个子结点中的败者对应的值。这句话其实说的比较含糊,真正生成败者树的过程是每次都将败者放在父节点上,同时胜者继续比较,胜者中的败者再放在父节点上,再记录下此时的胜者继续比较。……比赛的过程:将新进入树的节点与其父节点进行比赛,将败者存放在父节点,而胜者再与上一级的父节点继续比赛。……因此从这个过程也可以看出,其实败者树只会改变一个分支,不会影响到其他,因而重构的代价比较小。
需要归并的趟数就是log(b,m),b为几路归并,m为顺串的个数。产生一个大小为n的顺串时间为O(k+nlogk)。使用最佳归并可以减少输入/输出量。

你可能感兴趣的:(C++,外排)