Study/자료구조,알고리즘
[알고리즘] 병합 정렬 (Merge Sort)
게임 만드는 나무꾼
2022. 11. 4. 18:21
01. 병합 정렬의 개념
- 안정 정렬이다.
- 정렬을 위한 별도의 공간이 필요하다.
- 분할 정복 알고리즘이다.
- 주로 순환 호출로 구현
- 매우 빠른 속도를 보장 ( O(NlogN) )
02. 과정 설명
- 배열을 반으로 나누는 것을 반복한다.
- 사이즈 1짜리 배열까지 나누고 나면, 나눈 순서의 역순으로 정렬해가며 부분 배열을 합친다.
말로는 사실 설명할 게 별로 없다...
그림으로 보는 게 더 설명이 쉬울 듯 하여 첨부
03. C++ 코드
void Merge(int*& arr, int*& tmp, int left, int right)
{
if (left == right)
return;
int l = left;
int mid = (l + right) / 2;
int midIdx = mid + 1;
int idx = l;
// 작은 원소 순서대로 임시 배열에 채워넣는다.
while (l <= mid && midIdx <= right)
{
if (arr[l] < arr[midIdx])
tmp[idx++] = arr[l++];
else
tmp[idx++] = arr[midIdx++];
}
// 남아있는 원소들을 임시 배열에 넣는다.
while (l <= mid)
tmp[idx++] = arr[l++];
while (midIdx <= right)
tmp[idx++] = arr[midIdx++];
// 원래 배열에 정렬된 임시 배열을 복사
for (int i = left; i <= right; ++i)
arr[i] = tmp[i];
}
void MergePartitioning(int*& arr, int*& tmp, int left, int right)
{
if (left >= right)
return;
int mid = (left + right) / 2;
// 분할부터 수행한다
MergePartitioning(arr, tmp, left, mid);
MergePartitioning(arr, tmp, mid + 1, right);
// 부분 배열을 합병 정렬한다.
Merge(arr, tmp, left, right);
}
void MergeSort()
{
cout << "Merge Sort : " << endl;
int* arr = new int[6]{ 5, 1, 8, 9, 7, 3 };
int* tmp = new int[6]{ 0, 0, 0, 0, 0, 0 };
MergePartitioning(arr, tmp, 0, 5);
for (int i = 0; i < 6; ++i)
cout << arr[i] << " ";
cout << '\n';
delete[] arr;
delete[] tmp;
}
05. 병합 정렬의 시간 복잡도
- 레코드의 크기 N = 2^k 인 경우, 순환 호출의 깊이는 pivot에 의해 균등하게 나누어진다고 가정할 때 log2^k = k이다.
- size 1 짜리 부분 배열은 비교를 위해 1번의 연산을 수행
- size 2 짜리 부분 배열은 비교를 위해 2번의 연산을 수행
- size 4 짜리 부분 배열은 비교를 위해 4번의 연산을 수행
- 2^k-1 짜리 부분 배열은 비교를 2^k-1 번 하게 되고, 이 부분 배열은 2개가 있다.
- 따라서 비교 연산은 2^k-1 * 2 = 2^k 번
- 즉, 각 순환 호출마다 N번의 연산을 수행하게 된다.
- 따라서 전체 시간 복잡도는 O(NlogN)