💡 자바스크립트 언어로 자료구조 & 알고리즘에 대해 배운 내용을 기록합니다
이전에 알아보았던 bubble, insertion, selection 정렬은 전반적으로 O(n^2) 의 시간복잡도를 가지므로, 배열의 길이가 커졌을때 상당히 비효율적인 알고리즘이 됩니다.
이러한 시간복잡도를 O(n logn)으로 개선할 수 있는 정렬 알고리즘들이 있습니다. 대표적인 것들이 Merge, Quick, Radix Sort인데요, 이 알고리즘들은 보다 더 효율적이지만, 그만큼 구현하기에 더 복잡하다는 점이 있습니다.
이번 포스트에서는 병합 정렬 (Merge Sort)의 작동 방식을 알아보면서 자바스크립트 코드로 구현해보겠습니다.
병합정렬은 병합(merging)과 정렬(sorting) 두가지 큰 기능으로 구성됩니다. 길이가 0이나 1인 배열은 항상 정렬되어 있는 상태라는 점을 활용해서, 배열을 0개 혹은 1개의 요소로 모두 분리시킨 뒤, 배열을 새롭게 재구성(병합) 하면서 정렬시키는 정렬 방식입니다.
병합 정렬을 구현하기 위해서, 먼저 두개의 정렬된 배열을 하나로 병합하는 함수를 구현해보겠습니다.
병합되는 배열은 정렬 되어 있어야하며, 두 Input 배열의 모든 요소가 들어있어야 합니다. 또한, Input 배열들이 수정되면 안됩니다.
두 배열의 모든 요소를 순회하게 되므로 O(n+m) 의 시간복잡도와 공간복잡도로 동작하게 됩니다.
[Pseudocode]
function merge(arr1, arr2) {
let result = [];
let i = 0;
let j = 0;
while ( i < arr1.length && j <arr2.length) {
if (arr2[j] > arr1[i]) {
result.push(arr1[i]);
i++;
}
else {
result.push(arr2[j]);
j++;
}
while ( i < arr1.length) {
result.push(arr[i]);
i++;
}
while ( j < arr2.length) {
result.push(arr[j]);
j++;
}
return result;
}
이제 위에서 만든 merge 함수를 활용하여, Merge sort의 전체 로직을 구성해보겠습니다.
[Pseudocode]
function mergeSort(arr) {
let (arr.length <= 1) return arr;
let mid = Math.floor(arr.length / 2)
let left = mergeSort(arr.slice(0, mid));
let right = mergeSort(arr.slice(mid));
return merge(left, right);
}
위 코드가 동작하는 방식을 간단하게 도식화하면 아래와 같습니다.
지금까지 살펴본 병합 정렬 알고리즘의 시간복잡도는 아래와 같습니다
전반적으로 O(n logn)의 시간복잡도를 갖습니다.
n logn 이라는 시간복잡도는 조금 생소한데요, 어떻게 n logn 이 되는지 간단하게 살펴보겠습니다
먼저, 배열을 계속해서 반씩 쪼개는 알고리즘의 시간복잡도는 O(logn)입니다.
두 번째로 배열이 쪼개지고 난 뒤 다시 병합할 때 (merge 함수) 는 모든 배열의 요소를 순회하게 되므로 시간복잡도는 O(n)입니다.
아래 그림에서 보듯 쪼개진 level 마다 모든 요소를 탐색하면서 병합 & 정렬을 실행하면서 시간복잡도는 O (n logn)이 됩니다
이전에 살펴보았던 3가지 기본 정렬 알고리즘보다 시간복잡도가 상당히 개선되었음을 알 수 있습니다.
Visualgo
Sorting Algorithm Animations
Udemy - Javascript Algorithms and Data Structures Masterclass