컴퓨터/알고리즘
[알고리즘] 병합정렬 알고리즘 | Merge Sort | C++코드 해석
우유식빵
2020. 2. 20. 04:01
분할정복(Divide and Conquer) 알고리즘을 공부하고있습니다.
병합정렬을 이해해보겠습니다, 우선은 코드는 이렇게 생겼습니다
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
using namespace std; | |
void merge(int* A,int begin, int mid, int end, int* B){ // 분할해둔 배열의 값을 크기비교하여 정렬하고 합친다. | |
int i,j,k; | |
i=begin; | |
j=mid; | |
for(k=begin; k<=end; k++){//정렬하면서 배열B에 차례로 넣어 줄 것. | |
// 분할된 블럭중 i는 왼쪽블럭담당, j는 오른쪽 블럭담당이다. | |
// j가 end보다 커졌다는 의미는 i담당인 왼쪽블럭만 남았다는 이야기이다. | |
// if가 true일땐 왼쪽블럭에서 배열B에 저장 | |
if (i<mid&&(j>end||A[i]<=A[j])) { | |
B[k] = A[i]; | |
i = i + 1; | |
// if가 else일땐 오른쪽블럭에서 배열B에 저장 | |
} else { | |
B[k] = A[j]; | |
j = j + 1; | |
} | |
} | |
for(k=begin; k<=end; k++){ // update | |
A[k]=B[k]; | |
} | |
} | |
void split(int* A, int begin, int end, int* B){ //재귀함수를 이용해 분할한다. | |
int mid; | |
if(end-begin<1) return; //한 조각까지 분리됐으면 끝 | |
mid=begin+(end-begin)/2; | |
split(A,begin,mid,B); | |
split(A,mid+1,end,B); | |
merge(A,begin,mid+1,end,B); | |
} | |
int main(){ | |
int N; // 수열의 길이 | |
cin>>N; | |
int* A = new int[N]; // 정렬 전 배열 | |
int* B = new int[N]; // 정렬 하면서 결과물을 넣을 배열 | |
for(int i=0; i<N; i++){ | |
cin>>A[i]; | |
} | |
split(A,0,N-1,B); // 배열이 0 부터 시작하므로 end에는 N-1이 들어가야한다. | |
//결과물 확인 | |
for(int i=0; i<N; i++){ | |
cout<<A[i]<<" "; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
q |
코드를 이해하기 쉽도록 병합정렬의 개념과 예시그림을 설명하겠습니다!
병합정렬은 분할과 정렬로 나눌수있습니다.
먼저 처음과 끝의 중간에서 두 개로 분할합니다.
이후 분할된 블록들을 계속해서 최소단위까지 분할해줍니다.
8개의 수열을 분할하는 과정을 예로 들면,

이런 식이 됩니다.
코드를 보면 이에 재귀함수를 이용하였는데요, 빨간색 숫자는 재귀함수에 따라 분할이 되는 순서입니다.
재귀함수가 머리아프신분들은 저 순서를 보시면 직관적으로 바로 이해가 되실 거에요!
분할이 끝났으면 5번에서 정렬&병합 한번, 8번에서 한번,
8번 병합이끝나고 6번에 돌아와서 한번, 6번에서 끝나고 2번에서 한번... 이런식으로 이루어집니다.
5번 분할이 끝난후 정렬&병합되는 과정은

이렇습니다. i는 왼쪽 수열, j는 오른쪽 수열의 포인터를 담당한다고 생각하면됩니다.
한칸짜리로는 각각 i와 j가 어떤 역할을 하는지 바로 알기 어려움으로
8번 병합이 끝난후 6번에서 이루어지는 정렬&병합을 살펴보겠습니다

코드에 써있듯이, 왼쪽블럭과 오른쪽블럭을 비교하며 작은쪽이 임시배열인 B에 차례차례 들어가게됩니다.
B에 채워넣은다음에는 채워넣어진 쪽의 포인터가 한칸 전진하게됩니다.
이러한 전체적인 과정을 움짤로 보자면,

이런식이 됩니다 ;)