분할 정복 기법
유래
- 1805년 나폴레옹이 사용한 전략
- 연합군을 임의로 둘로 나누고 둘을 각각 격파
설계전략
- 분할(Divide) : 해결할 문제를 여러 개의 작은 부분으로 나눈다.
- 정복(conquer) : 나눈 작은 문제를 각각 해결한다.
- 통합(combine) : 해결된 해답을 모은다.
예시
Recursive_power(x, n):
if n ==1 : return x
if n is even:
y = Recursive_power(x, n/2)
return y * y
else:
y = Recursive_power(x, (n-1)/2)
return y * y * x
병합정렬
- 여러 개의 정렬된 자료의 집합을 병합하여 한 개의 정렬된 집합으로 만드는 방식
- 분할 정복 알고리즘 활용
- 자료를 최소 단위의 문제까지 나눈 후에 차례대로 정렬하여 최종 결과를 얻어냄
- top-down 방식
- 시간 복잡도
병합 정렬 과정
- 분할 단계 : 전체 자료 집합에 대하여, 최소 크기의 부분집합이 될 때까지 분할 작업 수행
- 병합 단계 : 2개의 부분지밥을 정렬하면서 하나의 집합으로 병합
def merge_sort(arr):
if len(arr) < 2:
return arr
mid = len(arr) // 2
low_arr = merge_sort(arr[:mid])
high_arr = merge_sort(arr[mid:])
merged_arr = []
l = h = 0
while l < len(low_arr) and h < len(high_arr):
if low_arr[l] < high_arr[h]:
merged_arr.append(low_arr[l])
l += 1
else:
merged_arr.append(high_arr[h])
h += 1
merged_arr += low_arr[l:]
merged_arr += high_arr[h:]
return merged_arr
- 외부 정렬의 기본이 되는 정렬 알고리즘이다.
- 멀티코어 CPU나 다수의 프로세서에서 정렬 알고리즘을 병렬화하기 위해 병합 정렬 알고리즘이 활용된다.
퀵 정렬
- 주어빈 배열을 두개로 분할 하고 각각을 정렬한다.
- 병합정렬과 다른점
- 병합정렬은 그냥 두 부분으로 나누는 반면에 퀵 정렬은 분할할 때 기준 아이템 중심으로 분할한다
- 각 부분 정렬이 끝난 후, 병합정렬은 "병합"이란 후처리 작업이 필요하나 퀵 정렬은 필요로 하지 않는다.
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
lesser_arr, equal_arr, greater_arr = [], [], []
for num in arr:
if num < pivot:
lesser_arr.append(num)
elif num > pivot:
greater_arr.append(num)
else:
equal_arr.append(num)
return quick_sort(lesser_arr) + equal_arr + quick_sort(greater_arr)
- p를 기준으로 큰 값은 오른쪽, 작은 값은 왼쪽으로 위치한다.
이진 검색
- 자료의 가운데에 있는 항목의 키 값과 비교하여 다음 검색의 위치를 결정하고 검색을 계속 진행하는 방법
- 목적 키를 찾을 때까지 이진 검색을 순환적으로 반복 수행함으로써 검색 범위의 반으로 줄여가면서 빠르게 검색
- 정렬 된 상태여야 검색이 가능
def binary_search(target, data):
data.sort()
start = 0
end = len(data) - 1
while start <= end:
mid = (start + end) // 2
if data[mid] == target:
return mid
elif data[mid] > target:
end = mid - 1
else:
start = mid + 1
return
def binary_search(target, start, end):
if start > end:
return -1
mid = (start + end) // 2
if data[mid] == target:
return mid
elif data[mid] > target:
end = mid - 1
else:
start = mid + 1
return binary_search(target, start, end)
- 정렬된 데이터를 기준으로 특정 값이나 범위를 검색하는데 사용
- Lower Bound, Upper Bound로 나뉨
- 정렬된 배열에서 특정 값 이상 또는 이하가 처음으로 나타나는 위치를 찾는 알고리즘
- 특정 데이터의 범위 검색 등에서 활용