본문 바로가기
학교 강의/컴퓨터알고리즘

합병 정렬

by dustnn 2025. 4. 23.

 

: 분할 정복 알고리즘

: 2개의 부분 문제로 분할 -> 부분 문제의 크기가 1/2로 감소

 

n개의 숫자들을 n/2씩 2개의 부분문제로 분할

-> 각각의 부분 문제를 순환으로 합병 정렬

-> 2개의 정렬된 부분을 합병하여 정렬(정복)

 

즉, 정복 과정이 합병이다.

 

알고리즘

 

A와 B를 앞 숫자부터 비교 -> 더 작은 것 선택 -> 반복

MergeSort(A,p,q)
입력: A[p]~A[q]
출력: 정렬된 A[p]~A[q]
	if(p<q){
    	k=[(p+q)/2] //내림값
        MergeSort(A,p,k)
        MergeSort(A,k+1,q)
        A[p]~A[k]와 A[k+1]~A[q]를 합병
    }

 

void merge_sort(int list[], int left, int right)
{
	int mid;
    if(left<right)
    {
    	mid = (left+right)/2;
        merge_sort(list, left, mid);
        merge_sort(list, mid+1, right);
        merge(list, left, mid, right);
    }
}

int sorted[MAX_SIZE]; //결과 임시저장을 위해 추가 공간이 필요
//i=정렬된 왼쪽 리스트에 대한 인덱스
//j=정렬된 오른쪽 리스트에 대한 인덱스
//k=정렬된 sorted 리스트에 대한 인덱스

void merge(int list[], int left, int mid, int right)
{
	int i,j,k,l;
    i=left; j=mid+1; k=left;
    //분할 정렬된 list의 합병
    while(i<=mid && j<=right){
    	if(list[i]<=list[j])
        	sorted[k++]=list[i++];
        else
        	sorted[k++]=list[j++];
    }
    if(i>mid) //남아 있는 레코드 일괄 복사
    	for(l=j;l<=mid;l++)
        	sorted[k++]=list[l];
    else
    	for(l=i;l<=mid;l++)
        	sorted[k++]=list[l];
    //(중요)배열 sorted[]의 리스트를 list[]로 복사
    for(l=left;l<=right;l++)
    	list[l]=sorted[l];
}

 

시간복잡도

 

1. 분할: O(1)

2. 합병: 입력의 크기에 비례

- 최소비교횟수: 작은 것의 크기만큼(n)

- 최대비교횟수: 정렬된 리스트의 데이터가 번갈아가면서 선택됨(m+n-1)

 

<층별 비교 횟수>

 

n을 계속하여 1/2로 나누다가, 더이상 나눌 수 없는 크기인 1이 될 때 분할 중단

k번 1/2로 분할했으면 -> k개의 층

2^k=n -> k=log2n

 

- 층 수=log2n

- 각 층에서 수행된 비교 횟수=O(n)

=> O(nlogn)

 

단점

 

- 변수, 인덱스 등을 위한 O(1) 크기의 메모리 공간 따로 필요

- O(n) 크기의 공간복잡도 필요

추가 공간이 필요하기 때문에 꼭 필요

sorted[]

 

응용

 

- 외부 정렬의 기준이 됨

- 연결리스트에 있는 데이터 정렬 시 퀵/힙 정렬보다 효율적

- 멀티코어 CPU와 다수의 프로세서로 구성된 그래픽 처리 장치의 등장으로 정렬 알고리즘을 병렬화하는 데 합병 정렬 알고리즘 활용

'학교 강의 > 컴퓨터알고리즘' 카테고리의 다른 글

선택 문제  (0) 2025.04.24
퀵 정렬  (0) 2025.04.24
분할 정복 알고리즘  (0) 2025.04.23
알고리즘 intro..  (0) 2025.04.23
3.4 최근점 점의 쌍 찾기  (0) 2025.03.30