# 합병 정렬
특징
1. 분할 정복 알고리즘
2. 동일한 원소 존재시, 원래의 순서를 보존하는 안정 정렬
3. 일반적으로 최고, 최악, 평균 시간 복잡도 O(N * logN)
4. 임시 버퍼의 필요로 공간 복잡도 O(N)
알고리즘
1. 입력 버퍼를 절반씩 분할하여 나눈 두 버퍼에 대해 각 재귀함수를 호출
2. 계속 나누면서 들어가다가, 버퍼의 크기가 1일 때 중단점을 걸어 반환
3. 재귀함수를 나오면서 두 버퍼의 첫 요소부터 비교하여 작은 요소부터 임시 버퍼에 복사
(복사한 요소는 더이상 비교 대상이 아니며, 해당 버퍼의 index는 1 증가)
4. 복사한 구간의 임시 버퍼를 입력 버퍼에 복사
구현 및 상세 설명
먼저 sort()에서 병합 정렬에서 사용할 임시 버퍼를 미리 할당하여 재귀 함수의 인자에 같이 삽입해준다.
호출한 recursion()은 버퍼를 절반씩 나누며 들어가는데,
실제로 버퍼를 반으로 나누어 넣는 것은 오버헤드가 크기 때문에 start와 end index로 구분한다.
버퍼가 절반씩 나누어지고, 나눠진 버퍼들은 각각 정렬되어야 하기 때문에 두 번의 재귀함수를 호출한다.
재귀 함수의 호출은 start가 end와 같을 때까지 진행한다.
이는 나눠진 버퍼의 크기가 1이라는 것을 뜻한다.
재귀가 풀리고 나올 때 병합이 시작된다.
아래는 중단점 이후 제일 처음 병합하는 과정이다.
left와 right는 각 버퍼의 맨 앞 요소를 가리킨다.
left와 right가 가리키는 요소끼리 비교하여 더 작은 요소를 result 버퍼에 담는다.
각 버퍼의 커서(left, right)가 버퍼의 끝에 도달했을 시, 반대편 요소를 담는다. (buffer overflow 방지)
이후 result를 담았던 구간 만큼만 buf (입력 버퍼)에 복사한다.
이로써 각 요소의 개수가 1개인 버퍼는 정렬된 상태가 보장된다.
본 알고리즘은 재귀적으로 이루어지기 때문에 2와 7이 정렬이 완료된 이후 4와 8도 같은 방식으로 정렬된다.
더 빠져나온 depth에선 2,7과 4,8이 각 버퍼를 이루며 이들은 아래와 같이 정렬된다.
result 버퍼는 알고리즘의 맨 마지막에서야 할당한 크기를 모두 사용하지만,
미리 한 번만 할당하는 것이 더 바람직할 것이다.
테스트
결과
전체 코드
https://github.com/SikPang/Algorithms/tree/main/MergeSort
개인 공부용 포스팅인 점을 참고하시고, 잘못된 부분이 있다면 댓글로 남겨주시면 감사드리겠습니다.