Come posso invertire un array int in Java?


238

Sto cercando di invertire un array int in Java.

Questo metodo non inverte l'array.

for(int i = 0; i < validData.length; i++)
{
    int temp = validData[i];
    validData[i] = validData[validData.length - i - 1];
    validData[validData.length - i - 1] = temp;
}

Cosa c'è che non va?


31
Vedo cosa ho fatto di sbagliato. Dovrebbe essere validData.length / 2. Altrimenti si invertirà, quindi si annullerà.
MichaelScott,

4
Vedi en.wikipedia.org/wiki/In-place_algorithm che contiene una descrizione della versione corretta di questo algoritmo.
Decano Povey, il

Risposte:


284

Per invertire un array int, scambia gli elementi verso l'alto fino a raggiungere il punto medio, in questo modo:

for(int i = 0; i < validData.length / 2; i++)
{
    int temp = validData[i];
    validData[i] = validData[validData.length - i - 1];
    validData[validData.length - i - 1] = temp;
}

Nel modo in cui lo fai, scambia ogni elemento due volte, quindi il risultato è lo stesso dell'elenco iniziale.


E vorrei mettere una validData.length / 2parte all'esterno del for-loop.
Jin Kwon

7
@Jin non lo farei. Offusca solo il significato e scommetto che il compilatore ottimizzante lo farebbe comunque per te. Indipendentemente da ciò, non ha senso micro-ottimizzazione fino a quando non si hanno prove chiare dalla profilazione che è necessario / utile.
Nicu Stiurca,

9
@JinKwon Sarebbe un po 'come fare validData.length >> 1. Questo è equivalente e più veloce, ma confonde molti programmatori e qualsiasi buon compilatore lo farà automaticamente.
Justin

2
Dovresti fare questo calcolo una sola volta validData.length - i - 1e salvarlo in una variabile.

Qualcuno può suggerire un'inversione senza la variabile temp !!
sg28,

303

Con Commons.Lang , potresti semplicemente usare

ArrayUtils.reverse(int[] array)

Il più delle volte, è più veloce e più sicuro da attaccare con le librerie facilmente disponibili già testate dall'unità e testate dall'utente quando si occupano del tuo problema.


3
Avrei preferito che restituisse l'array invertito (passato) per uno stile funzionale.
Laurent G,

2
@ laurent-g per essere onesti: invertire l'array in questo modo è più efficiente la memoria, motivo per cui probabilmente lo hanno fatto in questo modo.
Sirmyself

4
Il mio punto non era la copia o non la copia. Il mio messaggio afferma che "(passato)" deve essere restituito (dopo essere stato invertito), quindi potrebbe essere passato in un'espressione, senza bisogno di un'istruzione separata.
Laurent G,

52
public class ArrayHandle {
    public static Object[] reverse(Object[] arr) {
        List<Object> list = Arrays.asList(arr);
        Collections.reverse(list);
        return list.toArray();
    }
}

11
Certo che lo sarà. Un elenco può contenere solo oggetti, non primitivi, quindi tutti i primitivi ( intin questo caso) vengono Integerinseriti nei rispettivi wrapper ( in questo caso) e inseriti nell'elenco. Vedi, Integers sono oggetti. @Tom
11684,

6
Attenzione: se non sbaglio l'array originale viene modificato. Per chiarire che potresti voler semplicemente non restituire nulla.
Andrea Zilio,

3
@ 11684 Sì, gli elenchi generici possono contenere solo oggetti. Ma il metodo esclude un array. Le matrici possono contenere primitive. Pertanto int[]è diverso da Integer[]. Provalo: Integer[] array = new int[5]. Riceverai un errore di compilazione. Questo è il motivo per cui la Arraysclasse Java definisce un sacco di metodi per lavorare con array primitivi. Cercare di passare int[]al metodo sopra si tradurrà in qualcosa di simile The method reverse(Object[]) in the type MakeSimple is not applicable for the arguments (int[]). @Filip: un algoritmo sul posto utilizza meno memoria e funziona più velocemente.
Brian McCutchon,

