Como inverter uma matriz int em Java?


238

Eu estou tentando reverter uma matriz int em Java.

Este método não reverte a matriz.

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

O que está errado com isso?


31
Eu vejo o que fiz de errado. Deve ser validData.length / 2. Caso contrário, ele se inverterá e, em seguida, se inverterá.
26910 MichaelScott

4
Consulte en.wikipedia.org/wiki/In-place_algorithm, que contém uma descrição da versão correta desse algoritmo.
precisa saber é o seguinte

Respostas:


283

Para inverter uma matriz int, você troca itens até chegar ao ponto médio, assim:

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

Do jeito que você está fazendo isso, você troca cada elemento duas vezes, para que o resultado seja o mesmo da lista inicial.


E eu gostaria de colocar validData.length / 2parte do lado de fora do loop for.
Jin Kwon

7
@ Jin eu não faria. Isso apenas ofusca o significado, e aposto que o compilador de otimização faria isso por você de qualquer maneira. Independentemente disso, não adianta micro-otimizar até que você tenha evidências claras de que o perfil é necessário / útil.
Nicu Stiurca

9
@JinKwon Isso seria meio que fazer validData.length >> 1. Isso é equivalente e mais rápido, mas confunde muitos programadores e qualquer bom compilador fará isso automaticamente.
26678 Justin

2
Você deve fazer esse cálculo apenas uma vez validData.length - i - 1e salvá-lo em uma variável.

Qualquer um pode sugerir uma reversão sem a variável temp !!
S28 de 11/07

303

Com o Commons.Lang , você pode simplesmente usar

ArrayUtils.reverse(int[] array)

Na maioria das vezes, é mais rápido e mais seguro para os bichos ficar com bibliotecas facilmente disponíveis, já testadas em unidade e testadas pelo usuário quando cuidam do seu problema.


3
Eu preferiria que ele retornasse a matriz reversa (aprovada) para um estilo funcional.
Laurent G

2
@ laurent-g para ser justo: inverter a matriz dessa maneira é mais eficiente em termos de memória, e é provavelmente por isso que eles fizeram dessa maneira.
Sirmyself

4
Meu ponto não era a cópia ou não a cópia. Minha mensagem indica "(passado)" a ser retornado (depois de revertido), para que pudesse ser passado em uma expressão, sem precisar de uma declaração separada.
Laurent L

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

11
Claro que vai. Uma lista pode conter apenas Objetos, não primitivos, portanto, todos os primitivos ( ints neste caso) são agrupados em seus respectivos invólucros ( Integers neste caso) e colocados na lista. Você vê, Integers são objetos. @Tom
11684 03/12/12

6
Cuidado: se não estiver errado, a matriz original é modificada. Para deixar claro, você pode simplesmente não devolver nada.
Andrea Zilio

3
@ 11684 Sim, as listas genéricas só podem conter Objetos. Mas o método excede uma matriz. Matrizes podem conter primitivas. Portanto, int[]é diferente de Integer[]. Experimente: Integer[] array = new int[5]. Você receberá um erro de compilação. É por isso que a Arraysclasse Java define vários métodos para trabalhar com matrizes primitivas. Tentar passar um int[]para o método acima resultará em algo como The method reverse(Object[]) in the type MakeSimple is not applicable for the arguments (int[]). @Filip - um algoritmo no local usa menos memória e roda mais rápido.
Brian McCutchon

3
@ Andrea Na verdade, não é. A lista retornada por Arrays.asList()não faz referência à matriz original, nem a matriz retornada. Esse é um dos problemas desse método: ele usa o triplo da memória e o trabalho como um algoritmo no local.
Brian McCutchon

4
Esse método em si pode funcionar, mas simplesmente não se pode passar um int[]argumento para esse método ( "tipos incompatíveis: int [] não podem ser convertidos em Objeto []" ).
MC Emperor

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

java.util.Collections.reverse()pode reverter java.util.Lists e java.util.Arrays.asList()retorna uma lista que envolve a matriz do específico que você passar para ele, por isso yourArrayé revertido após a invocação de Collections.reverse().

O custo é apenas a criação de um objeto de lista e nenhuma biblioteca adicional é necessária.

Uma solução semelhante foi apresentada na resposta de Tarik e seus comentadores, mas acho que essa resposta seria mais concisa e mais facilmente analisável.


