카테고리 없음

Merge Sort(병합 정렬)

goakgoak 2019. 4. 2. 21:09

Merge Sort(병합 정렬)

정의

여러 개의 정렬된 자료의 집합을 결합하여 한 개의 정렬된 집합으로 만드는 방법

1단계

|60, 10, 30, 2, 16, 8, 31, 22|

8개의 데이터가 처음에는 하나의 집합으로 존재한다.

|60, 10, 30, 2|, |16, 8, 31, 22|

2등분으로 분리

|60, 10|, |30, 2|, |16, 8|, |31, 22|

그리고 또 분리

|60|, |10|, |30|, |2|, |16|, | 8|, |31|, |22|

더 이상 쪼갤 수 없을 때 까지 각각 1개의 원소로 분리된다.

2단계 : 합치면서 정렬하기 !!

|10, 60|, |2, 30|, |8, 16|, |22, 31|

다시 4개의 부분 집합으로 합쳐졌는데 아까와는 달리 각 부분집합들이 정렬된 상태로 합쳐진다.

(작은 숫자가 앞에 큰 숫자를 뒤에)

|2, 10, 30, 60|, |8, 16, 22, 31|

각 배열 내에서 가장 작은 값 2개를 비교, 다시 크기 순으로 정렬되면서 병합

|2, 8, 10, 16, 22, 30, 31, 60|

정렬 완성 !!

시간 복잡도

  • 알고리즘은 큰 그림에서 보면 분할 단계와 병합 단계로 나눌 수 있으며, 단순히 중간 인덱스를 찾아야 하는 분할 비용 보다 모든 값들을 비교하는 병합 비용이 크다.

  • 전반적인 반복의 수는 절반으로 줄어들기 때문에 O(logN) 시간이 필요하고, 각 패스에서 병합할 때 모든 값을 비교하므로 O(N) 시간이 소모된다.

  • 따라서 Merge Sort는 모든 케이스에 대해 O(NlogN)을 갖는다.

소스코드

먼저 배열을 나눌 수 없을 때 까지 분할한 후에, 다시 병합하면서 점점 큰 배열을 만들어 나간다.

입력 배열의 크기가 2보다 작으면 그대로 반환(값을 비교할 필요가 없기 때문에)        

import java.util.Arrays;

public class _2751 {
	static int[] tmp;
    public static void main(String[] args) {
        _2751 main = new _2751();
        main.go();
    }

    private void go() {
        int[] array = {60, 10, 30, 2, 16, 8, 31, 22};
        tmp = new int[array.length];
        int len = array.length;
        mergeSort(array, 0, len - 1);
    }

    private void mergeSort(int[] arr, int low, int high) {
        int mid;
        if (low < high) {
            mid = (low + high) / 2;
            mergeSort(arr, low, mid); // 배열을 쪼개는 재귀함수
            mergeSort(arr, mid + 1, high); // 배열을 쪼개는 재귀함수
            merge(arr, low, mid, high);
        }
    }

    private void merge(int[] arr, int low, int mid, int high) {
        int index = low, p1 = low, p2 = mid + 1;
        while (p1 <= mid && p2 <= high) {
            if (arr[p1] < arr[p2]) {
                tmp[index++] = arr[p1];
                p1++;
            } else {
                tmp[index++] = arr[p2];
                p2++;
            }
        }

        if (p1 > mid) { // p1 포인터가 배열을 먼저 채운 경우
            for (int i = p2; i <= high; i++) // 남은 p2 포인터 모두 사용
                tmp[index++] = arr[i]; 
        } else { // p2 포인터가 배열을 먼저 채운 경우
            for (int i = p1; i <= mid; i++) // 남은 p1 포인터 모두 사용
                tmp[index] = arr[i];
        }

        for (int i = low; i <= high; i++) {
            arr[i] = tmp[i];
        }
        System.out.println(Arrays.toString(arr));
    }
}