使用递归合并排序算法

时间:2015-01-09 19:12:10

标签: ruby recursion mergesort

我在做Odin项目。实践问题是:使用递归创建合并排序算法。以下内容是根据某人的解决方案修改的:

def merge_sort(arry)
  # kick out the odds or kick out of the recursive splitting?
  # I wasn't able to get the recombination to work within the same method.
  return arry if arry.length == 1
  arry1 = merge_sort(arry[0...arry.length/2])
  arry2 = merge_sort(arry[arry.length/2..-1])
  f_arry = []
  index1 = 0 # placekeeper for iterating through arry1
  index2 = 0 # placekeeper for iterating through arry2
  # stops when f_arry is as long as combined subarrays
  while f_arry.length < (arry1.length + arry2.length)
    if index1 == arry1.length
      # pushes remainder of arry2 to f_arry
      # not sure why it needs to be flatten(ed)!
      (f_arry << arry2[index2..-1]).flatten!
    elsif index2 == arry2.length
      (f_arry << arry1[index1..-1]).flatten!
    elsif arry1[index1] <= arry2[index2]
      f_arry << arry1[index1]
      index1 += 1
    else
      f_arry << arry2 [index2]
      index2 += 1
    end
  end
  return f_arry
end
  1. 第一行return arry if arry.length == 1是否将其从数组的递归拆分中踢出,然后绕过方法的递归拆分部分返回重组部分?看起来它应该只是在它回到那个部分时继续重新分析它。

  2. 为什么必须flatten - ed?

1 个答案:

答案 0 :(得分:0)

理解第一行的最简单方法是理解merge_sort绑定的唯一契约是“返回已排序的数组” - 如果数组只有一个元素(arry.length == 1)它已经排序 - 所以不需要做任何事情!只需返回数组本身。

在递归中,这被称为“停止条件”。如果你没有提供停止条件 - 递归将永远不会结束(因为它总是会调用自己 - 并且永远不会返回)!

结果需要flatten的结果,是因为您将数组作为结果数组中的元素推送:

arr = [1]
arr << [2, 3]
# => [1, [2, 3]]

如果您尝试仅在迭代结束时展平结果数组,而不是在添加元素时,则会出现问题,因为 length 将会出现偏差:< / p>

arr = [1, [2, 3]]
arr.length
# => 2

虽然arr包含三个数字但它只有两个元素 - 这会破坏您的解决方案。

您希望阵列中的所有元素都是数字,而不是数组。 flatten!确保数组中的所有元素都是原子,如果不是,则将子数组的元素添加到自身而不是子数组:

arr.flatten!
# => [1, 2, 3]

您可能想要考虑的另一个选项(并且效率更高)是使用concat代替:

arr = [1]
arr.concat([2, 3])
# => [1, 2, 3]

此方法将作为参数传递的数组中的所有元素添加到调用它的数组中。