DevNotes
Support
Collection Framework · Chapter 10

TreeSet

Sorted, navigable sets on a Red-Black Tree — Comparable vs Comparator, compare() == 0 duplicates, and floor/ceiling/range views.

◷ 13 min read§ 18 sections? 15 interview questions{ } 34 code examples

#Introduction

TreeSet is the Set implementation to know when the requirement is:

Unique elements + sorted order + range/navigation operations

Unlike HashSet and LinkedHashSet, TreeSet does not use hashing. Its core is a balanced Red-Black Tree.

#What is TreeSet?

TreeSet is a sorted implementation of the Set interface.

Package:

Java
java.util.TreeSet

Declaration:

Java
public class TreeSet<E>
        extends AbstractSet<E>
        implements NavigableSet<E>,
                   Cloneable,
                   Serializable
Iterable
Collection
Set
SortedSet
NavigableSet
TreeSet
The important interfaces are SortedSet and NavigableSet — they add functionality beyond a normal Set

#Key Characteristics

PropertyTreeSet
Duplicates❌ Not allowed
OrderingSorted
Index-based access❌ No
Typical operationsO(log n)
Internal structureRed-Black Tree
NullGenerally not supported
Thread-safe❌ No
Range operations✅ Yes
Navigation✅ Yes

#The Main Difference from HashSet

SetGives you
HashSetUniqueness + fast lookup
LinkedHashSetUniqueness + insertion order
TreeSetUniqueness + sorted order
Java
Set<Integer> set = new TreeSet<>();

set.add(50);
set.add(10);
set.add(40);
set.add(20);
Output
10
20
40
50

The elements are automatically ordered.

#How Does TreeSet Maintain Order?

This is the key internal concept. TreeSet uses a tree-based structure backed by TreeMap.

TreeSet
TreeMap
Red-Black Tree
TreeSet stores its elements as keys in the underlying sorted map

Why a Red-Black Tree?

A normal Binary Search Tree can become unbalanced. Inserting 10, 20, 30, 40 in order makes it effectively a linked list, and search becomes O(n):

10
20
30
40
Unbalanced BST

A Red-Black Tree automatically maintains approximate balance, so the height remains O(log n):

  • 20
    • 10
    • 30
      • 40
Balanced

Therefore search, insert and delete are all O(log n).

What is a Red-Black Tree?

A Red-Black Tree is a self-balancing Binary Search Tree with additional colour information. Each node conceptually holds:

Key
Left
Right
Parent
ColorRED or BLACK
One node

The colouring rules ensure the tree doesn't become excessively unbalanced. You don't need to memorize the complete balancing algorithm unless specifically asked, but you should understand why it exists.

#TreeSet Ordering

There are two ways to define ordering.

1. Natural ordering — Comparable

Java
TreeSet<Integer> set = new TreeSet<>();

Integer already implements Comparable.

2. Custom ordering — Comparator

Java
TreeSet<Integer> set = new TreeSet<>(Comparator.reverseOrder());
Output
50
40
30
20
10

Comparable vs Comparator

This is a major interview topic.

Comparable — the class defines its own natural ordering:

Java
class Employee implements Comparable<Employee> {

    @Override
    public int compareTo(Employee other) {
        return Integer.compare(this.id, other.id);
    }
}
Java
TreeSet<Employee> employees = new TreeSet<>();

Comparator — ordering is supplied externally:

Java
Comparator<Employee> byName = Comparator.comparing(Employee::getName);

TreeSet<Employee> employees = new TreeSet<>(byName);

Natural Ordering Example

Java
TreeSet<String> set = new TreeSet<>();

set.add("Zebra");
set.add("Apple");
set.add("Mango");
set.add("Banana");
Output
Apple
Banana
Mango
Zebra

Strings use their natural ordering.

#How TreeSet Detects Duplicates

TreeSet Doesn't Use equals() to Determine Uniqueness

This is one of the most important TreeSet interview questions. For ordering and duplicate determination, TreeSet uses compareTo() or Comparator.compare().

If compare(a, b) == 0, TreeSet treats them as equivalent for Set purposes, so the element is not added as a separate entry.

Java
TreeSet<Integer> set = new TreeSet<>();

set.add(10);
set.add(10);

The second 10 isn't added because compare(10, 10) == 0.

The Big Difference: HashSet vs TreeSet

HashSet
hashCode() + equals()
Uniqueness
TreeSet
compareTo() / Comparator.compare()
Ordering + uniqueness

This distinction explains most TreeSet interview questions.

Dangerous Comparator Example

Java
class Employee {
    int id;
    String name;
}
Java
Comparator<Employee> comparator = Comparator.comparing(Employee::getName);

