알고리즘/정렬

병합 정렬

Dero Lee 2021. 12. 25. 00:18
728x90

병합 정렬: 모든 원소들이 하나로 남을때까지 정확하게 절반으로 나눈 후 나중에 합쳐서 정렬하는 알고리즘.

 

Ex)

(이미 하나까지 전부 반으로 쪼게진 상태라 가정하고 2의 배수만큼 차례대로 합쳐진다.)

 

7 6 5 8 3 5 9 1

67 58 35 19

5678 1359

13556789

시간 복잡도: O(N*log N)

너비가 n이고 높이가 log n

(정렬이 되어있는 상태에서 데이터를 하나씩 읽어나가 새롭게 정렬을 하므로 n * log n에 비례.)

 

병합 정렬의 경우 항상 정확히 절반으로 분할되고 정복하는 과정이 반복되므로 최악의 경우에도 O(N*log N)을 보장한다. (퀵 정렬은 편향되게 분할 할 가능성이 있으므로 최악의 경우 O(N^2))

 

단점: 기존의 데이터를 담을 추가적인 배열 공간이 필요하여 메모리 활용이 비효율적임.

 

#include <stdio.h>

int n = 10;
int sorted_arr[10];
/* 병합 정렬에서는 추가적인 배열이 필요한데, 전역 변수로 배열을 선언하게 되면 모든 함수가 
 공통적으로 이용할 수 있기때문에 불필요한 메모리 사용을 최소화할 수 있다. */
			
void merge(int arr[], int start, int mid, int end);
void mergeSort(int arr[], int start, int end);

int main() {
	int arr[n] = {7, 6, 5, 8, 4, 5, 9, 2, 10, 1};
	mergeSort(arr, 0, n-1);
	for(int i = 0; i<n; i++) {
		printf("%d ",arr[i]);
	}
}

void merge(int arr[], int start, int mid, int end) {
	int i = start;
	int j = mid+1;
	int k = start;

	// 작은 순서대로 배열에 삽입.
	while(i<=mid && j<=end) {
		if(arr[i] <= arr[j]) {
			sorted_arr[k] = arr[i];
			i++;
		}
		else {
			sorted_arr[k] = arr[j];
			j++;
		}
		k++;
	} 

	// 남은 데이터도 삽입
	if(i > mid) {
		for(int t = j; t<=end; t++) {
			sorted_arr[k] = arr[t];
			k++;
		}
	} 
	else {
		for(int t = i; t<=mid; t++) {
			sorted_arr[k] = arr[t];
			k++;
		}
	}

	// 정렬된 배열을 실제 배열로 삽입 
	for(int t = start; t<=end; t++) {
		arr[t] = sorted_arr[t];
	}
} 

// 크기가 1일때까지 반으로 나누고 최종적으로 합쳐서 정렬
void mergeSort(int arr[], int start, int end) {  
	// 크기가 1보다 큰 경우
	if(start<end) {
		int mid = (start + end)/2;
		mergeSort(arr, start, mid);
		mergeSort(arr, mid+1, end); 
		merge(arr, start, mid, end);
	} 
}
728x90