3
@Andrea In realtà, non lo è. L'elenco restituito da Arrays.asList()non fa riferimento all'array originale, né l'array restituito. Questo è uno dei problemi con questo metodo: usa il triplo della memoria e triplica il lavoro come algoritmo sul posto.
Brian McCutchon,

4
Questo stesso metodo potrebbe funzionare, ma non è possibile passare un int[]argomento come argomento a questo metodo ( "tipi incompatibili: int [] non possono essere convertiti in Object []" ).
MC Emperor

47
Collections.reverse(Arrays.asList(yourArray));

java.util.Collections.reverse()può invertire java.util.Lists e java.util.Arrays.asList()restituisce una lista che avvolge la matrice specifico si passa ad esso, di conseguenza yourArrayviene invertito dopo l'invocazione Collections.reverse().

Il costo è solo la creazione di un oggetto List e non sono necessarie librerie aggiuntive.

Una soluzione simile è stata presentata nella risposta di Tarik e dei loro commentatori, ma penso che questa risposta sarebbe più concisa e più facilmente analizzabile.


15
Per matrici di oggetti, questa è una buona soluzione. Ma non funziona per le matrici di primitivi. Per esempio. passare un int[]a asList(...)non restituirà a List<Integer>, ma a List<int[]>, contenente un elemento. Non esiste AFAICS un modo integrato semplice per convertire un int[]in Integer[].
Martin Rust,

4
Questo non funzionerà con array primitivi ... le raccolte non restituiscono un valore, quindi ora hai un array inutile come elenco in memoria
NightSkyCode

@MartinRust Java 8+: Arrays.stream(arr).boxed().collect(Collectors.toList())oppureArrays.stream(arr).boxed().toArray(Integer[]::new)
Simon Forsberg il

39

Penso che sia un po 'più semplice seguire la logica dell'algoritmo se dichiari variabili esplicite per tenere traccia degli indici che stai scambiando ad ogni iterazione del ciclo.

public static void reverse(int[] data) {
    for (int left = 0, right = data.length - 1; left < right; left++, right--) {
        // swap the values at the left and right indices
        int temp = data[left];
        data[left]  = data[right];
        data[right] = temp;
    }
}

Penso anche che sia più leggibile farlo in un ciclo while.

public static void reverse(int[] data) {
    int left = 0;
    int right = data.length - 1;

    while( left < right ) {
        // swap the values at the left and right indices
        int temp = data[left];
        data[left] = data[right];
        data[right] = temp;

        // move the left and right index pointers in toward the center
        left++;
        right--;
    }
}

lo scambio di vecchia scuola sembra più semplice ma sì quando si coinvolgono i valori dell'indice di array a sinistra, a destra, ... sarà utile per il debug, se presente
Srinath Ganesh,

Puoi anche aggiungere 'public static void swap (int [] data, int index1, int index2) {...}' e usarlo da 'reverse' in questo modo: swap (data, left, right).
pm_

13

Ci sono già molte risposte qui, principalmente focalizzate sulla modifica dell'array sul posto. Ma per completezza, ecco un altro approccio che utilizza i flussi Java per preservare l'array originale e creare un nuovo array invertito:

    int[] a = {8, 6, 7, 5, 3, 0, 9};
    int[] b = IntStream.rangeClosed(1, a.length).map(i -> a[a.length-i]).toArray();

10

Con Guava:

Collections.reverse(Ints.asList(array));

4
È brillante! Breve ed efficace. Come tutti i asListmetodi, crea una vista che scrive direttamente nella matrice di supporto (primitiva). Penso che il down-voter qui abbia erroneamente pensato che questo abbia restituito una lista in scatola o qualcosa del genere.
Luke Usherwood il

@LukeUsherwood presumibilmente ci saranno ancora delle spese generali da boxe e unboxing quando si chiama get e si imposta su ogni elemento. Ma sono d'accordo con te che questa è una soluzione geniale.
Patrick Parker,

