Divide and conquer
- 문제를 쪼개서 각각 따로 처리한 다음 결과를 합쳐나가는 방법.
Merge
- 배열의 길이가 1이면 정렬이 끝난 것이다.
- 아니라면 배열을 반으로 나눠서 왼쪽과 오른쪽을 따로 정렬한다.
- 둘 다 정렬이 끝나면 merge라는 작업을 통해 배열을 합쳐준다.
Merge operation
- 이미 sorted인 2개의 서브 배열
- 이 2개의 서브 배열의 merge된, 병합된 하나의 결과를 담을 배열
- 와 같이 3개의 배열로 이루어져 있다.
위의 배열과 아래의 배열이 합쳐지는데 sorted를 읽지 않도록 합치는 것이다.
- 배열이 3개인만큼 포인터 역시 3개다.
- 윗쪽 배열을 A 아래쪽 배열을 B라고 했을때 포인터마다 원소를 비교해서 작은쪽을 3번째 배열에 넣는다.
만약 아래와 같이 더이상 비교할 대상이 없을 때는 그대로 옮겨다 복사해주면 된다.
Merge operation의 예제
template <typename Type>
void Merge(Type *_arrayA, Type *_arrayB, int _nA, int _nB, Type *_arrayOut){
int posA = 0;
int posB = 0;
int k = 0;
while (posA < _nA && posB < _nB){
if( _arrayA[posA] < _arrayB[posB]){
_arrayOut[k] = _arrayA[posA];
posA++;
} else {
_arrayOut[k] = _arrayB[posB];
posB++;
}
k++;
}
for (; posA < _nA; posA++){
_arrayOut[k] = _arrayA[posA];
k++;
}
for (; posB < _nB; posB++){
_arrayOut[k] = _arrayB[posB];
k++;
}
}
Merge operation의 단점
- in-place로 동작하지 않는다. → merge를 할 때 항상 새로운 제 3의 배열을 memory allocation해야한다는 점이다.
- in-plate한 동작은 새로운 공간을 할당하지 않고 작동하는것을 말한다.
Merge sort
- 길이가 8인 배열이 있으면 1에서 4까지, 5에서 8까지의 배열로 나누고 이 나뉜 배열을 재귀적으로 나눈다.
- 이론적으로는 길이가 1이 될 때 까지 나누는것이 맞으나 오버헤드를 고려하여 일정 길이 이하로 나눴을 경우 삽입 정렬 등으로 처리한다.
Merge sort implement
template <typename Type>
void Merge(Type *array, int first, int midpoint, int last){
//..
}
void Merge_Sort(Type *array, int first, int last){
if (last - first <= NUM_THRESHOLD){
Insertion_Sort<Type>(array, first, last);
}else{
int midpoint = (first + last) / 2;
Merge_Sort<Type>(array, first, midpoint);
Merge_Sort<Type>(array, midpoint, last);
Merge(array, first, midpoint, last);
}
}
- 오른쪽 과정 생략
- 정렬 완료