Set — HashSet, TreeSet, LinkedHashSet

Set — শুধু unique element; Map-এর প্রতিচ্ছবি

Read: ~25 min Intermediate 5 practice problems Live code runner

1. The Set Contract

A Set<T> is a collection that does not allow duplicates. If you add an element that is already present (per equals), the set remains unchanged. That one rule — plus the same three flavors as Map — is the whole story.

Set<T> হলো duplicate-বিহীন collection। একই element (equals-অনুযায়ী) আবার add করলে set-এ নতুন কিছু ঢোকে না। Map-এর মতই তিনটি flavor: HashSet, TreeSet, LinkedHashSet।
Internals: HashSet is literally a HashMap where values are a dummy constant. TreeSet wraps a TreeMap. LinkedHashSet wraps a LinkedHashMap. Master Maps and you have mastered Sets.

ভেতরের সত্য — HashSet আসলে একটি HashMap, যেখানে value একটি ডামি constant; TreeSet-এর ভেতরে TreeMap; LinkedHashSet-এর ভেতরে LinkedHashMap।

2. HashSet — Fast, Unordered

Average O(1) for add, contains, remove. No order guarantee.

HashSet — add/contains/remove গড়ে O(1), কোনো order guarantee নেই।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        Set<String> s = new HashSet<>();
        s.add("Dhaka");
        s.add("Chattogram");
        s.add("Dhaka");     // duplicate — ignored
        s.add("Sylhet");

        System.out.println("size = " + s.size());
        System.out.println("has Sylhet? " + s.contains("Sylhet"));
        System.out.println(s);
    }
}

3. TreeSet & LinkedHashSet

TreeSet keeps elements in sorted order (O(log n)). LinkedHashSet keeps insertion order at HashSet speed.

TreeSet sorted order রাখে (O(log n)); LinkedHashSet insertion order রাখে HashSet-এর গতিতেই।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        TreeSet<Integer> t = new TreeSet<>(List.of(3, 1, 4, 1, 5, 9, 2, 6));
        System.out.println("sorted:  " + t);
        System.out.println("first:   " + t.first());
        System.out.println("last:    " + t.last());
        System.out.println("floor(5): " + t.floor(5));
        System.out.println("ceil(7):  " + t.ceiling(7));

        Set<String> lh = new LinkedHashSet<>();
        lh.add("gamma"); lh.add("alpha"); lh.add("beta");
        System.out.println("insertion order: " + lh);
    }
}

4. Set Algebra — Union, Intersection, Difference

Java doesn't have built-in union/intersection operators, but addAll, retainAll, and removeAll do exactly that — on a copy.

Java-তে union/intersection-এর operator নেই, কিন্তু একটি copy-র উপর addAll, retainAll, removeAll ঠিক সেটাই করে।
A ∪ B · A ∩ B · A − B A B A ∩ B addAll = ∪ · retainAll = ∩ · removeAll = − Figure 25.1 — Set algebra via addAll/retainAll/removeAll।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        Set<Integer> a = new HashSet<>(List.of(1, 2, 3, 4));
        Set<Integer> b = new HashSet<>(List.of(3, 4, 5, 6));

        Set<Integer> union = new HashSet<>(a); union.addAll(b);
        Set<Integer> inter = new HashSet<>(a); inter.retainAll(b);
        Set<Integer> diff  = new HashSet<>(a); diff.removeAll(b);

        System.out.println("A ∪ B = " + union);
        System.out.println("A ∩ B = " + inter);
        System.out.println("A − B = " + diff);
    }
}

5. Custom Objects — equals & hashCode Required

For your own classes to work correctly in a HashSet, you must override both equals and hashCode. For TreeSet, the class must implement Comparable (or you must pass a Comparator).

নিজের class HashSet-এ সঠিকভাবে রাখতে হলে equals ও hashCode দুটিই override জরুরি। TreeSet-এর জন্য Comparable implement করুন অথবা Comparator দিন।
Main.java
import java.util.*;

