‘존 폰 노이만(John von Neumann)’이라는 사람이 제안한 방법으로 하나의 리스트를 두 개의 균등한 크기로 분할하고 분할된 부분 리스트를 정렬한 다음, 두 개의 정렬된 부분 리스트를 합하여 전체가 정렬된 리스트가 되게 하는 방법이다.
분할 ➡ 정복 ➡ 결합
❓ 2개의 배열을 merge 하는 과정은?
평균 : O(nlog₂n)
최악 : O(nlog₂n)
최선 : O(nlog₂n)
❓ 퀵정렬보다 병합정렬이 유리한 경우가 있을까?
만약 레코드를 연결 리스트(Linked List)로 구성하면, 링크 인덱스만 변경되므로 데이터의 이동은 무시할 수 있을 정도로 작아진다. 합병 정렬은 순차적인 비교로 정렬을 진행하므로, LinkedList의 정렬이 필요할 때, 사용하면 효율적이다. LinkedList를 퀵 정렬에 사용해 정렬하면 성능이 좋지 않다. 이유는 퀵 정렬은 순차 접근이 아닌 임의 접근이기 때문이다. LinkedList는 삽입과 삭제 연산에서는 유용하지만, 접근 연산에서는 비효율적이다.
👉 따라서 크기가 큰 레코드를 정렬할 경우에 연결 리스트를 사용한다면, 합병 정렬은 퀵 정렬을 포함한 다른 어떤 정렬 방법보다 효율적이다.
function merge(left, right) {
const sortedArr = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
sortedArr.push(left.shift());
} else {
sortedArr.push(right.shift());
}
}
return [...sortedArr, ...left, ...right];
}
function mergeSort(arr) {
if (arr.length === 1) return arr;
const boundary = Math.ceil(arr.length / 2);
const left = arr.slice(0, boundary);
const right = arr.slice(boundary);
return merge(mergeSort(left), mergeSort(right));
}
✔ mergeSort(arr) 👉 배열을 반으로 나누어 주는 함수
✔ merge(left,right) 👉 반으로 나누어준 함수를 갖고 정렬해 새로운 배열로 만들어주는 함수