Trabajando en MergeSort en Java:
public void mergeSort(int[] A)
{
if (A.length > 1)
{
int q = A.length/2;
int[] leftArray = Arrays.copyOfRange(A, 0, q);
int[] rightArray = Arrays.copyOfRange(A,q,A.length);
mergeSort(leftArray);
mergeSort(rightArray);
merge(A,leftArray,rightArray);
}
}
La recursión en el código anterior funciona bien en Java.
Entonces, por curiosidad, quiero convertir la función Arrays.copyOfRange de Java a C#. Array.copy en C# toma cinco argumentos. ¿Conoce alguna función más simple en C# que obtenga ciertos elementos de la matriz que comienzan en la posición x a y (como java).
En C# codifiqué el método anterior así:
public void mergeSort(int[] A)
{
if (A.Length > 1)
{
int q = A.Length / 2;
int[] leftArray = new int[q];
int[] rightArray = new int[A.Length];
for (int i = 0; i < q; i++)
{
leftArray[i] = A[i];
Console.WriteLine(leftArray[i]);
}
for (int i = q; i < A.Length; i++)
{
rightArray[i] = A[i];
Console.WriteLine(rightArray[i]);
}
Console.ReadKey();
mergeSort(leftArray);
mergeSort(rightArray);
merge(A, leftArray, rightArray);
}
}
Como puede ver, he reemplazado las funciones Arrays.copyOfRange en Java con dos bucles en C# y esto funciona en C# sin recursividad. Sin embargo, llamando a mergeSort(leftArray) y mergeSort(rightArray) imprime esto en C#:
¡El proceso finalizó debido a StackOverflowException!
¿Alguna idea mejor sobre cómo obtener ciertos elementos en C#?
Solución del problema
El problema es que la copia de matriz portada no está haciendo lo mismo.
Dada una entrada del [a,b,c,d,e,f]
código Java está creando dos matrices, [a,b,c]
y [d,e,f]
mientras que el puerto C# está creando dos matrices, [a,b,c]
y [0,0,0,d,e,f]
. Notablemente,
- La nueva matriz de la derecha es del tamaño de A (
new int[A.Length]
). Esto es lo que causa la excepción StackOverflowException ya que nunca se alcanza el caso de terminación, y; - A la nueva matriz de la derecha solo se le asignan valores que comienzan en el
q
índice, que es el índice intermedio.
Considere este método de reemplazo usando Array.Copy
: un método con la misma firma se puede usar como un reemplazo directo en el código portado, siempre que lo que hay dentro del método tenga el mismo efecto que el original.
int[] copyOfRange (int[] src, int start, int end) {
int len = end - start;
int[] dest = new int[len];
Array.Copy(src, start, dest, 0, len);
return dest;
}
O bien, una versión que lo hace con un bucle pero sin el problema en el puerto original. Otra razón para usar funciones discretas: hace que la tarea sea fácil de ver y razonar. Ser capaz de eliminar también el código duplicado no duele.
int[] copyOfRange (int[] src, int start, int end) {
int len = end - start;
int[] dest = new int[len];
// note i is always from 0
for (int i = 0; i < len; i++)
{
dest[i] = src[start + i]; // so 0..n = 0+x..n+x
}
return dest;
}
Si eres perezoso como yo, el código también podría escribirse trivialmente usando LINQ.
int[] leftArray = A.Take(q).ToArray();
int[] rightArray = A.Skip(q).ToArray();
No hay comentarios:
Publicar un comentario