본문 바로가기
Java의 정석/컬렉션 프레임워크

Comparator & Comparable

by Hwanii_ 2023. 9. 20.
728x90

ch11-30 ~ 33 Comparator & Comparable

 

 

 

ch11 - 30 Comparator & Comparable

- 객체 정렬에 필요한 메서드 (정렬 기준 제공이 목적) 를 정의한 인터페이스 이다.

Comparable : 기본 정렬 기준을 구현 하는데 사용 한다.

Comparator : 기본 정렬 기준 외에 다른 기준으로 정렬하고자 할 때 사용 한다.

아래의 이미지는 다음과 같다.

 


인터페이스 내부의 compare() 또는 compareTo() 메서드를 사용 하면,
반환값이 양수 또는 0 또는 음수가 나오게 된다.

왼쪽이 크면 양수
왼쪽과 오른쪽이 같으면 0
오른쪽이 크면 음수

를 반환 하게 된다.

compare() 메서드는 두 객체를 비교 하는 메서드 이고,

compareTo() 메서드는 인자에 들어온 객체와 자기 자신을 비교 하는 메서드 이다.

두 메서드는 정렬에 사용되고, 정렬 기준을 제공한다는점에 있어서 근본적으로 동일 하다고 할 수 있다.

정렬 기준은 엄청 다양 하다.

오름차순
내림차순
나이순
몸무게
성적
..

굉장히 많은 기준으로 정렬을 할 수 있다.

근데 컴퓨터는 이러한 정렬 기준을 알아서 잡을 수 없기 때문에,

개발자가 정렬 기준을 컴퓨터에게 제시해 줘야 한다.

이럴때 사용 하는 메서드가 바로 compare() 메서드와 compareTo() 메서드 이다.

아래의 이미지를 보면 다음과 같다.

 


compare() 메서드와 compareTo() 메서드는 두 객체의 비교 결과를 반환하도록 작성 된다.

같으면 0, 오른쪽이 크면 음수 (-), 오른쪽이 작으면 양수 (+) 의 결과를 반환 한다.

return 값은 삼항 연산자가 사용 되었다.

v1 < v2 ? -1 : (v1 == v2 ? 0 : 1));

v1과 v2를 비교해서 v1이 더 작으면 -1을 반환 하고,
v1과 v2를 비교해서 v1이 v2보다 작지 않으면,
또 한번의 삼항연산식으로 비교 하게 된다.
v1 하고 v2 하고 같으면 0을 반환 하고,
v1 하고 v2 하고 같지 않으면 1을 반환 한다.

 

 

 

ch11 - 31 Comparator & Comparable - 예제

sort() 메서드를 사용 하여 정렬을 한다.

정렬은 무조건 두가지 조건이 필요 하다.

1) 정렬 대상

2) 정렬 기준

이다.

static void sort(Object[] a) // 객체 배열에 저장된 객체가 구현한 Comparable에 의한 정렬

위는 정렬 대상만 있고, 정렬 기준이 보이지 않는데, 이런 경우에는,
기본 정렬 기준을 가지고 있는 대상 이면 사용이 가능 하고,
기본 정렬 기준이 없으면 사용이 불가능 하다.

만약에 Object[] a가 String 타입의 배열이면 어떻게 될까 ?

정답은 사용이 가능 하다.

왜냐하면 String 클래스는 Comparable 인터페이스를 구현한 클래스 이기 때문에,
기본 정렬 기준값이 존재 한다.

 


static void sort(Object[] a, Comparator c) // 지정한 Comparator 에 의한 정렬.

기본 정렬 기준이 없으면 위의 코드와 같이, Comparator c 라는 정렬 기준을 넣어 주면 된다.

또는 기본 정렬 기준이 있더라도, 원하는 정렬 방식이 있다면, 그 정렬 방식 기준을 인자로 넣어 주면 된다.

String.CASE_INSENSITIVE_ORDER 는 대소문자를 구분 하지 않는다는 정렬 기준이다.

 

 

 

 

정렬 기준을 직접 생성 하는 예제를 확인 하기.

 

import java.util.*;

class Ex11_7 {
	