Now Employee 101 → John and Employee 102 → John: the comparator returns 0, so TreeSet considers them equivalent. Only one may be stored — even though their IDs differ.

#Range Views

One of TreeSet's biggest advantages over HashSet: subSet(), headSet(), tailSet().

Java
TreeSet<Integer> set = new TreeSet<>(Arrays.asList(10, 20, 30, 40, 50));

subSet()

Java
set.subSet(20, 50);   // 20, 30, 40

By default: from → inclusive, to → exclusive. You can control the boundaries explicitly:

Java
set.subSet(20, true, 50, true);   // 20, 30, 40, 50

headSet()

Returns elements before a specified point. By default the point is excluded:

Java
set.headSet(30);         // 10, 20
set.headSet(30, true);   // 10, 20, 30

tailSet()

Returns elements from a specified point onward. By default the point is included:

Java
set.tailSet(30);   // 30, 40, 50

Range Methods Return Views

This is an excellent interview question.

Java
NavigableSet<Integer> subset = set.subSet(20, 50);

The subset is generally a view backed by the original TreeSet, not an independent copy. Changes to the view can affect the original Set, subject to the range restrictions.

#Null Handling

Generally, TreeSet does not allow null when using natural ordering.

Java
TreeSet<Integer> set = new TreeSet<>();

set.add(null);
Output
NullPointerException

Why? The tree needs to compare elements to determine their position. There is no natural ordering between null and an Integer.

Can TreeSet Store Null with a Comparator?

Potentially yes, if the supplied comparator explicitly defines how null should be ordered:

Java
TreeSet<String> set = new TreeSet<>(
        Comparator.nullsFirst(Comparator.naturalOrder())
);

Now null can be ordered before non-null values.

#Custom Objects

Java
class Employee {
    int id;
    String name;
}

This will not work automatically:

Java
TreeSet<Employee> set = new TreeSet<>();

set.add(new Employee());

unless Employee provides natural ordering or the TreeSet has a Comparator. Otherwise Java cannot compare Employee A vs Employee B, and a comparison-related exception (ClassCastException) can occur.

Using Comparable

Java
class Employee implements Comparable<Employee> {

    int id;

    Employee(int id) {
        this.id = id;
    }

    @Override
    public int compareTo(Employee other) {
        return Integer.compare(this.id, other.id);
    }
}
Java
TreeSet<Employee> employees = new TreeSet<>();

employees.add(new Employee(103));
employees.add(new Employee(101));
employees.add(new Employee(102));
Output
101
102
103

Using Comparator

You don't need to modify Employee:

Java
TreeSet<Employee> employees = new TreeSet<>(Comparator.comparingInt(e -> e.id));

This is often preferable when you need different sorting strategies — by ID, by name, by salary, by joining date — each with a different Comparator.

TreeSet and Mutable Objects

Another advanced interview trap. Suppose the ordering depends on employee.salary. You insert the Employee, then later:

Java
employee.salary = 900000;

The object's ordering key changed, but the tree structure wasn't automatically rebuilt. Now operations may behave unexpectedly.

#Thread Safety and Performance

Thread Safety

TreeSet is not thread-safe. For synchronized access:

Java
SortedSet<Integer> set = Collections.synchronizedSortedSet(new TreeSet<>());

For concurrent sorted collections, Java provides specialized options such as ConcurrentSkipListSet.

Performance

OperationComplexity
add()O(log n)
remove()O(log n)
contains()O(log n)
first() / last()O(log n)
lower() / floor()O(log n)
ceiling() / higher()O(log n)
iterationO(n)

TreeSet sacrifices HashSet's average O(1) lookup in exchange for sorted order and navigation.

HashSet vs LinkedHashSet vs TreeSet

FeatureHashSetLinkedHashSetTreeSet
DuplicatesNoNoNo
OrderingNone guaranteedInsertionSorted
Internal structureHash tableHash table + linksRed-Black Tree
Typical addO(1)O(1)O(log n)
containsO(1) avgO(1) avgO(log n)
Range operationsNoNoYes
NavigationNoNoYes
NullOneOneGenerally no
MemoryLowerHigherTree-node overhead

#When to Use TreeSet

Use TreeSet when you need unique elements + sorted order + navigation/range queries.

ExampleType / method
Sorted scoresTreeSet<Integer> scores;
Sorted timestampsTreeSet<Instant> timestamps;
Range queriesAll values between 100 and 500 → subSet()
Nearest-value lookupSmallest value >= X → ceiling()

When NOT to Use TreeSet

You needUse instead
Only uniqueness + fast lookupHashSet
Insertion orderLinkedHashSet
DuplicatesList
Queue / stack behaviourArrayDeque

#Interview Scenarios

Q1Employee salaries

