Comment inverser un tableau int en Java?


238

J'essaie d'inverser un tableau int en Java.

Cette méthode n'inverse pas le tableau.

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;
}

Qu'est-ce qui va pas avec ça?


31
Je vois ce que j'ai fait de mal. Doit être validData.length / 2. Sinon, il s'inversera puis se réinversera.
MichaelScott

4
Voir en.wikipedia.org/wiki/In-place_algorithm qui contient une description de la version correcte de cet algorithme.
Dean Povey

Réponses:


284

Pour inverser un tableau int, vous permutez les éléments jusqu'à ce que vous atteigniez le milieu, comme ceci:

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;
}

La façon dont vous le faites, vous permutez chaque élément deux fois, donc le résultat est le même que la liste initiale.


Et je voudrais mettre une validData.length / 2partie à l'extérieur de la boucle for.
Jin Kwon

7
@Jin, je ne le ferais pas. Cela ne fait que masquer le sens, et je parie que le compilateur d'optimisation le ferait pour vous de toute façon. Quoi qu'il en soit, la micro-optimisation est inutile tant que le profilage n'a pas clairement démontré qu'il est nécessaire / utile.
Nicu Stiurca

9
@JinKwon Ce serait un peu comme faire validData.length >> 1. C'est équivalent et plus rapide, mais cela confond de nombreux programmeurs et tout bon compilateur le fera automatiquement.
Justin

2
Vous ne devez effectuer ce calcul qu'une seule fois validData.length - i - 1et l'enregistrer dans une variable.

Quelqu'un peut-il suggérer une inversion sans variable de température !!
sg28

303

Avec Commons.Lang , vous pouvez simplement utiliser

ArrayUtils.reverse(int[] array)

La plupart du temps, il est plus rapide et plus sûr de conserver les bogues avec des bibliothèques facilement disponibles déjà testées par les unités et testées par les utilisateurs lorsqu'elles prennent soin de votre problème.


3
J'aurais préféré qu'il retourne le tableau inversé (passé) pour un style fonctionnel.
Laurent G

2
@ laurent-g pour être juste: inverser le tableau de cette façon est plus efficace en mémoire, c'est probablement pourquoi ils l'ont fait de cette façon.
Sirmyself

4
Mon point n'était pas la copie ou pas la copie. Mon message indique "(passé)" à renvoyer (après avoir été inversé), il peut donc être passé dans une expression, sans avoir besoin d'une instruction distincte.
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
Bien sur. Une liste ne peut contenir que des objets, pas des primitives, donc toutes les primitives ( ints dans ce cas) sont enveloppées dans leurs wrappers respectifs ( Integers dans ce cas) et placées dans la liste. Vous voyez, Integers sont des objets. @Tom
11684

6
Attention: si je ne me trompe pas, le tableau d'origine est modifié. Pour être clair, vous pouvez simplement ne rien retourner.
Andrea Zilio

3
@ 11684 Oui, les listes génériques ne peuvent contenir que des objets. Mais la méthode exclut un tableau. Les tableaux peuvent contenir des primitives. C'est donc int[]différent de Integer[]. Essayez: Integer[] array = new int[5]. Vous obtiendrez une erreur de compilation. C'est pourquoi la Arraysclasse Java définit un tas de méthodes pour travailler avec des tableaux primitifs. Essayer de passer un int[]à la méthode ci-dessus se traduira par quelque chose comme The method reverse(Object[]) in the type MakeSimple is not applicable for the arguments (int[]). @Filip - un algorithme sur place utilise moins de mémoire et s'exécute plus rapidement.
Brian McCutchon

3
@Andrea En fait, ce n'est pas le cas. La liste renvoyée par Arrays.asList()ne fait pas référence au tableau d'origine, pas plus que le tableau renvoyé. C'est l'un des problèmes de cette méthode: elle utilise le triple de la mémoire et triple le travail en tant qu'algorithme sur place.
Brian McCutchon

4
Cette méthode elle-même pourrait fonctionner, mais on ne peut tout simplement pas passer un int[]argument comme argument à cette méthode ( "les types incompatibles: int [] ne peuvent pas être convertis en Object []" ).
MC Emperor

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

java.util.Collections.reverse()peut inverser java.util.Lists et java.util.Arrays.asList()renvoie une liste qui encapsule le tableau spécifique que vous lui passez, yourArrayest donc inversé après l'invocation de Collections.reverse().

Le coût n'est que la création d'un objet List et aucune bibliothèque supplémentaire n'est requise.

Une solution similaire a été présentée dans la réponse de Tarik et de ses commentateurs, mais je pense que cette réponse serait plus concise et plus facilement analysable.


15
Pour les tableaux d'objets, c'est une bonne solution. Mais cela ne fonctionne pas pour les tableaux de primitives. Par exemple. passer un int[]à asList(...)ne renverra pas un List<Integer>, mais un List<int[]>contenant un élément. Il n'y a pas de moyen intégré AFAICS pour convertir un int[]en un Integer[].
Martin Rust

