简体   繁体   中英

Is this iterative implementation of merge sort correct?

It seems deceptively simple to me. Note this doesn't produce single element arrays by splitting in half, but through instead using a single loop.

function mergeSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    arr[i] = [arr[i]]
  }
  while (arr.length > 1) {
    for (let i = 0; i < arr.length; i = i + 2) {
      arr.splice(i, 2, mergeTwoSortedArrays(arr[i], arr[i + 1] || []))
    }
  }
  return arr[0]
}

My tests are passing, but perhaps the time/space complexity isn't as good?

arr.splice(i, 2, ...) will need to shift the content that follows i , so this is not a constant time operation, and so you exceed the time complexity of O(nlogn) that you would expect to get with Merge Sort.

To resolve this, I would suggest to not splice anything out of the array at all, but just skip the array entries that are no longer relevant.

 function mergeSort(arr) { for (let i = 0; i < arr.length; i++) { arr[i] = [arr[i]]; } for (let step = 1; step < arr.length; step *= 2) { for (let i = 0; i + step < arr.length; i += step*2) { arr[i] = mergeTwoSortedArrays(arr[i], arr[i+step]); delete arr[i+step]; // optional; to have it garbage collected } } return arr[0]; } function mergeTwoSortedArrays(a, b) { let merged = []; let i = 0, j = 0; while (i < a.length || j < b.length) { merged.push( i < a.length && (j >= b.length || a[i] < b[j]) ? a[i++] : b[j++] ); } return merged; } let arr = Array.from({length: 1000}, () => Math.floor(Math.random() * 1000000)); let sorted = mergeSort([...arr]); let sorted2 = arr.sort((a,b) => ab); // verify console.log(sorted+"" === sorted2+""); // output verification result

This is O(n^2) but with good constants.

The problem is that arr.splice is a O(n) operation and there is no way to optimize it. You are taking 2 values out of the middle of the array and then having to move everything else over. That move operation is highly optimized, but is still O(n) .

Instead use shift / push to get rid of that problem. This will cause elements to "rotate" through the array. (Actually the array will travel in memory until it gets moved, then travel in memory again. But this should all be nicely optimized.)

function mergeSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    arr[i] = [arr[i]]
  }
  while (arr.length > 1) {
    let elt1 = arr.shift()
    let elt2 = arr.shift()
    arr.push(mergeTwoSortedArrays(elt1, elt2))
  }
  return arr[0]
}

(Side note, I kept your style. But oh boy did I want to sprinkle ; around in a few places!)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM