분할 정복 이란?
분할 정복 기법의 구조
Top-down approach 예시

분할 정복 기법의 예시 - 거듭 제곱
<aside> 💡
분할 정복 기법을 이해하기 위해, 자연수 C의 n 제곱 값을 구하는 함수를 구현해보자
</aside>
반복 (Iterative) 알고리즘 : $O(n)$

분할 정복 기반의 알고리즘 : $O(log_2n)$


: 여러 개의 정렬된 자료의 집합을 병합하여 한 개의 정렬된 집합으로 만드는 방식
자료를 최소 단위의 문제까지 나눈 후에 차례대로 정렬하여 최종 결과를 얻어냄
Top-down 방식
시간 복잡도 → $O(n logn)$
병합 정렬 과정 예시 : {69, 10, 30, 2, 17, 8, 31, 22}
분할 단계 : 전체 자료 집합에 대하여, 최소 크기의 부분집합이 될 때까지 분할 작업을 계속함

병합 단계 : 2개의 부분집합을 정렬하면서 하나의 집합으로 병합함. 8개의 부분집합이 1개로 병합될 때까지 반복

코드 구현
merge_sort(arr): 분할과 재귀 호출을 담당하는 '매니저' 함수merge(left, right): 정렬된 두 배열을 합치는 '실무자' 함수def merge(left_arr, right_arr):
"""
이미 정렬된 두 배열(left_arr, right_arr)을
하나의 정렬된 배열로 '병합'하는 함수.
"""
merged_arr = []
# 두 배열을 가리킬 포인터(인덱스) 초기화
left_idx, right_idx = 0, 0
# 두 배열 중 하나라도 원소가 남아있는 동안 반복
while left_idx < len(left_arr) and right_idx < len(right_arr):
# 왼쪽 배열의 값이 더 작거나 같으면, 결과에 추가하고 왼쪽 포인터 이동
if left_arr[left_idx] <= right_arr[right_idx]:
merged_arr.append(left_arr[left_idx])
left_idx += 1
# 오른쪽 배열의 값이 더 작으면, 결과에 추가하고 오른쪽 포인터 이동
else:
merged_arr.append(right_arr[right_idx])
right_idx += 1
# 위 루프가 끝난 후, 아직 남아있는 원소들을 결과 뒤에 그대로 붙여줌
# (한쪽 배열은 이미 모든 원소가 소진되었으므로, 둘 중 하나만 실행됨)
merged_arr.extend(left_arr[left_idx:])
merged_arr.extend(right_arr[right_idx:])
return merged_arr
def merge_sort(arr):
"""
병합 정렬을 재귀적으로 구현하는 '매니저' 함수.
"""
# 기저 조건(Base Case): 배열의 길이가 1 이하면 이미 정렬된 상태이므로 그대로 반환
if len(arr) <= 1:
return arr
# 1. 분할 (Divide): 배열을 절반으로 나눔
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
# 2. 정복 (Conquer): 각 절반을 재귀적으로 정렬
# left_half와 right_half는 결국 정렬된 상태로 반환됨
left_sorted = merge_sort(left_half)
right_sorted = merge_sort(right_half)
# 3. 통합 (Combine): 정렬된 두 부분을 병합하여 반환
return merge(left_sorted, right_sorted)
# --- 실행 코드 ---
data_array = [69, 10, 30, 2, 16, 8, 31, 22]
print(f"정렬 전: {data_array}")
sorted_array = merge_sort(data_array)
print(f"정렬 후: {sorted_array}")
정렬 전: [69, 10, 30, 2, 16, 8, 31, 22]
정렬 후: [2, 8, 10, 16, 22, 30, 31, 69]
: 기준값을 중심으로 주어진 배열을 두 개로 분할하고, 각각을 정렬하여 전체 배열을 정렬하는 방식. 이름처럼, 평균적으로 가장 빠른 성능을 자랑한다
병합 정렬 vs 퀵 정렬
| 병합 정렬 | 퀵 정렬 | |
|---|---|---|
| 분할 기준 | 단순히 배열을 반으로 나눔 | 기준 아이템(pivot item)을 중심으로 기준보다 작은 것을 왼편, 큰 것을 오른편에 위치 시킴 |
| 병합 처리 | 정렬된 부분을 다시 병합하는 과정이 필요함 | 별도의 병합 과정 불필요 |
시간 복잡도
작업 영역을 정함

작업 영역 중 가장 왼쪽에 있는 수를 Pivot이라고 하자 (Pivot을 “기준”으로 해석함) → Pivot은 중간값, 우측 끝 값으로 설정해도 상관없지만, 우리는 왼쪽 끝 값을 기준으로 함