14
Para matrizes de objetos, esta é uma boa solução. Mas isso não funciona para matrizes de primitivos. Por exemplo. passar um int[]para asList(...)não retornará a List<Integer>, mas a List<int[]>, contendo um elemento. Não existe no AFAICS uma maneira integrada simples de converter um int[]para um Integer[].
Martin Rust

4
Isso não vai funcionar com matrizes primitivas ... coleções dosnt retornar um valor então agora você tem uma matriz inútil como uma lista na memória
NightSkyCode

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

39

Eu acho que é um pouco mais fácil seguir a lógica do algoritmo se você declarar variáveis ​​explícitas para acompanhar os índices que você está trocando a cada iteração do loop.

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

Eu também acho que é mais legível fazer isso em um loop 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--;
    }
}

velhas de swap escola parece mais fácil, mas sim quando envolve valores de índice de matriz esquerda, direita, ... será útil para a depuração se houver
Srinath Ganesh

Você também pode adicionar 'swap estático público vazio (int [] dados, int index1, int index2) {...}' e usar isso de 'reverse' assim: swap (dados, esquerda, direita).
pm_

13

Já existem muitas respostas aqui, principalmente focadas na modificação do array no local. Mas, para fins de completude, aqui está outra abordagem usando fluxos Java para preservar a matriz original e criar uma nova matriz reversa:

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

10

Com goiaba:

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

4
Isto é brilhante! Curto e eficaz. Como todos os asListmétodos, ele cria uma exibição que grava diretamente na matriz de backup (primitiva). Eu acho que o eleitor de baixo aqui erroneamente pensou que isso retornava uma lista em caixa ou algo assim.
Luke Usherwood

@LukeUsherwood presumivelmente ainda haverá alguma sobrecarga do boxe e do unboxing ao chamar get e set em cada elemento. Mas concordo com você que esta é uma solução brilhante.
Patrick Parker

Na verdade, vale a pena estar ciente disso. Eu não acho que seria um grande problema na maioria dos códigos com os quais trabalho pessoalmente - nossas áreas "quentes" são bem definidas, o resto são tipos de códigos de cola. Ao mesmo tempo, estou ciente de que o churn de memória também cria um custo "oculto" adicional que os criadores de perfil não atribuem à função real.
9606 Luke Usherwood #

@LukeUsherwood ainda retorna uma lista em caixa em vez de uma matriz prim #
AnthonyJClink 1/18/18

2
@AnthonyJClink Não sei ao que "se refere", mas o utilitário JDK Collections.reverseé um método nulo. Isso opera no local em uma classe interna do Guava que envolve um int[](Como nunca armazena uma lista de Integers em caixas, eu não chamaria a classe de "lista em caixas", mas sim de uma "exibição de lista de uma matriz"). Mas sim, ele opera através de uma interface que passa Integerobjetos, portanto, isso criaria uma grande quantidade de rotatividade e encaixe de objetos temporários, conforme mencionado. Tente uma IntStreamou uma biblioteca de coleção primitiva para saber onde o desempenho é importante. (Trove, Koloboke, Eclipse Collections, ...)
Luke Usherwood

9

No caso do Java 8 , também podemos usar IntStreampara reverter a matriz de números inteiros como:

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

Simples para 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
No futuro, informe ao solicitante especificamente o que fez incorretamente e o que você fez corretamente.
Kartik Chugh

1
alterar start <= endparastart < end
Leonard Pauli

5

Isso irá ajudá-lo

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

Infelizmente, esta é a resposta mais limpa disponível aqui, porque todos os desenvolvedores sabem como fazê-lo e não exigem instalação prolongada do pacote.
HoldOffHunger

4

É assim que eu pessoalmente resolveria. A razão por trás da criação do método parametrizado é permitir que qualquer matriz seja classificada ... não apenas seus números inteiros.

Espero que você tire algo disso.

@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
Não resolve o problema original usando primitivos.
Melinda Green

Existem várias maneiras de converter prims em objetos. Eu sempre recomendo evitar prims sempre que possível em java e também acredito que isso deve ser incentivado.
AnthonyJClink 12/02

Converter uma matriz de primitivas de comprimento desconhecido em uma matriz pode ser uma péssima idéia, especialmente se for feita sem perceber. Java não é Smalltalk. As primitivas fazem parte do idioma e têm seu lugar. Não importa se não gostamos deles, devemos aceitá-los e usá-los quando apropriado.
Melinda Green

