본문 바로가기

알고리즘/algospot

분할 정복

분할 정복이란?

주어진 문제를 둘 이상의 부분 문제로 나눈 뒤,

각 부분 문제에 대한 답을 재귀 호출을 이용(basecase : 상수 크기의 부문제들)해 계산하고,

그 답으로 부터 전체 문제의 답을 계산

일반적 재귀 호출과의 차이점 ?

문제를 나누는 크기 !

재귀 호출은 문제를 한 조각과 나머지 전체로 나누지만, 분할 정복은 거의 같은 크기의 부분 문제로 나눔

예제 1) 분할 정복을 이용한 수열의 합 구하기

fastSum(n) 

= 1+2+3+...+n 

= (1+2+3+..+n/2) + ((n/2+1)+...+n)

= (1+2+3+..+n/2) + (n/2+1) + (n/2+2) + ... + (n/2 + n/2)

= (1+2+3+..+n/2) + n/2 * n/2 + (1+2+...+n/2)

= fastSum(n/2) + n/2 * n/2 + fastSum(n/2)

 

코드

#include <iostream>
using namespace std;

int fastSum(int n) {
	if (n == 1) return 1;
	if (n % 2 == 1) return fastSum(n - 1) + n;
	return 2 * fastSum(n / 2) + n / 2 * n / 2;
}

예제2) 병합 정렬과 퀵 정렬

병합정렬 (Merge sort) ?

  • 수열을 가운데에서 쪼개 비슷한 크기의 수열 2개로 만든 후, 재귀 호출을 통해 각각 정렬 → 정렬된 배열을 하나로 합침
  • 즉, 각 수열의 크기가 1이 될 때까지 절반씩 쪼갠 후, 정렬된 부분 배열들을 다시 합침
  • 실행시간 : O(nlogn)
    주어진 배열을 절반으로 나누는 시간 + 정렬한 배열들을 하나의 배열로 합치는 시간 = O(1) + O(n) = O(n)
    ▶ 배열은 절반으로 나누어지기 때문에 필요한 단계의 수는 logn

퀵 정렬 (Quick sort) ?

  • 병합 정렬 방법에서 병합 과정이 필요없도록 한쪽 배열에 포함된 수가 다른 쪽 배열보다 항상 작도록 배열 분할
  • 배열에서 임의의 기준 수(pivot)를 지정한 후, 기준보다 작거나 같은 숫자를 왼쪽, 더 큰 숫자를 오른쪽으로 보냄(파티션 단계라고 부름)
  • 최악 실행시간 : O(n^2) → 기준으로 택한 원소가 최소/최대인 경우
  • 기대 실행시간 : O(nlogn)

 

'알고리즘 > algospot' 카테고리의 다른 글

[C++]algospot FENCE  (0) 2021.08.21
[C++]algospot QUADTREE  (0) 2021.08.17
동적 계획법(Dynamic Programming)  (0) 2021.07.28
[C++]algospot CLOCKSYNC  (0) 2021.07.26
[C++]algospot BOARDCOVER  (0) 2021.07.25