Anzi, vale la pena essere consapevoli. Non penso che sarebbe un grosso problema nella maggior parte del codice con cui lavoro personalmente - le nostre aree "calde" sono ben definite, il resto è una specie di "codice colla". Allo stesso tempo, sono consapevole del fatto che la varianza della memoria crea anche un costo "nascosto" aggiuntivo che i profiler non attribuiscono alla funzione effettiva.
Luke Usherwood,

@LukeUsherwood restituisce comunque un elenco in scatola invece di un array
primario

2
@AnthonyJClink Non sono sicuro di cosa si riferisca "it", ma l'utilità JDK Collections.reverseè un metodo nullo. Funziona sul posto su una classe interna di Guava che racchiude un int[](Dal momento che non memorizza mai un elenco di inscatolati Integer, non definirei la classe un "elenco inscatolato", ma piuttosto una "Visualizzazione elenco di un array"). Ma sì, funziona attraverso un'interfaccia che passa Integeroggetti, quindi questo creerebbe un sacco di sfasature e boxe di oggetti temporanei come menzionato. Prova una IntStreamlibreria o una raccolta di primitive per cui conta la performance. (Trove, Koloboke, Eclipse Collections, ...)
Luke Usherwood,

10

Nel caso di Java 8 possiamo anche usare IntStreamper invertire l'array di numeri interi come:

int[] sample = new int[]{1,2,3,4,5};
int size = sample.length;
int[] reverseSample = IntStream.range(0,size).map(i -> sample[size-i-1])
                      .toArray(); //Output: [5, 4, 3, 2, 1]

7

Semplice per loop!

for (int start = 0, end = array.length - 1; start <= end; start++, end--) {
    int aux = array[start];
    array[start]=array[end];
    array[end]=aux;
}

4
In futuro, si prega di far sapere al richiedente specificamente cosa hanno fatto in modo errato e cosa hai fatto correttamente.
Kartik Chugh,

1
cambia start <= endinstart < end
Leonard Pauli,

5

Questo ti aiuterà

int a[] = {1,2,3,4,5};
for (int k = 0; k < a.length/2; k++) {
    int temp = a[k];
    a[k] = a[a.length-(1+k)];
    a[a.length-(1+k)] = temp;
}

5
for(int i=validData.length-1; i>=0; i--){
  System.out.println(validData[i]);
 }

Sfortunatamente, questa è la risposta più chiara disponibile qui, perché ogni sviluppatore saprà come farlo e non richiede installazioni estese di pacchetti.
HoldOffHunger,

5

È così che lo risolverei personalmente. Il motivo alla base della creazione del metodo parametrizzato è quello di consentire l'ordinamento di qualsiasi array ... non solo i tuoi numeri interi.

Spero che tu ne ricava qualcosa.

@Test
public void reverseTest(){
   Integer[] ints = { 1, 2, 3, 4 };
   Integer[] reversedInts = reverse(ints);

   assert ints[0].equals(reversedInts[3]);
   assert ints[1].equals(reversedInts[2]);
   assert ints[2].equals(reversedInts[1]);
   assert ints[3].equals(reversedInts[0]);

   reverseInPlace(reversedInts);
   assert ints[0].equals(reversedInts[0]);
}

@SuppressWarnings("unchecked")
private static <T> T[] reverse(T[] array) {
    if (array == null) {
        return (T[]) new ArrayList<T>().toArray();
    }
    List<T> copyOfArray = Arrays.asList(Arrays.copyOf(array, array.length));
    Collections.reverse(copyOfArray);
    return copyOfArray.toArray(array);
}

private static <T> T[] reverseInPlace(T[] array) {
    if(array == null) {
        // didn't want two unchecked suppressions
        return reverse(array);
    }

    Collections.reverse(Arrays.asList(array));
    return array;
}

2
Non risolve il problema originale usando i primitivi.
Melinda Green,

Esistono molti modi per convertire i prim in oggetti. Consiglio sempre di evitare prims, ove possibile, in Java e credo anche che dovrebbe essere incoraggiato.
AnthonyJClink,