class Main {
    record Point(int x, int y) {}  // records auto-impl equals & hashCode

    public static void main(String[] args) {
        Set<Point> s = new HashSet<>();
        s.add(new Point(1, 2));
        s.add(new Point(1, 2));    // duplicate — same equals/hashCode
        s.add(new Point(3, 4));
        System.out.println("unique points: " + s);
        System.out.println("size = " + s.size());    // 2
    }
}

6. Vocabulary

TermMeaningবাংলায়
HashSetO(1) avg, no order.দ্রুত, order নেই।
TreeSetO(log n), sorted iteration, navigational methods.Sorted; floor/ceiling আছে।
LinkedHashSetO(1) avg, insertion order iteration.Insertion order রাখা হয়।
addAllUnion with another collection.Union।
retainAllIntersection.Intersection।
removeAllSet difference.Set difference।

7. Practice Problems

  1. Count the number of unique words in "the cat sat on the mat".
    "the cat sat on the mat"-এ unique শব্দের সংখ্যা বের করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            Set<String> u = new HashSet<>(List.of("the", "cat", "sat", "on", "the", "mat"));
            System.out.println("unique = " + u.size());
            System.out.println(u);
        }
    }
  2. Compute A ∩ B for A = {1,2,3,4} and B = {3,4,5,6}.
    A = {1,2,3,4} ও B = {3,4,5,6}-এর intersection বের করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            Set<Integer> a = new HashSet<>(List.of(1, 2, 3, 4));
            Set<Integer> b = new HashSet<>(List.of(3, 4, 5, 6));
            a.retainAll(b);
            System.out.println(a);
        }
    }
  3. Print every integer in {8, 1, 3, 9, 2, 7} in ascending order without sorting manually.
    Manually sort না করে {8,1,3,9,2,7} ascending order-এ প্রিন্ট করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            TreeSet<Integer> t = new TreeSet<>(List.of(8, 1, 3, 9, 2, 7));
            for (int n : t) System.out.println(n);
        }
    }
  4. Why does a HashSet<Person> containing two "equal" people sometimes show size 2?
    HashSet<Person>-এ দুটি "equal" Person কেন কখনো size 2 দেখায়?
    ✨ Show Answer

    Answer: It happens when the class overrides equals but not hashCode (or vice versa). HashSet routes by hash first, then compares; mismatched hash codes place the two "equal" objects in different buckets, so the set never detects the duplicate. Always override both — or use a record, which generates them for you.

    তখনই হয় যখন equals override করা হয়েছে কিন্তু hashCode নয় (বা উল্টো)। HashSet প্রথমে hash দিয়ে bucket খোঁজে — mismatched hashCode দুটি equal object-কে আলাদা bucket-এ রাখে, তাই duplicate ধরা পড়ে না। সব সময় দুটিই override করুন, অথবা record ব্যবহার করুন।

  5. Use a LinkedHashSet to dedupe a list while preserving first-occurrence order.
    LinkedHashSet দিয়ে প্রথম উপস্থিতির order রেখে একটি list dedupe করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            List<String> xs = List.of("a", "b", "a", "c", "b", "d");
            Set<String> uniq = new LinkedHashSet<>(xs);
            System.out.println(uniq);
        }
    }

Summary — Module 25

A Set is a duplicate-free collection. HashSet is fast and unordered, TreeSet is sorted, LinkedHashSet preserves insertion order. Correct equals/hashCode on element classes is non-negotiable. Set algebra (addAll, retainAll, removeAll) lets you do union, intersection, and difference in one line.

Set হলো duplicate-free collection। HashSet দ্রুত-unordered, TreeSet sorted, LinkedHashSet insertion order রাখে। Element class-এ সঠিক equals/hashCode অত্যাবশ্যক। Union/intersection/difference এক লাইনেই সম্ভব।

Next Module → Queue, Deque ও PriorityQueue — algorithm-এর মেরুদণ্ড।