Divide and Conqure Algorithm(1)
분할정복 방법의 원리
: 순환적(recursively)으로 문제를 푸는 하향식(top-down) 접근 방법
-
주어진 문제의 입력을 더 이상 나눌 수 없을 때까지 두 개 이상의 작은 문제로 순환적으로 분할하고, 이렇게 분할된 작은 문제들을 각각 해결한 후 이 해들을 결합해 원래 문제의 해를 구하는 방식
→ 문제들을 작은 문제로 분할하다보면 원하는 해가 구해짐
-
특징
-
분할된 작은 문제는 원래 문제와 동일하다
→ 단 입력 크기만 작아짐
-
분할된 작은 문제는 서로 독립적
→ 순환적 분할 및 결과 통합이 가능
-
- 분할정보 방법의 처리 단계
-
각 순환 호출마다 세 단계의 처리 과정을 가짐
- 분할: 주어진 문제를 여러 개의 작은 문제로 분할
- 정복: 작은 문제를 순환적으로 분할. 더 이상 분할되지 않을 정도로 크기가 작다면 순환호출 없이 작은 문제의 해를 구함
- 결합: 작은 문제에 대해 정복된 해를 결합하여 원래 문제의 해를 구한다 (* 결합단계가 없는 문제도 존재)
적용 알고리즘의 종류 및 분할과정
-
이진탐색
n개가 있다면 n/2씩 쪼갬. 절반은 처리 대상에서 제거, 나머지 절반을 n/2씩 쪼갬을 반복
-
합병정렬
n개가 있다면 n/2씩 쪼갬. 양 쪽 모두 충분히 작아질 때까지 n/2씩 쪼갬을 반복
-
퀵 정렬
n개가 있다면 a와 b(크기가 일정하지 않음)으로 쪼갬. 이를 반복
-
선택 문제
n개가 있다면 a와 b(크기가 일정하지 않음)으로 쪼갬. 한 쪽은 처리 대상에서 제거, 나머지 절반을 a와 b로 나눔을 반복
이진 탐색
데이터가 나열되어 있다면 그 중 내가 원하는 데이터를 찾아내는 방식.
-
정렬된 상태의 입력데이터에 대한 효과적인 탐색 방법
→ 여기서 정렬은 오름차순으로 정렬되어있다고 가정.
-
탐색 방법
-
배열의 가운데 원소 A[mid]와 탐색키 x를 비교
1) 탐색키 = 가운데 원소 → 탐색 성공!(인덱스 mid반환 후 종료)
2) 탐색키 < 가운데 원소 → 이진탐색(원래 크기 1/2 왼쪽 부분 배열) 순환 호출
3) 탐색키 > 가운데 원소 → 이진탐색(원래 크기 1/2 오른쪽 부분 배열) 순환 호출
⇒ 탐색을 반복할 때마다 대상원소의 개수가 1/2씩 감소
-
개념의 원리
-
분할
배열의 가운데 원소를 기준으로 왼쪽 오른쪽 부분 배열로 분할, 탐색키와 가운데 원소가 같으면 가운데 원소의 배열 인덱스를 반환/종료
-
정복
탐색키가 가운데 원소보다 작으면 왼쪽 부분배열을 대상으로 이진 탐색을 순환 호출, 크면 오른쪽 부분배열을 대상으로 이진 탐색을 순환 호출
-
결합
필요 없음(부분배열에 대해서 탐색결과가 직접 반환된다)
알고리즘
BinarySearch(A[], Left, Right, x)
{
if(Left > Rigth) return -1; // fail
Mid = (Left+Right)/2; // floor(소수점버림)
if(x==A[Mid]) return Mid; // success
else if (x<Mid) BinarySearch(A, Left, Mid-1, x); // 왼쪽 부분배열
else BinarySearch(A, Mid+1, Right, x); // 오른쪽 부분배열
}
→ 순환 형태 (비효율
BinarySearch_Iteration(A[], n, x)
{
Left = 0; Right = n-1;
while(Left <= Right) {
Mid = (Left+Right)/2;
if(x == A[mid]) return Mid; //success
else if (x<A[Mid])Right = Mid - 1; // 왼쪽 부분배열
else Left = Mid + 1; // 오른쪽 부분배열
}
return -1; // fail
}
이진탐색에서의 분할 및 비교 횟수
입력크기 n일 때 최대 분할횟수와 비교횟수
- 최대 분할횟수 = n/2k = 1 → $
k = log n
$ - 최대 비교횟수 → 최대분할횟수 + 1
성능 분석
BinarySearch(A[], Left, Right, x)
{
if(Left > Rigth) return -1;
Mid = (Left+Right)/2;
if(x==A[Mid]) return Mid;
else if (x<Mid) BinarySearch(A, Left, Mid-1, x);
else BinarySearch(A, Mid+1, Right, x);
}
T(n) = 입력크기 n에 대한 탐색 과정에서의 모든 비교횟수의 합
= 맨 바깥수준에서의 비교횟수(상수) + 순환 호출에서의 비교 횟수(n)
= T(n) = T(n/2) + O(1) , T(1) = 1
⇒ O(logn)
특징
- 입력 배열의 데이터가 정렬된 경우에 대해서만 적용 가능
- 삽입/삭제 연산은 부가적인 데이터 이동을 수반
- 데이터의 정렬 상태 유지를 위해서 평균 n/2개의 데이터 이동이 발생 → 삽입/삭제가 빈번한 응용에서는 부적합