Javaでint配列を反転するにはどうすればよいですか?


238

Javaでint配列を反転しようとしています。

このメソッドは配列を反転しません。

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

それの何が問題になっていますか?


31
私は何を間違えたかわかります。validData.length / 2である必要があります。それ以外の場合は、元に戻してから元に戻します。
MichaelScott、2010年

4
このアルゴリズムの正しいバージョンの説明を含むen.wikipedia.org/wiki/In-place_algorithmを参照してください。
Dean Povey、2010年

回答:


283

次のように、int配列を反転するには、中点に到達するまでアイテムを交換します。

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

あなたがそれをしている方法では、各要素を2回交換するので、結果は最初のリストと同じです。


そしてvalidData.length / 2、forループの外側に部品を入れたいと思います。
ジンクォン2014年

7
@ジン私はしません。それは意味を難読化するだけであり、とにかく最適化コンパイラーがあなたのためにそれをやると思います。いずれにせよ、プロファイリングからそれが必要/有用であるという明確な証拠が得られるまで、マイクロ最適化を行う意味はありません。
Nicu Stiurca 2014

9
@JinKwonそんな感じvalidData.length >> 1です。これは同等で高速ですが、多くのプログラマを混乱させ、優れたコンパイラは自動的にそれを実行します。
ジャスティン

2
この計算は1回だけ実行validData.length - i - 1して、変数に保存する必要があります。

誰でも一時変数なしで逆転を提案できますか?
sg28 2018

303

ではCommons.Lang、あなたは単に使用することができます

ArrayUtils.reverse(int[] array)

ほとんどの場合、問題を処理するときに、すでにユニットテストとユーザーテストが行​​われている簡単に利用できるライブラリを使用するほうが、より速く、より安全です。


3
私はそれが機能のようなスタイルのために反転した(渡された)配列を返すことを好んだでしょう。
Laurent G

2
@ laurent-gは公平です:この方法で配列を逆にすることは、よりメモリ効率がよくなります。これが、おそらく彼らがこのようにした理由です。
Sirmyself

4
私のポイントはコピーではないか、コピーではありませんでした。私のメッセージは、「(渡された)」が返される(反転された後)と述べているので、別のステートメントを必要とせずに式で渡すことができます。
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
もちろんそうです。リストはプリミティブではなくオブジェクトのみを保持できるため、すべてのプリミティブ(intこの場合はs)はそれぞれのラッパー(Integerこの場合はs )にラップされ、リストに入れられます。ご覧Integerのとおり、sはオブジェクトです。@トム
11684

6
注意:私が間違っていない場合は、元の配列が変更されます。明確にするために、何も返さないほうがよい場合があります。
Andrea Zilio 2013

3
@ 11684はい、ジェネリックリストはオブジェクトのみを保持できます。ただし、メソッドは配列を除きます。配列はプリミティブを保持できます。したがってint[]とは異なりInteger[]ます。試してみてくださいInteger[] array = new int[5]。コンパイルエラーが発生します。これが、Java Arraysクラスがプリミティブ配列を操作するための一連のメソッドを定義する理由です。int[]上記のメソッドにを渡そうとすると、のような結果になりThe method reverse(Object[]) in the type MakeSimple is not applicable for the arguments (int[])ます。@Filip-インプレースアルゴリズムは、より少ないメモリを使用し、より高速に実行されます。
Brian McCutchon 2014年

3
@Andrea実はそうではありません。によって返されるリストはArrays.asList()元の配列を参照せず、返される配列も参照しません。これはこの方法の問題の1つです。メモリを3倍に使用し、インプレースアルゴリズムとして作業を3倍にします。
Brian McCutchon 2014年

4
このメソッド自体は機能する可能性がint[]ありますが、このメソッドに引数としてを渡すことはできません(「互換性のない型:int []はObject []に変換できません」)。
MC皇帝

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

java.util.Collections.reverse()java.util.Listsを逆にjava.util.Arrays.asList()して、渡した特定の配列をラップするリストを返すためyourArray、の呼び出し後に逆になりますCollections.reverse()

コストは1つのListオブジェクトを作成するだけで、追加のライブラリは必要ありません。

同様の解決策がTarikとそのコメントの回答にも示されていますが、この回答はより簡潔で、より簡単に解析できると思います。