1
Na verdade, você não precisa copiar a matriz apenas Collections.reverse(asList(arraytoReverse)); return arrayToReverse;. asListé apenas um invólucro em torno da matriz, portanto, a matriz original é invertida.
Radiodef

3

Seu programa funcionará apenas para length = 0, 1. Podes tentar :

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

3
Talvez você quisesse trocar como pseudo-código para uma troca embutida em vez de uma chamada de método, mas se não, isso não funcionará. O Java passa por referência, portanto, não é possível escrever um método de troca para variáveis.
precisa saber é o seguinte

Eu quis dizer de qualquer maneira que você possa trocar v [i] e v [j]. Estou ciente de como as chamadas de método funcionam em java. Para o método, você pode fazer algo como swap (v, i ++, j--);
fastcodejava

1
Dean, o array validData é um objeto, passado por referência, para que o método swap () funcione perfeitamente.
Gaël Oberson

3

Se você estiver trabalhando com dados mais primitivos (por exemplo, char, byte, int, etc.), poderá executar algumas operações divertidas do 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
Muito fofo para usar no código de produção, mas divertido. Para fofura máxima, utilizar a% = operação como esta: Matriz [i]% = matriz [len - i - 1], etc
Melinda verde

Semelhante, mas um pouco mais curto: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

É mais eficiente simplesmente iterar a matriz para trás.

Não tenho certeza se a solução de Aaron faz esta ligação Collections.reverse(list);. Alguém sabe?


A iteração para trás na matriz requer uma nova matriz. Eu gosto da solução postada acima que faz a inversão inline sem criar uma nova matriz.
precisa saber é

1
@ Simucal, por que criar uma nova matriz? Basta iterar para trás.
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
sim, eu tentei o mesmo código e o código claro, juntamente com a saída, é int [] a = {1,3,5,2,6,7}; for (int i = a.length-1; i> = 0; i--) {System.out.print (a [i] + ""));} `inverte a matriz do último índice para o primeiro índice
Rocket_03

1

Fazer dessa maneira não seria muito mais improvável por erros?

    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

Solução com o (n) complexidade de tempo e o (1) complexidade de espaço.

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

Apenas FYI, este pode ser simplificado em um complexo para loop: for (int start = 0, end = array.length - 1; start < end; start++, end--) { ... }.
Tim Cooke

1

2 maneiras de reverter uma matriz.

  1. Usando o loop For e troque os elementos até o ponto médio com a complexidade temporal 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. Usando a função incorporada (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));

    }

    Saída: [6, 5, 4, 3, 2, 1]


3
O que é Ints?
CodingNow

@CodingNow um É uma das classes utilitário auxiliar Goiaba - veja aqui
MREC

0

abaixo está o programa completo para executar em sua máquina.

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

Para programas em matriz usando matrizes, essa será a boa fonte. Acesse o link.


0

Usando a solução XOR para evitar a variável temp, seu código deve parecer

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

Veja este link para uma melhor explicação:

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
Por favor, considere adicionar uma explicação à sua resposta. Respostas apenas de código não explicam nada.
Rdttman

0

Aqui está uma implementação simples, para reverter a matriz de qualquer tipo , além de suporte total / parcial .

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

}

Aqui está o teste de unidade correspondente

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

Aqui está o que eu vim com:

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

Existem duas maneiras de ter uma solução para o problema:

1. Inverta uma matriz no espaço.

Etapa 1. Troque os elementos no índice inicial e final.

Etapa 2. Incremente o índice inicial e diminua o índice final.

Etapa 3. Repita a Etapa 1 e a Etapa 2 até o índice inicial <índice final

Para isso, a complexidade do tempo será O (n) e a complexidade do espaço será O (1)

O código de exemplo para reverter uma matriz no espaço é como:

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. Inverta uma matriz usando uma matriz auxiliar.

Etapa 1. Crie uma nova matriz de tamanho igual à matriz especificada.

Etapa 2. Insira elementos na nova matriz iniciando no índice inicial, a partir da matriz especificada iniciando no índice final.

Para isso, a complexidade do tempo será O (n) e a complexidade do espaço será O (n)

O código de exemplo para reverter uma matriz com matriz auxiliar é como:

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

Além disso, podemos usar a API Collections de Java para fazer isso.

A API de coleções usa internamente o mesmo método de inversão no espaço.

O código de exemplo para usar a API de coleções é como:

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

    }

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

0

Há algumas ótimas respostas acima, mas foi assim que eu fiz:

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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.