![[JAVA] 자바의 정렬 인터페이스 Comparable과 Comparator](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F82ETj%2FbtsIokhcnV1%2FH03XNj5qswYrQkiumORvPk%2Fimg.png)
자바에서 배열에 대해 정렬을 하고싶다면 어떻게해야할까?
코드를 통해 살펴보자
import java.util.Arrays;
public class SortMain1 {
public static void main(String[] args) {
Integer[] array = {3, 2, 1};
System.out.println(Arrays.toString(array));
System.out.println("기본 정렬 후");
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
}
실행결과
[3, 2, 1]
기본 정렬 후
[1, 2, 3]
util
패키지의 Arrays.sort
를 사용하면 배열의 데이터를 정렬할 수 있다.
정렬을 할 때 사용되는 정렬알고리즘은 다양하게 있지만 자바는 데이터가 32개 이하일 때는 듀얼 피벗 퀵소트를 사용하고, 데이터가 많을 때는 팀소트를 사용한다. 이런 알고리즘의 성능은 평균 O(log N)의 시간복잡도로 제공된다.
만약 배열을 정렬하는데 1->2->3의 순서가아닌 3->2->1과 같이 역순으로 정렬하고싶다면 어떻게 해야할까?
이런 경우에 사용되는 인터페이스가 바로 Comparator
이다.
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparator
는 compare
라는 메서드를 제공하는데 이 메서드는 int
타입을 반환한다.
만약 첫번째 인수가 작으면 음수를 반환하고, 두 값이 같다면 0, 첫번쨰 인수가 더 크다면 양수를 반환하게된다. 이 반환값을 기준으로 원하는대로 배열을 정렬시킬 수 있다.
Comparator
를 구현하여 오름차순, 내림차순 구현하기
import java.util.Arrays;
import java.util.Comparator;
public class SortMain2 {
public static void main(String[] args) {
Integer[] array = {3, 2, 1};
System.out.println(Arrays.toString(array));
System.out.println("Comparator 비교");
Arrays.sort(array, new AscComparator());
System.out.println(Arrays.toString(array));
System.out.println();
Arrays.sort(array, new DescComparator());
System.out.println(Arrays.toString(array));
System.out.println();
Arrays.sort(array, new AscComparator().reversed());
System.out.println(Arrays.toString(array));
}
static class AscComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println("o1 = " + o1 + " o2=" + o2);
return (o1 < o2) ? -1 : ((o1 == o2) ? 0 : 1);
}
}
static class DescComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println("o1 = " + o1 + " o2=" + o2);
return (o1 < o2) ? -1 : ((o1 == o2) ? 0 : 1) * -1;
}
}
}
Arrays.sort()
메서드의 매개변수로 Comparator
를 구현한 클래스를 넣어줄 수 있다.
이 때 compare()
메서드를 재정의하여 원하는대로 정렬의 기준을 바꿀 수 있다.
참고로 이중 삼항연산자가 어색할 수 있는데 if
문으로 변경하면 아래와 같이 구현된다.(오름차순 기준)
int result;
if (o1 < o2) {
result = -1;
} else if (o1 == o2) {
result = 0;
} else {
result = 1;
}
이렇게 Comparator
(비교자)를 사용하여 정렬의 기준을 자유롭게 변경할 수 있다.
문자도 숫자를 정렬하는 개념과 같이 ABC(오름차순), CBA(내림차순)과 같이 정렬할 수 있으며 자바에서 Integer클래스와 String클래스에 이미 구현을 해놓았다.
하지만 만약 내가 정의한 클래스 예를들면 Member
, Order
와 같은 객체들은 어떻게 정렬할 수 있을까?Member
클래스를 정렬한다고하면 id
값으로 정렬을 할수도있고, name
값으로 정렬을 할수도있을 것이다.
이 때는 Comparable
인터페이스를 구현하면 객체를 비교할수 있도록하여 자유롭게 정렬할 수 있도록 한다.
public interface Comparable<T> {
public int compareTo(T o);
}
Comparable
인터페이스는 compareTo()
라는 메서드를 제공한다. 이 메서드를 내가 만든 객체(Member
)에서 재정의하여 정렬의 기준을 정할 수 있다.compareTo
메서드도 int
타입으로 반환하는데, 현재 객체가 인수로 주어진 객체보다 더 작으면 음수를, 두 객체의 크기가 같다면 0, 현재 객체가 인수로 주어진 객체보다 더 크면 양수를 반환한다.
회원의 나이를 정렬의 기준값으로 정의
public class MyMember implements Comparable<MyMember>{
private String id;
private int age;
public MyMember(String id, int age) {
this.id = id;
this.age = age;
}
public String getId() {
return id;
}
public int getAge() {
return age;
}
@Override
public int compareTo(MyMember o) {
return this.age < o.age ? -1 : ((this.age == o.age) ? 0 : 1);
}
@Override
public String toString() {
return "MyMember{" + "id='" + id + '\'' + ", age=" + age + '}';
}
}
compareTo()
메서드만 살펴보자
위에서 정수값을 정렬할 때와 같으며 단지 비교하는 대상을 객체자신의 age
필드와 파라미터의 age
로 변경했을 뿐이다.
이렇게 Comparable
을 통해 구현한 순서를 자연순서라고 한다.
import java.util.Arrays;
public class SortMain3 {
public static void main(String[] args) {
MyMember aMember = new MyMember("a", 30);
MyMember bMember = new MyMember("b", 20);
MyMember cMember = new MyMember("c", 10);
MyMember[] members = {aMember, bMember, cMember};
System.out.println(Arrays.toString(members));
System.out.println();
System.out.println("재정의한 Comparable로 정렬");
Arrays.sort(members);
System.out.println(Arrays.toString(members));
}
}
실행결과
[MyMember{id='a', age=30}, MyMember{id='b', age=20}, MyMember{id='c', age=10}]
재정의한 Comparable로 정렬
[MyMember{id='c', age=10}, MyMember{id='b', age=20}, MyMember{id='a', age=30}]
실행결과를 살펴보면 나이순서대로 데이터가 정렬된 것을 확인할 수 있다.
여기서 핵심은 MyMember
클래스 안에 Comparable
을 구현한 재정의 메서드 compareTo
는 해당 클래스타입의 배열을 정렬할 때 기본값으로 사용된다.
만약 특별한 경우에 나이의 역순으로 정렬하고싶다거나, id를 기준으로 정렬을 하고싶다면 Comparator
를 구현하는 구현클래스를 따로 만들어주어야한다.
정리하자면
Comparable
인터페이스는 클래스 자체에 기본 정렬 기준을 정의하며compareTo
메서드를 재정의 하면Arrays.sort()
메서드를 호출할 때의 기준을 정하게된다.Comparator
인터페이스는 기본 정렬 기준과는 다른 기준으로 정렬을 할 때 사용한다.compare
메서드를 재정의한 뒤,Arrays.sort
(정렬하고자하는 배열
,new compare()를 재정의한 정렬기준 클래스
)와 같이 인자를 주면 원하는 정렬기준으로 정렬할 수 있다.
멤버별 나이의 역순으로 정렬
public class DescAgeComparator implements Comparator<MyMember> {
@Override
public int compare(MyMember o1, MyMember o2) {
return (o1.getAge() < o2.getAge()) ? -1 : ((o1.getAge() == o2.getAge()) ? 0 : 1) * -1;
}
}
import java.util.Arrays;
public class SortMain3 {
public static void main(String[] args) {
MyMember aMember = new MyMember("a", 30);
MyMember bMember = new MyMember("b", 20);
MyMember cMember = new MyMember("c", 10);
MyMember[] members = {aMember, bMember, cMember};
System.out.println(Arrays.toString(members));
System.out.println();
System.out.println("재정의한 Comparable로 정렬");
Arrays.sort(members);
System.out.println(Arrays.toString(members));
Arrays.sort(members, new DescAgeComparator());
System.out.println("나이의 역순으로 정렬");
System.out.println(Arrays.toString(members));
}
}
실행결과
나이의 역순으로 정렬
[MyMember{id='a', age=30}, MyMember{id='b', age=20}, MyMember{id='c', age=10}]
멤버의 아이디를 기준으로 오름차순정렬
import java.util.Comparator;
public class IdComparator implements Comparator<MyMember> {
@Override
public int compare(MyMember o1, MyMember o2) {
return o1.getId().compareTo(o2.getId());
}
}
이미 재정의 된 MyMember
의 compareTo
메서드를 사용하여 간단하게 정렬기준을 재정의할 수 있다.
또한 역순정렬을 원할 때 따로 클래스를 정의할 필요없이 reverse()
메서드를 사용하여 간단하게 역순으로 정렬할 수 있다.
Id로 오름차순/내림차순
import java.util.Arrays;
public class SortMain3 {
public static void main(String[] args) {
MyMember aMember = new MyMember("a", 30);
MyMember bMember = new MyMember("b", 20);
MyMember cMember = new MyMember("c", 10);
MyMember[] members = {aMember, bMember, cMember};
System.out.println(Arrays.toString(members));
System.out.println();
Arrays.sort(members, new IdComparator());
System.out.println("아이디순으로 오름차순");
System.out.println(Arrays.toString(members));
System.out.println("아이디순으로 내림차순");
Arrays.sort(members, new IdComparator().reversed());
System.out.println(Arrays.toString(members));
}
}
실행결과
아이디순으로 오름차순
[MyMember{id='a', age=30}, MyMember{id='b', age=20}, MyMember{id='c', age=10}]
아이디순으로 내림차순
[MyMember{id='c', age=10}, MyMember{id='b', age=20}, MyMember{id='a', age=30}]
참고로 Arrays.sort
를 호출할 때 Comparator
가 구현되어있지 않으면 자동적으로 클래스 내부에 기본으로 정의된 Comparable
을 사용하는데 Comparable
도 정의되어있지 않다면 예외가 발생한다.
#### 컬렉션프레임워크의 정렬
컬렉션프레임워크도 배열과 같은 개념으로 정렬기준을 제공한다.
물론 순서가 있는 List
같은 자료구조에만 제공되며 Map
, Set
과 같은 자료구조는 순서가 없기때문에 정렬을 제공하지 않는다.Tree
자료구조 같은경우에는 데이터를 보관할 때 데이터를 정렬하면서 보관하기때문에 정렬기준을 반드시 명시해야한다.
Collections.sort(list)
- 기본 정렬을 제공한다.
- 객체지향을 강조하기위해서는 잘 사용되지 않는다.
list.sort(null)
- 별도의 비교자가 없기때문에
Comparable
로 비교해서 정렬한다
- 별도의 비교자가 없기때문에
Collecions.sort(list, new IdComparator)
- 별도의 비교자로 비교할 수 있지만 이 메서드 또한 잘 사용되지 않고
list.sort()
를 사용한다.
- 별도의 비교자로 비교할 수 있지만 이 메서드 또한 잘 사용되지 않고
list.sort(new IdComparator())
- 전달한 비교자로 비교한다.
'Language > Java' 카테고리의 다른 글
[Java] 람다 표현식과 함수 인터페이스 (0) | 2024.11.08 |
---|---|
[JAVA] 예외 계층 (0) | 2024.07.09 |
해시 알고리즘 (0) | 2024.06.29 |
[JAVA - 자료구조] HashSet (0) | 2024.06.29 |
[JAVA] 불변객체 (0) | 2024.06.24 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!