2012-12-07 11 views
28

Mi chiedo se c'è un modo più efficiente di scambiare due elementi di un array, di fare qualcosa di simile:efficace scambio di elementi di un array in Java

String temp = arr[1]; 
arr[1] = arr[2]; 
arr[2] = temp; 

Beh, questo è ovviamente non è male o anche sbagliato, ma ho bisogno di scambiare molto spesso quindi sono interessato se ci sono Libs o qualcosa che fornisce un modo più efficiente per fare questo?

+0

Per stringa? No, non proprio. Se hai bisogno di farlo spesso potresti anche eseguire una sola volta la tua funzione e non è una seccatura – Grambot

+2

Se puoi lavorare con List invece che con Array, puoi usare Collections.swap (List, i, j). –

+0

@Sergio Nakanishi: Interesting Point, forse sarò in grado di passare alle collezioni, tuttavia non sono sicuro che l'uso di array puro non sia più veloce? – Robin

risposta

12

No. Potresti avere una funzione per renderla più concisa in ogni posto in cui la usi, ma alla fine il lavoro svolto sarebbe lo stesso (più il sovraccarico della chiamata di funzione, fino a quando HotSpot non lo ha spostato in linea   — per aiutarlo con quello, crea il functon static final).

+2

Solo per la cronaca, qual è il vantaggio nell'uso di 'static final' invece di solo' statico' o addirittura nessuno? – Robin

+4

@Robin: 'static' dice al compilatore e alla VM (ricordate, HotSpot è la VM, che esegue un sacco di ottimizzazione del runtime) che non si preoccupa di impostare' this', il che rende più facile incorporare la funzione . 'final' dice che non verrà sovrascritto in una sottoclasse. Potrei facilmente sbagliare sul grado a cui HotSpot si preoccupa di nessuno di loro, davvero, non sono al corrente dell'ultima magia di HotSpot. :-) –

+2

Penso che non sia possibile sovrascrivere un metodo statico. –

5

Se si desidera scambiare una stringa. è già il modo efficace per farlo.

Tuttavia, se si desidera scambiare intero, è possibile utilizzare XOR per scambiare due interi in modo più efficiente in questo modo:

int a = 1; int b = 2; a ^= b; b ^= a; a ^= b; 
+2

Quali test hai utilizzato per eseguire il benchmark e quali sono stati i miglioramenti di velocità? – djechlin

+0

Vedi il mio commento. – djechlin

+0

@djechlin almeno, non è necessario creare una variabile temporanea – bhuang3

20

Questo dovrebbe rendere più senza soluzione di continuità:

public static final <T> void swap (T[] a, int i, int j) { 
    T t = a[i]; 
    a[i] = a[j]; 
    a[j] = t; 
} 

public static final <T> void swap (List<T> l, int i, int j) { 
    Collections.<T>swap(l, i, j); 
} 

private void test() { 
    String [] a = {"Hello", "Goodbye"}; 
    swap(a, 0, 1); 
    System.out.println("a:"+Arrays.toString(a)); 
    List<String> l = new ArrayList<String>(Arrays.asList(a)); 
    swap(l, 0, 1); 
    System.out.println("l:"+l); 
} 
+2

Questa sarebbe stata la mia soluzione, grazie – Robin

+1

questo funziona bene, grazie. si noti che questo richiede una serie di oggetti, quindi se si ottengono quegli strani errori di compilazione, assicurarsi di utilizzare l'array 'Integer [] invece di' int [] array'. – LostNomad311

1

Se sei Scambiando numeri e volendo un modo conciso per scrivere il codice senza creare una funzione separata o usando un hackeraggio confuso di XOR, trovo che questo sia molto più facile da capire e che sia anche un solo liner.

public static void swap(int[] arr, int i, int j) { 
    arr[i] = (arr[i] + arr[j]) - (arr[j] = arr[i]); 
} 

Quello che ho visto da alcuni benchmark primitivi è che la differenza di prestazioni è sostanzialmente trascurabile pure.

+0

ma arr [i] + arr [j] può overflow –

+0

@ChaojunZhong che non dovrebbe essere un problema. Il nuovo '[i]' verrà calcolato correttamente quando l'altro numero viene sottratto. Provalo in un IDE – kmecpp

+0

Sì, hai ragione. Lo stesso come dici tu. –

0

Incredibilmente in ritardo alla festa (le mie scuse), ma una soluzione più generica rispetto a quelle qui fornite possono essere implementate (lavorerà con primitive e non-primitive simili):

public static void swap(final Object array, final int i, final int j) { 
    final Object atI = Array.get(array, i); 
    Array.set(array, i, Array.get(array, j)); 
    Array.set(array, j, atI); 
} 

si perde in fase di compilazione tempo di sicurezza , ma dovrebbe fare il trucco.

Nota I: Otterrete un NullPointerException se il dato è arraynull, un IllegalArgumentException se il dato è arraynon una matrice e un ArrayIndexOutOfBoundsException se uno degli indici non sono validi per la data array.

Nota II: Avere metodi separati per questo per ogni tipo array (Object[] e tutti i tipi primitivi) sarebbe più performante (utilizzando gli altri approcci qui riportati) dal momento che questo richiede un po 'di boxe/unboxing. Ma sarebbe anche molto più codice da scrivere/mantenere.

1

Prova questo:

int lowIndex = 0; 
    int highIndex = elements.length-1; 

    while(lowIndex < highIndex) { 
     T lowVal = elements[lowIndex]; 
     T highVal = elements[highIndex]; 
     elements[lowIndex] = highVal; 
     elements[highIndex] = lowVal; 

     lowIndex += 1; 
     highIndex -=1; 
    } 
1

Usa Collections.swap e Arrays.asList:

Collections.swap(Arrays.asList(arr), i, j); 
Problemi correlati