merge sort는 2가지 사실에 기반한다
위 2가지 사실에 기반하여 merge sort가 진행된다
이때 먼저 쪼개고, 그 후 merge할 때, 동시에 sort 한다
쪼개는 것 이전에 먼저 merge 하는 function 부터 작성해보자 그 후 쪼개는 logic을 작성할 것이다
두 array의 모든 item을 살펴볼때까지 반복한다
function merge(arr1, arr2) {
let results = []
let i = 0
let j = 0
while (i < arr1.length && j < arr2.length) {
if (arr2[j] > arr1[i]) {
results.push(arr1[i])
i++
} else {
results.push(arr2[j])
j++
}
}
if (i === arr1.length) {
results = results.concat(arr2.slice(j))
} else if (j === arr2.length) {
results = results.concat(arr1.slice(i))
}
return results
}
merge 하는 function이 완성된 후 이제 쪼개는 logic을 작성할 차례다
mergeSort는 아래와 같은 pseudocode를 가진다
즉 merge sort란 sort된 array를 merge하여 전체 array를 sort한다
여기서 쪼개는 logic은 recursion을 활용한다
function mergeSort(arr) {
if (arr.length <= 1) return arr
let cutIndex = Math.floor(arr.length / 2)
return merge(
mergeSort(arr.slice(0, cutIndex)),
mergeSort(arr.slice(cutIndex))
)
}
recursion을 활용하는 방법은 위와 같다
우선 base case 를 작성한다
mergeSort 의 base case는
arr.length 가 1보다 같거나 작은 경우이다
item이 0 혹은 1개면 이미 정렬된 array이기 때문이다
그리고 return해야 하는 값은 merge된 array이다
따라서 merge function을 호출한 결과값을 return해야 한다
이때 merge function에게 arguments가 중요하다
다시 mergeSort를 호출한 결과값이 arguments가 된다(이게 recursion의 활용)
base case 즉, item이 0 혹은 1개인 array를 return 할 때까지
slice로 array를 쪼개서 mergeSort의 인자로 준다
끝까지 쪼개어진 array
즉, item이 0 혹은 1개가 된 array는 return 되고
return 된 각각 array 2개는
merge function에 의해 정렬되어 merge 된다
그렇게 끝까지 쪼개어진 후 다시 정렬되며 merge되는 방식으로
전체 array가 sort 된다
Time Complexity(Best) | Time Complexity(Ave) | Time Complexity(Worst) | Space Complexity |
---|---|---|---|
O(n log n) | O(n log n) | O(n log n) | O(n) |
best, ave, worst 모두 O(n log n)
이다
여기서 n 은 merge function 을 호출할 때
비교 연산을 arr.length 만큼 수행하기 때문에 발생한다
log n 은 arr를 반으로 쪼개는 함수가 log 2 n 만큼 실행되기 때문이다
(n을 계속 2로 나누어서 1이 될때까지 몇번 나누느냐가 곧 log 2 n 임)
log 2 n 이지만 Big O 로 표기하면 log n 이 된다
따라서 최종적인 Time Complexity는 n * log n
이므로 O(n log n)
이 된다
results 라는 array를 변수에 할당하였으므로
최종적인 arr의 길이만큼 즉, n 만큼 공간이 필요하다
따라서 Space Complexity는 O(n)
이다