Mergesort可以节省内存

时间:2010-11-05 05:24:24

标签: algorithm sorting lua

我正在参加算法课程,最新的作业真的让我很难受。本质上,赋值是实现一个合并排序版本,它不会像CLRS中的实现那样分配尽可能多的临时内存。我应该通过在开头只创建一个临时数组来做到这一点,并在拆分和合并时将所有临时内容放入其中。

我还应该注意,该类的语言是Lua,这很重要,因为唯一可用的数据结构是表。它们就像Java映射一样,它们来自键值对,但它们就像数组一样,你不需要成对插入东西 - 如果你只插入一个被视为值的东西,它的关键将是它的索引将使用真实数组的语言。至少我是这样理解的,因为我也是Lua的新手。此外,任何东西,原语,字符串,对象等都可以成为关键 - 甚至是同一个表中的不同类型。

无论如何,有两件令我困惑的事情:

首先,它是如何完成的?您是否只是在每次拆分和合并递归时都会覆盖临时数组?

其次,我对作业说明感到困惑(我正在免费审核课程,所以我不能问任何工作人员)。以下是说明:

  1. 编写一个顶级过程merge_sort,以ar-为参数 射线来排序。它应声明一个临时数组,然后调用merge_sort_1, 一个四个参数的过程:要排序的数组,用作tem-的数组 诗歌空间,以及此调用的开始和结束索引 merge_sort_1应该有效。

  2. 现在编写merge_sort_1,它计算开始结束的中点 interval,并为每一半做一次递归调用。之后呢 调用merge来合并两半。 您现在编写的合并程序将是永久性的功能 数组和临时数组,开始,中点和结束。 它维护临时数组的索引,并将索引i,j保存到每个数组中 (已排序)永久阵列的一半。 它需要从头到尾遍历临时阵列,复制 来自永久阵列的下半部分或来自的永久数组的值 永久阵列的上半部分。它选择较低的i处的值 如果小于或等于上半部分j的值,则为一半 进步我如果小于,则选择上半部分j的值 下半部分的i值,并提前j。 永久阵列的一部分用完后,请务必复制其余部分 另一部分教科书使用具有无限值∞的技巧 避免检查任一部分是否用完。但是,这个伎俩很难 在这里申请,你会把它放在哪里? 最后,复制临时数组中从开始到结束的所有值 回到永久阵列。

  3. 数字2令人困惑,因为我不知道merge_sort_1应该做什么,以及为什么它必须是与merge_sort不同的方法。我也不知道为什么需要传递开始和结束索引。事实上,也许我误读了一些东西,但说明听起来像merge_sort_1并没有做任何实际的工作。

    此外,整个作业令人困惑,因为我没有从指令中看到进行拆分的原因是制作原始数组的两半。或者我误解了mergesort?

    我希望我有一些道理。谢谢大家!

3 个答案:

答案 0 :(得分:1)

首先,我会确保你理解mergesort 查看this解释,使用精美的动画来帮助您理解它。

这是它们的伪代码版本:

# split in half
m = n / 2

# recursive sorts
sort a[1..m]
sort a[m+1..n]

# merge sorted sub-arrays using temp array
b = copy of a[1..m]
i = 1, j = m+1, k = 1
while i <= m and j <= n,
    a[k++] = (a[j] < b[i]) ? a[j++] : b[i++]
    → invariant: a[1..k] in final position
while i <= m,
    a[k++] = b[i++]
    → invariant: a[1..k] in final position

了解他们如何使用b来保存数据的临时副本? 老师想要的是你传递一张桌子用于这个临时存储。

这会清除作业吗?

答案 1 :(得分:1)

你的主要排序例程如下:(抱歉,我不认识Lua,所以我会写一些Javaish代码)

void merge_sort(int[] array) {
  int[] t = ...allocate a temporary array...
  merge_sort_1(array, 0, array.length, t);
}

merge_sort_1接受一个数组排序,一些开始和结束索引,以及一个用于某些临时空间的数组。它执行实际的分而治之的调用并调用merge例程。请注意,递归调用需要转到merge_sort_1而不是merge_sort,因为您不希望在每个递归级别上分配数组,只需在合并排序过程开始时分配一次。 (这是将合并排序分为两个例程的重点。)

我会留给你写一个merge程序。它应该采用包含2个已排序子部件和临时数组的原始数组,并对原始数组进行排序。最简单的方法是合并到临时数组中,然后在完成后将其复制回来。

答案 2 :(得分:0)

  

首先,它是如何完成的?你呢   只是继续覆盖临时数组   每次递归分裂和   合并?

是的,临时数组不断被覆盖。在合并阶段使用临时数组来保存合并结果,然后在合并结束时将其复制回永久数组。

  

2号令人困惑,因为我有   不知道merge_sort_1应该是什么   要做,为什么它必须是一个   merge_sort的不同方法。

merge_sort_1是递归合并排序的递归中心。 merge_sort只是一个便利函数,创建临时数组并填充初始开始和结束位置。

  

我也不知道为什么需要这样做   传递了开始和结束索引。在   事实上,也许我误读了一些东西,但是   说明听起来像   merge_sort_1没有做任何实际的工作。

     

此外,整个作业是   令人困惑,因为我没有看到   分裂的指示   完成原来的两半   阵列。或者我误解了   归并排序

递归函数merge_sort_1仅适用于传入数组的一部分。它所处理的部分由起始和结束索引定义。开始和结束之间的中点是如何拆分数组,然后在递归调用时再次拆分。在完成对上半部分和下半部分的递归调用之后,将两半合并到临时数组中,然后将其复制回永久数组。

我能够按照描述在Lua中编写合并排序,并可以评论我的实现。它看起来似乎是通过说明写成,好像它们是关于教师实施的评论。

这是merge_sort函数。正如我所说,它只是一种便利功能,我觉得这不是问题的关键。

-- Write a top level procedure merge_sort that takes as its argument
-- the array to sort.
function merge_sort(a)
    -- It should declare a temporary array and then call merge_sort_1,
    -- a procedure of four arguments: The array to sort, the one to use
    -- as temporary space, and the start and finish indexes within which
    -- this call to merge_sort_1 should work.
    merge_sort_1(a,{},1,#a)
end