外部在两个文件之间排序

时间:2015-10-03 17:52:16

标签: arrays algorithm sorting external-sorting

为了满足我的要求,我试图绕过外部排序 - 我无法做到。

要求是对任意大小的文件进行外部排序,但仅使用原始文件和另一个文件(称为fileAfileB) - 两个文件,包括原始文件。我可以读/写其中任何一个 - 所以可以在两者之间交换...

我无法弄清楚如何实现这一点 - 因为大多数排序算法都要求您能够对内存中的整个数组进行概述以对其进行排序,当然?

假设我有一个随机整数数组:

[1, 5, 8, 7, 3, 4, 1, 9, 0, 1, 8, 7, 7, 3, 2, 9, 1, 2];

在任何给定时间,我只能将四页(例如四个整数)读入内存。

在每次传递中,这给了我五个单独的数组来排序:

[1, 5, 8, 7]
[3, 4, 1, 9] 
[0, 1, 8, 7] 
[7, 3, 2, 9]
[1, 2]

如果我对这些应用内存排序,我会得到:

[1, 5, 7, 8]
[1, 3, 4, 9] 
[0, 1, 7, 8] 
[2, 3, 7, 9]
[1, 2]

但是,如果我一次只能将四个页面放入内存中,我就不知道如何在没有一些可怕的复杂算法的情况下进一步对它们进行排序,这种算法会一次又一次地遍历整个数组以确保其全部排序

我彻底迷茫 - 因为没有将整个数组读入内存,我们不知道在四页之前或之后是什么元素 - 所以我们不能真正对它们进行排序?

请有人帮助我并解释解决这个问题的关键步骤吗?

2 个答案:

答案 0 :(得分:1)

因为,External Sort的基本思想是合并大于可用内存的列表,因此您可以通过处理。要从列表中读取元素,您将使用某些方法,如listHandle.getNextElement()。要写入列表中的磁盘,请使用mergedDoubleSizedList.writeNextElement()

你有:

[1, 5, 7, 8] // controlled using handle1
[1, 3, 4, 9] // controlled using handle2
[0, 1, 7, 8] // controlled using handle3
[2, 3, 7, 9] // controlled using handle4
[1, 2] // controlled using handle5

并且您只读取了4个整数,您可以获得前两个数组( handle1 handle2 )的句柄,同时逐个元素读取它们并写入它们返回作为一个排序的整合数组( mergedListHandle1 )。像这样:

[1, 1, 3, 4, 5, 7, 8, 9] // written by creating new handle - mergedListHandle1
[0, 1, 2, 3, 7, 7, 8, 9] // written by creating - mergedListHandle2
[1, 2] // written back by creating mergedListHandle3

现在再次获得上一步产生的两个数组( mergedListHandle1 mergedListHandle2 )的句柄,并继续合并它们直到你离开只有两个句柄,导致一个最终排序的数组。如果您想要基于代码的解决方案,请提供您的代码。

一次,如果你的记忆允许的话,你的内存中只有4个元素。因此,要合并由 handle1 handle2 表示的列表,您将执行以下操作:

  1. 从handle1和handle2(11
  2. 读取第一个元素
  3. 将这两个中较小的一个写入mergedListHandle1(即handle1的写1
    1. 您目前可能无法刷新mergedListHandle1中的数字。
  4. 从handle1(5
  5. 中读取下一个元素
  6. 将handle1和handle2中较小的当前数字写入mergedListHandle1
  7. 当mergedListHandle1已满时,刷新其内容
  8. 从磁盘(handle3和handle4)获取下一个较小的句柄,并在写入名为mergedListHandle2的新的较大列表句柄时,使用它们重复相同的循环。

答案 1 :(得分:1)

简单的2方式自下而上合并排序的说明。 将数据视为大小为1的18次运行。由于大小为1,因此可以将每次运行视为已排序。

[1] [5] [8] [7] [3] [4] [1] [9] [0] [1] [8] [7] [7] [3] [2] [9] [1] [2]

在每次传递中,偶数运行与从源数组或文件从左到右的奇数运行合并到目标数组或文件中。每次传递后,交换源和目标的角色。

第一次通过

[1 5] [7 8] [3 4] [1 9] [0 1] [7 8] [3 7] [2 9] [1 2]

第二次传递

[1 5 7 8] [1 3 4 9] [0 1 7 8] [2 3 7 9] [1 2]

第三次传递

[1 1 3 4 5 7 8 9] [0 1 2 3 7 7 8 9] [1 2]

Forth pass

[0 1 1 1 2 3 3 4 5 7 7 7 8 8 9 9] [1 2]

第五遍(完成)

[0 1 1 1 1 2 2 3 3 4 5 7 7 7 8 8 9 9]

主要变量是运行大小,以及一对运行(偶数和奇数)的开始和结束的4个索引。最后一次运行在数据结束时结束,可以是偶数或奇数运行。对于外部排序,索引成为文件指针。

外部排序只需要2个内存位置来保存数据,一个元素来自偶数运行,一个元素来自奇数运行。比较两个元素,写入目标文件的低或相等,并读取该运行的下一个元素。如果到达该运行的结尾,则写入另一个元素,并将另一个运行的其余部分复制到目标文件。两个文件指针前进到下一对偶数和奇数运行的开始,并继续合并,直到达到数据结束,结束合并传递。运行大小加倍,源文件和目标文件的角色交换,下一次合并传递完成,重复直到运行大小变为> =元素数。