合并两个排序的数组,没有内置的ruby函数

时间:2017-02-01 06:40:00

标签: arrays ruby algorithm sorting

我尝试合并两个已排序的数组,而不使用排序方法中的任何构建。这是我到目前为止所拥有的。

def merge(array_1, array_2)
    i = 0
    k = 0
    merged_array = []
    while i < array_1.count && k < array_2.count
        while k < array_2.count && array_1[i] > array_2[k]
            merged_array << array_2[k]
            k += 1
        end
        merged_array << array_1[i]
        i += 1
    end
    merged_array
end

array_1 = [5,8,9,11]
array_2 = [4,6,7,12,13]

p merge(array_1, array_2)

输入为array_1 = [5,8,9,11]array_2 = [4,6,7,12,13],输出为[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]。有人可以解释为什么它不起作用。谢谢!

2 个答案:

答案 0 :(得分:10)

试试这个

def merge(array_1, array_2)
  return enum_for(__method__, array_1, array_2) unless block_given?

  a = array_1.each
  b = array_2.each
  loop { yield a.peek < b.peek ? a.next : b.next }

  # Your code is not working because the equivalent of these two lines
  # is missing. After you reach the end of one array you have to append
  # all remaining elements of the other array. I am doing this here by
  # just exhausting both enumerators, one of which is empty by now.

  loop { yield a.next }
  loop { yield b.next }
end

p merge([5, 8, 9, 11], [4, 6, 7, 12, 13]).entries

无需跟踪指数。合并排序可以追溯到大型机和磁带的时代,因此只能使用枚举器来实现。

这是如何运作的?

  • each创建枚举器
  • peek返回下一个元素而不推进枚举器
  • next通过推进枚举器
  • 返回下一个元素
  • 以上两者在到达枚举器结尾时都会StopIteration
  • loop重复一段代码,直到StopIteration被提升

答案 1 :(得分:1)

可以使用Array#bsearch_index将一个数组的元素插入到另一个数组的副本中,以确定第一个数组的每个元素应该去的位置。

def merge(array_1, array_2)
  array_2.each_with_object(array_1.dup) { |n,arr|
     arr.insert(arr.bsearch_index { |i| i>n } || arr.size, n) }
end

array_1
  #=> [5, 8, 9, 11] 
array_2
  #=> [4, 6, 7, 12, 13, 14] 

merge(array_1, array_2)
  #=> [4, 5, 6, 7, 8, 9, 11, 12, 13, 14] 

这是O(n 1 * log(n 2 )),n 1 和n 2 作为两个数组的大小,所以循环越过两个数组中的较小者就会更有效。