› Module 10: The Collections Framework › 10.3 Set: HashSet and TreeSet
M O D U L E

Module 10: The Collections Framework

Architecture of java.util collections: List, Set, Queue, and Map implementations, asymptotic complexities, and hashing mechanics.

10.1 Collection Hierarchy Overview

The Java Collections Framework (JCF) provides a unified architecture for storing and manipulating groups of objects. It eliminates the need to manually build linked lists, dynamic arrays, hash tables, and search trees.

The Three Main Collection Interfaces

  • List: An ordered sequence of elements that allows duplicate values. Elements are indexed with zero-based integers. (Implementations: ArrayList, LinkedList, Vector).
  • Set: An unordered collection that guarantees no duplicate elements. (Implementations: HashSet, LinkedHashSet, TreeSet).
  • Queue: Designed specifically for holding elements prior to processing, typically in First-In, First-Out (FIFO) or priority order. (Implementations: ArrayDeque, PriorityQueue, LinkedList).

Note on Map: A Map stores key-value pairs rather than individual elements. Because a mapping of keys to values has fundamentally different operational semantics (e.g. put, get, keySet), Map sits in a separate hierarchy and does NOT extend Collection.

Collection (interface) List (ordered, dupes OK) ArrayList, LinkedList Set (no duplicates) HashSet, TreeSet Queue (FIFO processing) ArrayDeque, PriorityQueue Map (HashMap, TreeMap) is a separate hierarchy — it does not extend Collection.
Figure 10.1 — The Collection interface family: List, Set, and Queue implementations.

10.2 List: ArrayList and LinkedList

Choosing between ArrayList and LinkedList is a classic algorithmic engineering trade-off:

Comparative Analysis

  • ArrayList: Backed internally by a dynamically resizing array.
    • Random Access get(i): $O(1)$ constant time (direct memory indexing).
    • Middle Insertions/Deletions: $O(n)$ linear time because subsequent elements must shift left or right in memory.
    • Capacity Growth: Expands by 50% ($1.5 imes$) whenever its internal buffer reaches capacity.
  • LinkedList: Backed by a doubly-linked chain of node objects.
    • Head/Tail Insertions/Deletions: $O(1)$ constant time (only pointer links change).
    • Random Access get(i): $O(n)$ linear time (must traverse pointers from head or tail).
    • Memory Overhead: Higher memory consumption due to node object allocation and two reference pointers (next and prev) per element.

💡 Placement & Interview Deep-Dive

Rule of Thumb: Default to ArrayList for virtually all general-purpose tasks because CPU cache locality and contiguous memory access make it vastly superior in practice. Use LinkedList (or better, ArrayDeque) only when implementing queues or frequently inserting/removing elements at the ends.

10.3 Set: HashSet and TreeSet

Sets guarantee that no duplicate elements exist within the collection. Java provides two primary set implementations:

  • HashSet: Backed internally by a HashMap instance.
    • Provides average $O(1)$ time complexity for add, remove, and contains.
    • Elements have unspecified iteration order.
    • Detects duplicates using the elements' hashCode() and equals() methods.
  • TreeSet: Backed internally by a self-balancing binary search tree (specifically, a Red-Black Tree / TreeMap).
    • Provides guaranteed $O(log n)$ time complexity for fundamental operations.
    • Maintains elements in strictly sorted natural ascending order (or according to a custom Comparator).
    • Detects duplicates using compareTo() or compare() (returns 0).

10.4 Map: HashMap and TreeMap

A Map associates unique keys with corresponding values. Duplicate keys are prohibited; inserting a duplicate key overwrites the existing value associated with that key.

Map<String, Integer> ages = new HashMap<>();
ages.put("Amit", 21);
ages.put("Neha", 23);
"Amit" hash 21 bucket "Neha" hash 23 bucket
Figure 10.4 — A HashMap stores unique keys, each mapped to one value, via hashing.

💡 Placement & Interview Deep-Dive: HashMap Internals & Java 8 Treeification

  • How does HashMap.put(key, value) work under the hood?
    1. Calls key.hashCode() and applies a supplemental hash function to distribute bits.
    2. Calculates bucket index: index = (n - 1) & hash where n is array capacity (default 16).
    3. If the bucket is empty, a new Node is stored directly.
    4. If a collision occurs (two different keys hash to the same bucket), elements form a linked list via separate chaining.
    5. Java 8 Treeification: When the number of collided elements in a single bucket reaches 8 (and total table capacity $ge 64$), the bucket converts from a linked list to a balanced Red-Black Tree. This changes worst-case lookup from $O(n)$ down to $O(log n)$!
  • The equals() and hashCode() Contract: If a.equals(b) is true, then a.hashCode() == b.hashCode() MUST be true! If you fail to override both together, a HashMap will fail to find entries or store duplicate keys.
MODULE COMPREHENSIVE QUIZ

Module 10 Final Quiz

Test your understanding across all 4 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 10 Final Quiz →
Yukti Mascot