14
オブジェクトの配列の場合、これは良い解決策です。ただし、プリミティブの配列に対しては機能しません。例:int[]to asList(...)を渡すとは返されませんList<Integer>が、List<int[]>1つの要素を含むが返されます。AFAICSには、int[]をに変換する単純な組み込みの方法はありませんInteger[]
Martin Rust

4
これはプリミティブ配列では機能しません...コレクションは値を返さないので、メモリ内にリストとして役に立たない配列があります
NightSkyCode

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

39

ループの各反復でスワップしているインデックスを追跡するために明示的な変数を宣言すると、アルゴリズムのロジックに従う方が少し簡単になると思います。

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

また、これを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--;
    }
}

古い学校の交換はより簡単に見えますが、配列のインデックス値の左、右、...を含む場合、そうであればデバッグに役立ちます
Srinath Ganesh

また、「public static void swap(int [] data、int index1、int index2){...}」を追加して、「reverse」から次のように使用することもできます:swap(data、left、right)。
pm_

13

ここにはすでに多くの答えがあり、主に配列をその場で変更することに焦点を当てています。ただし、完全を期すために、Javaストリームを使用して元の配列を保持し、新しい反転配列を作成する別のアプローチを次に示します。

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

10

グアバで:

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

4
これは素晴らしいです!短くて効果的。すべてのasListメソッドと同様に、バッキング(プリミティブ)配列に直接書き込むビューを作成します。ここの反対投票者は、これが箱入りのリストか何かを返したと誤って考えたと思います。
ルークアッシャーウッド16

@LukeUsherwoodおそらく、各要素に対してgetおよびsetを呼び出すときに、ボクシングとアンボクシングからのオーバーヘッドがまだ存在します。しかし、これは素晴らしい解決策であると私はあなたに同意します。
Patrick Parker

確かに、それは知っておく価値があります。私が個人的に扱っているコードの大部分でそれが大したことになるとは思わない-私たちの「ホット」領域は明確に定義されており、残りは一種の「グルーコード」です。同時に、メモリチャーンは、プロファイラーが実際の機能に起因しない追加の「隠された」コストを生み出すことにも自信があります。
ルークアッシャーウッド2017

@LukeUsherwoodはまだプリム配列の代わりにボックス化リストを返します
AnthonyJClink

2
@AnthonyJClink「それ」が何を指しているのかわかりませんが、JDKユーティリティCollections.reverseはvoidメソッドです。これは、をラップするGuava内部クラスでインプレースで動作しますint[](ボックス化されたIntegersのリストを格納することはないため、クラスを「ボックス化リスト」と呼ぶのではなく、「配列のリストビュー」と呼びます)。しかし、はいInteger、オブジェクトを渡すインターフェイスを介して動作するため、前述のように、一時的なオブジェクトのチャーンとボクシングが大量に発生します。IntStreamパフォーマンスが重要な場合は、またはプリミティブコレクションライブラリを試してください。(Trove、Koloboke、Eclipseコレクションなど)
Luke Usherwood、2018年

9

Java 8の場合、IntStream次のように整数の配列を逆にするためにも使用できます。

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]



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

残念ながら、これはここで利用できる最も明確な答えです。すべての開発者がそれを行う方法を知っており、拡張パッケージのインストールを必要としないためです。
HoldOffHunger 2017年

4

これは私が個人的に解決する方法です。パラメータ化されたメソッドを作成する背後にある理由は、整数だけでなく、配列をソートできるようにするためです。

あなたはそれから何かを集めることを望みます。

@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
プリミティブを使用して元の問題を解決しません。
Melinda Green、

プリムをオブジェクトに変換する方法はたくさんあります。私は常にJavaで可能な限りプリムを避けることをお勧めします。また、推奨されると信じています。
AnthonyJClink 2015

長さが不明なプリミティブの配列を配列に変換することは、特にそれを実現せずに行う場合、非常に悪い考えかもしれません。JavaはSmalltalkではありません。プリミティブは言語の一部であり、その場所があります。それらが気に入らなくてもかまいません。それらを受け入れ、必要に応じて使用する必要があります。
Melinda Green

1
実際には、配列をコピーする必要はありませんCollections.reverse(asList(arraytoReverse)); return arrayToReverse;asListは配列のラッパーにすぎないため、元の配列は逆になります。
Radiodef、2015年

3

