정렬 알고리즘 문제를 푸는 중에 매우 깔끔한 코드를 발견했습니다.
저는 열심히 퀵소트로 문제를 풀었는데, 어떤 분들은 Arrays.sort와 lambda 함수를 사용해서 아주 깔끔한 코드로 풀이를 완성한 것이었죠!!!
저는 그런 식으로 코딩해본 적이 없어서 한 줄씩 뜯어봤는데,
사실 '저 코드가 도대체 왜 오름차순 정렬을 하는 코드인거지???' 하는 생각이 계속 들었습니다.
그래서 다시 찾아보면서 이해를 하고 메모를 해두려고 합니당
정렬하는 부분만 작성해둔 예시 코드는 다음과 같습니다.
// 예시 코드
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] arr1d = new int[]{5,3,1,4,2,5};
int[][] arr2d = new int[][]{{5,10},{3,30},{1,50},{4,20},{2,40},{5,60}};
Arrays.sort(arr1d);
System.out.println(Arrays.toString(arr1d));
// 오름차순 정렬
Arrays.sort(arr2d, (o1, o2) -> {
return o1[0] - o2[0];
});
System.out.println(Arrays.deepToString(arr2d));
// 내림차순 정렬
Arrays.sort(arr2d, (o1, o2) -> {
return o2[0] == o1[0] ? o2[1] - o1[1] : o2[0] - o1[0];
});
System.out.println(Arrays.deepToString(arr2d));
}
}
// 실행 결과
[1, 2, 3, 4, 5, 5]
[[1, 50], [2, 40], [3, 30], [4, 20], [5, 10], [5, 60]]
[[5, 60], [5, 10], [4, 20], [3, 30], [2, 40], [1, 50]]
제가 이해하지 못했던 부분은 Arrays.sort() 함수의 두 번째 인자에 들어간 람다 함수로 인해, 오름차순 또는 내림차순 정렬이 된다는 부분이었습니다.
뺀...다고 왜 정렬이 되 . . ? 이런 생각이었던 것이죱
이걸 이해하기 위해 sort 함수를 까보았습니다.
sort 메서드의 정의는 다음과 같습니다.
public static <T> void sort(T[] a, Comparator<? super T> c)
오. 저는 sort 함수에 c 라는 인자가 있는지도 몰랐었습니다.
Comparator 라는 인터페이스를 까 봅니다. FunctionalInterface네요.
Compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. 라고 설명이 써있습니다.
그리고 이건 sort()함수에 구현되어있는 정렬 알고리즘 중 일부입니다.
제가 밑줄 친 부분의 조건이 참이 되면 순서를 바꾼다는 것을 알 수 있습니다.
즉, 첫 번째 값(o1)이 두 번째 값(o2)보다 크면 -> c.compare() 함수 값이 양수가 되고 -> 두 값의 순서를 바꿉니다.
자 다시 정리를 해봅시다.
1. Arrays.sort()는 배열을 정렬하는 메서드이고, Comparator를 이용해서 두 원소를 비교하는 방식을 직접 지정할 수 있습니다. 즉, 사용자 정의 비교 기준입니다.
2. Comparator의 동작 방식: 두 개의 값(o1, o2)을 비교해서 o1 < o2이면 음수를, o1 == o2이면 0을, o1 > o2이면 양수를 리턴합니다. 순서를 바꾸는 측면에서 보면,
- 두 값을 비교해서 0 또는 음수가 나오면, 두 값의 순서를 바꾸지 않습니다.
- 두 값을 비교해서 양수가 나오면, 두 값의 순서를 바꿉니다.
그럼 이제 다시 아까의 람다 함수로 돌아가 봅시다.
o1[0] - o2[0]을 계산했을 때 음수이면 그대로 둡니다.
그러니까 o1[0], o2[0] 순서대로 둔다는 것이고, 저 값이 음수라는 것은 o2[0]이 o1[0]보다 크다는 뜻입니다.
즉, `작은 값, 큰 값` 순서대로 정렬이 되는 것입니다.
반대로, o1[0] - o2[0]을 계산했을 때 양수이면 앞 뒤 값을 바꿉니다. 그러면 o2[0], o1[0] 순서가 된다는 뜻이고, 저 값이 양수니까 o1[0] > o2[0] 입니다.
즉, 이번에도 `작은 값, 큰 값` 순서대로 정렬이 되는 것입니다.
이러한 원리로 인해 저 람다 함수를 통해 오름차순 정렬이 가능해진 것입니다.
제가 아까 궁금했던 부분이 해결되었습니다!!!
Q: 뺄셈을 한다고 왜 정렬이 되는 것일까?
A: 뺄셈을 하는 이유는, 두 값을 비교하고 그 차이에 따라 정렬 순서를 결정하기 위함입니다. 차이가 음수이면 첫 번째 값이 더 작은 것이므로 순서를 바꾸지 않고, 양수이면 순서를 바꿉니다. 이 차이 값을 통해 어떻게 정렬될지가 정해집니다.
참고로, 여기서 쓰인 람다 함수는 compare 메서드를 간단하게 표현한 방식입니다.
위에 있는 sort 메서드의 정의를 참고하면, Comparator<? super T> c 이 위치에 람다 함수가 들어갑니다.
이렇게 함수형 인터페이스 형 변수에 람다 함수를 넣으면 그 람다 함수가 해당 함수형 인터페이스의 유일한 추상 메서드를 구현한 것과 같습니다. 자바에서 지원해주는 기능이지요! 비교를 위한 코드를 첨부하겠습니다.
자바 8 이전에는 익명 클래스 방식을 사용했다고 합니다.
// 익명 클래스 방식
Comparator<int[]> comparator = new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
};
// 람다 표현식 방식
Comparator<int[]> comparator = (o1, o2) -> o1[0] - o2[0];
추가적인 연습이 필요하다면 다음 사이트를 활용해봐도 좋을 것 같습니다.
https://www.w3schools.com/java/java_advanced_sorting.asp
W3Schools.com
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
www.w3schools.com
'💻 Computer Science > Algorithm' 카테고리의 다른 글
최단 경로 알고리즘 (0) | 2024.11.02 |
---|---|
이진탐색 알고리즘 (0) | 2022.10.10 |