Java TreeSet
TreeSet is a Set implementation that stores unique elements in sorted order.
It implements the NavigableSet interface and uses a tree-based data structure internally.
import java.util.TreeSet;
public class HelloWorld {
public static void main(String[] args) {
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(50);
numbers.add(10);
numbers.add(30);
numbers.add(20);
System.out.println(numbers);
}
}Output
[10, 20, 30, 50]Although the numbers were inserted in a different order, the TreeSet returns them in sorted order.
Why Use TreeSet?
Suppose we need to store unique scores and always want them sorted.
We could add:
80
50
90
60A TreeSet automatically maintains:
50
60
80
90So TreeSet provides:
Uniqueness + Sorted orderMain Characteristics
TreeSet:
- Does not allow duplicate elements.
- Maintains elements according to sorted ordering.
- Implements NavigableSet.
- Supports navigation operations such as finding the next higher or lower element.
- Uses a tree-based structure.
- Provides logarithmic-time performance for basic operations such as add, remove, and contains.
- Does not generally permit null when using natural ordering.
Creating a TreeSet
TreeSet<Integer> numbers = new TreeSet<>();Or program against the interface:
Set<Integer> numbers = new TreeSet<>();If you need TreeSet-specific methods:
NavigableSet<Integer> numbers = new TreeSet<>();Adding Elements
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(40);
numbers.add(10);
numbers.add(30);
numbers.add(20);The elements are maintained in ascending order.
[10, 20, 30, 40]Duplicate Elements
Like every Set implementation, TreeSet does not store duplicate elements.
numbers.add(20);
numbers.add(20);Only one 20 remains.
Natural Ordering
If no Comparator is supplied, TreeSet uses the natural ordering of its elements.
For numbers:
10 < 20 < 30For Strings, the natural ordering is based on their defined string comparison.
Example
TreeSet<String> names = new TreeSet<>();
names.add("Rahul");
names.add("Amit");
names.add("Priya");
System.out.println(names);The strings are returned in their natural sorted order.
Reverse Ordering
We can create a TreeSet with a Comparator for descending order.
TreeSet<Integer> numbers =
new TreeSet<>(Comparator.reverseOrder());
numbers.add(10);
numbers.add(30);
numbers.add(20);
System.out.println(numbers);Output
[30, 20, 10]first() and last()
TreeSet provides methods to get the smallest and largest elements.
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
System.out.println(numbers.first());
System.out.println(numbers.last());Output
10
40higher()
higher() returns the smallest element strictly greater than the specified element.
System.out.println(numbers.higher(20));Output
30lower()
lower() returns the largest element strictly less than the specified element.
System.out.println(numbers.lower(20));Output
10ceiling()
ceiling() returns the smallest element greater than or equal to the specified value.
System.out.println(numbers.ceiling(20));Output
20If 21 is searched:
System.out.println(numbers.ceiling(21));Output
30floor()
floor() returns the largest element less than or equal to the specified value.
System.out.println(numbers.floor(20));Output
20For 21:
System.out.println(numbers.floor(21));Output
20headSet()
headSet() returns elements that come before a specified value.
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
System.out.println(numbers.headSet(30));Output
[10, 20]tailSet()
tailSet() returns elements from a specified value onward.
System.out.println(numbers.tailSet(30));Output
[30, 40]subSet()
subSet() can be used to retrieve a range of elements.
System.out.println(numbers.subSet(20, 40));Output
[20, 30]The upper boundary is exclusive in this form.
TreeSet and Comparable
TreeSet needs a way to determine how elements should be ordered.
One way is to use the element's natural ordering through Comparable.
For example, String and wrapper classes such as Integer provide natural ordering.
For custom objects, we can implement Comparable.
class Student implements Comparable<Student> {
int marks;
Student(int marks) {
this.marks = marks;
}
@Override
public int compareTo(Student other) {
return Integer.compare(this.marks, other.marks);
}
}Then:
TreeSet<Student> students = new TreeSet<>();
students.add(new Student(80));
students.add(new Student(60));
students.add(new Student(90));The TreeSet can use compareTo() to determine the ordering.
TreeSet and Comparator
We can also provide a Comparator when creating the TreeSet.
TreeSet<Integer> numbers =
new TreeSet<>(Comparator.reverseOrder());For custom objects:
TreeSet<Student> students =
new TreeSet<>(
Comparator.comparingInt(student -> student.marks)
);This allows us to define an ordering without changing the class's natural ordering.
TreeSet and Custom Objects
When using custom objects, the comparison mechanism is especially important.
TreeSet uses the ordering comparison to determine whether two elements occupy the same position in the sorted set.
Therefore, if two objects compare as 0, TreeSet can treat them as equivalent for Set purposes even if their equals() method says otherwise.
This is an important difference to understand when designing custom ordering.
TreeSet Does Not Generally Allow Null
With natural ordering:
TreeSet<String> names = new TreeSet<>();
names.add(null);This results in a NullPointerException.
Therefore, avoid using null elements with a naturally ordered TreeSet.
TreeSet vs HashSet vs LinkedHashSet
| Feature | HashSet | LinkedHashSet | TreeSet |
|---|---|---|---|
| Duplicates | No | No | No |
| Ordering | No guaranteed order | Insertion order | Sorted order |
| Underlying approach | Hash-based | Hash + linked ordering | Tree-based |
| Basic operation complexity | Average O(1) | Average O(1) | O(log n) |
| Null | One allowed | One allowed | Generally not with natural ordering |
| Main purpose | Unique elements | Unique + insertion order | Unique + sorted order |
Example: Unique Sorted Scores
import java.util.TreeSet;
public class HelloWorld {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<>();
scores.add(85);
scores.add(70);
scores.add(95);
scores.add(85);
scores.add(60);
System.out.println("Scores: " + scores);
System.out.println("Lowest: " + scores.first());
System.out.println("Highest: " + scores.last());
System.out.println("Next after 70: " + scores.higher(70));
}
}Output
Scores: [60, 70, 85, 95]
Lowest: 60
Highest: 95
Next after 70: 85When Should You Use TreeSet?
Use TreeSet when:
- Duplicate elements should not be allowed.
- Elements must remain sorted.
- You need range or navigation operations.
- You need methods such as higher(), lower(), ceiling(), and floor().
Examples include:
- Sorted unique scores
- Sorted product prices
- Unique dates in chronological order
- Unique IDs that need sorted traversal
- Range-based searches
Important Points
- TreeSet implements NavigableSet.
- It does not allow duplicate elements.
- Elements are maintained in sorted order.
- Natural ordering can be provided through Comparable.
- Custom ordering can be provided through Comparator.
Basic operations generally take O(log n) time. first() returns the smallest element. last() returns the largest element. higher() finds the next greater element. lower() finds the next smaller element. ceiling() finds the smallest element greater than or equal to a value. floor() finds the largest element less than or equal to a value.
Key Takeaway
TreeSet is the right choice when you need unique elements maintained in sorted order. Unlike HashSet, which focuses on efficient hash-based storage, TreeSet also provides sorted-set and navigation operations.
See you in next page....🙂