【问题标题】:External merge sort algorithm外部归并排序算法
【发布时间】:2015-06-08 13:44:52
【问题描述】:

我在理解外部排序算法中的合并步骤时遇到了一些麻烦。我在 Wikipedia 中看到了这个示例,但无法理解。

外部排序的一个例子是外部合并排序算法,它对每个适合 RAM 的块进行排序,然后将排序后的块合并在一起。例如,仅使用 100 兆字节的 RAM 对 900 兆字节的数据进行排序: 1) 读取主存中的 100 MB 数据并通过一些常规方法进行排序,例如快速排序。 2) 将排序后的数据写入磁盘。 3) 重复第 1 步和第 2 步,直到所有数据都在排序后的 100 MB 块中(有 900MB / 100MB = 9 个块),现在需要将其合并到一个输出文件中。 4) 将每个已排序块的前 10 MB (= 100MB / (9 块 + 1)) 读入主内存中的输入缓冲区,并将剩余的 10 MB 分配给输出缓冲区。 (实际上,使输出缓冲区更大而输入缓冲区稍小可能会提供更好的性能。) 5) 执行 9 路合并并将结果存储在输出缓冲区中。如果输出缓冲区已满,则将其写入最终排序的文件,并将其清空。如果 9 个输入缓冲区中的任何一个变空,则用其关联的 100 MB 排序块中的下一个 10 MB 填充它,直到该块中没有更多数据可用。

我无法理解这里的第四步。为什么当我们有 100 MB 的可用内存时要读取前 10MB 的内存。我们如何确定外部合并的传递次数?我们会对每个块进行排序并将它们存储在9 个文件?

【问题讨论】:

    标签: sorting merge external


    【解决方案1】:

    假设您已将要排序的范围分解为 k 个已排序的元素块。如果您可以对这些已排序的块执行 k 路合并并将结果写回磁盘,那么您已经对输入进行了排序。

    要进行 k 路合并,您存储 k 个读取指针,每个文件一个,并重复查看所有 k 个元素,取最小的,然后将该元素写入输出流并推进相应的读取指针。

    现在,由于您将所有数据都存储在磁盘上的文件中,因此您实际上无法存储指向尚未读取的元素的指针,因为您无法将所有内容都放入主内存中。

    所以让我们从一个简单的方法开始来模拟正常的合并算法会做什么。假设您在内存中存储了一个包含 k 个元素的数组。您将每个文件中的一个元素读入每个数组槽。然后,您重复以下操作:

    • 扫描阵列槽并取最小的。
    • 将该元素写入输出流。
    • 通过从相应文件中读取下一个值来替换该数组元素。

    这种方法可以正常工作,但速度会非常缓慢。请记住,磁盘 I/O 操作所花费的时间比主内存中的相应操作要长得多,很多。这种合并算法最终会进行 Θ(n) 磁盘读取(我假设 k 远小于 n),因为每次选择下一个元素时,我们都需要进行另一次读取。这将非常昂贵,因此我们需要一种更好的方法。

    让我们考虑修改。现在,我们不是存储一个由 k 个元素组成的数组,每个文件一个,而是存储一个由 k 个插槽组成的数组,每个插槽都保存相应文件中的前 R 个元素。为了找到下一个要输出的元素,我们扫描整个数组,对于每个数组,查看我们尚未考虑的第一个元素。我们取最小值,将其写入输出,然后从数组中删除该元素。如果这清空了数组中的一个插槽,我们通过从文件中读取 R 个更多元素来补充它。

    这更复杂,但它显着减少了我们需要执行的磁盘读取次数。具体来说,由于元素是按大小为 R 的块读取的,我们只需要进行 Θ(n / R) 磁盘读取。

    我们可以采取类似的方法来最小化写入。我们不是一次将每个元素写入磁盘(需要 Θ(n) 写入),而是存储一个大小为 W 的缓冲区,在我们进行过程中将元素累积到其中,并且只有在缓冲区填满时才写入缓冲区。这需要 Θ(n / W) 磁盘写入。

    显然,增大 R 和 W 将使这种方法运行得更快,但代价是更多的内存。具体来说,我们需要 kR 个项目的空间来存储大小为 R 的读缓冲区的 k 个副本,我们需要 W 个项目的空间来存储大小为 W 的写缓冲区。因此,我们需要选择 R 和 W 使得 kR + W项目适合主内存。

    在上面给出的示例中,您有 100MB 的主内存和 900MB 的排序空间。如果将数组拆分为 9 块,则需要选择 R 和 W 使得 (kR + W) · sizeof(record) ≤ 100MB。如果每个项目都是一个字节,那么选择 R = 10MB 和 W = 10MB 可以确保一切都适合。这也可能是一个相当不错的分布,因为它使读写次数保持在较低水平。

    【讨论】:

      猜你喜欢
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-21
      • 1970-01-01
      • 2015-07-04
      • 2017-07-05
      相关资源
      最近更新 更多