안오늘 2021. 7. 19. 08:29

MergeSort란?

합병정렬은 분할과 정복으로 정렬하는 방법으로서, O(nlogn)로 정렬 속도가 빠르다.

입력이 2개의 부분문제로 분할되고, 부분문제의 크기가 1/2로 감소한다.

분할하는 부분은 중간 인덱스 계산과 2회의 순환 호출이므로 O(1) 시간이 소요된다.

합병 수행시간은 입력의 크기에 비례한다. 

2개의 정렬된 배열 A와 B의 크기가 각각 m과 n이라면, 최대비교횟수 = (m+n-1)으로, 시간복잡도는 O(m+n) => O(n)

층수는 k번 1/2로 분할했으면 k개의 층이 생기는 것이고, 입력의 크기가 n일 때 2^k = n으로부터 k는 logn임을 알 수 있다.

따라서 합병정렬의 시간복잡도는 O(nlogn)이다.

 

단점! 공간복잡도가 O(n)이다. 2개의 정렬된 부분을 하나로 합병하기 위해, 합병된 결과를 저장할 곳이 필요하기 때문이다.

 

 

data가 [5, 10, 66, 77, 54, 32, 11, 15]라고 가정한다.

분할

[5, 10, 66, 77, 54, 32, 11, 15]

 

[5, 10, 66, 77], [54, 32, 11, 15]

[5, 10], [66, 77], [54, 32], [11, 15]

[5], [10], [66], [77], [54], [32], [11], [15]

 

정복

[5, 10], [66, 77], [32, 54], [11, 15]

정렬되어 있는 상태이기 때문에 첫번째 그룹과 두번째 그룹의 0번째 항을 비교한다.

1회차 [10], [66, 77], [32, 54], [15]

[5], [11]

 

2회차 [], [66, 77], [32, 54], []

[5, 10], [11, 15]

 

3회차 [], [], [], [] 이미 정렬된 상태이므로 그대로 가져온다.

[5, 10, 66, 77], [11, 15, 32, 54]

 

4회차 [5, 10, 66, 77], [11, 15, 32, 54]

[5]

 

5회차 [10, 66, 77], [11, 15, 32, 54]

[5, 10]

 

6회차 [66, 77], [15, 32, 54]

[5, 10, 11]

 

7회차 [66, 77], [32, 54]

[5, 10, 11, 15]

 

8회차 [66, 77], [54]

[5, 10, 11, 15, 32]

 

9회차 [66, 77], []

[5, 10, 11, 15, 32, 54]

 

10회차 [], [] 이미 정렬된 상태이므로 그대로 가져온다.

[5, 10, 11, 15, 32, 54, 66, 77]

 

코드

let data = [5, 10, 66, 77, 54, 32, 11, 15];

function mergeSort(arr) {
    let arrLen = arr.length;
    let result = [];
    if (arrLen <= 1) {
        return arr;
    }
    let middle = parseInt(arrLen / 2)
    let group1 = mergeSort(arr.slice(0, middle));
    let group2 = mergeSort(arr.slice(middle));

    while (group1.length != 0 && group2.length != 0) {
        // 원소 값이 0이면 그냥 바로 뒤에 붙여주면 되기 때문이다.
        if (group1[0] < group2[0]) {
            result.push(group1.shift());
        } else {
            result.push(group2.shift());
        }
    }

    while (group1.length != 0) {
        result.push(group1.shift());
    }

    while (group2.length != 0) {
        result.push(group2.shift());
    }
    return result;
}

console.log(mergeSort(data));

 

 

pop() 메서드는 배열에서 마지막 요소를 제거하고 그 요소를 반환한다. 

shift() 메서드는 배열에서 첫 번째 요소를 제거하고, 제거된 요소를 반환한다. 이 메서드는 배열의 길이를 변하게 한다.

가장 작은 것을 가져와야하기 때문에, 첫번째 요소에 접근해야 하고, shift()를 사용한다.