4
Cela ne fonctionnera pas avec les tableaux primitifs ... les collections ne renvoient pas de valeur alors maintenant vous avez un tableau inutile en tant que liste en mémoire
NightSkyCode

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

39

Je pense qu'il est un peu plus facile de suivre la logique de l'algorithme si vous déclarez des variables explicites pour garder une trace des indices que vous permutez à chaque itération de la boucle.

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;
    }
}

Je pense également qu'il est plus lisible de le faire dans une boucle 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--;
    }
}

le swap de la vieille école semble plus facile, mais oui lors de l'implication des valeurs d'index de tableau à gauche, à droite, ... sera utile pour le débogage le cas échéant
Srinath Ganesh

Vous pouvez également ajouter «échange statique statique public (données int [], index int1, index int2) {...}» et l'utiliser à partir de «inverser» comme ceci: swap (données, gauche, droite).
pm_

13

Il y a déjà beaucoup de réponses ici, principalement axées sur la modification du tableau sur place. Mais par souci d'exhaustivité, voici une autre approche utilisant des flux Java pour conserver le tableau d'origine et créer un nouveau tableau inversé:

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

10

Avec la goyave:

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

4
C'est génial! Court et efficace. Comme toutes les asListméthodes, il crée une vue qui écrit directement dans le tableau de support (primitif). Je pense que l'électeur ici a pensé à tort que cela renvoyait une liste encadrée ou quelque chose.
Luke Usherwood

@LukeUsherwood vraisemblablement, il y aura encore des frais généraux de boxe et de déballage lors de l'appel de get et set sur chaque élément. Mais je suis d'accord avec vous que c'est une solution brillante.
Patrick Parker

En effet, cela vaut la peine d'être conscient. Je ne pense pas que ce serait un gros problème dans la majorité du code avec lequel je travaille personnellement - nos zones «chaudes» sont bien définies, le reste est du «code de colle» en quelque sorte. En même temps, je suis conscient que le désabonnement de la mémoire crée également un coût "caché" supplémentaire que les profileurs n'attribuent pas à la fonction réelle.
Luke Usherwood

@LukeUsherwood, il retourne toujours une liste en boîte au lieu d'un tableau de prim
AnthonyJClink

2
@AnthonyJClink Vous ne savez pas à quoi "il" se réfère, mais l'utilitaire JDK Collections.reverseest une méthode nulle. Cela fonctionne sur place sur une classe interne de Guava qui encapsule un int[](Puisqu'il ne stocke jamais une liste de Integers en boîte, je n'appellerais pas la classe une "liste en boîte", mais plutôt une "Vue de liste d'un tableau"). Mais oui, il fonctionne via une interface passant des Integerobjets, donc cela créerait beaucoup de désabonnement temporaire et de boxe comme mentionné. Essayez une IntStreamou une bibliothèque de collections primitives pour savoir où les performances sont importantes. (Trove, Koloboke, Eclipse Collections, ...)
Luke Usherwood

10

Dans le cas de Java 8, nous pouvons également utiliser IntStreampour inverser le tableau d'entiers comme:

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

Simple pour boucle!

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

4
À l'avenir, veuillez indiquer au demandeur ce qu'il a fait de mal et ce que vous avez fait correctement.
Kartik Chugh

1
changer start <= endpourstart < end
Leonard Pauli

5

Cela vous aidera

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]);
 }

Malheureusement, c'est la réponse la plus claire disponible ici, car chaque développeur saura le faire et ne nécessite aucune installation de package étendue.
HoldOffHunger

5

C'est ainsi que je le résoudrais personnellement. La raison derrière la création de la méthode paramétrée est de permettre à n'importe quel tableau d'être trié ... pas seulement vos entiers.

J'espère que vous en tirez quelque chose.

@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
Ne résout pas le problème d'origine en utilisant des primitives.
Melinda Green

Il existe de nombreuses façons de convertir des prims en objets. Je recommande toujours d'éviter les prims dans la mesure du possible en java et je pense également que cela devrait être encouragé.
AnthonyJClink le

La conversion d'un tableau de primitives de longueur inconnue en tableau peut être une très mauvaise idée, surtout si elle est réalisée sans s'en rendre compte. Java n'est pas Smalltalk. Les primitifs font partie du langage et ont leur place. Peu importe si nous ne les aimons pas, nous devons les accepter et les utiliser le cas échéant.
Melinda Green

1
En fait, vous n'avez pas besoin de copier le tableau, juste Collections.reverse(asList(arraytoReverse)); return arrayToReverse;. asListest juste un wrapper autour du tableau, donc le tableau d'origine est inversé.
Radiodef

3

