web-dev-qa-db-ja.com

HashSetとArrayList

だから私は別のカスタムクラスの学生のセットを持つカスタムクラスクラスを持っています。したがって、次のようになります。

public class Class {
    private Set<Student> students;

    // other methods
}

今度は、セットの学生に多くの学生を追加および削除します。また、すでにセットの学生の学生のプライベートフィールドの多くを変更します。

質問:これを最適に実装するには、どのデータ構造を使用する必要がありますか?セットstudentのStudentオブジェクトのプロパティを変更する(それによってハッシュコードを変更する)ので、代わりにArrayListを使用する必要がありますか?

9
Q Liu

これを最適に実装するには、どのデータ構造を使用する必要がありますか?セットstudentのStudentオブジェクトのプロパティを変更する(それによってハッシュコードを変更する)ので、代わりにArrayListを使用する必要がありますか?

セット要素のハッシュコードが変更される可能性がある場合は、HashSetを使用しないでください。 (そうすると、データ構造が壊れ、セット内の要素が失われる可能性があります。)

しかし、ArrayListも使用する必要があるとは思えません。なぜなら、hashcode()がオブジェクトの変更に敏感である場合、equals(Object)もそうなる可能性が高いからです。つまり、contains(...)や同様のメソッドはオブジェクトを見つけることができません。

Map型を使用し、キーとして「学生識別子」を使用する必要があると思います。

hashcodeequalsをオーバーライドして、2つのオブジェクトが同じIDを持つことを意味するようにすることもできます。ただし、equals(Object)は他の目的には使用できません。)

4
Stephen C

ArrayListHashSetの動作に関しては、これらは完全に異なるクラスです。

配列リスト

  • ArrayList重複を検証しません。
  • get()O(1)です
  • contains()O(n)ですが、エントリの順序は完全に制御できます。

    _                      get  add  contains next remove(0) iterator.remove
    ArrayList             O(1) O(1) O(n)     O(1) O(1)      O(1)
    _
  • スレッドセーフではありません。スレッドセーフにするには、Collections.synchronizedList(...)を使用する必要があります。

HashSet

  • HashSetは、重複がないことを保証します。
  • O(1)contains()メソッドを提供しますが、順序は保持されません。

    _                      add      contains next     notes
    HashSet               O(1)     O(1)     O(h/n)   h is the table 
    _
  • スレッドセーフではありません。スレッドセーフにするには、Collections.synchronizedSet(...)を使用する必要があります。
11
tk_

コードに重複データがある場合は、ArrayListを使用する必要があります。それ以外の場合は、以下に示すようにハッシュセットを使用できます。したがって、コードで重複値が必要ない場合は、リストの代わりにセットを使用します。これにより、セットのパフォーマンスが大幅に向上します(O( n)対O(n ^ 2)(リストの場合)。重複を回避することがセットの目的であるため、これは正常です。

配列リスト

public static void main(String [] args){

ArrayList arr =new ArrayList();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr);  //As we are using Arraylist therefore 
                          //the duplicate elements are allowed therefore
                          //"Hello" is not removed in the output

}

HashSet

public static void main(String [] args){

HashSet arr =new HashSet();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr);  //As we are using Hashset therefore 
                          //the duplicate elements removed therefore
                          //"Hello" is removed in the output

}

3
Rajat

場合によります。あなたが学生について話しているので、idやrollnoのようなユニークなものがあるに違いありません。はいの場合、ハッシュコードメソッドをオーバーライドし、IDに基づいてハッシュコードを実装します。その後、studentの他のプロパティを変更しても、ハッシュコードに影響はありません。

セットまたはリストを選択するかどうかは、要件によって異なります。このリンクを読むと、セットとリストの違いが明確になります
セットとリストの違いは何ですか?

また、セット内のオブジェクトを使用している場合は、ハッシュコードとequalsメソッドの両方をオーバーライドして、制御できるようにすることができます。独自性のはあなたの手にあります。

2
Ashish Aggarwal

あなたの要件から、私は最良の構造はマップであるべきだと思いました。実際に基礎となるSetは、内部のMap構造を使用します。また、ルックアップを改善するために、equalsメソッドのオーバーライドにも注意する必要があります。また、setとarraylistは、ターゲットオブジェクトを検索するために、検索アルゴリズムを使用する必要があるため、期待したほど効率的ではありません(特に、非常に大規模なコレクションの状況で)。マップでさえいくらかのスペースを浪費しますが、IDが何らかのプリミティブ型である場合は、 Troveライブラリ でマップ実装のプリミティブ型を検討できます。

1
Andy Song

質問:これを最適に実装するには、どのデータ構造を使用する必要がありますか?セットstudentのStudentオブジェクトのプロパティを変更する(それによってハッシュコードを変更する)ので、代わりにArrayListを使用する必要がありますか?

間違いなく、hashCodeまたはequalsで使用される値を変更する場合、HashMapまたはHashSetを使用することはできません。

あなたはあなたがたくさん削除して追加したいと言っています。問題は、それを連続的に実行するか、ランダムに(インデックスに基づいて)実行するかです。追加する場合は、順番に削除してください。間違いなく最良の選択はLinkedListです。オブジェクトにランダムにアクセスする場合は、ArrayListの方がはるかに効率的です。

1

HashSetなどのハッシュコレクションの場合、キーはimmutableである必要があります。ハッシュセットは、内部でハッシュを使用して、オブジェクトを格納するバケットを決定します。また、オブジェクトを取得している間、ハッシュを使用してオブジェクトバケットを検索します。保存後にオブジェクトを変更すると、オブジェクトのハッシュコードが変更され、Setが正しいオブジェクトを取得できない場合があります。コレクションにオブジェクトを追加した後でもオブジェクトを変更する必要がある場合は、ハッシュ化されたコレクションを使用することはお勧めできません。むしろArraylistを選択しますが、ArrayListを使用すると、セットの場合と同様に、目的の生徒をすばやく取得できるという利点が失われることに注意してください。

0
Juned Ahsan

オブジェクトのSetメソッドの結果が変更される場合は、equalsを使用しないでください。安定した一意のID番号で学生を識別していて、equalsがそのIDをチェックするだけの場合は、Setを使用しても問題ありません。

HashSetはインデックス作成と比較にhashCodeを使用し、hashCodeequalsを決定するために使用されるフィールドを正確に組み込む必要があることに注意してください。

0

Set のjavadocは

注:可変オブジェクトをセット要素として使用する場合は、細心の注意を払う必要があります。 オブジェクトがセット内の要素であるときに、オブジェクトの値が等しい比較に影響を与える方法で変更された場合、セットの動作は指定されません。この禁止の特別な場合は、セットがそれ自体を要素として含むことは許可されないということです。

したがって、HashSetを使用する場合、不変フィールドに基づいてhashCode()equals()を作成すると、この問題は発生しません。たとえば、インスタンスごとに一意のstudentIDを使用します。

0
nachokk