2016-05-11 10 views
0

これは、配列内の反転をカウントするためのJavaコードです。'count'の値が異なる再帰間で保持されないのはなぜですか?

private void findInversions(int begin, int end, Integer count) { 
    System.out.println("begin: " + begin + ", end: " + end + ", and count is " + count); 
    if (end - begin < 1) 
     return; 
    int middle = (begin + end)/2; 
    findInversions(begin, middle, count); 
    System.out.println("begin: " + begin + ", end: " + end + ", here count is " + count); 
    findInversions(middle + 1, end, count); 
    mergeAndCount(begin, middle, end, count); 
    System.out.println("begin: " + begin + ", end: " + end + ", count now is: " + count); 
} 



private void mergeAndCount(int begin, int middle, int end, Integer count) { 

    int[] result = new int[end - begin + 1]; 
    int aptr = begin; 
    int bptr = middle + 1; 
    for (int i = 0; i < result.length; i++) { 
     if (aptr <= middle && bptr <= end) { 
      if (numbers[aptr] < numbers[bptr]) { 
       result[i] = numbers[aptr]; 
       aptr++; 
      } 
      else { // numbers[aptr] > numbers[bptr] 
       // (a[aptr], b[bptr]) is an inversion here 
       count++; 
       System.out.println("Found: (" + numbers[aptr] + "," + numbers[bptr] + ") " + count); 
       result[i] = numbers[bptr]; 
       bptr++; 
      } 
     } 
     else if (aptr > middle) { 
      result[i] = numbers[bptr]; 
      bptr++; 
     } 
     else if (bptr > end) { 
      result[i] = numbers[aptr]; 
      aptr++; 
     } 

    } 

    for (int i = 0; i < result.length; i++) { 
     numbers[begin + i] = result[i]; 
    } 

} 

反転がうまく印刷されているが、それは再帰呼び出しが戻った後にその価値を失うのでcountは、決して正しいです。私は数回デバッグしましたが、再帰が終了したときにcountが再び0になったことがわかりましたが、なぜそれを見つけることができませんでした。誰でも説明できますか?

+4

なぜあなたはそれが保存されると思いますか? Javaは、 'Integer'オブジェクトなどの参照を含むすべての値渡しを使用します。 'count ++'は新しい 'Integer'オブジェクトを生成することに注意してください。すべてのJavaラッパー・タイプは不変です。もしあなたが望むのであれば、 'AtomicInteger'を可変ラッパー型として使うことができます。 –

+2

は' 'javaがpass-by-value'であるためです(http://stackoverflow.com/questions/40480/is-java-pass-参照渡しによる値渡し) – SomeJavaGuy

+0

Integerクラスはjavaで不変ではありませんか? –

答えて

2

Integerは不変クラスです。 count++を実行すると、値はintに自動アンボックスされ、このintがインクリメントされ、結果はcountに割り当てられます。しかし、メソッドに埋め込んだインスタンスは変更しないでください。あなたはe。 g。 AtomicIntegerインスタンスを使用し、incrementAndGet()またはgetAndIncrement()メソッドを使用します。

+0

ありがとうございます。しかし、Integerが変更可能であっても、なぜ動作しませんか?私は価値が正しく変更されることを意味する? –

+0

できません。あなたが私の答えで読むことができるように、新しい値が割り当てられたボクシングが解除されているので、新しいオブジェクトと同じオブジェクトが変更されていません。 'Integer'が変更可能で**かつ** increment()メソッドを持っていれば** ++の代わりにそれを使用します(Javaでは演算子のオーバーロードはありません)、**それから** it 'AtomicInteger'を使うとそうであるように動作します。なぜなら、これらはすべてそれに当てはまるからです。いくらかの同期オーバーヘッドが追加されるため、パフォーマンスが重要な場合は、代わりにintメソッドとインクリメントメソッドを使用して独自のホルダークラスを作成することができます。 – Vampire

1

mergeAndCount()メソッドを返す必要があります。これらのメソッドを呼び出すメソッドは、戻り値を使用する必要があります。そして、私はそれを整数型にしましたが、必要はありません。プリミティブintを使用することができます。

private Integer findInversions(int begin, int end, Integer count) { 
    // ... do all your stuff here but change recursive calls: 
    count += findInversions(begin, end, count); 
    count += mergeAndCount(begin, middle, end, count0; 
    // and return what you find 
    return count; 
} 

private Integer mergeAndCount(int begin, int middle, int end, Integer count) { 
    // ... do all your stuff here 
    return count; 
} 

あなたの他の代替numbersは明らかにあなたのカウントクラスのフィールドであるため、クラスのフィールドとしてcount維持することです。それはあなたが求めるものと同じ効果があります。

+0

お時間をありがとう。私は再帰(と思った!)でエクササイズのパラメータとして 'count'を渡し続けたいと思っていました。私はコード全体にこのバグがあったと思っていたので、このようにしておき、それを見つけ出すことを主張しました。 あなたはあなたの答えをアップアップするのに十分なほどの評判がないと言うことができます。 –

関連する問題