Votre programme ne fonctionnera que pour length = 0, 1. Tu peux essayer :

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

3
Peut-être que vous vouliez dire swap comme pseudo-code pour un swap en ligne plutôt qu'un appel de méthode, mais sinon cela ne fonctionnera pas. Java passe par référence, il n'est donc pas possible d'écrire une méthode de swap pour les variables.
Dean Povey

Je voulais dire quelle que soit la façon dont vous pouvez obtenir v [i] et v [j] pour échanger. Je sais comment les appels de méthode fonctionnent en java. Pour la méthode, vous pouvez faire quelque chose comme swap (v, i ++, j--);
fastcodejava

1
Dean, le tableau validData est un objet, passé par référence, donc la méthode swap () fonctionnera parfaitement.
Gaël Oberson

3

Si vous travaillez avec des données plus primitives (c.-à-d. Char, byte, int, etc.), vous pouvez effectuer des opérations XOR amusantes.

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
Trop mignon pour être réellement utilisé dans le code de production mais amusant quand même. Pour une gentillesse maximale, utilisez l'opération% = comme ceci: array [i]% = array [len - i - 1], etc.
Melinda Green

Similaire, mais un peu plus court:for (int m = x.length, i = --m / 2; ++i <= m;) { x[i] ^= x[m - i]; x[i] ^= x[m - i] ^= x[i]; }
Thomas Mueller

2

Il est plus efficace d'itérer simplement le tableau vers l'arrière.

Je ne sais pas si la solution d'Aaron fait cela via cet appel. Collections.reverse(list);Quelqu'un le sait-il?


L'itération vers l'arrière sur le tableau nécessite un nouveau tableau. J'aime la solution publiée ci-dessus qui effectue l'inversion en ligne sans créer de nouveau tableau.
mmcdole

1
@Simucal pourquoi créer un nouveau tableau? Il suffit de l'itérer en arrière.
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
oui j'ai essayé le même code clair avec la sortie est int [] a = {1,3,5,2,6,7}; for (int i = a.length-1; i> = 0; i--) {System.out.print (a [i] + "");} `il inversera le tableau du dernier index au premier index
Rocket_03

1

Ne serait-il pas beaucoup plus improbable de le faire de cette façon pour des erreurs?

    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

Solution à complexité temporelle o (n) et complexité spatiale o (1).

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--;
    }
}

Juste Pour votre information, cela peut être simplifié dans un complexe pour la boucle: for (int start = 0, end = array.length - 1; start < end; start++, end--) { ... }.
Tim Cooke

1

2 façons d'inverser un tableau.

  1. Utilisation de la boucle For et échange les éléments jusqu'au milieu avec une complexité temporelle de 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. Utilisation de la fonction intégrée (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));

    }

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


3
Qu'est-ce que c'est Ints?
CodingNow

@CodingNow, c'est l'une des classes d'aide utilitaire Guava - voir ici
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

Il y a quelques bonnes réponses ci-dessus, mais voici comment je l'ai fait:

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

ci-dessous est le programme complet à exécuter sur votre machine.

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]);
        }   
    }
}

Pour les programmes sur matrice utilisant des tableaux, ce sera la bonne source. Passez par le lien.


0

Utilisation de la solution XOR pour éviter la variable temporaire à laquelle votre code devrait ressembler

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];
}

Voir ce lien pour une meilleure explication:

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
Veuillez envisager d'ajouter une explication à votre réponse. Les réponses uniquement codées n'expliquent rien.
rgettman

0

Voici une implémentation simple, pour inverser un tableau de tout type , plus un support complet / partiel .

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;
 }  

}

Voici le test unitaire correspondant

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

Voici ce que j'ai trouvé:

// 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

Il existe deux façons d'avoir une solution au problème:

1. Inversez un tableau dans l'espace.

Étape 1. Échangez les éléments au début et à la fin de l'index.

Étape 2. Incrémentez l'index de début décrémentez l'index de fin.

Étape 3. Répétez les étapes 1 et 2 jusqu'à l'index de début <index de fin

Pour cela, la complexité temporelle sera O (n) et la complexité spatiale sera O (1)

Un exemple de code pour inverser un tableau dans l'espace est comme:

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. Inversez un tableau à l'aide d'un tableau auxiliaire.

Étape 1. Créez un nouveau tableau de taille égale au tableau donné.

Étape 2. Insérez des éléments dans le nouveau tableau à partir de l'index de début, du tableau donné à partir de l'index de fin.

Pour cela, la complexité temporelle sera O (n) et la complexité spatiale sera O (n)

Un exemple de code pour inverser un tableau avec un tableau auxiliaire est comme:

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;
}

De plus, nous pouvons utiliser l'API Collections de Java pour ce faire.

L'API Collections utilise en interne la même approche inverse dans l'espace.

Voici un exemple de code d'utilisation de l'API Collections:

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);

    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.