병합 정렬 알고리즘의 기본 개념
- 존 폰 노이만 이라는 사람이 제안한 방법
- 일반적인 방법으로 구현했을 때 이 정렬은 안정 정렬에 속하며, 분할 정복 알고리즘의 하나이다.
- 분할 정복 방법
- 문제를 작은 2개의 문제로 분리하고 각각을 해결한 다음, 결과를 모아서 원래의 문제를 해결하는 전략.
- 분할 정복 방법은 대게 재귀적 호출을 이용하여 구현한다.
- 분할 정복 방법
- 알고리즘의 과정
- 리스트의 길이가 0 또는 1이면 이미 정렬된 것으로 본다.
- 그렇지 않은 경우 정렬되지 않은 리스트를 절반으로 잘라 비슷한 크기의 두 부분 리스트로 나눈다.
- 각 부분 리스트를 재귀적으로 병합 정렬을 이용해 정렬한다.
- 두 부분 리스트를 다시 하나의 정렬된 리스트로 병합한다.
파이썬으로 코드 구현
코드 구현
def mergesort(list):
if len(list) <= 1: # 배열의 길이가 1 이하면 리스트 배열
return list
mid = len(list)//2 # 리스트를 2등분한뒤 재귀 호출을 통해 왼쪽 배열과 오른쪽 배열을 정렬한다.
left = mergesort(list[:mid])
right = mergesort(list[mid:])
return merge(left, right) # 정렬되어있는 왼쪽 배열과 오른쪽 배열을 병합한다.
def merge(left, right):
result = []
left_ = 0
right_ = 0
# 양쪽 배열의 값들을 비교하면서 작은값을 결과에 추가해 나간다.
while left_ < len(left) and right_ < len(right):
if left[left_] <= right[right_]:
result.append(left[left_])
left_ += 1
else:
result.append(right[right_])
right_ += 1
result += left[left_:]
result += right[right_:]
return result
알고리즘 테스트 1
test = [14, 2, 644, 65, 12, 99, 9, 34, 23, 65]
print(mergesort(test))
결과
[2, 9, 12, 14, 23, 34, 65, 65, 99, 644]
알고리즘 테스트 2
아래의 네가지 데이터를 넣고 테스트도 진행해 보았다.
- 정렬이 끝난 배열
- 역순으로 정렬된 배열
- 원소가 전부 같은 배열
- 랜덤으로 구성된 배열
import time
def mergesort(list):
if len(list) <= 1:
return list
mid = len(list)//2
left = mergesort(list[:mid])
right = mergesort(list[mid:])
return merge(left, right)
def merge(left, right):
result = []
left_ = 0
right_ = 0
while left_ < len(left) and right_ < len(right):
if left[left_] <= right[right_]:
result.append(left[left_])
left_ += 1
else:
result.append(right[right_])
right_ += 1
result += left[left_:]
result += right[right_:]
return result
test1 = [1, 2, 3, 4, 5, 6, 7]
test2 = [7, 6, 5, 4, 3, 2, 1]
test3 = [1, 1, 1, 1, 1, 1, 1, 1]
test4 = [23, 15, 38, 94, 62, 123, 243, 234, 112]
start_time1 = time.time()
mergesort(test1)
end_time1 = time.time()
total_time1 = (end_time1 - start_time1) * 1000
start_time2 = time.time()
mergesort(test2)
end_time2 = time.time()
total_time2 = (end_time2 - start_time2) * 1000
start_time3 = time.time()
mergesort(test3)
end_time3 = time.time()
total_time3 = (end_time3 - start_time3) * 1000
start_time4 = time.time()
mergesort(test4)
end_time4 = time.time()
total_time4 = (end_time4 - start_time4) * 1000
print(f'{total_time1:.4f}ms')
print(f'{total_time2:.4f}ms')
print(f'{total_time3:.4f}ms')
print(f'{total_time4:.4f}ms')
결과
0.0923ms
0.0865ms
0.0889ms
0.0880ms
병합정렬의 장단점
- 장점
- 안정적인 성능 보장 : 최선, 최악, 평균 모든 경우에서 시간 복잡도가 O(nlogn)으로 일정하다.
- 안정 정렬(Stable Sort) : 정렬 후에도 값이 같은 데이터들의 원래 순서가 유지된다.
- 연결 리스트(Linked List) 정렬에 최적화 : 데이터 이동이 많은 연결 리스트를 정렬할 때 퀵 정렬 대비 효율이 높다.
- 단점
- 추가 메모리 공간 필요 : 데이터를 합치는 과정에서 임시 배열이 필요하므로 공간 복잡도가 O(n)이다. 데이터가 아주 크면 메모리 낭비가 심해질 수 있다.
- 제자리 정렬 불가 : 메모리를 추가로 사용하지 않는 정렬 알고리즘에 비해 상대적으로 비효율적일 수 있다.
'자료구조, 알고리즘' 카테고리의 다른 글
| 재귀 함수 (Recursive Function) (0) | 2026.06.14 |
|---|---|
| 퀵 정렬 (Quick Sort) (0) | 2026.06.14 |
| 버블 정렬 vs 선택 정렬 vs 삽입 정렬 성능 테스트 코드 (0) | 2026.06.11 |
| 삽입 정렬 (Insertion Sort) (0) | 2026.06.10 |
| 선택 정렬 (Selection Sort) (0) | 2026.06.10 |