Convertire una matrice di primitive di lunghezza sconosciuta in una matrice potrebbe essere una pessima idea, soprattutto se fatto senza accorgersene. Java non è Smalltalk. I primitivi fanno parte della lingua e hanno il loro posto. Non importa se non ci piacciono, dobbiamo accettarli e usarli dove appropriato.
Melinda Green,

1
In realtà non è necessario copiare l'array, solo Collections.reverse(asList(arraytoReverse)); return arrayToReverse;. asListè solo un wrapper attorno all'array, quindi l'array originale è invertito.
Radiodef,

3

Il tuo programma funzionerà solo per length = 0, 1. Puoi provare :

int i = 0, j = validData.length-1 ; 
while(i < j)
{
     swap(validData, i++, j--);  // code for swap not shown, but easy enough
}

3
Forse intendevi scambiare come pseudo codice per uno scambio in linea anziché una chiamata al metodo, ma in caso contrario non funzionerà. Java passa per riferimento, quindi non è possibile scrivere un metodo di scambio per le variabili.
Decano Povey, il

Intendevo in qualunque modo puoi scambiare v [i] & v [j]. Sono consapevole di come funzionano le chiamate di metodo in Java. Per il metodo, puoi fare qualcosa come swap (v, i ++, j--);
fastcodejava,

1
Dean, l'array validData è un oggetto, passato per riferimento, quindi il metodo swap () funzionerà perfettamente.
Gaël Oberson,

3

Se lavori con dati più primitivi (ad esempio char, byte, int, ecc.) Allora puoi fare alcune divertenti operazioni XOR.

public static void reverseArray4(int[] array) {
    int len = array.length;
    for (int i = 0; i < len/2; i++) {
        array[i] = array[i] ^ array[len - i  - 1];
        array[len - i  - 1] = array[i] ^ array[len - i  - 1];
        array[i] = array[i] ^ array[len - i  - 1];
    }
}

1
Troppo carino da usare nel codice di produzione ma divertente comunque. Per la massima carineria, utilizzare l'operazione% = in questo modo: array [i]% = array [len - i - 1], ecc.
Melinda Green,

Simile, ma un po 'più breve:for (int m = x.length, i = --m / 2; ++i <= m;) { x[i] ^= x[m - i]; x[i] ^= x[m - i] ^= x[i]; }
Thomas Mueller il

2

È più efficiente iterare semplicemente l'array all'indietro.

Non sono sicuro che la soluzione di Aaron faccia questo vi questa chiamata Collections.reverse(list);Qualcuno lo sa?


L'iterazione all'indietro sull'array richiede un nuovo array. Mi piace la soluzione pubblicata sopra che esegue l'inversione in linea senza creare un nuovo array.
mmcdole,

1
@Simucal perché creare un nuovo array? Basta iterarlo all'indietro.
Trejkaz,

2
public void getDSCSort(int[] data){
        for (int left = 0, right = data.length - 1; left < right; left++, right--){
            // swap the values at the left and right indices
            int temp = data[left];
            data[left]  = data[right];
            data[right] = temp;
        }
    }

1
public void display(){
  String x[]=new String [5];
  for(int i = 4 ; i > = 0 ; i-- ){//runs backwards

    //i is the nums running backwards therefore its printing from       
    //highest element to the lowest(ie the back of the array to the front) as i decrements

    System.out.println(x[i]);
  }
}

