TreeSet Sorted Collection in Java

Table of Contents

  1. Introduction
  2. TreeSet vs Other Sets
  3. Constructors and Creation
  4. Natural Ordering
  5. Custom Comparators
  6. Basic Operations
  7. Navigation Methods
  8. Range Operations
  9. Performance Characteristics
  10. Use Cases
  11. Best Practices
  12. Complete Examples

Introduction

TreeSet is a NavigableSet implementation based on a TreeMap. It stores elements in a sorted order and provides guaranteed log(n) time cost for basic operations.

Key Characteristics:

  • Sorted Order: Elements are stored in sorted order
  • No Duplicates: Like all Set implementations
  • Red-Black Tree: Backed by a balanced tree structure
  • Null Elements: Doesn't allow null elements (if natural ordering)
  • Performance: O(log n) for add, remove, contains operations

TreeSet vs Other Sets

Comparison Table:

FeatureTreeSetHashSetLinkedHashSet
OrderingSorted (natural/comparator)No orderInsertion order
ImplementationRed-Black TreeHash tableHash table + Linked list
PerformanceO(log n)O(1)O(1)
Null elementsNot allowed (if natural)AllowedAllowed
Use CaseSorted dataGeneral purposeInsertion order

Code Comparison:

import java.util.*;
public class SetComparison {
public static void main(String[] args) {
// TreeSet - Sorted order
Set<String> treeSet = new TreeSet<>();
treeSet.add("Orange");
treeSet.add("Apple");
treeSet.add("Banana");
treeSet.add("Cherry");
System.out.println("TreeSet: " + treeSet); // Sorted order
// HashSet - No order
Set<String> hashSet = new HashSet<>();
hashSet.add("Orange");
hashSet.add("Apple");
hashSet.add("Banana");
hashSet.add("Cherry");
System.out.println("HashSet: " + hashSet); // Random order
// LinkedHashSet - Insertion order
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Orange");
linkedHashSet.add("Apple");
linkedHashSet.add("Banana");
linkedHashSet.add("Cherry");
System.out.println("LinkedHashSet: " + linkedHashSet); // Insertion order
}
}

Output:

TreeSet: [Apple, Banana, Cherry, Orange]        # Sorted order
HashSet: [Apple, Cherry, Banana, Orange]        # Random order  
LinkedHashSet: [Orange, Apple, Banana, Cherry]  # Insertion order

Constructors and Creation

Available Constructors:

import java.util.*;
public class TreeSetConstructors {
public static void main(String[] args) {
// 1. Default constructor - natural ordering
TreeSet<String> defaultSet = new TreeSet<>();
defaultSet.add("Banana");
defaultSet.add("Apple");
defaultSet.add("Cherry");
System.out.println("Default: " + defaultSet);
// 2. Constructor with Comparator
TreeSet<String> reverseSet = new TreeSet<>(Comparator.reverseOrder());
reverseSet.add("Banana");
reverseSet.add("Apple");
reverseSet.add("Cherry");
System.out.println("Reverse: " + reverseSet);
// 3. Constructor from existing collection
List<String> list = Arrays.asList("Orange", "Grape", "Mango");
TreeSet<String> fromCollection = new TreeSet<>(list);
System.out.println("From collection: " + fromCollection);
// 4. Constructor from sorted set
TreeSet<String> fromSortedSet = new TreeSet<>(defaultSet);
System.out.println("From sorted set: " + fromSortedSet);
}
}

Output:

Default: [Apple, Banana, Cherry]
Reverse: [Cherry, Banana, Apple]
From collection: [Grape, Mango, Orange]
From sorted set: [Apple, Banana, Cherry]

Natural Ordering

With Comparable Objects:

