새소식

Algorithm/개념정리

Comparable, Comparator 인터페이스

  • -

  백준 문제풀이를 진행하는데 있어 정렬에 조건을 줄 때, 아직 미흡한 이해 때문에 구글링을 번복하고 있다. 그렇기에 이번 기회에 확실하게 개념을 잡고 활용해보고자 정리하게 되었다.

 

Comparable 인터페이스를 사용하려면 compareTo 메소드를 구현해야하는 것,

Comparator 인터페이스를 쓰려면 compare 메소드를 구현해야 하는 점이 서로의 차이점이다.

 

 보통 두 인터페이스는 "객체를 비교할 수 있도록 만든다." 라고 생각하는 것이 편하다. 하지만 왜 객체를 비교할 수 있도록 생각하라는 것일까? 우리는 원시 타입의 실수 변수 경우 부등호로 쉽게 비교할 수 있기 떄문이다. 하지만 새로운 클래스 객체를 만들어 비교하고자 한다면 본질적으로 객체는 사용자가 기준을 정해주지 않는 이상 어떤 객체가 더 높은 우선순위를 갖는지 판단 할 수가 없다는 것이다.

 

 

 

그래서 이러한 문제점을 해결하기 위해 바로 Comparable 과 Comparator을 사용한다는 것이다.

 

 왜 Comparable의 compareTo(T o) 메소드는 파라미터(매개변수)가 한 개이고, Comparator의 compare(T o1, T o2) 메소드는 파라미터가 왜 두 개인 것일까?

 

일단, 두 인터페이스를 구체적으로 알아보기에 앞서 먼저 정답부터 말하자면, Comparable은 "자기 자신과 매개변수 객체를 비교"하는 것이고, Comparator는 "두 매개변수 객체를 비교"한다는 것이다.

 

 쉽게 말하자면, Comparable은 자기 자신과 파라미터로 들어오는 객체를 비교하는 것이고, Comparator는 자기 자신의 상태가 어떻던 상관없이 파라미터로 들어오는 두 객체를 비교하는 것이다. 즉, 본질적으로 비교한다는 것 자체는 같지만, 비교 대상이 다르다는 것이다.

 

 또 다른 차이점이라면 Comparable은 lang패키지에 있기 때문에 import 를 해줄 필요가 없지만, Comparator는 util패키지에 있다.

이것만 기억해도 일단 기초는 이해한 것이라고 보면 된다.

 

 

 

 

Comparable

 

일단 Comparable 인터페이스는 interface Comparable<T> { ... } 라고 되어있다. 쉽게 이야기 하자면, <T>는 하나의 객체 타입이 지정 될 자리라고 생각하면 된다. 

 

 

이 때, 필수 구현 부분인 compareTo() 메소드가 바로 우리가 객체를 비교할 기준을 정의해주는 부분이 된다.

 

쉽게 생각하면 이렇다. 여러분이 클래스를 만들 때, ClassName을 비교하고 싶을 것이다.

 

 아까 Comparable은 자기 자신과 매개변수 객체를 비교한다고 했다. 즉, 자기자신은 ClassName으로 생성한 객체 자신이 되고, 매개변수 객체는 ClassName.compareTo(o); 를 통해 들어온 파라미터 o가 비교 할 객체가 되는 것이다.

 

 

 이제 compareTo 메소드를 구현해야 할 것이다. 만약 나이를 기준으로 비교(대소 관계)를 하고자 한다면 어떻게 하면 될까?

자기 자신의 age(나이)와 매개변수로 들어온 o의 age(나이)의 값을 비교하면 된다.

 

 

 

 compareTo 메소드를 보면 int값을 반환하도록 되어있다.

즉, 쉽게 말해 우리는 '값'을 비교해서 정수를 반환해야 한다는 것이다. this는 a객체 자신을 의미하고, o는 b객체를 의미하게 된다.

 

 

[Comparable의 특징]

 

1. 자기 자신과 매개변수를 비교한다.

2. compareTo 메소드를 반드시 구현해야한다.

 

 

 

 

Comparator

 

 

  "두 매개변수 객체를 비교"한다고 했다. 이 말은 자기 자신이 아니라 파라미터(매개 변수)로 들어오는 두 객체를 비교하는 것이다. 여기서 바로 Comparable과 차이가 발생하는 것이다. 이 부분은 Comparable에서 설명했던 것과 같이 <T>는 하나의 객체 타입이 지정 될 자리라고 생각하면 된다. 

 

 

 

 이 때, 필수 구현 부분인 compare() 메소드가 바로 우리가 객체를 비교할 기준을 정의해주는 부분이 된다. 앞서 말했듯, Comparable과 다르게 Comparator는 매개변수로 들어오는 두 객체를 비교하는 것이기 때문에 당연히 매개변수가 두 개가 되는 것이다.

 

 

 

 

 앞서 Comparable의 compareTo()와는 다르게, 두 객체를 비교하는 것이기 때문에 파라미터로 들어오는 o1과 o2의 classNumber을 비교해주는 것이다.

 

 좀 더 구체적으로 말하자면 Comparable의 compareTo는 선행 원소가 자기 자신이 되고, 후행 원소가 매개 변수로 들어오는 o 가 되는 반면에, Comparator의 compare는 선행 원소가 o1이 되고, 후행 원소가 o2가 된다.

 

 

 

추가로 오름차순과 내림차순의 정렬 예시로는

 

 

 이는 선행 원소가 후행 원소보다 작으면 compare 혹은 compareTo 메소드의 반환값이 음수가 나오고, 정렬 알고리즘에서는 두 원소를 비교할 때 두 원소는 오름차순 상태라는 의미이므로 두 원소가 교환되지 않는다는 것이다.

 

 반대로 선행 원소가 후행원소보다 크면  compare 혹은 compareTo 메소드의 반환값이 양수가 나오고, 정렬 알고리즘에서는 두 원소를 비교할 때 두 원소는 내림차순 상태라는 의미이므로 두 원소가 교환된다는 것이다.

 

즉, 정렬 알고리즘에서는 두 원소를 compare 혹은 compareTo 를 써서 양수값이 나오냐, 음수값이 나오냐에 따라 판단을 한다는 것이다.

 

 위 방법이 오름차순이라면 내림차순으로 정렬하고 싶은 경우 두 원소를 비교한 반환값을 반대로 해주면 되는 것 아닌가?

쉽게 말해 두 값의 차가 양수가 된다면 이를 음수로 바꿔 반환해주고, 만약 음수가 된다면 그 값을 양수로 바꾸어 반환해주면 된다는 것이다.

'Algorithm > 개념정리' 카테고리의 다른 글

Kruskal vs Prim  (1) 2023.12.02
글을 쓰기에 앞서서  (0) 2023.04.13
이진 트리와 순회 방법  (0) 2023.04.13
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.