TreeSet and NavigableSet
Master sorted set operations with TreeSet and NavigableSet. Learn when logarithmic time complexity beats constant time, how Red-Black trees maintain balance, and when to use ceiling, floor, and range queries for elegant solutions.
π At a Glance
| Aspect | Details |
|---|---|
| Topic | TreeSet, NavigableSet, SortedSet, Red-Black Trees |
| Complexity | Intermediate to Advanced |
| Prerequisites | Part 3 (equals/hashCode), Part 9 (HashSet) |
| Time to Master | 3-4 hours |
| Interview Frequency | High (tree operations, NavigableSet methods) |
π― What You'll Learn
After completing this article, you will be able to:
- Understand TreeSet's Red-Black tree implementation
- Use NavigableSet operations (ceiling, floor, higher, lower) effectively
- Create efficient range queries with subset views
- Choose between TreeSet and HashSet for different use cases
- Avoid ClassCastException with proper Comparable/Comparator usage
Interactive Visualizer
Explore how TreeSet maintains a Binary Search Tree structure - watch as elements are inserted and searched with O(log n) complexity:
Loading visualizer...
Production Story: The Range Query Performance Disaster
The Incident
Our analytics dashboard was timing out. The query to find all events between two timestamps was taking 30+ seconds for power users with millions of events.
The problematic code:
JAVA(15 lines)CodeLoading syntax highlighter...
For a user with 2 million events, this method:
- Iterated through all 2M events: O(n)
- Sorted the results: O(k log k) where k is result size
- Total time: ~30 seconds
The Fix: TreeSet with Range Query
JAVA(18 lines)CodeLoading syntax highlighter...
- Before: O(n) iteration + O(k log k) sort = 30 seconds
- After: O(log n) range lookup + O(k) iteration = 50 milliseconds
- 600x faster!
Why TreeSet Wins for Range Queries
TEXT(21 lines)CodeLoading syntax highlighter...
Lessons Learned
- HashSet is O(1) for exact match, but O(n) for range queries
- TreeSet is O(log n) for everything, including range queries
- NavigableSet's subSet() is a view, not a copy - very efficient
- Choose data structure based on query patterns, not just insert/lookup
Mental Model: The Library Card Catalog
Think of TreeSet as an old-school library card catalog:
TEXT(25 lines)CodeLoading syntax highlighter...
Deep Dive: TreeSet Internals
Red-Black Tree Basics
TEXT(20 lines)CodeLoading syntax highlighter...
TreeSet Construction
JAVA(24 lines)CodeLoading syntax highlighter...
Comparable vs Comparator
JAVA(29 lines)CodeLoading syntax highlighter...
ClassCastException Deep Dive
JAVA(26 lines)CodeLoading syntax highlighter...
Deep Dive: NavigableSet Operations
Core Navigation Methods
JAVA(22 lines)CodeLoading syntax highlighter...
Visual Guide to Navigation
TEXT(18 lines)CodeLoading syntax highlighter...
Polling Operations
JAVA(20 lines)CodeLoading syntax highlighter...
Deep Dive: Subset Views
subSet(), headSet(), tailSet()
JAVA(19 lines)CodeLoading syntax highlighter...
Views Are Live!
JAVA(19 lines)CodeLoading syntax highlighter...
Descending Views
JAVA(22 lines)CodeLoading syntax highlighter...
Deep Dive: Performance Characteristics
Operation Complexity
| Operation | TreeSet | HashSet |
|---|---|---|
| add(e) | O(log n) | O(1) |
| remove(e) | O(log n) | O(1) |
| contains(e) | O(log n) | O(1) |
| first()/last() | O(log n) | N/A |
| ceiling()/floor() | O(log n) | N/A |
| higher()/lower() | O(log n) | N/A |
| subSet() | O(log n) | N/A |
| Iteration | O(n) sorted | O(n) unsorted |
When to Use TreeSet
JAVA(25 lines)CodeLoading syntax highlighter...
When to Use HashSet
JAVA(18 lines)CodeLoading syntax highlighter...
β οΈ Common Mistakes
Mistake 1: Missing Comparable/Comparator
JAVA(21 lines)CodeLoading syntax highlighter...
Mistake 2: Inconsistent compareTo and equals
JAVA(35 lines)CodeLoading syntax highlighter...
Mistake 3: Modifying Elements After Adding
JAVA(21 lines)CodeLoading syntax highlighter...
Mistake 4: subSet() Range Violations
JAVA(10 lines)CodeLoading syntax highlighter...
Mistake 5: Null Handling
JAVA(18 lines)CodeLoading syntax highlighter...
π Debug This
Challenge 1: The Missing Element
JAVA(8 lines)CodeLoading syntax highlighter...
Double.NaN violates comparison contract because NaN.compareTo(x) is inconsistent.NaN is not equal to anything, not even itself, which breaks TreeSet's assumptions. The tree structure becomes corrupted.NaN to TreeSet:JAVA(3 lines)CodeLoading syntax highlighter...
Challenge 2: The Duplicate Elements
JAVA(16 lines)CodeLoading syntax highlighter...
2compareTo returns 0. TreeSet considers them equal and only keeps one.JAVA(6 lines)CodeLoading syntax highlighter...
Challenge 3: The Infinite Loop
JAVA(8 lines)CodeLoading syntax highlighter...
ConcurrentModificationException.Even though we add outside the subSet range, the subSet is a view backed by the original set. Modifying the original set during iteration of the view triggers the fail-fast mechanism.
JAVA(7 lines)CodeLoading syntax highlighter...
π» Exercises
Exercise 1: Find Closest Value
Implement a method that finds the closest value to a target:
JAVA(8 lines)CodeLoading syntax highlighter...
JAVA(12 lines)CodeLoading syntax highlighter...
Exercise 2: Range Count
Implement efficient range counting:
JAVA(7 lines)CodeLoading syntax highlighter...
JAVA(14 lines)CodeLoading syntax highlighter...
Exercise 3: Top K Elements
Implement efficient top-K retrieval:
JAVA(7 lines)CodeLoading syntax highlighter...
JAVA(15 lines)CodeLoading syntax highlighter...
Exercise 4: Scheduling System
Create a scheduling system using TreeSet:
JAVA(10 lines)CodeLoading syntax highlighter...
JAVA(46 lines)CodeLoading syntax highlighter...
Exercise 5: Leaderboard
Implement a game leaderboard with efficient ranking:
JAVA(13 lines)CodeLoading syntax highlighter...
JAVA(58 lines)CodeLoading syntax highlighter...
π€ Senior-Level Interview Questions
Question 1: TreeSet vs HashSet Performance
TreeSet can outperform HashSet in these scenarios:
-
Range queries: Finding elements between X and Y is O(log n + k) for TreeSet vs O(n) for HashSet.
-
Sorted iteration: TreeSet iterates in order naturally. HashSet requires collecting and sorting: O(n log n).
-
Min/Max access: TreeSet provides O(log n) first()/last(). HashSet requires O(n) scan.
-
Navigation queries: ceiling(), floor(), higher(), lower() are O(log n) in TreeSet, impossible efficiently in HashSet.
JAVA(5 lines)CodeLoading syntax highlighter...
Question 2: Red-Black Tree Properties
A simple BST can degenerate to O(n) operations if elements are inserted in sorted order (becomes a linked list). Red-Black trees guarantee O(log n) by maintaining these properties:
- Self-balancing through rotations
- Maximum height of 2 * log(n+1)
- Rebalancing is O(log n) worst case
TEXT(17 lines)CodeLoading syntax highlighter...
Question 3: Comparable Consistency
TreeSet uses compareTo() for both ordering AND equality checking. If compareTo() returns 0 for two objects that aren't equal(), you get unexpected behavior:
JAVA(12 lines)CodeLoading syntax highlighter...
The Java documentation explicitly warns: "The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface."
Question 4: subSet View Behavior
The subSet is a live view backed by the original TreeSet. Modifications to either affect both:
-
Modifying original: Changes visible in subSet (if in range). Triggers ConcurrentModificationException during iteration.
-
Modifying subSet: Changes visible in original. Subject to range restrictions.
JAVA(10 lines)CodeLoading syntax highlighter...
Question 5: Custom Comparator with Natural Ordering
Comparator.comparing().thenComparing():JAVA(21 lines)CodeLoading syntax highlighter...
Question 6: NavigableSet ceiling vs higher
ceiling(e): Returns smallest element >= e (inclusive)higher(e): Returns smallest element > e (exclusive)
JAVA(9 lines)CodeLoading syntax highlighter...
Use cases:
ceiling(): "What's the cheapest option at or above $X?"higher(): "What's the next item after this one?"
π Summary & Key Takeaways
TreeSet Fundamentals
- Backed by Red-Black tree: O(log n) for all operations
- Elements must be Comparable or use Comparator
- No null elements allowed (can't compare null)
- compareTo() determines both ordering AND equality
NavigableSet Operations
ceiling(e)/floor(e): Closest >= / <=higher(e)/lower(e): Strictly > / <pollFirst()/pollLast(): Remove and return extremesdescendingSet(): Reversed view
Subset Views
subSet(),headSet(),tailSet(): Live views- Changes in view affect original (and vice versa)
- Range restrictions enforced on views
- ConcurrentModificationException during iteration with modifications
When to Use TreeSet
- Need sorted iteration
- Range queries (find between X and Y)
- Closest match queries (ceiling/floor)
- Min/Max access needed
- O(log n) is acceptable for add/remove/contains
π Conclusion
TreeSet is more than just a sorted set - it's a powerful tool for range-based queries and navigation operations. The NavigableSet interface provides methods that can replace complex loops with elegant, efficient single calls.
Key takeaways:
- TreeSet uses Red-Black tree for guaranteed O(log n) operations
- Range queries are TreeSet's superpower - O(log n) vs O(n) for HashSet
- Subset views are live - changes propagate bidirectionally
- compareTo() must be consistent with equals() to avoid surprises
- NavigableSet navigation methods (ceiling, floor, higher, lower) enable elegant solutions
In the next article, we'll explore specialized sets like EnumSet and CopyOnWriteArraySet, and when they outperform general-purpose implementations.
π Review Schedule
To solidify your understanding, review this material:
- Tomorrow: Re-read NavigableSet operations (ceiling, floor, etc.)
- In 3 days: Implement Exercise 4 (Scheduler) again
- In 1 week: Explain TreeSet vs HashSet tradeoffs to a colleague
- In 2 weeks: Review the production story and common mistakes