간단히 말하자면 자연스러운 정렬 즉, 자연정렬은 자연스러운 순서 1,2,3, ... 를 따라 정렬한다.
하지만 모든 타입의 배열이 이러한 자연스러운 정렬 방식을 따르는 것은 아니다.
배열의 정렬 방식은 배열 요소의 형식(타입, 클래스)마다 다르다.
좋은 예시 하나는 String클래스다. String 즉 문자열의 정렬 방법을 확인해보자.
String[] a = {"324", "43", "12", "1", "39", "9"};
System.out.println(Arrays.toString(a));
Arrays.sort(a);
System.out.println(Arrays.deepToString(a));
실행 결과는 아래와 같다.
[324, 43, 12, 1, 39, 9]
[1, 12, 324, 39, 43, 9]
위 예시를 보면, 문자열의 오름차순 정렬 방식이 확연히 보일 것이다. 문자열 정렬은 동일 위치에 있는 문자의 대소 비교를 통해 정렬한다. 한글이나 알파벳도 마찬가지다. 이렇게 String의 정렬방식은, 수의 정렬방식과는 다르다.
[랄라, 맛있는, 거, 먹고, 싶다, 간식, ab, z]
이 배열은↓
[ab, z, 간식, 거, 랄라, 맛있는, 먹고, 싶다]
이렇게 정렬된다. 우리가 알고있는 영문, 한글 오름차순
정렬된 배열을 탐색하는 이진탐색에 대해 이야기하면서 '클래스의 정렬'을 조금 더 깊이 이해해보자.
정렬된 배열은 이진탐색할 수 있다.
신기한 것은 java.util.Arrays클래스의 이진탐색하는 메서드인 binarySearch는 제일 최상위클래스 Object를 인자로 받는다. 즉, 어떠한 형태의 클래스라도 binarySearch의 인자로 받을 수 있다. 모든 클래스를 정렬가능하다는 말이다. 신기하다. 형식이 다른 클래스들은 각각 어떻게 그 정렬방식이 결정되는 것일까? 어떻게 모든 클래스의 대소관계를 정의해낼 수 있다는 말일까?
다시 String 클래스를 예시로 들자. String클래스가 오름차순 정렬이 가능한 이유는:
String클래스가 '순서비교(대소비교)해주는 인터페이스'를 구현하고 있기 때문이다. 이 인터페이스는 Comparable<T>라는 인터페이스인데, String클래스가 Comparable 인터페이스를 구현하고 있다. 그리고 그와 관련된 compareTo나 equals이라는 메소드를 구현하고도 있는데, 이 메소드에다가 두 객체의 대소를 판단하는 방법을 구현한다. 그러니까 우리가 알고 있는 문자열 정렬 방식인 한글, 영문 등 오름차순의 방법을 Comparable 인터페이스의 메소드인 compareTo, equals 메소드에 구현한 상태라는 것이다.
그래서 정렬기준을 가지는 클래스는 Comparable인터페이스, compareTo메소드를 통해 정렬방식을 구현하고 있다. 만약 내가 직접 만든 어떤 클래스에도 대소기준을 세우고 싶다면, Comparable인터페이스를 구현하여 정의해주면 된다.
어 그런데, 이러한 정렬방법이 구현되어있지 않은 배열에서는 어떠한 방법으로 검색할 수 있을까? 우리가 어떤 클래스에 대하여는 따로 대소판단 기준을 이야기해주어야 할 수도 있을 것이다. 그 대소기준을 따로 작성해 인자로 넣어 사용하는 방법을 알아보자. 그 기준을 따로 작성한다는 것은, 대소판정 기준이 담겨있는 comparator를 구현해 인자로 넣어주겠다는 말이다.
이진검색하는 메소드인 Arrays.binarySearch를 기준으로 알아보자.
세번째 인자로 들어가는 Comparator은 각 배열요소의 대소관계(정렬순서)를 어떻게 판단할 것인지의 정보를 담고 있는 인터페이스를 구현하고 있다. 다시 말하면, 세번쨰 인자에는 java.util.Comparator라는 인터페이스를 구현하는 클래스가 들어간다. 이 클래스에서는 compare(T data1, T data2)를 구현하여 대소관계를 정의하고 있다. 이렇게 만들어진 클래스를 인스턴스화하여 사용하면 된다. 그 인스턴스가 바로 comparator고 세번째 인자에 들어가는 것이다.
다음은 클래스X에 comparator객체를 생성하는 모습이다.
import java.util.Comparator;
class X {
.
.
.
//comparator의 인스턴스 생성 - 이렇게 생성한 comparator를
//binarySearch의 세번째 인자에 넣어 사용한다.
//COMPARATOR은 클래스변수니까 X.COMPARATOR가 인자에 들어가게 되겠죠!
public static final Comparator<T> COMPARATOR = new Comp();
//comparator 인터페이스를 구현한 Comp라는 클래스 -> 즉 Comp라는 comparator
//comparator 구현을 굳이 내부클래스로 하지는 않아도 된다. 상관없다.
private static class Comp implements Comparator<T> {
//compare메서드 구현하기
public int compare(T d1, T d2) {
//d1과 d2의 대소판정이 이루어진다
}
}
}
이렇게 따로 정의한 comparator를, 이진탐색 메소드 binSearch(T[] a, T key, Comparator c)의 세번째 인자에 넣어줌으로써, 우리가 원하는 대로 작성한 대소판정 기준을 전달해줄 수 있다는 이야기를 해보았다. (단, 끝까지 유의해야 할 것은 이진검색에 들어가는 배열은 '정렬된 상태'여야 한다는 것이다. 하지만 컴퓨터는 우리가 정렬한 게 어떤 것을 기준으로 한 건지 모르기에 Comparator를 인자에 넣어줘야 한다는 말이다.)
예를 들어보자.
사람의 신체정보인 키, 시력, 이름을 담은 PhyscData라는 클래스가 있다고 하자. 우리는 이 객체를 담은 배열을 '키'를 기준으로 정렬했다고 하자. 그러면 binarySearch에 이 배열을 넣었으면, '키를 기준으로 정렬한 거다'라는 정보를 comparator에 넣어줘야 한다는 말이다. 이 Comparator의 이름을 HEIGHT_ORDER라고 한다면, binarySearch(x, new PhyscData("",찾을height값,0.0), HEIGHT_ORDER)의 의미는 배열x에서 원하는 height를 가진 요소(객체)를 HEIGHT_ORDER에 의해 검색한다는 의미다.
요약: 어느 클래스를 정렬(대소판단)하는 기준은 comparator에다가 따로 구현해낼 수 있다. 그리고 이 comparator를 인스턴스화하여 사용하면 된다.
'JAVA' 카테고리의 다른 글
실전 Java 소프트웨어 개발 | 입출금 내역 분석기 실습하기 (0) | 2022.03.26 |
---|---|
열거 타입, 열거 상수란? | 열거타입(enum) 변수 | enum, enumeration type (0) | 2021.07.03 |
[Java] String.format() | 문자열 형식 지정하기 | %%%ds가 뭘까? | %% (0) | 2021.06.24 |
Spring 학습 1일차 - 자바 웹 개발 첫경험을 위해 (0) | 2021.02.07 |
안드로이드 - 챕터10, 지도와 GPS (0) | 2021.01.28 |