합병 정렬 또는 병합 정렬은 O(n log n)의 비교 기반 정렬 알고리즘입니다. 일반적인 방법으로 구현했을 때 이 정렬은 안정 정렬에 속하며, 분할 정복 알고리즘의 하나입니다. 존 폰 노이만이 1945년에 개발했습니다.
병합 정렬의 근간은 divide and qonquer입니다. 분할 정복은 문제를 작은 문제로 쪼개고 그 후 다시 조합하여 큰 문제를 해결하는 것입니다. 병합 정렬 개념의 시작은 이 분할로 시작해서 합치는 것으로 정복됩니다.
구현은 크게 2가지 단계로 이루어집니다. 분할과 정복입니다.
가장 먼저 해야할 작업은 분할입니다. 배열을 계속 양분하다 보면 하나의 원소만 갖게 됩니다. 분할은 그때까지 이루어집니다.
void mergeSort(int arr[], int left, int right) {
if(left==right) return;
int mid = (left + right) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, right);
}
병합은 분할이 다 이루어진 이후에 진행됩니다. 하나의 원소가 남은 배열끼리 합치기 시작하면서 원소를 정렬합니다.
void merge(int arr[], int left, int right) {
int L, R, k, a;
int mid = ( left + right ) / 2;
L = left;
R = mid + 1;
k = left;
// 1
while (L <= mid && R <= right)
tmp[k++] = arr[L] <= arr[R] ? arr[L++] : arr[R++];
// 2
if (L>mid)
for (a = R; a <= right; a++)
tmp[k++] = arr[a];
else
for (a = L; a <= mid; a++)
tmp[k++] = arr[a];
// 3
for (a = left; a <= right; a++)
arr[a] = tmp[a];
}
위 코드와 아래의 그림을 함께 보면 이해가 더욱 쉽습니다.
하나의 배열을 L과 R을 기준으로 나누었다고 생각하면 좋습니다. 왼쪽 배열과 오른쪽 배열이 정해진 인덱스를 넘기 전까지 while문을 반복합니다. 이 반복문을 통해 오름차순으로 정렬을 위한 임시 배열을 채워 넣습니다.
왼쪽과 오른쪽 배열 중 하나라도 범위를 넘어선다면 while문이 종료가 됩니다. 남은 한 쪽 배열의 원소 또한 오름차순을 위해 tmp 배열에 채워 넣는 작업을 시도합니다.
#include <stdio.h>
#define SIZE 5
int tmp[SIZE];
void merge(int arr[], int left, int right) {
int L, R, k, a;
int mid = (left + right) / 2;
L = left;
R = mid + 1;
k = left;
while (L <= mid && R <= right)
tmp[k++] = arr[L] <= arr[R] ? arr[L++] : arr[R++];
if (L>mid)
for (a = R; a <= right; a++)
tmp[k++] = arr[a];
else
for (a = L; a <= mid; a++)
tmp[k++] = arr[a];
for (a = left; a <= right; a++)
arr[a] = tmp[a];
}
void mergeSort(int arr[], int left, int right) {
if (left == right) return;
int mid;
mid = (left + right) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, right);
}
void printArr(int arr[], int size) {
int i;
for (i = 0; i<size; i++)
printf("%d ", arr[i]);
printf("\n");
}
void main() {
int i;
int arr[SIZE] = { 3,4,1,5,2 };
mergeSort(arr, 0, SIZE - 1);
printArr(arr, SIZE);
}