Enfoque iterativo de Merge Sort en Javascript

Aug 23 2020

Estoy tratando de implementar la ordenación combinada de forma iterativa pero en javascript. También intenté buscar en Internet, pero solo tienen en C, Python y Java. La matriz que da mi función no está ordenada. Intenté cosas diferentes pero no puedo entender el error. ¿Alguien puede señalar por favor lo que estoy haciendo mal?

function mergeSortIterative(arr){
    let sorted=[...arr];//copying the array so that original remains unchanged.
    let n=sorted.length;
    let currSize;
    let leftStart;
    for(currSize=1;currSize<=n-1;currSize=2*currSize){
        for(leftStart=0;leftStart<n-1;leftStart+=2*currSize){
            let mid=Math.min(leftStart+currSize-1,n-1);
            let rightEnd=Math.min(leftStart+2*currSize-1,n-1);
            // let left=sorted.slice(leftStart,mid);
            // let right=sorted.slice(mid,rightEnd);
            // sorted=mergeIterative(sorted,left,right);
            mergeIterative(sorted,leftStart,mid,rightEnd);
        }
    }
    return sorted;
}

function mergeIterative(sorted,leftStart,mid,rightEnd){
    let left=sorted.slice(leftStart,mid);
    let right=sorted.slice(mid,rightEnd);
    let leftIndex=0,rightIndex=0,k=leftStart;
    while(leftIndex<left.length && rightIndex<right.length){
        //picking the lesser one 
        if(left[leftIndex]<=right[rightIndex]){
            sorted[k]=left[leftIndex];
            leftIndex++;
            k++;
        }
        else{
            sorted[k]=right[rightIndex];
            rightIndex++;
            k++;
        }
    }
    while(leftIndex<left.length && k<sorted.length){
        sorted[k]=left[leftIndex];
        leftIndex++;
        k++;
    }
    while(rightIndex<right.length && k<sorted.length){
        sorted[k]=right[rightIndex];
        rightIndex++;
        k++;
    }
}

Respuestas

2 trincot Aug 23 2020 at 22:35

El error en su código está en una definición inconsistente de qué midy rightEndsignifica.

Del siguiente código, aprendemos que esos índices apuntan a la entrada después del subarreglo anterior:

let left = sorted.slice(leftStart, mid);
let right = sorted.slice(mid, rightEnd);

Pero al mirar las asignaciones:

let mid = Math.min(leftStart + currSize - 1, n - 1); 
let rightEnd = Math.min(leftStart + 2 * currSize - 1, n - 1);

... vemos que apuntan al elemento final de la submatriz anterior.

Puede corregir esto de dos maneras, pero dado que la forma en que sliceinterpreta sus argumentos es la forma "estándar", sugeriría hacer la corrección en las asignaciones, eliminando todas esas - 1, de la siguiente manera:

let mid = Math.min(leftStart + currSize, n); 
let rightEnd = Math.min(leftStart + 2 * currSize, n);
1 Omair Aug 23 2020 at 21:48

Pranav: He citado a continuación un algoritmo iterativo de ordenación por fusión proporcionado por Michael Laszlo a una pregunta similar formulada anteriormente: Implementar la ordenación por fusión de forma iterativa

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(', '));