본문 바로가기

알고리즘/분할정복

병합(합병) 정렬(Merge Sort)

 병합정렬(Merge-sort)은 퀵 정렬(Quick Sort)와 같이 분할정복 알고리즘을 이용한 정렬 알고리즘중 하나입니다. 선택정렬같은 O(N²)의 느린 정렬 알고리즘과 다르게 병합정렬은 시간복잡도 O(NlogN)의 빠른 정렬 알고리즘입니다.


「병합 정렬의 동작 과정」


1. 분할 과정 (Divide)

 병합정렬의 첫 번째 단계인 분할과정에서는 배열을 가능한 한 작게 나눕니다. 이 단계에서는 배열을 중간을 기준으로 두 개의 하위 배열로 분할합니다. 이 과정을 배열에 원소가 하나가 될때까지 계속 반복하면 됩니다.

 

-처음 주어진 배열 ↓

[38, 27, 43, 3, 9, 82, 10]

-첫번째 분할 ↓

[38, 27, 43], [3, 9, 82, 10]

-두번째 분할 

[38, 27], [43],  [3, 9], [82, 10]

-세번째 분할

[38], [27], [3], [9], [82], [10]


2. 정복 과정 (Conquer)

 정복(Conquer) 단계에서는 위 과정에서 나누어진 배열들중 서로 인접한 배열을 비교하며 병합합니다. 배열의 크기가 1이 될 때까지 분할한 배열들을 두 개씩 비교하여 정렬된 배열로 병합합니다. 이 과정을 반복하여 더 큰 정렬된 배열을 만듭니다.

-첫번째 과정

[38]과 [27]을 비교하여 [27, 38]으로 병합

-두번째 과정

[3]과 [9]을 비교하여 [3, 9]으로 병합

-세번째 과정

[82]과 [10]을 비교하여 [10, 82]으로 병합


3. 결합 과정 (Combine)

 마지막 결합 단계는 정렬된 하위 배열들을 다시 병합하여 최종적으로 전체 배열을 정렬된 상태로 만드는 과정입니다.

-첫번째 과정

[27, 38]과 [43]을 병합하여 [27, 38, 43]으로 병합

-두번째 과정

[3, 9]과 [10, 82]을 병합하여 [3, 9, 10, 82]으로 병합

-마지막 과정

[27, 38, 43]과 [3, 9, 10, 82]을 병합하여 최종 정렬된 배열 [3, 9, 10, 27, 38, 43, 82]이 만들어짐.

하지만 이렇게만 보면 결합과정에 대해 이해가 안가기 때문에 마지막 과정을 통해 결합과정(Combine 또는 Merge)에 대해 자세히 설명해보겠습니다.

 

배열 a

27 38 43

배열 b

3 9 10 82

 

위 두 배열을 Merge하는 과정은 다음과 같습니다.

27 38 43
i    
3 9 10 82
j      

 

i의 값과 j의 값을 비교하여 더 작은 값을 정답 배열에 넣어줍니다. 

 

-현재 정답배열 = [3]

 

넣었다면 더 작은 배열의 idx값인 j를 증가시킵니다.

27 38 43
 i    
3 9 10 82
   j    

 

그후 i의 값과 j의 값을 비교하여 더 작은 값을 정답 배열에 넣어줍니다. 

 

-현재 정답배열 = [3, 9]

 

넣었다면 더 작은 배열의 idx값인 j를 증가시킵니다.

27 38 43
 i    
3 9 10 82
     j  

 

그후 i의 값과 j의 값을 비교하여 더 작은 값을 정답 배열에 넣어줍니다. 

 

-현재 정답배열 = [3, 9, 10]

 

넣었다면 더 작은 배열의 idx값인 j를 증가시킵니다.

27 38 43
 i    
3 9 10 82
       j

 

그후 i의 값과 j의 값을 비교하여 더 작은 값을 정답 배열에 넣어줍니다. 

 

-현재 정답배열 = [3, 9, 10, 27]

 

넣었다면 더 작은 배열의 idx값인 i를 증가시킵니다.

27 38 43
   i  
3 9 10 82
       j

 

그후 i의 값과 j의 값을 비교하여 더 작은 값을 정답 배열에 넣어줍니다. 

 

-현재 정답배열 = [3, 9, 10, 27, 38]

 

넣었다면 더 작은 배열의 idx값인 i를 증가시킵니다.

27 38 43
     i
3 9 10 82
       j

 

그후 i의 값과 j의 값을 비교하여 더 작은 값을 정답 배열에 넣어줍니다. 

 

-현재 정답배열 = [3, 9, 10, 27, 38, 43]

 

넣었다면 더 작은 배열의 idx값인 i를 증가시켜야 하지만 a배열은 이미 끝났음으로 남은 b배열을 모두 정답에 넣어줍니다.

 

-현재 정답배열 = [3, 9, 10, 27, 38, 43, 82]

 

이 과정을 모든 결합과정에서 해준다면 배열이 모두 정렬됩니다.


병합정렬을 공부했으니 다음 문제를 병합정렬을 통해 풀어보자

https://www.acmicpc.net/problem/2751

《소스코드》

더보기
더보기
더보기
더보기
#include <stdio.h>

int n;
int arr[1000010];
int res[1000010];

void Merge(int low, int mid, int high) {
	int i;
	
	int res_len = 0;
	int pointer_first = low;
	int pointer_second = mid + 1;

	while (pointer_first <= mid && pointer_second <= high) {
		if (arr[pointer_first] < arr[pointer_second]) {
			res[res_len++] = arr[pointer_first++];
		}
		else {
			res[res_len++] = arr[pointer_second++];
		}
	}
	if (pointer_first > mid) {
		for (i = pointer_second; i <= high; i++) {
			res[res_len++] = arr[i];
		}
	}
	else if (pointer_second > high) {
		for (i = pointer_first; i <= mid; i++) {
			res[res_len++] = arr[i];
		}
	}
	for (i = low; i <= high; i++) {
		arr[i] = res[i - low];
	}
	return;
}

void Merge_sort(int low, int high) {
	int mid = (low + high) / 2;
	if (low >= high) return;
	Merge_sort(low, mid);
	Merge_sort(mid + 1, high);
	Merge(low, mid, high);
}

int main()
{
	int i;
	scanf("%d", &n);
	for (i = 0; i < n; i++) scanf("%d", &arr[i]);
	Merge_sort(0, n - 1);
	for (i = 0; i < n; i++) printf("%d\n", arr[i]);
	return 0;
}

'알고리즘 > 분할정복' 카테고리의 다른 글

이진 탐색(Binary Search)  (0) 2024.08.06
퀵 정렬(Quick Sort)  (0) 2024.08.06
분할 정복(Divide and conquer) 알고리즘  (0) 2024.08.04