병합 정렬이란?
- 분할 정복 기법 + 재귀 알고리즘을 이용한 정렬 알고리즘이다. 즉, 주어진 배열을 원소가 하나 밖에 남지 않을 때까지 계속 둘로 쪼갠 후에 다시 크기 순으로 재배열 하면서 원래 크기의 배열로 합칩니다.
- 전반적으로 반복의 수는 점점 절반으로 줄어들기 때문에 O(logN)시간이 필요하며, 각 패스에서 병합할때 모든 값들을 비교해야 하므로 O(N)시간이 소모됩니다. 따라서 총 시간 복잡도는 O(NlogN)입니다.
- 두 개의 배열을 병합할 때 병합 결과를 담아 놓을 배열이 추가로 필요합니다. 따라서 공간 복잡도는 O(N)입니다.
전개
- 리스트의 길이가 1이하이면 이미 정렬된 것으로 본다. 그렇지 않은 경우에는
- 분할(divide) : 정렬되지 않은 배열을 재귀적으로 절반으로 잘라 비슷한 크기의 두 부분 배열로 길이가 1이 될 때까지 나눈다.
- 정복(conquer) : 각 부분 배열을 재귀적으로 병합 정렬을 이용해 정렬한다.
- 결합(combine) : 두 부분 배열을 다시 하나의 정렬된 배열로 합병한다.
분할 정복(divide and conquer): 큰 문제를 작은 문제로 나누어(분할하여 푸는 (정복하는)방법)코드
def merge_sort(data):
return split(data)
def split(data):
if len(data) <= 1:
return data
mid = len(data) // 2
left = split(data[:mid])
right = split(data[mid:])
return merge(left,right)
def merge(left,right):
temp = []
l, h = 0,0
# case 1: left/right가 아직 남아있을 때
while l < len(left) and h < len(right):
if left[l] > right[h]:
temp.append(right[h])
h+=1
else:
temp.append(left[l])
l+=1
# case 2: left만 남아있을 때
while l < len(left):
temp.append(left[l])
l+=1
# case 3: right만 남아있을 때
while h < len(right):
temp.append(right[h])
h+=1
return temp
if __name__ == '__main__':
data = [6, 5, 3, 1, 8, 7, 2, 4]
print(merge_sort(data))
출력
4
2
1
split: [6] [5]
merge: [6] [5]
합병: [5, 6]:
1
split: [3] [1]
merge: [3] [1]
합병: [1, 3]:
split: [5, 6] [1, 3]
merge: [5, 6] [1, 3]
합병: [1, 3, 5, 6]:
2
1
split: [8] [7]
merge: [8] [7]
합병: [7, 8]:
1
split: [2] [4]
merge: [2] [4]
합병: [2, 4]:
split: [7, 8] [2, 4]
merge: [7, 8] [2, 4]
합병: [2, 4, 7, 8]:
split: [1, 3, 5, 6] [2, 4, 7, 8]
merge: [1, 3, 5, 6] [2, 4, 7, 8]
합병: [1, 2, 3, 4, 5, 6, 7, 8]:
[1, 2, 3, 4, 5, 6, 7, 8]반응형
'알고리즘' 카테고리의 다른 글
| [인프런] 후위표기식 만들기(스택) - 파이썬 (0) | 2022.06.11 |
|---|---|
| [인프런] 뮤직비디오(이분탐색 알고리즘) - 파이썬 (0) | 2022.06.03 |
| 다익스트라(dijkstra) 알고리즘 (0) | 2021.12.23 |
| 동적계획법(Dynamic Programming) (0) | 2021.12.20 |
