1. 概要

コード内の2つの変数を交換したい場合があります。

このチュートリアルでは、交換する変数のタイプに応じて、これを行うためのいくつかの方法を説明します。 次に、各メソッドのパフォーマンスを確認します。

2. 簡単な方法:一時変数を使用する

2つの変数を交換する最も簡単な方法は、3番目の変数を一時ストレージとして使用することです。

Object a, b;
Object temp;
temp = a;
a = b;
b = temp;

この方法は、初心者でも特に読みやすく、理解しやすい方法です。 その主な欠点は、一時変数が必要なことです。

このメソッドは、Object変数を交換できる唯一のメソッドであることに注意してください。

2.1. メソッドを入れ替えてみませんか?

コード内のいくつかのポイントで変数を交換する必要がある場合は、次のような変数を交換するメソッドを作成するのが魅力的に聞こえるかもしれません。

public void swap(Object a, Object b)

残念ながら、これはJava では機能しません。オブジェクトへの参照は、メソッドの呼び出し中にコピーされるためです。

本当にスワップメソッドが必要な場合は、オブジェクトのラッパークラスを使用して、ラッパーに含まれるオブジェクトをスワップする必要があります。

private class Wrapper {
    public String string;
}

そして、スワップ方法:

private static void swap(Wrapper a, Wrapper b) {
    String temp = b.string;
    b.string = a.string;
    a.string = temp;
}

このメソッドでは、囲まれた Strings は、メソッドが戻った後もスワップされたままになります。

3. 一時変数なし

変数がプリミティブ型の場合、一時変数なしでそれらを交換する方法を見つけることができます。

いくつかの例を見てみましょう。

3.1. 算術演算の使用

数学を使用して、いくつかの方法で一時変数なしで変数を交換できます。 次の例では、2つの整数 a =5b=10を交換するとします。

スワッピングには加算と減算を使用できます。

a = a + b;  // a = 15
b = a - b;  // b = 5
a = a - b;  // a = 10

または、乗算と除算を使用できます。

a = a * b;  // a = 50
b = a / b;  // b = 5
a = a / b;  // a = 10

最初の操作ではゼロが格納され、残りのアルゴリズムが役に立たなくなるため、いずれかの数値が0の場合、このメソッドは機能しないことに注意してください。 さらに、 b = 0の場合、ゼロ除算のためにArithmeticExceptionがスローされます。

加算/乗算により、プリミティブ型の最大値を超える数値が発生する可能性があるため、プリミティブの容量にも注意する必要があります。これにより、例外をスローせずにスワップ後にエラーが発生する可能性があります。

たとえば、 a = Integer.MAX_VALUEの場合、 a =2147483647b= 10 を交換する前、および交換した後、 a = 10 [X137X ]、 b =-1.

char byte 、または short タイプのデータを使用している場合、算術演算子の結果はタイプの値であるため、明示的なキャストが必要です。 ] int 少なくともJavaでは:

a = (char)(a + b);
b = (char)(a - b);
a = (char)(a - b);

3.2. 論理演算の使用

整数データ型(つまり、 char、short、byte、int、long )を使用している場合は、排他的論理和ビット演算子(XOR)を使用できます。 「^」演算子は、変数のすべてのビットに対してビット単位のXOR演算を処理します。

a = a ^ b;  // a = 1111 (15)
b = a ^ b;  // b = 1010 (5) 
a = a ^ b;  // a = 0101 (10)

算術演算子の場合、ビット単位のXOR演算子は少なくともintデータ型を返すことに注意してください。 したがって、chars、bytes、またはshorts変数を使用している場合は、各行のXORの結果をキャストする必要があります。

3.3. 単一行バリアント

1行バージョンのスワッピングメソッドを使用して、コードサイズを減らすことができます。

b = (a + b) – (a = b);
a += b – (b = a);
a = a * b / (b = a);
a = a ^ b ^ (b = a);

これは、式が演算子の優先順位に関して評価されるために機能します。 最初にa=5およびb = 10の場合、最後の式は a = 5 ^ 10 ^(b = 5)と同等です。 最初の操作( 5 ^ 10 )は、マルチラインアルゴリズムの最初の行であり、 b (括弧が優先)に5を割り当て、最後に[ X179X] 15 ^5これはまさにアルゴリズムの3行目です。

4. パフォーマンス分析

Javaで2つの変数を交換する方法はいくつかあることがわかりましたが、どちらがより効率的ですか? 各アルゴリズムのパフォーマンスの傾向を示すために、変数スワッピングメソッドのループを実行し、2つの変数を100.000回スワップするのに必要な時間を測定しました。 テストを10回実行して、各アルゴリズムの平均実行時間を計算しました。 結果は次のとおりです。

絶対時間は、テストを実行しているマシンに依存するため、ここでは重要ではありません。 一部のアルゴリズムが他のアルゴリズムよりも遅いことがわかります。 これは、単一行バージョンのどちらでも大幅に遅い乗算/除算の場合に特に当てはまります。 反対に、XORアルゴリズムは、複数行バージョンと単一行バージョンの両方で最も効率的です。

オブジェクトを一時変数と交換することも非常に効率的です。この場合、ポインターのみが操作されるため、非常に理解しやすくなります。

5. 結論

この記事では、変数のタイプに応じて、Javaで2つの変数を交換する方法について説明しました。

オブジェクトを交換する方法を説明した後、いくつかのアルゴリズムを使用してプリミティブタイプを交換するいくつかの方法を研究しました。 最後に、各メソッドのパフォーマンスを確認しました。

いつものように、すべての例のソースコードは、GitHubから入手できます。