プログラムはでのみ機能しlength = 0, 1ます。あなたが試すことができます :

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

3
おそらく、メソッド呼び出しではなく、インラインスワップの疑似コードとしてスワップを意味していましたが、そうでない場合は機能しません。Javaは参照渡しであるため、変数のスワップメソッドを作成することはできません。
Dean Povey、2010年

私は、v [i]とv [j]を交換できる方法を意味しました。Javaでメソッド呼び出しがどのように機能するかを知っています。メソッドについては、swap(v、i ++、j--);のようなことができます。
fastcodejava

1
Dean、配列validDataはオブジェクトであり、参照によって渡されるため、swap()メソッドは完全に機能します。
ガエル・Oberson

3

よりプリミティブなデータ(char、byte、intなど)を扱う場合は、楽しい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
実際にプロダクションコードで使用するには可愛すぎますが、それでも楽しいです。可愛らしさを最大限に引き出すには、%=演算を次のように使用します:array [i]%= array [len-i-1]など
Melinda Green

似ていますが、少し短い:for (int m = x.length, i = --m / 2; ++i <= m;) { x[i] ^= x[m - i]; x[i] ^= x[m - i] ^= x[i]; }
トーマス・ミュラー

2

単純に配列を逆方向に反復することが最も効率的です。

アーロンのソリューションがこのviをこの呼び出しで実行するCollections.reverse(list);かどうかはわかりませんが、誰か知っていますか?


配列を逆方向に反復するには、新しい配列が必要です。私は、新しい配列を作成せずにインライン反転を行う上記のソリューションが好きです。
mmcdole 2010年

1
@Simucalなぜ新しい配列を作成するのですか?逆方向に繰り返すだけです。
Trejkaz、2015年

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
はい、私は同じで明確なコードを試しましたが、出力はint [] a = {1,3,5,2,6,7}です。for(int i = a.length-1; i> = 0; i--){System.out.print(a [i] + "");} `配列を最後のインデックスから最初のインデックスに逆にします
Rocket_03

1

この方法でこれを行うと、間違いが発生する可能性がはるかに低くなりますか?

    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

o(n)時間の複雑さと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--;
    }
}

参考までに、これは複雑なforループに単純化できますfor (int start = 0, end = array.length - 1; start < end; start++, end--) { ... }
Tim Cooke

1

配列を逆にする2つの方法。

  1. Forループを使用し、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. 組み込み関数の使用(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));

    }

    出力:[6、5、4、3、2、1]


3
なにInts
CodingNow

@CodingNowこれはGuavaユーティリティヘルパークラスの1つです- ここを
mrec

0

以下は、マシンで実行する完全なプログラムです。

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

配列を使用する行列のプログラムの場合、これは良いソースになります。リンクをたどってください。


0

XORソリューションを使用して、コードが次のようになるはずの一時変数を回避する

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

より良い説明はこのリンクを見てください:

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
回答に説明を追加することを検討してください。コードのみの回答では何も説明されません。
rgettman 14

0

ここでの逆配列に単純な実装であり、任意の型、プラスフル/部分的にサポート。

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

}

これは対応する単体テストです

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

これが私が思いついたものです:

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

問題を解決するには2つの方法があります。

1.空間で配列を反転します。

手順1.開始インデックスと終了インデックスの要素を交換します。

手順2.開始インデックスをインクリメントして、終了インデックスをデクリメントします。

ステップ3.開始インデックス<終了インデックスまでステップ1とステップ2を繰り返す

このため、時間の複雑度はO(n)になり、空間の複雑度はO(1)になります。

空間で配列を逆にするサンプルコードは次のようになります。

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.補助配列を使用して配列を反転します。

手順1.指定された配列と同じサイズの新しい配列を作成します。

ステップ2.開始インデックスから開始して、指定された配列から終了インデックスから開始して、新しい配列に要素を挿入します。

このため、時間の複雑度はO(n)になり、空間の複雑度はO(n)になります。

補助配列で配列を逆にするためのサンプルコードは次のようになります。

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

また、JavaのコレクションAPIを使用してこれを行うこともできます。

コレクションAPIは、内部で同じ逆空間アプローチを使用します。

コレクションAPIを使用するためのサンプルコードは次のとおりです。

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

上記のいくつかの素晴らしい答えがありますが、これは私がそれをした方法です:

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.