在Javascript中合并n个排序数组

时间:2014-11-14 17:18:54

标签: javascript arrays algorithm

我有n(n在1到100之间)排序的数字数组,每个数组都有m个元素(在我的情况下,m大约为1000)。我想将它们合并为一个排序的数组。

我可以想到两种可能性:

1.使用两个数组合并算法(如http://www.nczonline.net/blog/2012/10/02/computer-science-and-javascript-merge-sort/下面的merge()函数)并迭代应用它(第1和第2,然后合并第1 - 第2和第3等)

  function merge(left, right) {
      var result  = [],
        il      = 0,
        ir      = 0;
      while (il < left.length && ir < right.length){
        if (left[il] < right[ir]){
            result.push(left[il++]);
        } else {
            result.push(right[ir++]);
        }
    }
    return result.concat(left.slice(il)).concat(right.slice(ir));
}
  1. 同时将merge()函数概括为n个数组。在每次迭代中,我会选择尚未处理的n个第一个值的最小值,并将其附加到结果中。
  2. 这两个算法在复杂性方面是否相同?我觉得两个算法都在o(m * n)。我是对的吗?

    是否有任何表现考虑采取一个算法而不是另一个算法?我觉得1比2简单。

2 个答案:

答案 0 :(得分:3)

使用优先级队列合并n个数组(例如,基于二进制堆) 总元素数是m * n,因此算法复杂度为O(m * n * Log(n))。 算法草图:

Add numbers 1..n to priority queue, using 1st element of every 
array as sorting key 
(you may also use pairs (first element/array number).
At every step - 
  J = pop_minimum
  add current head of Jth array to result
  move head of Jth array to the right
  if Jth array is not exhausted, insert J in queue (with new sorting key)

第一个算法的复杂性是

2*m + 3*m+ 4*m+...+n*m = m * (n*(n-1)/2-1) =  O(n^2 * m)

答案 1 :(得分:1)

这是一个老问题,但是为了后代:

两个算法的确为O(n * m)。在算法1中,您必须为每个m数组重新合并。在算法2中,您只进行了一次大合并,但是从m个数组中选择最小值仍然是线性的。

我要做的是实现合并排序的修改版本以获取O(mlogn)。

如果有人需要,代码可以在GitHub https://github.com/jairemix/merge-sorted上找到。

这是它的工作方式

这个想法是修改算法1并成对而不是线性地合并每个数组。

因此,在第一次迭代中,您将array1与array2合并,array3与array4合并,等等。

然后在第二次迭代中,将array1 + array2与array3 + array4,array5 + array6与array7 + array8等合并。

例如:

// starting with:
[1, 8], [4, 14], [2, 5], [3, 7], [0, 6], [10, 12], [9, 15], [11, 13]

  // after iteration 1:
  [1, 4, 8, 14],  [2, 3, 5, 7],   [0, 6, 10, 12],   [9, 11, 13, 15]

    // after iteration 2
    [1, 2, 3, 4, 5, 7, 8, 14],      [0, 6, 9, 10, 11, 12, 13, 15]

        // after iteration 3
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

在JS中:

function mergeSortedArrays(arrays) {

  // while there are still unmerged arrays
  while (arrays.length > 1) {
    const result = [];

    // merge arrays in pairs
    for (let i = 0; i < arrays.length; i += 2) {
      const a1 = arrays[i];
      const a2 = arrays[i + 1];

      // a2 can be undefined if arrays.length is odd, so let's do a check
      const mergedPair = a2 ? merge2SortedArrays(a1, a2) : a1;
      result.push(mergedPair);
    }

    arrays = result;
  }

  // handle the case where no arrays is input
  return arrays.length === 1 ? arrays[0] : [];

}

请注意合并排序的相似性。实际上,在归并排序中,唯一的区别是n = m,因此您将从m个预排序的数组(每个数组分别包含1个项)开始。因此,合并排序的O(mlogm)复杂性。