머지 소트(병합 정렬) 역시 강력하고 쉬운 알고리즘이다.
절반으로 계속 나누어 나가다가 더 이상 나눌 수 없어지면 다시 합치는 알고리즘이다.
단지 합칠 때 작은 값과 큰 값의 순서를 확인하면서 합쳐나가는 것이 포인트다.
퀵 소트와 마찬가지로 절반으로 나누어 재귀호출하기 때문에 로그단위의 복잡도를 가진다.
하지만 퀵 소트와는 다르게 이미 정렬된 값은 순서 그대로 합쳐져 stable한 결과를 가진다.
위키백과의 그림을 참고해 설명하자면
이렇게 두 단계로 나눌 수 있다.
노란 색으로 표시한 두 배열을 합치는 방법을 좀 더 자세히 보면
이런 순서가 된다.
합칠 값 두개를 비교한 후 더 작은 값을 새로 만들 배열에 넣고, 나머지 값을 재귀호출 하는 것이다.
스칼라 코드로 구현하면 아래처럼 될 것이다.
def mergeSort[A](lst: List[A])(implicit ord: A => Ordered[A]): List[A] = {
def merge(lLst: List[A], rLst: List[A]): List[A] = (lLst, rLst) match {
case (Nil, right) => right
case (left, Nil) => left
case (lh::lt, rh::rt) =>
if(lh > rh) rh::merge(lLst, rt)
else lh::merge(lt, rLst)
}
if(lst.isEmpty || lst.length == 1) lst
else {
val mid = lst.length / 2
val (lLst, rLst) = lst.splitAt(mid)
merge(mergeSort(lLst), mergeSort(rLst))
}
}
두개의 리스트를 입력받아 합쳐 리턴하는 merge 함수와 그 과정을 재귀호출하는 mergeSort 함수로 구성했다.
포인트가 되는 merge 함수에서는
어느 한 쪽이 비어있으면 비어있지 않은 쪽을 리턴하고
양 쪽 다 비어있지 않으면 양 쪽 리스트의 head를 비교해 더 작은 값을 head로, 나머지 값들로 재귀호출을 한다.
다른 정렬 알고리즘도 대부분 마찬가지지만, mutable 콜렉션으로 구현하는게 훨씬 어려울 것 같다.
'Scala' 카테고리의 다른 글
Scala의 암시(implicit) (1) | 2017.03.16 |
---|---|
Java의 Comparator/Comparable, Scala의 Ordered/Ordering (0) | 2017.03.15 |
Scala로 만들어본 Quick Sort (0) | 2017.02.28 |
Scala trait과 Java interface에서의 변수 (0) | 2017.02.24 |
Scala의 static, companion object (0) | 2017.02.24 |