분할 정복 알고리즘(Divide and conquer algorithm)이란?
적용 방식
function F(x) :
if F(x)가 간단/단순 then :
return F(x)를 계산한 값;
else
x를 x₁과 x₂로 분할
F(x₁)과 F(x₂)를 호출
retrun F(x₁)와 F(x₂)로 구한 F(x) 값;
로직
"막연하게 글로써 설명하면 해당 알고리즘에 대해 긴가민가할 수도 있다. 그래서 코드로 정리해서 설명을 해보고자 한다."
// 큰 문제를 작은 문제로 분할하는 코드
static void mergeSort(int left, int right){
//왼쪽 요소가 오른쪽 요소보다 같거나 큰 경우는 모두 분할한 경우이다.
if(left >= right) return;
//주어진 왼쪽 요소와 오른쪽 요소의 중심 값을 찾기
int mid = (left+right)/2;
mergeSort(left, mid); //분할 - 왼쪽 부분
mergeSort(mid+1, right); //분할 - 오른쪽 부분
//분할 후 합치기(조합)
merge(left, mid, right);
}
//분할한 문제를 다시 합치는 코드
static void merge(int left, int mid, int right){
int l = left; // 왼쪽 요소의 시작점
int r = mid+1; // 오른쪽 요소의 시작점
int idx = l; // 정렬 시작 점
// 왼쪽 요소의 시작점이 왼쪽 요소 끝(=mid)보다 작거나 같은 경우는 아직 조회하지 못한게 있는 경우
// 오른쪽 요소의 시작점이 오른쪽 요소 끝(=right)보다 작거나 같은 경우는 아직 조회하지 못한게 있는 경우
// => 즉 왼쪽 요소나 오른쪽 요소 중 조회하지 못한게 있는 경우(정렬하지 못한게 있는 경우)
while(l <= mid || r <= right){
// 오른쪽 분할의 원소를 모두 가져온 경우(=오른쪽 요소쪽은 정렬이 완료가 된 경우/ 단, 왼쪽 요소를 고려안하고 오른쪽 요소끼리만)
// 왼쪽 분할에서 가져오지 않은 원소가 있는 경우
// 해당 원소(l)가 오른쪽 원소보다 작을 경우)
if(r > right || (l <= mid && arr[l] < arr[r]){
tmp[idx++] = arr[l++];
}else{ //그 외
tmp[idx++] = arr[r++];
}
}
}
import java.io.*;
import java.util.StringTokenizer;
public class Main {
static int[] arr, tmp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int N = Integer.parseInt(br.readLine());
arr = new int[N];
tmp = new int[N];
st = new StringTokenizer(br.readLine());
for(int i = 0; i < N; i++){
arr[i] = Integer.parseInt(st.nextToken());
}
arrayDivid(0, N-1);
for(int i = 0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
static void arrayDivid(int left, int right){ //분할
if(left >= right) return; //더 이상 정렬할 요소가 없을 경우
int mid = (left+right)/2; //중간 값
arrayDivid(left, mid); //왼쪽 분할
arrayDivid(mid+1, right); //오른쪽 분할
arraySort(left, mid, right);
}
static void arraySort(int left, int mid, int right){ //정렬 후 조합
int l = left; //왼쪽 시작점
int r = mid+1; //오른쪽 시작점
int sortStart = l; //정렬 시작점
while(l <= mid || r <= right){ //정렬할게 남아 있을 경우
//오른쪽 정렬이 끝난 경우
// 왼쪽 정렬은 아직 마치지 않았고 왼쪽 정렬이 오른쪽 정렬보다 작은 경우
//=> 왼쪽에서 가져온다.
if(r > right || (l <= mid && arr[l] < arr[r])){
tmp[sortStart++] = arr[l++];
}else{ //그 외의 경우에는 오른쪽에서 가져온다
tmp[sortStart++]= arr[r++];
}
}
for(int i = left; i <= right; i++){
arr[i] = tmp[i];
}
}
}