1
sì, ho provato lo stesso codice chiaro insieme a output è int [] a = {1,3,5,2,6,7}; per (int i = a.length-1; i> = 0; i--) {System.out.print (a [i] + "");} `invertirà l'array dall'ultimo indice al primo indice
Rocket_03

1

Farlo in questo modo non sarebbe molto più improbabile per errori?

    int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int[] temp = new int[intArray.length];
    for(int i = intArray.length - 1; i > -1; i --){
            temp[intArray.length - i -1] = intArray[i];
    }
    intArray = temp;

1

Soluzione con o (n) complessità temporale e o (1) complessità spaziale.

void reverse(int[] array) {
    int start = 0;
    int end = array.length - 1;
    while (start < end) {
        int temp = array[start];
        array[start] = array[end];
        array[end] = temp;
        start++;
        end--;
    }
}

Cordiali saluti, questo può essere semplificata in un complesso ciclo for: for (int start = 0, end = array.length - 1; start < end; start++, end--) { ... }.
Tim Cooke,

1

2 modi per invertire una matrice.

  1. Utilizzando For loop e scambiare gli elementi fino al punto medio con complessità temporale di O (n / 2).

    private static void reverseArray() {
    int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
    
    for (int i = 0; i < array.length / 2; i++) {
        int temp = array[i];
        int index = array.length - i - 1;
        array[i] = array[index];
        array[index] = temp;
    }
    System.out.println(Arrays.toString(array));

    }

  2. Utilizzo della funzione integrata (Collections.reverse ())

    private static void reverseArrayUsingBuiltInFun() {
    int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
    
    Collections.reverse(Ints.asList(array));
    System.out.println(Arrays.toString(array));

    }

    Uscita: [6, 5, 4, 3, 2, 1]


3
Che cosa è Ints?
CodingOow

@CodingNow è una delle classi helper di utilità di Guava - vedi qui
mrec

1
    public static void main(String args[])    {
        int [] arr = {10, 20, 30, 40, 50}; 
        reverse(arr, arr.length);
    }

    private static void reverse(int[] arr,    int length)    {

        for(int i=length;i>0;i--)    { 
            System.out.println(arr[i-1]); 
        }
    }

1

Ci sono alcune grandi risposte sopra, ma è così che l'ho fatto:

public static int[] test(int[] arr) {

    int[] output = arr.clone();
    for (int i = arr.length - 1; i > -1; i--) {
        output[i] = arr[arr.length - i - 1];
    }
    return output;
}

0

di seguito è riportato il programma completo da eseguire sulla macchina.

public class ReverseArray {
    public static void main(String[] args) {
        int arr[] = new int[] { 10,20,30,50,70 };
        System.out.println("reversing an array:");
        for(int i = 0; i < arr.length / 2; i++){
            int temp = arr[i];
            arr[i] = arr[arr.length - i - 1];
            arr[arr.length - i - 1] = temp;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }   
    }
}

Per i programmi su matrice che usano array questa sarà la buona fonte . Passa attraverso il link.


0

Usando la soluzione XOR per evitare la variabile temp dovrebbe apparire il tuo codice

for(int i = 0; i < validData.length; i++){
    validData[i] = validData[i] ^ validData[validData.length - i - 1];
    validData[validData.length - i - 1] = validData[i] ^ validData[validData.length - i - 1];
    validData[i] = validData[i] ^ validData[validData.length - i - 1];
}

Vedi questo link per una spiegazione migliore:

http://betterexplained.com/articles/swap-two-variables-using-xor/


0
private static int[] reverse(int[] array){
    int[] reversedArray = new int[array.length];
    for(int i = 0; i < array.length; i++){
        reversedArray[i] = array[array.length - i - 1];
    }
    return reversedArray;
} 

4
Ti preghiamo di considerare di aggiungere una spiegazione alla tua risposta. Le risposte di solo codice non spiegano nulla.
rgettman,

0

Ecco una semplice implementazione, per invertire l'array di qualsiasi tipo , oltre al supporto completo / parziale .

import java.util.logging.Logger;

public final class ArrayReverser {
 private static final Logger LOGGER = Logger.getLogger(ArrayReverser.class.getName());

 private ArrayReverser () {

 }

 public static <T> void reverse(T[] seed) {
    reverse(seed, 0, seed.length);
 }

 public static <T> void reverse(T[] seed, int startIndexInclusive, int endIndexExclusive) {
    if (seed == null || seed.length == 0) {
        LOGGER.warning("Nothing to rotate");
    }
    int start = startIndexInclusive < 0 ? 0 : startIndexInclusive;
    int end = Math.min(seed.length, endIndexExclusive) - 1;
    while (start < end) {
        swap(seed, start, end);
        start++;
        end--;
    }
}

 private static <T> void swap(T[] seed, int start, int end) {
    T temp =  seed[start];
    seed[start] = seed[end];
    seed[end] = temp;
 }  

}

Ecco il test unitario corrispondente

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

public class ArrayReverserTest {
private Integer[] seed;

@Before
public void doBeforeEachTestCase() {
    this.seed = new Integer[]{1,2,3,4,5,6,7,8};
}

@Test
public void wholeArrayReverse() {
    ArrayReverser.<Integer>reverse(seed);
    assertThat(seed[0], is(8));
}

 @Test
 public void partialArrayReverse() {
    ArrayReverser.<Integer>reverse(seed, 1, 5);
    assertThat(seed[1], is(5));
 }
}

0

Ecco cosa mi è venuto in mente:

// solution 1 - boiler plated 
Integer[] original = {100, 200, 300, 400};
Integer[] reverse = new Integer[original.length];

int lastIdx = original.length -1;
int startIdx = 0;

for (int endIdx = lastIdx; endIdx >= 0; endIdx--, startIdx++)
   reverse[startIdx] = original[endIdx];

System.out.printf("reverse form: %s", Arrays.toString(reverse));

// solution 2 - abstracted 
// convert to list then use Collections static reverse()
List<Integer> l = Arrays.asList(original);
Collections.reverse(l);
System.out.printf("reverse form: %s", l);

0

Esistono due modi per avere una soluzione al problema:

1. Invertire una matrice nello spazio.

Passaggio 1. Scambia gli elementi all'inizio e l'indice di fine.

Passaggio 2. Incrementa l'indice di inizio decrementa l'indice di fine.

Passaggio 3. Iterare i passaggi 1 e 2 fino all'indice iniziale <indice finale

Per questo, la complessità temporale sarà O (n) e la complessità spaziale sarà O (1)

Il codice di esempio per invertire un array nello spazio è come:

public static int[] reverseAnArrayInSpace(int[] array) {
    int startIndex = 0;
    int endIndex = array.length - 1;
    while(startIndex < endIndex) {
        int temp = array[endIndex];
        array[endIndex] = array[startIndex];
        array[startIndex] = temp;
        startIndex++;
        endIndex--;
    }
    return array;
}

2. Invertire un array utilizzando un array ausiliario.

Passaggio 1. Creare un nuovo array di dimensioni uguale all'array specificato.

Passaggio 2. Inserire elementi nel nuovo array a partire dall'indice iniziale, dall'array specificato a partire dall'indice finale.

Per questo, la complessità temporale sarà O (n) e la complessità spaziale sarà O (n)

Il codice di esempio per invertire un array con un array ausiliario è simile a:

public static int[] reverseAnArrayWithAuxiliaryArray(int[] array) {
    int[] reversedArray = new int[array.length];
    for(int index = 0; index < array.length; index++) {
        reversedArray[index] = array[array.length - index -1]; 
    }
    return reversedArray;
}

Inoltre, possiamo usare l'API Collections di Java per farlo.

L'API Collections utilizza internamente lo stesso approccio inverso nello spazio.

Il codice di esempio per l'utilizzo dell'API Collections è simile a:

public static Integer[] reverseAnArrayWithCollections(Integer[] array) {
    List<Integer> arrayList = Arrays.asList(array);
    Collections.reverse(arrayList);
    return arrayList.toArray(array);
}

0
static int[] reverseArray(int[] a) {
     int ret[] = new int[a.length];
     for(int i=0, j=a.length-1; i<a.length && j>=0; i++, j--)
         ret[i] = a[j];
     return ret;
}

0
 public static int[] reverse(int[] array) {

    int j = array.length-1;
    // swap the values at the left and right indices //////
        for(int i=0; i<=j; i++)
        {
             int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
           j--;
        }

         return array;
    }

      public static void main(String []args){
        int[] data = {1,2,3,4,5,6,7,8,9};
        reverse(data);

    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.