	public static void main(String[] args) {
		
		String[] strArr = {"cat", "Dog", "lion", "tiger"};

		Arrays.sort(strArr); // String의 Comparable구현에 의한 정렬	//	기본값은 오름차순이고, 알파벳 기준으로는 대문자 부터 정렬 된다.
		System.out.println("strArr = " + Arrays.toString(strArr));

		Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 대소문자 구분안함
		System.out.println("strArr = " + Arrays.toString(strArr));

		Arrays.sort(strArr, new Descending()); // 역순 정렬
		System.out.println("strArr = " + Arrays.toString(strArr));
		
	}
	
}

class Descending implements Comparator { 
	
	public int compare(Object o1, Object o2){
		
		if( o1 instanceof Comparable && o2 instanceof Comparable) {
			Comparable c1 = (Comparable)o1;
			Comparable c2 = (Comparable)o2;
			return c1.compareTo(c2) * -1 ; // -1을 곱해서 기본 정렬방식의 역으로 변경한다.
			// 또는 c2.compareTo(c1)와 같이 순서를 바꿔도 된다.
		}
		return -1;
		
	} 
	
}

 

import java.util.*; 

class Ex11_8 { 
	
	public static void main(String[] args) { 
		
		Integer[] arr = { 30, 50, 10, 40, 20 }; 

		Arrays.sort(arr); // Integer가 가지고 있는 기본 정렬기준 compareTo()로 정렬 
		System.out.println(Arrays.toString(arr));

		// sort(Object[] objArr, Comparator c)
		Arrays.sort(arr, new DescComp()); // DescComp에 구현된 정렬 기준으로 정렬
		System.out.println(Arrays.toString(arr));
		
	} // main
	
}	

class DescComp implements Comparator {
	
	public int compare(Object o1, Object o2) {
		
		if(!(o1 instanceof Integer && o2 instanceof Integer))
			return -1; // Integer가 아니면, 비교하지 않고 -1 반환

		Integer i  = (Integer)o1;
		Integer i2 = (Integer)o2;
		
		// return i2 - i; 또는 return i2.compareTo(i);도 가능
		return i.compareTo(i2) * -1; // 기본 정렬인 compareTo()의 역순으로 정렬
		
	}
	
}

 

 

 

ch11 - 32 Integer & Comparable

 

public final class Integer extends Number implements Comparable {

...
public int compareTo(Object o) {

return compareTo((Integer) o);
}

public int compareTo(Integer anotherInteger) {

int thisVal = this.value;
int anotherVal = anotherInteger.value;

// 비교하는 값이 크면 - 1, 같으면 0, 작으면 1을 반환.

return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
}

..
}

정렬 방법 : 두 대상 비교 자리 바꿈 반복 하기.

수많은 정렬 기준 방법이 있지만,
모두 공통의 행동은 두 대상을 비교 하고 자리 바꿈을 반복 한다.

정렬 방법의 종류 : 
버블정렬
삽입정렬
선택정렬
퀵정렬
쉘정렬
병합정렬
..

>> 상황에 맞게 전략적으로 다양한 정렬 방법을 사용 할 수 있다.

아래는 버블 정렬 코드 예시 이다.

 


처음에 두개를 비교 하고, if문에서 조건에 부합되면 자리 바꿈을 한다.

전체 for문이 끝날때까지 비교 및 자리 바꿈을 반복 하게 된다.

아래의 이미지를 확인 하기.

 


sort() 메서드의 인자로 정렬 대상과 정렬기준을 넣어 준다.

그러면 if문에서 정렬 기준을 가지고 조건에 따라 자리 바꿈을 진행 한다.

 

 


결론은,
정렬 방법 (로직) 은 이미 다 만들어져 있기 때문에,
가져다가 사용 하면 되고,
상황에 맞는 정렬 기준만 넣어주면 된다.

반응형

'Java의 정석 > 컬렉션 프레임워크' 카테고리의 다른 글

HashSet (2)  (0) 2023.10.09
HashSet (1)  (0) 2023.09.20
Arrays 클래스  (0) 2023.09.20
Iterator, Enumeration / Map 과 Iterator  (0) 2023.09.20
Stack / Queue (스택 / 큐)  (0) 2023.09.17