2009-02-16 13 views
10

He leído esto post about card shuffling y en muchos algoritmos de mezcla y ordenación debe intercambiar dos elementos en una lista o matriz. Pero, ¿cómo se ve un buen y eficiente método de intercambio?C#: Buena/mejor implementación del método Swap

Digamos por un T[] y por un List<T>. ¿Cómo implementaría mejor un método que intercambia dos elementos en esos dos?

Swap(ref cards[i], ref cards[n]); // How is Swap implemented? 

Respuesta

22

Bueno, el código que ha publicado (ref cards[n]) sólo puede trabajar con una matriz (no una lista) - pero usted podría utilizar simplemente (donde foo y bar son los dos valores):

static void Swap(ref int foo, ref int bar) { 
    int tmp = foo; 
    foo = bar; 
    bar = tmp; 
} 

O posiblemente (si quieres atómica):

Interlocked.Exchange(ref foo, ref bar); 

Personalmente, no creo que me moleste con un método de intercambio, simplemente hazlo directamente; esto significa que se puede utilizar (ya sea de una lista o de una matriz):

int tmp = cards[n]; 
cards[n] = cards[i]; 
cards[i] = tmp; 

Si realmente quería escribir un método de intercambio que funcionaba en cualquiera de una lista o una matriz, que tendría que hacer algo como:

static void Swap(IList<int> list, int indexA, int indexB) 
{ 
    int tmp = list[indexA]; 
    list[indexA] = list[indexB]; 
    list[indexB] = tmp; 
} 

(sería trivial para hacer de este genérico) - sin embargo, la versión original "en línea" (es decir, no es un método) que trabajan en una matriz será más rápido.

+0

Interlocked.Exchange? – Svish

+0

¿Cómo funcionaría con una matriz? – Svish

+0

Golpee el intercambio ... –

3

Un buen intercambio es aquel en el que no intercambia los contenidos. En C/C++ esto sería similar a intercambiar punteros en lugar de intercambiar los contenidos. Este estilo de intercambio es rápido y viene con alguna garantía de excepción. Desafortunadamente, mi C# está demasiado oxidado como para permitirme ponerlo en el código. Para tipos de datos simples, este estilo no le da mucho. Pero una vez que esté acostumbrado y tenga que lidiar con objetos más grandes (y más complicados), puede salvarle la vida.

+3

Pero para un int [] o List , los contenidos son los mismos (x86) o la mitad del tamaño (x64). En este caso, intercambie los contenidos. –

5

Uso:

void swap(int &a, int &b) 
{ 
    // &a != &b 
    // a == b OK 
    a ^= b; 
    b ^= a; 
    a ^= b; 
    return; 
} 

no me di cuenta que estaba en la sección C#. Este es el código C++, pero debería tener la misma idea básica. Yo creo que^es XOR en C# también. Parece que en lugar de & puede necesitar "ref" (?). No estoy seguro.

+0

Interesante ... ¿qué significan esos comentarios? – Svish

+5

(¿Y es que 'return;' realmente es necesario?) – Svish

+0

return no es necesario, y usaría ref en lugar de & yes, +1 –

3

¿Qué tal esto? Es una implementación genérica de un método de intercambio. ¡Jit creará una versión compilada SOLAMENTE para los tipos cerrados, por lo que no tendrá que preocuparse por los perfomances!

/// <summary> 
/// Swap two elements 
/// Generic implementation by LMF 
/// </summary> 
public static void Swap<T>(ref T itemLeft, ref T itemRight) { 
    T dummyItem = itemRight; 
    itemLeft = itemRight; 
    itemRight = dummyItem; 
} 

HTH Lorenzo

0

Para cualquiera que se pregunte, intercambiando también se puede hacer también con métodos de extensión (.NET 3.0 y posteriores).

En general, parece que no hay posibilidad de decir que los métodos de extensión "este" valor es ref, por lo que debe devolverlo y anular el valor anterior.

public static class GeneralExtensions { 
    public static T SwapWith<T>(this T current, ref T other) { 
     T tmpOther = other; 
     other = current; 
     return tmpOther; 
    } 
} 

Este método de extensión se puede utilizar luego como esto:

int val1 = 10; 
int val2 = 20;  
val1 = val1.SwapWith(ref val2); 
Cuestiones relacionadas