在Javascript中实现合并排序

时间:2014-11-21 16:19:37

标签: javascript

所以我正在研究Khan Academy的算法课程,并尝试在Javascript中实现递归合并排序。到目前为止,这是我的代码:

var mergeSort = function(array, p, r) {
    if(r>p) {
        var q = floor(r/2);
        mergeSort(array, p, q);
        mergeSort(array, q+1, r);
        merge(array, p, q, r);
    }
};

merge是Khan Academy提供的一个函数,用于将子数组合并在一起。它给了我错误:' Uncaught RangeError:超出最大调用堆栈大小'。

编辑:更多细节:我很确定错误在我的代码中,代码有目的地被混淆和不可读,因为用户需要在以后的挑战中自己实现它。

这是最初实际调用mergeSort函数并声明数组的代码:

var array = [14, 7, 3, 12, 9, 11, 6, 2];
mergeSort(array, 0, array.length-1);
println("Array after sorting: " + array);
Program.assertEqual(array, [2, 3, 6, 7, 9, 11, 12, 14]);

这里是合并函数的代码,尽管如上所述它是模糊的:

var merge = function(array, p, q, r) {
    var a = [],
        b = [],
        c = p,
        d, e;
    for (d = 0; c <= q; d++, c++) {
        a[d] = array[c];
    }
    for (e = 0; c <= r; e++, c++) {
        b[e] = array[c];
    }
    c = p;
    for (e = d = 0; d < a.length && e < b.length;) {
        if (a[d] < b[e]) {
            array[c] = a[d];
            d++;
        } else {
            array[c] = b[e];
            e++;
        }
        c++;
    }
    for (; d < a.length;) {
        array[c] = a[d];
        d++;
        c++;
    }
    for (; e < b.length;) {
        array[c] = b[e];
        e++;
        c++;
    }
};

他们还要求我在mergeSort函数中的代码格式为:

if (____) {
    var ____ = ____;
    mergeSort(____,____,____);
    mergeSort(____,____,____);
    merge(____,____,____,____);
}

5 个答案:

答案 0 :(得分:9)

Mergesort是一种分而治之的算法,它将索引范围分成两部分,分别对它们进行排序,然后合并结果。

因此,middle变量应该是fromto的算术平均值,而不是to的一半。

我已经重命名变量以使其更容易理解:

var mergeSort = function(array, from, to) {
    if(to > from) {
        var middle = Math.floor( (from+to)/2 ); // Arithmetic mean
        mergeSort(array, from, middle);
        mergeSort(array, middle+1, to);
        merge(array, from, middle, to);
    }
};

答案 1 :(得分:4)

q应该是pr之间的中间点,但您未能考虑起点(即{{1} })执行此操作时可能不是p

0

您需要执行以下操作:

var q = floor(r/2);

虽然@Oriol指出中间点实际上与算术平均值完全相同,因此可以简化计算。

答案 2 :(得分:0)

合并排序实施,稳定且到位

function sort(arr, start, end) {
    if (start >= end-1) return;
    var mid = start + ~~((end-start)/2);
    // after calling this
    // left half and right half are both sorted
    sort(arr, start, mid);
    sort(arr, mid, end);

    /**
     * Now we can do the merging
     */

    // holding merged array
    // size = end-start
    // everything here will be copied back to original array
    var cache = Array(end-start).fill(0);
    var k=mid;
    // this is O(n) to arr[start:end]
    for (var i=start, r=0;i<mid;r++,i++) {
        while (k<end && arr[k] < arr[i]) cache[r++] = arr[k++];
        cache[r] = arr[i];
    }
    // k marks the position of the element in the right half that is bigger than all elements in the left
    // effectively it tells that we should only copy start~start+k element from cache to nums
    // because the rests are the same
    for (var i=0;i<k-start;i++) arr[i+start]=cache[i];
}

答案 3 :(得分:0)

只是为了在JS中实现合并排序

function merge(arr){
  if(arr.length <= 1) return arr;
  let mid = Math.floor(arr.length/2);
  let left = merge( arr.slice(0, mid));
  let right = merge(arr.slice(mid))
      function mergeSort(arr1, arr2) {
        let result = [];
        let i=0;
        let j=0;
        while(i< arr1.length && j < arr2.length) {
          if(arr1[i] < arr2[j]){
            result.push(arr1[i])
            i++;
          } else {
            result.push(arr2[j])
            j++;
          }
        }
       while(i < arr1.length) {
          result.push(arr1[i])
          i++;
       }
       while(j < arr2.length){
          result.push(arr2[j])
          j++;
       }    
        return result
    }
  return mergeSort(left,right)
}

console.log(merge([1,4,3,6,2,11,100,44]))

答案 4 :(得分:0)

一个不错的解决方案:

const merge = (left, right) => {
  const resArr = [];
  let leftIdx = 0;
  let rightIdx = 0;

  while (leftIdx < left.length && rightIdx < right.length) {
    left[leftIdx] < right[rightIdx]
      ? resArr.push(left[leftIdx++])
      : resArr.push(right[rightIdx++]);
  }
  return [...resArr, ...left.slice(leftIdx), ...right.slice(rightIdx)];
};

const mergeSort = arr =>
  arr.length <= 1
    ? arr
    : merge(
        mergeSort(arr.slice(0, Math.floor(arr.length / 2))),
        mergeSort(arr.slice(Math.floor(arr.length / 2)))
      );