SetとHashSet

Setは重複のないコレクションです。このレッスンでは、Setの使用方法と重複排除の原則を学びます。

Setインターフェースの特徴

特徴 説明
順序なし 固定の順序がない(HashSet)
重複不可 自動的に重複を排除
インデックスなし インデックスでアクセスできない

HashSet

HashSetはHashMapベースで、最も一般的に使用されるSet実装です。

HashSetの作成

JAVA
import java.util.HashSet;
import java.util.Set;

Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>(100);  // 指定容量
Set<String> set3 = new HashSet<>(set1);  // 他のコレクションから作成

基本操作

JAVA
import java.util.HashSet;
import java.util.Set;

public class HashSetDemo {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        
        // 要素を追加
        set.add("Alice");
        set.add("Bob");
        set.add("Charlie");
        set.add("Alice");  // 重複、追加されない
        System.out.println("Set: " + set);  // [Alice, Bob, Charlie](順序なし)
        
        // チェック
        System.out.println("サイズ: " + set.size());  // 3
        System.out.println("Aliceを含む: " + set.contains("Alice"));  // true
        System.out.println("空か: " + set.isEmpty());  // false
        
        // 削除
        set.remove("Bob");
        System.out.println("削除後: " + set);
        
        // 走査
        for (String name : set) {
            System.out.println(name);
        }
    }
}

重複排除の原則

HashSetはhashCodeとequalsを使用して要素が重複しているかどうかを判断します。

重複排除フロー

TEXT
1. 要素のhashCodeを計算
2. hashCodeが異なる → 重複ではない
3. hashCodeが同じ → equalsを呼び出し
4. equalsがtrueを返す → 重複
5. equalsがfalseを返す → 重複ではない(ハッシュ衝突)

例:カスタムオブジェクトの重複排除

JAVA
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class Student {
    private String name;
    private int age;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // hashCodeとequalsをオーバーライドする必要がある
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    
    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
    
    public static void main(String[] args) {
        Set<Student> set = new HashSet<>();
        set.add(new Student("Alice", 20));
        set.add(new Student("Bob", 22));
        set.add(new Student("Alice", 20));  // 重複、追加されない
        
        System.out.println("サイズ: " + set.size());  // 2
        System.out.println("Set: " + set);
    }
}
▶ 試してみよう
⚠️ 重要: HashSetにカスタムオブジェクトを格納する場合、hashCodeとequalsメソッドをオーバーライドする必要があります。otherwise 重複排除が正しく機能しません。

TreeSet

TreeSetは赤黒木ベースで、要素が自動的にソートされます。

特徴

特徴 説明
順序あり 自然順序またはカスタム順序でソート
重複不可 自動的に重複を排除
インデックスなし インデックスでアクセスできない

例:TreeSet

JAVA
import java.util.Set;
import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        // 自然順序
        Set<Integer> numbers = new TreeSet<>();
        numbers.add(3);
        numbers.add(1);
        numbers.add(4);
        numbers.add(1);  // 重複、追加されない
        numbers.add(5);
        System.out.println("順序付き集合: " + numbers);  // [1, 3, 4, 5]
        
        // 文字列の順序
        Set<String> names = new TreeSet<>();
        names.add("Charlie");
        names.add("Alice");
        names.add("Bob");
        System.out.println("順序付き名前: " + names);  // [Alice, Bob, Charlie]
    }
}
▶ 試してみよう

カスタム順序

JAVA
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class CustomSortDemo {
    public static void main(String[] args) {
        // 長さでソート
        Set<String> words = new TreeSet<>(Comparator.comparingInt(String::length));
        words.add("Hello");
        words.add("Hi");
        words.add("Java");
        words.add("Go");
        System.out.println("長さ順: " + words);  // [Go, Hi, Java, Hello]
    }
}

LinkedHashSet

LinkedHashSetは挿入順序を維持します。

特徴

特徴 説明
順序あり 挿入順に要素を格納
重複不可 自動的に重複を排除

例:LinkedHashSet

JAVA
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>();
        set.add("Charlie");
        set.add("Alice");
        set.add("Bob");
        System.out.println("順序付き集合: " + set);  // [Charlie, Alice, Bob]
    }
}
▶ 試してみよう

集合演算

和集合

JAVA
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3));
Set<Integer> set2 = new HashSet<>(Arrays.asList(3, 4, 5));

Set<Integer> union = new HashSet<>(set1);
union.addAll(set2);
System.out.println("和集合: " + union);  // [1, 2, 3, 4, 5]

積集合

JAVA
Set<Integer> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
System.out.println("積集合: " + intersection);  // [3]

差集合

JAVA
Set<Integer> diff = new HashSet<>(set1);
diff.removeAll(set2);
System.out.println("差集合: " + diff);  // [1, 2]

Setの比較

特徴 HashSet TreeSet LinkedHashSet
順序 順序なし ソート済み 挿入順
実装 HashMap 赤黒木 リンクリスト + HashMap
パフォーマンス O(1) O(log n) O(1)
null 1つ許可 許可しない 1つ許可

選択ガイド

ニーズ 選択
順序を気にしない HashSet
ソートが必要 TreeSet
挿入順序を維持 LinkedHashSet

例:重複排除の練習

JAVA
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class RemoveDuplicates {
    // 方法1:Setによる重複排除
    public static <T> List<T> removeDuplicates1(List<T> list) {
        return new ArrayList<>(new LinkedHashSet<>(list));
    }
    
    // 方法2:Streamによる重複排除
    public static <T> List<T> removeDuplicates2(List<T> list) {
        return list.stream().distinct().collect(Collectors.toList());
    }
    
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Alice");
        list.add("Bob");
        list.add("Alice");
        list.add("Charlie");
        list.add("Bob");
        
        System.out.println("元のリスト: " + list);
        System.out.println("重複排除後: " + removeDuplicates1(list));
    }
}

❓ よくある質問

Q SetとListのどちらを選ぶべきですか?
A 重複排除が必要な場合はSetを使用し、順序付きで重複を許可する場合はListを使用します。
Q TreeSetのソートルールは?
A デフォルトは自然順序(Comparable)です。Comparatorでカスタマイズできます。
Q HashSetはなぜ高速なのですか?
A HashMapベースで、hashCodeを使用して直接検索し、O(1)の時間複雑度を持ちます。

📖 まとめ

📝 演習

  1. 重複排除: Listから重複を削除し、元の順序を維持
  2. 積集合: 2つのSetの積集合を見つける
  3. ソート: TreeSetを使用して文字列を長さでソート

次のレッスン

次のレッスンでは、MapとHashMapを学びます — キーと値のペアコレクション。

100%