You need no duplicates, sorted salaries, and the next salary greater than 500,000.

Best choice: TreeSet<Integer> salaries; then salaries.higher(500000);

Q2Millions of IDs

Unique IDs, fast membership check, no ordering → HashSet<Long>, not TreeSet.

Q3Transaction IDs

Remove duplicates and preserve first-seen order → LinkedHashSet<Long>, not TreeSet.

Q4Quick coding question: what is the output?
Java
TreeSet<Integer> set = new TreeSet<>();

set.add(10);
set.add(20);
set.add(30);
set.add(40);

System.out.println(set.lower(25));
System.out.println(set.floor(20));
System.out.println(set.ceiling(25));
System.out.println(set.higher(30));
Output
20
20
30
40
Q5Tricky coding question: what happens?
Java
TreeSet<String> set = new TreeSet<>(Comparator.comparingInt(String::length));

set.add("Java");
set.add("Code");
set.add("Spring");

"Java" and "Code" have the same length, so the comparator returns 0 for them. TreeSet considers them equivalent for Set purposes. The result contains only one of those equal-length strings (the first one added, "Java") plus "Spring". A classic interview trap.

#Common Interview Traps

ClaimVerdict
"TreeSet uses hashCode() to detect duplicates."❌ Wrong — it uses compareTo() or Comparator.compare().
"TreeSet always allows null."❌ Wrong — natural ordering generally doesn't support null; a Comparator can define null ordering.
"TreeSet preserves insertion order."❌ Wrong — it preserves sorted order.
"TreeSet is faster than HashSet."❌ Generally wrong — HashSet is O(1) average; TreeSet is O(log n) but offers sorting and navigation.
"compareTo() == 0 always means equals() == true."❌ Not necessarily — but if the comparator returns zero, TreeSet treats the elements as equivalent.

#Frequently Asked Interview Questions

Q1How does TreeSet work internally?

It uses a balanced tree-based structure, specifically a Red-Black Tree through TreeMap infrastructure.

Q2Why is TreeSet O(log n)?

Because the Red-Black Tree maintains logarithmic height.

Q3How does TreeSet determine duplicates?

If comparison returns zero (compareTo() == 0 or Comparator.compare() == 0), TreeSet treats the elements as equivalent for Set purposes.

Q4Does TreeSet use equals()?

equals() is not the primary mechanism for ordering/duplicate determination. The comparator or natural ordering determines equivalence.

Q5What happens if objects don't implement Comparable?

If no Comparator is supplied, TreeSet cannot establish natural ordering and insertion can fail with a comparison-related exception.

Q6What is the difference between lower() and floor()?
  • lower(x) → greatest element < x
  • floor(x) → greatest element <= x
Q7Difference between higher() and ceiling()?
  • higher(x) → smallest element > x
  • ceiling(x) → smallest element >= x
Q8What is the difference between first() and pollFirst()?
  • first() returns the smallest element and does not remove it.
  • pollFirst() returns the smallest element and removes it.
Q9What is the difference between TreeSet and HashSet?

HashSet optimizes for fast average lookup without ordering. TreeSet provides sorted ordering and navigation at O(log n).

Q10Can TreeSet store custom objects?

Yes, if they implement Comparable, or a compatible Comparator is provided.

#Decision Framework

Need uniqueness?
Need sorted order?
TreeSet
Need insertion order?
LinkedHashSet
HashSet
When choosing a Set

Final Mental Model

  • Set
    • HashSethashing · no ordering
    • LinkedHashSethashing · insertion order
    • TreeSetordering · sorted order
      • Red-Black TreeO(log n) operations
        • NavigableSetlower / floor / ceiling / higher

#Chapter Summary

ConceptTreeSet
InterfaceNavigableSet
DuplicatesNot allowed
OrderingSorted
Internal structureRed-Black Tree
Backing infrastructureTreeMap
add()O(log n)
contains()O(log n)
remove()O(log n)
NavigationYes
Range queriesYes
Natural orderingComparable
Custom orderingComparator
NullGenerally unsupported with natural ordering
Thread-safeNo

Interview Readiness Checklist

  • Why does TreeSet use a Red-Black Tree?
  • How does TreeSet determine duplicates?
  • TreeSet vs HashSet?
  • TreeSet vs LinkedHashSet?
  • Comparable vs Comparator?
  • What happens when compareTo() returns 0?
  • Why can TreeSet reject null?
  • What are lower(), floor(), ceiling() and higher()?
  • Difference between first() and pollFirst()?
  • What are subSet(), headSet() and tailSet()?
  • Why are TreeSet operations O(log n)?
  • What happens if a TreeSet's ordering field is mutated?
  • Why can two objects that are not equals() be treated as duplicates by TreeSet?