【问题标题】:Recursive merge sort in RubyRuby中的递归合并排序
【发布时间】:2015-07-10 22:41:38
【问题描述】:

我正在尝试编写一个递归执行合并排序的 ruby​​ 方法。我有这个方法工作,但这是我不小心让它工作的时候之一,所以我不知道它为什么工作,并且很想了解我编写的代码是如何工作的。在伪代码中,我遵循的步骤如下所示。

  1. 拆分长度为 n 的原始数组,直到我有 n 个长度为 1 的数组
  2. 一次合并并排序 2 个长度为 m 的数组,返回一个长度为 m*2 的数组
  3. 重复上述步骤,直到我得到一个长度为 n 的已排序数组

基本上这对我来说是一棵大树分支成 n 个分支,每个分支包含一个长度为 1 的数组。然后我需要取这 n 个分支并以某种方式将它们合并回方法中的单个分支.

def merge_sort(arr)
  return arr if arr.length == 1
  merge(merge_sort(arr.slice(0, arr.length/2)), 
        merge_sort(arr.slice(arr.length/2, arr[-1])))
end

def merge(arr1, arr2)
  sorted = []
  begin
    less_than = arr1[0] <=> arr2[0]
    less_than = (arr1[0] == nil ? 1 : -1) if less_than == nil
    case less_than
    when -1  
      sorted << arr1[0]
      arr1 = arr1.drop(1)
    when 0
      sorted << arr1[0]
      sorted << arr2[0]
      arr1 = arr1.drop(1)
      arr2 = arr2.drop(1)
    when 1
      sorted << arr2[0]
      arr2 = arr2.drop(1)
    end
  end until (arr1.length == 0 && arr2.length == 0)
  sorted
end

merge_sort([1,6,3,8,22,3,11,24,54,68,79,80,98,65,46,76,53])

#Returns => [1, 3, 3, 6, 8, 11, 22, 24, 46, 53, 54, 65, 68, 76, 79, 80, 98]

我实际上正确地对列表进行排序的方法,但我不完全确定该方法如何组合每个分支,然后返回排序后的合并列表,而不仅仅是它组合的前两个长度为一个的数组。

另外,如果有人对如何使合并方法更漂亮以看起来更像我已经爱上的 ruby​​ 代码有任何想法,请告诉我。

【问题讨论】:

    标签: ruby sorting recursion mergesort


    【解决方案1】:

    这是我在 Ruby 中的合并排序实现

    def mergesort(array)
      return array if array.length == 1
      middle = array.length / 2
      merge mergesort(array[0...middle]), mergesort(array[middle..-1])
    end
    
    
    def merge(left, right)
      result = []
      until left.length == 0 || right.length == 0 do
        result << (left.first <= right.first ? left.shift : right.shift)
      end
      result + left + right
    end
    

    如您所见,mergesort 方法与您的方法基本相同,这就是递归发生的地方,所以这就是我将重点介绍的内容。

    首先,你有你的基本情况:return array if array.length == 1 这就是允许递归工作而不是无限期地继续下去的原因。

    接下来,在我的实现中,我定义了一个变量middle 来表示数组的中间:middle = array.length / 2

    最后,第三行是所有工作发生的地方:merge mergesort(array[0...middle]), mergesort(array[middle..-1])

    您在这里所做的是告诉合并方法将合并排序的左半部分与合并排序的右半部分合并。

    如果您假设您的输入数组是[9, 1, 5, 4],那么您所说的是merge mergesort([9, 1]), mergesort([5, 4])

    为了执行合并,您首先必须合并排序 [9, 1] 和合并排序 [5, 4]。那么递归就变成了

    merge((merge mergesort([9]), mergesort([1])), (merge mergesort([5]), mergesort([4])))
    

    当我们再次递归时,mergesort([9]) 已达到基本情况并返回 [9]。同样,mergesort([1]) 也达到了基本情况并返回[1]。现在您可以合并[9][1]。合并的结果是[1, 9]

    现在是合并的另一边。我们必须先弄清楚merge mergesort([5]), mergesort([4]) 的结果,然后才能将其与[1, 9] 合并。按照与左侧相同的过程,我们得到[5][4] 的基本情况,并将它们合并得到[4, 5]

    现在我们需要将[1, 9][4, 5] 合并。

    1. 在第一次通过时,result 收到 1,因为 1
    2. 在下一轮中,我们正在与result = [1]left = [9]right = [4, 5] 合作。当我们查看left.first &lt;= right.first 是否为假时,我们返回right.shift4。现在result = [1, 4]
    3. 在第三轮中,我们正在使用result = [1, 4]left = [9]right = [5]。当我们查看left.first &lt;= right.first 是否为假时,我们返回right.shift5。现在result = [1, 4, 5]
    4. 循环到此结束,因为right.length == 0
    5. 我们只是连接result + left + right[1, 4, 5] + [9] + [],从而得到一个排序数组。

    【讨论】:

    • 非常感谢您的回答正是我正在寻找的解释。它真的为我清除了很多关于递归的知识,再次感谢您。
    • 要正确处理空数组,您应该将return array if array.length == 1更改为return array if array.length &lt;= 1
    【解决方案2】:

    这是我的 Ruby 递归 merge_sort 方法的版本。与上述完全相同,但略有不同。

        def merge_sort(array)
            array.length <= 1 ? array : merge_helper(merge_sort(array[0...array.length / 2]), merge_sort(array[array.length / 2..-1]))
        end
    
    
        def merge_helper(left, right, merged = [])
            left.first <= right.first ? merged << left.shift : merged << right.shift until left.length < 1 || right.length < 1 
            merged + left + right
        end
    
    
    p merge_sort([]) # => []
    p merge_sort([20, 8]) # => [8, 20]
    p merge_sort([16, 14, 11]) # => [11, 14, 16]
    p merge_sort([18, 4, 7, 19, 17]) # => [4, 7, 17, 18, 19]
    p merge_sort([10, 12, 15, 13, 16, 7, 19, 2]) # => [2, 7, 10, 12, 13, 15, 16, 19]
    p merge_sort([3, 14, 10, 8, 11, 7, 18, 17, 2, 5, 9, 20, 19]) # => [2, 3, 5, 7, 8, 9, 10, 11, 14, 17, 18, 19, 20]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 2019-01-22
      • 2018-07-26
      • 2014-01-21
      相关资源
      最近更新 更多