TreeSet 정렬 완벽 이해하기, 자바 개발자라면 꼭 알아야 할 핵심 개념
📌 자동 정렬과 범위 검색까지, TreeSet을 제대로 활용해보세요
자바(Java)에서 컬렉션을 사용할 때, 데이터를 자동으로 정렬하고 중복 없이 저장하고 싶다면 어떤 자료구조를 사용하시나요?
많은 분들이 TreeSet을 떠올리실 텐데요.
특히 사전순 정렬이나 범위 검색 같은 기능이 필요한 상황이라면 TreeSet이 아주 유용하게 쓰입니다.
하지만 내부 구조나 정렬 방식에 대해 정확히 이해하지 못한 채 사용하는 경우도 많죠.
이번 글에서는 TreeSet의 원리부터 실전 사용법까지 차근차근 정리해드릴게요.
개념이 어렵게 느껴졌던 분들도 걱정 마세요.
쉽고 친절한 설명으로 TreeSet을 완벽하게 이해하실 수 있도록 도와드리겠습니다.
이 글에서는 TreeSet의 동작 원리와 정렬 방식은 물론, 사용 시 주의할 점과 실제 예제까지 함께 소개합니다.
Java의 컬렉션 프레임워크 중에서도 이진 트리 구조를 사용하는 Set인 TreeSet은 정렬이 자동으로 이루어진다는 특징 덕분에 실무에서도 자주 사용됩니다.
이 글을 통해 TreeSet의 개념을 확실히 정리하고, 개발 실력도 한 단계 업그레이드해보세요.
📋 목차
🌲 TreeSet이란 무엇인가요?
Java에서 TreeSet은 java.util 패키지에 포함된 클래스이며, Set 인터페이스를 구현한 컬렉션입니다.
다른 Set 구현체들과 달리, 요소들이 자동으로 정렬된다는 큰 특징을 갖고 있어요.
중복된 요소는 허용하지 않으며, 내부적으로는 Red-Black Tree라는 이진 탐색 트리 구조로 관리됩니다.
TreeSet은 요소를 추가하는 순간 즉시 정렬되기 때문에, 데이터를 정렬한 후 따로 저장할 필요가 없습니다.
이러한 특성 덕분에 사전순 정렬이 필요한 경우나 범위 검색이 필요한 알고리즘에서 자주 사용되죠.
특히 실무에서는 사용자 이름, 단어 사전, 고유 코드 정렬 등 다양한 곳에서 TreeSet의 장점이 발휘됩니다.
💬 HashSet과 달리 TreeSet은 요소의 순서가 고정되어 있다는 점이 가장 큰 차이입니다.
- 🌿중복 없이 데이터를 저장할 수 있다
- 📈자동 정렬로 코드가 간결해진다
- 🔎범위 검색이 가능해 알고리즘 문제에 유용하다
💡 TIP: TreeSet은 정렬 기준이 중요한 컬렉션이므로, 사용자 정의 객체를 저장할 때는 반드시 정렬 기준을 정의해야 합니다.
⚙️ TreeSet의 정렬 원리
TreeSet이 가장 큰 강점을 발휘하는 부분은 바로 자동 정렬입니다.
TreeSet에 데이터를 추가하면 내부적으로 Red-Black Tree를 통해 이진 정렬 구조가 유지됩니다.
이는 요소들이 항상 오름차순으로 정렬되도록 보장해주는 장점이 있습니다.
기본적으로 TreeSet은 저장되는 요소가 Comparable 인터페이스를 구현하고 있어야 합니다.
즉, compareTo() 메서드를 통해 정렬 기준을 결정하죠.
하지만 개발자가 별도로 Comparator를 제공하면, 그 기준에 따라 커스터마이징된 정렬도 가능합니다.
💬 TreeSet은 add() 시점마다 정렬 기준에 따라 적절한 위치에 노드를 배치하며, 항상 균형 잡힌 트리 구조를 유지합니다.
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(30);
numbers.add(10);
numbers.add(20);
System.out.println(numbers); // 출력: [10, 20, 30]
}
}
위 예제에서 보듯이, 요소를 추가한 순서와 관계없이 TreeSet은 항상 정렬된 상태를 유지합니다.
만약 문자열을 저장하면 사전순으로, 숫자를 저장하면 오름차순으로 자동 정렬되죠.
💎 핵심 포인트:
TreeSet은 내부적으로 이진 탐색 트리를 활용하여 빠르게 데이터를 정렬하고, 삽입과 삭제 시에도 성능을 보장합니다.
🧩 Comparable과 Comparator 차이
TreeSet을 제대로 활용하기 위해서는 정렬 기준을 어떻게 설정하는지가 매우 중요합니다.
Java에서는 객체의 정렬 기준을 설정할 때 Comparable 또는 Comparator 인터페이스를 사용하게 됩니다.
이 두 인터페이스는 비슷해 보이지만, 쓰임새와 목적에 차이가 있어요.
🧭 Comparable – 기본 정렬 기준
Comparable은 클래스 자체에 정렬 기준을 내장하는 방식입니다.
클래스에 implements Comparable<T>를 선언하고, compareTo() 메서드를 오버라이드하여 정렬 기준을 정의합니다.
public class User implements Comparable<User> {
String name;
public User(String name) {
this.name = name;
}
@Override
public int compareTo(User other) {
return this.name.compareTo(other.name); // 이름 기준 정렬
}
}
🧮 Comparator – 외부에서 정렬 기준 정의
Comparator는 객체 외부에서 별도로 정렬 기준을 정의하고자 할 때 사용됩니다.
TreeSet 생성자에 Comparator를 전달하면 기본 정렬 기준을 덮어쓰고 해당 기준으로 정렬하게 됩니다.
TreeSet<User> users = new TreeSet<>(new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return u1.name.length() - u2.name.length(); // 이름 길이 기준 정렬
}
});
💎 핵심 포인트:
Comparable은 클래스 내부에, Comparator는 외부에서 정렬 기준을 설정하는 방식입니다.
유연한 정렬이 필요하다면 Comparator를 사용하세요.
🔍 TreeSet의 범위 검색 활용법
TreeSet이 정렬된 컬렉션이라는 점은 단순히 보기 좋게 정리된다는 수준을 넘어, 범위 기반 탐색이 가능하다는 큰 장점을 제공합니다.
특히 숫자나 문자열처럼 순서가 있는 데이터를 다룰 때 TreeSet은 매우 강력한 기능을 발휘합니다.
TreeSet에서 제공하는 주요 탐색 메서드는 다음과 같습니다.
- 🔼higher(E e): 지정된 값보다 큰 첫 번째 요소
- 🔽lower(E e): 지정된 값보다 작은 첫 번째 요소
- 🔁subSet(E from, E to): 특정 범위의 서브 집합 반환
- ⏬headSet(E to): 특정 값보다 작은 모든 요소
- ⏫tailSet(E from): 특정 값 이상인 모든 요소
TreeSet<Integer> set = new TreeSet<>();
set.add(10);
set.add(20);
set.add(30);
set.add(40);
set.add(50);
System.out.println(set.subSet(20, 50)); // 출력: [20, 30, 40]
이처럼 TreeSet의 범위 검색 기능은 원하는 조건에 맞는 데이터를 매우 빠르게 추출할 수 있게 해주며, 알고리즘 문제나 검색 기반 기능을 구현할 때 굉장히 유용합니다.
⚠️ 주의: subSet, headSet, tailSet은 반환된 집합을 직접 수정할 수 있으며, 원본 TreeSet에도 영향을 줄 수 있으니 사용 시 주의가 필요합니다.
🛠️ 실무에서 TreeSet 사용할 때 주의점
TreeSet은 정렬 기능이 뛰어나고 탐색도 효율적이지만, 모든 상황에서 완벽한 자료구조는 아닙니다.
실제 개발 환경에서는 TreeSet의 특성과 동작 방식을 잘 이해하고 적절한 상황에서만 사용하는 것이 중요해요.
⚠️ null 값 저장 불가
TreeSet은 내부적으로 정렬을 수행하기 때문에 null 요소를 저장할 수 없습니다.
null을 추가하려고 하면 NullPointerException이 발생하므로 주의가 필요합니다.
⛔ 중복 판단 기준이 다를 수 있음
TreeSet은 요소의 정렬 기준에 따라 중복 여부를 판단합니다.
따라서 equals()나 hashCode() 기준이 아닌, compareTo() 또는 Comparator 기준에서 같으면 같은 요소로 간주돼 추가되지 않아요.
- 🚫null 값은 저장할 수 없습니다
- ⚠️중복 판단은 정렬 기준(compareTo 또는 Comparator)에 따릅니다
- 🐢정렬 처리로 인해 HashSet보다 성능이 느릴 수 있습니다
💡 TIP: 데이터 정렬이 필요 없는 경우라면 TreeSet보다 HashSet이 더 빠른 성능을 보입니다.
정렬이 중요한 경우에만 TreeSet을 사용하세요.
❓ 자주 묻는 질문 (FAQ)
TreeSet과 HashSet은 어떤 차이가 있나요?
TreeSet은 자동 정렬이 되지만 비교적 느립니다.
TreeSet에 null을 추가하면 어떻게 되나요?
TreeSet에서 요소가 중복된다고 판단되는 기준은 무엇인가요?
사용자 정의 클래스도 TreeSet에 넣을 수 있나요?
TreeSet은 스레드에 안전한가요?
TreeSet에서 정렬 기준을 변경하려면 어떻게 하나요?
TreeSet의 성능은 어떤가요?
TreeSet은 어떤 상황에서 가장 잘 쓰이나요?
🧠 TreeSet을 이해하면 자료구조가 쉬워집니다
이번 글에서는 자바의 Set 구현체 중 하나인 TreeSet의 개념부터 정렬 원리, 범위 검색 활용법, 그리고 실무에서의 주의점까지 폭넓게 알아보았습니다.
TreeSet은 이진 탐색 트리 구조 기반으로 데이터를 저장하며, 자동으로 정렬된 상태를 유지하는 점에서 HashSet과 뚜렷하게 구분됩니다.
또한 Comparable과 Comparator를 활용한 정렬 기준 설정을 통해 유연한 데이터 처리가 가능하죠.
알고리즘 문제 풀이나 실무에서의 검색 최적화, 정렬된 데이터 유지가 필요한 작업이라면 TreeSet은 매우 강력한 도구가 될 수 있습니다.
하지만 null 저장 불가, 중복 기준의 차이, 성능 이슈 등 사용 전 반드시 체크해야 할 요소들도 존재하므로, 이러한 특성을 잘 이해하고 사용하는 것이 중요합니다.
TreeSet을 제대로 활용하면 자바 컬렉션 프레임워크에 대한 이해도도 자연스럽게 향상될 것입니다.
이 글이 여러분의 개발 실력을 한층 더 업그레이드하는 데 도움이 되었다면 좋겠습니다.
🏷️ 관련 태그 : TreeSet, 자바컬렉션, 정렬자료구조, Comparator, Comparable, 범위검색, 자바기초, 알고리즘준비, HashSet비교, 자바정렬