import java.util.*;
class Student implements Comparable<Student> {
private int id;
private String name;
private double gpa;
public Student(int id, String name, double gpa) {
this.id = id;
this.name = name;
this.gpa = gpa;
}
// Natural ordering by ID
@Override
public int compareTo(Student other) {
return Integer.compare(this.id, other.id);
}
@Override
public String toString() {
return String.format("Student{id=%d, name='%s', gpa=%.2f}", id, name, gpa);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return id == student.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
public class NaturalOrderingExample {
public static void main(String[] args) {
TreeSet<Student> students = new TreeSet<>();
students.add(new Student(103, "Alice", 3.8));
students.add(new Student(101, "Bob", 3.5));
students.add(new Student(102, "Charlie", 3.9));
students.add(new Student(100, "Diana", 3.7));
System.out.println("Students sorted by ID (natural order):");
for (Student student : students) {
System.out.println(student);
}
}
}

Output:

Students sorted by ID (natural order):
Student{id=100, name='Diana', gpa=3.70}
Student{id=101, name='Bob', gpa=3.50}
Student{id=102, name='Charlie', gpa=3.90}
Student{id=103, name='Alice', gpa=3.80}

Custom Comparators

Using Different Comparison Strategies:

import java.util.*;
class Product {
private String name;
private double price;
private int quantity;
public Product(String name, double price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
public String getName() { return name; }
public double getPrice() { return price; }
public int getQuantity() { return quantity; }
@Override
public String toString() {
return String.format("Product{name='%-10s', price=$%6.2f, quantity=%2d}", 
name, price, quantity);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Product)) return false;
Product product = (Product) o;
return Objects.equals(name, product.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
public class CustomComparatorExample {
public static void main(String[] args) {
// 1. Sort by name
TreeSet<Product> byName = new TreeSet<>(
Comparator.comparing(Product::getName)
);
// 2. Sort by price
TreeSet<Product> byPrice = new TreeSet<>(
Comparator.comparingDouble(Product::getPrice)
);
// 3. Sort by quantity (descending)
TreeSet<Product> byQuantityDesc = new TreeSet<>(
Comparator.comparingInt(Product::getQuantity).reversed()
);
// 4. Sort by price then by name
TreeSet<Product> byPriceThenName = new TreeSet<>(
Comparator.comparingDouble(Product::getPrice)
.thenComparing(Product::getName)
);
// Add products
List<Product> products = Arrays.asList(
new Product("Laptop", 999.99, 5),
new Product("Mouse", 25.99, 20),
new Product("Keyboard", 75.50, 15),
new Product("Monitor", 299.99, 8),
new Product("Mouse", 19.99, 25) // Different mouse
);
// Add to all sets
for (Product product : products) {
byName.add(product);
byPrice.add(product);
byQuantityDesc.add(product);
byPriceThenName.add(product);
}
System.out.println("Sorted by Name:");
byName.forEach(System.out::println);
System.out.println("\nSorted by Price:");
byPrice.forEach(System.out::println);
System.out.println("\nSorted by Quantity (Descending):");
byQuantityDesc.forEach(System.out::println);
System.out.println("\nSorted by Price then Name:");
byPriceThenName.forEach(System.out::println);
}
}

Output:

Sorted by Name:
Product{name='Keyboard ', price=$ 75.50, quantity=15}
Product{name='Laptop   ', price=$999.99, quantity= 5}
Product{name='Monitor  ', price=$299.99, quantity= 8}
Product{name='Mouse    ', price=$ 25.99, quantity=20}
Sorted by Price:
Product{name='Mouse    ', price=$ 25.99, quantity=20}
Product{name='Keyboard ', price=$ 75.50, quantity=15}
Product{name='Monitor  ', price=$299.99, quantity= 8}
Product{name='Laptop   ', price=$999.99, quantity= 5}
Sorted by Quantity (Descending):
Product{name='Mouse    ', price=$ 25.99, quantity=20}
Product{name='Keyboard ', price=$ 75.50, quantity=15}
Product{name='Monitor  ', price=$299.99, quantity= 8}
Product{name='Laptop   ', price=$999.99, quantity= 5}
Sorted by Price then Name:
Product{name='Mouse    ', price=$ 25.99, quantity=20}
Product{name='Keyboard ', price=$ 75.50, quantity=15}
Product{name='Monitor  ', price=$299.99, quantity= 8}
Product{name='Laptop   ', price=$999.99, quantity= 5}

Basic Operations

Common Operations Examples:

import java.util.*;
public class BasicOperations {
public static void main(String[] args) {
TreeSet<Integer> numbers = new TreeSet<>();
// Add elements
numbers.add(50);
numbers.add(20);
numbers.add(80);
numbers.add(10);
numbers.add(30);
numbers.add(70);
numbers.add(40);
numbers.add(60);
System.out.println("TreeSet: " + numbers);
System.out.println("Size: " + numbers.size());
System.out.println("Contains 30: " + numbers.contains(30));
System.out.println("Contains 35: " + numbers.contains(35));
// Remove elements
numbers.remove(20);
System.out.println("After removing 20: " + numbers);
// First and last
System.out.println("First element: " + numbers.first());
System.out.println("Last element: " + numbers.last());
// Iteration (sorted order)
System.out.print("Iteration: ");
for (Integer num : numbers) {
System.out.print(num + " ");
}
System.out.println();
// Descending iteration
System.out.print("Descending iteration: ");
for (Integer num : numbers.descendingSet()) {
System.out.print(num + " ");
}
System.out.println();
// Clear
numbers.clear();
System.out.println("After clear - Empty: " + numbers.isEmpty());
System.out.println("Size: " + numbers.size());
}
}

Output:

TreeSet: [10, 20, 30, 40, 50, 60, 70, 80]
Size: 8
Contains 30: true
Contains 35: false
After removing 20: [10, 30, 40, 50, 60, 70, 80]
First element: 10
Last element: 80
Iteration: 10 30 40 50 60 70 80 
Descending iteration: 80 70 60 50 40 30 10 
After clear - Empty: true
Size: 0

Navigation Methods

TreeSet Navigation Features:

import java.util.*;
public class NavigationMethods {
public static void main(String[] args) {
TreeSet<Integer> numbers = new TreeSet<>(Arrays.asList(
10, 20, 30, 40, 50, 60, 70, 80, 90, 100
));
System.out.println("Original set: " + numbers);
// Lower and higher
System.out.println("Lower than 45: " + numbers.lower(45));  // Greatest element < 45
System.out.println("Higher than 45: " + numbers.higher(45)); // Smallest element > 45
// Floor and ceiling
System.out.println("Floor of 45: " + numbers.floor(45));    // Greatest element <= 45
System.out.println("Ceiling of 45: " + numbers.ceiling(45)); // Smallest element >= 45
// Head and tail sets
System.out.println("Head set (elements < 50): " + numbers.headSet(50));
System.out.println("Head set inclusive (elements <= 50): " + numbers.headSet(50, true));
System.out.println("Tail set (elements >= 60): " + numbers.tailSet(60));
System.out.println("Tail set exclusive (elements > 60): " + numbers.tailSet(60, false));
// Subset
System.out.println("Subset [40, 80): " + numbers.subSet(40, 80));
System.out.println("Subset [40, 80]: " + numbers.subSet(40, true, 80, true));
// Poll first and last
System.out.println("Poll first: " + numbers.pollFirst() + ", Remaining: " + numbers);
System.out.println("Poll last: " + numbers.pollLast() + ", Remaining: " + numbers);
}
}

Output:

Original set: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
Lower than 45: 40
Higher than 45: 50
Floor of 45: 40
Ceiling of 45: 50
Head set (elements < 50): [10, 20, 30, 40]
Head set inclusive (elements <= 50): [10, 20, 30, 40, 50]
Tail set (elements >= 60): [60, 70, 80, 90, 100]
Tail set exclusive (elements > 60): [70, 80, 90, 100]
Subset [40, 80): [40, 50, 60, 70]
Subset [40, 80]: [40, 50, 60, 70, 80]
Poll first: 10, Remaining: [20, 30, 40, 50, 60, 70, 80, 90, 100]
Poll last: 100, Remaining: [20, 30, 40, 50, 60, 70, 80, 90]

Range Operations

Practical Range Query Examples:

import java.util.*;
public class RangeOperations {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<>(Arrays.asList(
45, 67, 89, 92, 78, 56, 83, 71, 95, 62, 88, 76
));
System.out.println("All scores: " + scores);
// Find scores in different ranges
System.out.println("\n--- Grade Ranges ---");
System.out.println("Failing (< 60): " + scores.headSet(60));
System.out.println("Passing (60-69): " + scores.subSet(60, 70));
System.out.println("Good (70-79): " + scores.subSet(70, 80));
System.out.println("Very Good (80-89): " + scores.subSet(80, 90));
System.out.println("Excellent (>= 90): " + scores.tailSet(90));
// Find nearest scores
int target = 75;
System.out.println("\n--- Nearest to " + target + " ---");
System.out.println("Floor: " + scores.floor(target));
System.out.println("Ceiling: " + scores.ceiling(target));
System.out.println("Lower: " + scores.lower(target));
System.out.println("Higher: " + scores.higher(target));
// Range for scholarship (top 30%)
int minScholarshipScore = getPercentile(scores, 70);
System.out.println("\nScholarship candidates (top 30%): " + 
scores.tailSet(minScholarshipScore));
}
private static int getPercentile(TreeSet<Integer> set, int percentile) {
if (set.isEmpty()) return 0;
int index = (int) Math.ceil(set.size() * percentile / 100.0) - 1;
return set.stream().sorted().skip(index).findFirst().orElse(0);
}
}

Output:

All scores: [45, 56, 62, 67, 71, 76, 78, 83, 88, 89, 92, 95]
--- Grade Ranges ---
Failing (< 60): [45, 56]
Passing (60-69): [62, 67]
Good (70-79): [71, 76, 78]
Very Good (80-89): [83, 88, 89]
Excellent (>= 90): [92, 95]
--- Nearest to 75 ---
Floor: 71
Ceiling: 76
Lower: 71
Higher: 76
Scholarship candidates (top 30%): [83, 88, 89, 92, 95]

Performance Characteristics

Time Complexity:

OperationTime Complexity
add()O(log n)
remove()O(log n)
contains()O(log n)
first() / last()O(1)
lower() / higher()O(log n)
headSet() / tailSet()O(log n)

Performance Comparison:

import java.util.*;
public class PerformanceComparison {
public static void main(String[] args) {
final int SIZE = 100000;
// TreeSet
TreeSet<Integer> treeSet = new TreeSet<>();
long startTime = System.nanoTime();
for (int i = 0; i < SIZE; i++) {
treeSet.add(i);
}
long treeSetAddTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
treeSet.contains(SIZE / 2);
long treeSetContainsTime = System.nanoTime() - startTime;
// HashSet
HashSet<Integer> hashSet = new HashSet<>();
startTime = System.nanoTime();
for (int i = 0; i < SIZE; i++) {
hashSet.add(i);
}
long hashSetAddTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
hashSet.contains(SIZE / 2);
long hashSetContainsTime = System.nanoTime() - startTime;
System.out.println("Performance Comparison (nanoseconds):");
System.out.printf("TreeSet - Add: %,d, Contains: %,d\n", treeSetAddTime, treeSetContainsTime);
System.out.printf("HashSet - Add: %,d, Contains: %,d\n", hashSetAddTime, hashSetContainsTime);
System.out.printf("TreeSet add is %.2fx slower than HashSet\n", 
(double) treeSetAddTime / hashSetAddTime);
}
}

Use Cases

1. Sorted Leaderboard:

import java.util.*;
class Player implements Comparable<Player> {
private String name;
private int score;
public Player(String name, int score) {
this.name = name;
this.score = score;
}
// Higher scores first
@Override
public int compareTo(Player other) {
return Integer.compare(other.score, this.score); // Descending
}
public String getName() { return name; }
public int getScore() { return score; }
@Override
public String toString() {
return String.format("%-10s: %d", name, score);
}
}
public class Leaderboard {
private TreeSet<Player> players;
public Leaderboard() {
players = new TreeSet<>();
}
public void addPlayer(String name, int score) {
players.add(new Player(name, score));
}
public void displayTopPlayers(int count) {
System.out.println("Top " + count + " Players:");
int rank = 1;
for (Player player : players) {
if (rank > count) break;
System.out.println(rank + ". " + player);
rank++;
}
}
public void displayRank(String playerName) {
int rank = 1;
for (Player player : players) {
if (player.getName().equals(playerName)) {
System.out.println(playerName + " is ranked #" + rank);
return;
}
rank++;
}
System.out.println(playerName + " not found in leaderboard");
}
public static void main(String[] args) {
Leaderboard leaderboard = new Leaderboard();
leaderboard.addPlayer("Alice", 1500);
leaderboard.addPlayer("Bob", 1800);
leaderboard.addPlayer("Charlie", 1200);
leaderboard.addPlayer("Diana", 2000);
leaderboard.addPlayer("Eve", 1600);
leaderboard.addPlayer("Frank", 1900);
leaderboard.displayTopPlayers(3);
System.out.println();
leaderboard.displayRank("Alice");
leaderboard.displayRank("Diana");
}
}

Output:

Top 3 Players:
1. Diana    : 2000
2. Frank    : 1900
3. Bob      : 1800
Alice is ranked #5
Diana is ranked #1

2. Event Scheduler:

import java.util.*;
class Event implements Comparable<Event> {
private String name;
private Date timestamp;
public Event(String name, Date timestamp) {
this.name = name;
this.timestamp = timestamp;
}
@Override
public int compareTo(Event other) {
return this.timestamp.compareTo(other.timestamp);
}
public String getName() { return name; }
public Date getTimestamp() { return timestamp; }
@Override
public String toString() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return String.format("Event{name='%s', time=%s}", name, sdf.format(timestamp));
}
}
public class EventScheduler {
private TreeSet<Event> events;
public EventScheduler() {
events = new TreeSet<>();
}
public void scheduleEvent(String name, Date time) {
events.add(new Event(name, time));
System.out.println("Scheduled: " + name + " at " + time);
}
public Event getNextEvent() {
return events.isEmpty() ? null : events.first();
}
public Event getNextEventAfter(Date time) {
Event next = events.higher(new Event("", time));
return next;
}
public Set<Event> getEventsBetween(Date start, Date end) {
return events.subSet(new Event("", start), true, new Event("", end), true);
}
public void displayUpcomingEvents(int count) {
System.out.println("\nUpcoming " + count + " events:");
int displayed = 0;
for (Event event : events) {
if (displayed >= count) break;
System.out.println((displayed + 1) + ". " + event);
displayed++;
}
}
public static void main(String[] args) throws Exception {
EventScheduler scheduler = new EventScheduler();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
// Schedule events
scheduler.scheduleEvent("Meeting", sdf.parse("2024-01-15 10:00"));
scheduler.scheduleEvent("Lunch", sdf.parse("2024-01-15 12:30"));
scheduler.scheduleEvent("Conference", sdf.parse("2024-01-15 09:00"));
scheduler.scheduleEvent("Training", sdf.parse("2024-01-15 14:00"));
scheduler.displayUpcomingEvents(3);
Date searchTime = sdf.parse("2024-01-15 11:00");
Event next = scheduler.getNextEventAfter(searchTime);
System.out.println("\nNext event after " + sdf.format(searchTime) + ": " + next);
}
}

Output:

Scheduled: Meeting at Mon Jan 15 10:00:00 IST 2024
Scheduled: Lunch at Mon Jan 15 12:30:00 IST 2024
Scheduled: Conference at Mon Jan 15 09:00:00 IST 2024
Scheduled: Training at Mon Jan 15 14:00:00 IST 2024
Upcoming 3 events:
1. Event{name='Conference', time=2024-01-15 09:00:00}
2. Event{name='Meeting', time=2024-01-15 10:00:00}
3. Event{name='Lunch', time=2024-01-15 12:30:00}
Next event after 2024-01-15 11:00: Lunch

Best Practices

1. Consistent equals() and compareTo():

class ConsistentStudent implements Comparable<ConsistentStudent> {
private int id;
private String name;
public ConsistentStudent(int id, String name) {
this.id = id;
this.name = name;
}
// compareTo consistent with equals
@Override
public int compareTo(ConsistentStudent other) {
return Integer.compare(this.id, other.id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ConsistentStudent)) return false;
ConsistentStudent that = (ConsistentStudent) o;
return id == that.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

2. Handle Null Values:

public class NullHandling {
public static void main(String[] args) {
// TreeSet with natural ordering doesn't allow null
try {
TreeSet<String> naturalSet = new TreeSet<>();
naturalSet.add(null); // Throws NullPointerException
} catch (NullPointerException e) {
System.out.println("Natural ordering TreeSet doesn't allow null");
}
// TreeSet with custom comparator can allow null
TreeSet<String> customSet = new TreeSet<>(
Comparator.nullsFirst(Comparator.naturalOrder())
);
customSet.add(null);
customSet.add("Apple");
customSet.add("Banana");
System.out.println("With nullsFirst: " + customSet);
}
}

3. Choose Appropriate Initial Capacity:

public class TreeSetConfiguration {
public static void main(String[] args) {
// For large datasets, consider initial capacity
// (Though TreeSet doesn't have capacity constructor like HashSet)
// Better approach: Use appropriate comparator
TreeSet<Integer> largeSet = new TreeSet<>(Comparator.reverseOrder());
// Add bulk data efficiently
List<Integer> bulkData = Arrays.asList(5, 2, 8, 1, 9, 3, 7, 4, 6);
largeSet.addAll(bulkData);
System.out.println("Large set: " + largeSet);
}
}

Complete Examples

Complete Working Example:

import java.util.*;
import java.text.SimpleDateFormat;
public class TreeSetCompleteExample {
public static void main(String[] args) throws Exception {
System.out.println("=== TreeSet Complete Example ===\n");
// Example 1: Basic Sorted Operations
basicSortedOperations();
// Example 2: Custom Object Sorting
customObjectSorting();
// Example 3: Navigation and Range Queries
navigationAndRangeQueries();
// Example 4: Real-world Use Case - Product Catalog
productCatalogExample();
}
public static void basicSortedOperations() {
System.out.println("1. Basic Sorted Operations:");
TreeSet<String> fruits = new TreeSet<>();
// Add in random order
fruits.add("Orange");
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
fruits.add("Mango");
fruits.add("Grape");
System.out.println("Natural order: " + fruits);
System.out.println("Reverse order: " + fruits.descendingSet());
System.out.println("First fruit: " + fruits.first());
System.out.println("Last fruit: " + fruits.last());
System.out.println();
}
public static void customObjectSorting() {
System.out.println("2. Custom Object Sorting:");
// Sort by name
TreeSet<Employee> byName = new TreeSet<>(
Comparator.comparing(Employee::getName)
);
// Sort by salary (descending)
TreeSet<Employee> bySalary = new TreeSet<>(
Comparator.comparingDouble(Employee::getSalary).reversed()
);
// Add employees
byName.add(new Employee("John", 50000, "IT"));
byName.add(new Employee("Alice", 60000, "HR"));
byName.add(new Employee("Bob", 55000, "Finance"));
byName.add(new Employee("Diana", 75000, "IT"));
bySalary.addAll(byName);
System.out.println("Sorted by Name:");
byName.forEach(System.out::println);
System.out.println("\nSorted by Salary (Descending):");
bySalary.forEach(System.out::println);
System.out.println();
}
public static void navigationAndRangeQueries() {
System.out.println("3. Navigation and Range Queries:");
TreeSet<Integer> numbers = new TreeSet<>(Arrays.asList(
10, 25, 35, 40, 50, 65, 70, 85, 90, 100
));
System.out.println("All numbers: " + numbers);
int target = 45;
System.out.println("\nNavigation around " + target + ":");
System.out.println("Floor: " + numbers.floor(target));
System.out.println("Ceiling: " + numbers.ceiling(target));
System.out.println("Lower: " + numbers.lower(target));
System.out.println("Higher: " + numbers.higher(target));
System.out.println("\nRange queries:");
System.out.println("Numbers < 50: " + numbers.headSet(50));
System.out.println("Numbers >= 70: " + numbers.tailSet(70));
System.out.println("Numbers between 30 and 80: " + numbers.subSet(30, 80));
System.out.println();
}
public static void productCatalogExample() throws Exception {
System.out.println("4. Product Catalog Example:");
ProductCatalog catalog = new ProductCatalog();
// Add products
catalog.addProduct(new CatalogProduct("Laptop", 999.99, "Electronics"));
catalog.addProduct(new CatalogProduct("Mouse", 25.99, "Electronics"));
catalog.addProduct(new CatalogProduct("Desk", 199.99, "Furniture"));
catalog.addProduct(new CatalogProduct("Chair", 149.99, "Furniture"));
catalog.addProduct(new CatalogProduct("Monitor", 299.99, "Electronics"));
System.out.println("All products by name:");
catalog.displayAllProducts();
System.out.println("\nProducts under $200:");
catalog.displayProductsUnderPrice(200);
System.out.println("\nProducts in price range $100-$300:");
catalog.displayProductsInPriceRange(100, 300);
System.out.println("\nElectronics products:");
catalog.displayProductsByCategory("Electronics");
}
}
// Supporting classes
class Employee {
private String name;
private double salary;
private String department;
public Employee(String name, double salary, String department) {
this.name = name;
this.salary = salary;
this.department = department;
}
public String getName() { return name; }
public double getSalary() { return salary; }
public String getDepartment() { return department; }
@Override
public String toString() {
return String.format("Employee{name='%-6s', salary=$%6.2f, department='%s'}", 
name, salary, department);
}
}
class CatalogProduct implements Comparable<CatalogProduct> {
private String name;
private double price;
private String category;
public CatalogProduct(String name, double price, String category) {
this.name = name;
this.price = price;
this.category = category;
}
@Override
public int compareTo(CatalogProduct other) {
return this.name.compareTo(other.name);
}
public String getName() { return name; }
public double getPrice() { return price; }
public String getCategory() { return category; }
@Override
public String toString() {
return String.format("Product{name='%-10s', price=$%6.2f, category='%s'}", 
name, price, category);
}
}
class ProductCatalog {
private TreeSet<CatalogProduct> productsByName;
private TreeSet<CatalogProduct> productsByPrice;
public ProductCatalog() {
productsByName = new TreeSet<>();
productsByPrice = new TreeSet<>(
Comparator.comparingDouble(CatalogProduct::getPrice)
);
}
public void addProduct(CatalogProduct product) {
productsByName.add(product);
productsByPrice.add(product);
}
public void displayAllProducts() {
productsByName.forEach(System.out::println);
}
public void displayProductsUnderPrice(double maxPrice) {
CatalogProduct dummy = new CatalogProduct("", maxPrice, "");
productsByPrice.headSet(dummy, true).forEach(System.out::println);
}
public void displayProductsInPriceRange(double minPrice, double maxPrice) {
CatalogProduct minDummy = new CatalogProduct("", minPrice, "");
CatalogProduct maxDummy = new CatalogProduct("", maxPrice, "");
productsByPrice.subSet(minDummy, true, maxDummy, true)
.forEach(System.out::println);
}
public void displayProductsByCategory(String category) {
productsByName.stream()
.filter(p -> p.getCategory().equals(category))
.forEach(System.out::println);
}
}

Expected Output:

=== TreeSet Complete Example ===
1. Basic Sorted Operations:
Natural order: [Apple, Banana, Cherry, Grape, Mango, Orange]
Reverse order: [Orange, Mango, Grape, Cherry, Banana, Apple]
First fruit: Apple
Last fruit: Orange
2. Custom Object Sorting:
Sorted by Name:
Employee{name='Alice ', salary=$60000.00, department='HR'}
Employee{name='Bob   ', salary=$55000.00, department='Finance'}
Employee{name='Diana ', salary=$75000.00, department='IT'}
Employee{name='John  ', salary=$50000.00, department='IT'}
Sorted by Salary (Descending):
Employee{name='Diana ', salary=$75000.00, department='IT'}
Employee{name='Alice ', salary=$60000.00, department='HR'}
Employee{name='Bob   ', salary=$55000.00, department='Finance'}
Employee{name='John  ', salary=$50000.00, department='IT'}
3. Navigation and Range Queries:
All numbers: [10, 25, 35, 40, 50, 65, 70, 85, 90, 100]
Navigation around 45:
Floor: 40
Ceiling: 50
Lower: 40
Higher: 50
Range queries:
Numbers < 50: [10, 25, 35, 40]
Numbers >= 70: [70, 85, 90, 100]
Numbers between 30 and 80: [35, 40, 50, 65, 70]
4. Product Catalog Example:
All products by name:
Product{name='Chair     ', price=$149.99, category='Furniture'}
Product{name='Desk      ', price=$199.99, category='Furniture'}
Product{name='Laptop    ', price=$999.99, category='Electronics'}
Product{name='Monitor   ', price=$299.99, category='Electronics'}
Product{name='Mouse     ', price=$ 25.99, category='Electronics'}
Products under $200:
Product{name='Mouse     ', price=$ 25.99, category='Electronics'}
Product{name='Chair     ', price=$149.99, category='Furniture'}
Product{name='Desk      ', price=$199.99, category='Furniture'}
Products in price range $100-$300:
Product{name='Chair     ', price=$149.99, category='Furniture'}
Product{name='Desk      ', price=$199.99, category='Furniture'}
Product{name='Monitor   ', price=$299.99, category='Electronics'}
Electronics products:
Product{name='Laptop    ', price=$999.99, category='Electronics'}
Product{name='Monitor   ', price=$299.99, category='Electronics'}
Product{name='Mouse     ', price=$ 25.99, category='Electronics'}

Key Takeaways

  1. TreeSet maintains sorted order - elements are always sorted
  2. No duplicates - standard Set behavior
  3. Red-Black Tree implementation - provides O(log n) performance
  4. Natural ordering or custom comparator - flexible sorting
  5. Rich navigation API - ceiling, floor, higher, lower methods
  6. Range operations - headSet, tailSet, subSet for efficient queries
  7. No null elements - with natural ordering (unless specified in comparator)
  8. Perfect for sorted data - leaderboards, event schedulers, sorted catalogs

TreeSet is the ideal choice when you need a sorted collection with efficient range queries and navigation operations, making it perfect for applications that require maintaining data in sorted order.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper