【问题标题】:Implementing merge sort iteratively迭代地实现归并排序
【发布时间】:2015-08-16 23:55:12
【问题描述】:

我正在尝试实现归并排序,以便更好地了解它的工作原理。在下面的代码中,我试图对一个数字数组进行排序。我目前拥有的代码有问题并且在无限循环中运行。我现在正在尝试以非递归方式解决这个问题:

function mergeSort(arr) {

  var mid = Math.floor(arr.length/2);
  var left = arr.slice(0, mid);
  var right = arr.slice(mid, arr.length);

  if (arr.length === 1) {return arr};

  var sorted = [];

  var i = 0;

  while (left.length || right.length) {
   if (left.length && right.length) {
     if (left[0] < right[0]) {
       sorted.push(left.shift())
     } else {
       sorted.push(right.shift())
     }
   } else if (left) {
     sorted.push(left.shift())
   } else {
     sorted.push(right.shift())
   }
   i++;
  }

  return sorted;
}

所以如果我有一个数组 var nums = [1, 4, 10, 2, 9, 3]; 调用 mergeSort(nums) 应该返回 [1, 2, 3, 4, 9, 10]

【问题讨论】:

  • 你在哪里定义merge
  • 你的问题到底是什么?
  • 如果您没有提供任何意见或预期结果,我们应该如何提供帮助?
  • 抱歉。我现在提供了输入和预期结果。此外,我希望此函数仅适用于数字数组。

标签: javascript algorithm sorting


【解决方案1】:

您已经编写了将数组一分为二并合并两半的代码。这不会导致排序数组,因为两半未排序。 Mergesort 的工作原理是对两半进行排序,然后合并它们。

有很多方法可以迭代地实现归并排序。让我提供一个。从合并大小为 1 的子数组开始。您知道大小为 1 的数组已经排序,因此合并两个大小为 1 的连续子数组是安全的。如果对原始数组中所有大小为 1 的连续子数组对执行此操作,你最终得到一个由大小为 2 的连续排序子数组组成的数组。

你知道这是怎么回事吗?现在您可以合并每两个大小为 2 的连续子数组。您最终得到一个大小为 4 的连续排序子数组的数组。继续重复此过程,直到整个数组被排序。

下面的 sn-p 实现了这种方法。

function mergeSort(arr) {
  var sorted = arr.slice(),
      n = sorted.length,
      buffer = new Array(n);

  for (var size = 1; size < n; size *= 2) {
    for (var leftStart = 0; leftStart < n; leftStart += 2*size) {
      var left = leftStart,
          right = Math.min(left + size, n),
          leftLimit = right,
          rightLimit = Math.min(right + size, n),
          i = left;
      while (left < leftLimit && right < rightLimit) {
        if (sorted[left] <= sorted[right]) {
          buffer[i++] = sorted[left++];
        } else {
          buffer[i++] = sorted[right++];
        }
      }
      while (left < leftLimit) {
        buffer[i++] = sorted[left++];
      }
      while (right < rightLimit) {
        buffer[i++] = sorted[right++];
      }
    }
    var temp = sorted,
        sorted = buffer,
        buffer = temp;
  }

  return sorted;
}

function print(s) {
  document.write(s + '<br />');
}

var data = [1, 4, 10, 2, 9, 3];
print('input: ' + data.join(', '));
print('output: ' + mergeSort(data).join(', '));

【讨论】:

  • 这些嵌套循环不会导致疯狂的时间复杂度吗?
  • 请注意,外部循环的索引在每次迭代时翻倍,因此循环运行 O(log n) 次。内循环是线性扫描。因此,整体时间复杂度为 O(n log n)。
  • 在内循环结束时,为什么交换用缓冲区排序,缓冲区不会被覆盖。排序 = 缓冲区; buffer = [] 似乎工作正常。我不明白为什么我们不重用它们时需要保存以前排序的值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多