병합 정렬(Merge Sort)
병합 정렬(Merge Sort)은 분할 정복(Divide and Conquer) 전략을 사용하는 안정 정렬 알고리즘입니다. 데이터를 작은 단위로 나눈 뒤, 정렬하며 병합하는 과정을 통해 정렬된 배열을 만들어냅니다.
1. 정렬 방식
- 분할(Divide): 배열을 절반으로 나눕니다.
- 정복(Conquer): 각 부분 배열을 재귀적으로 병합 정렬을 수행합니다.
- 병합(Merge): 두 정렬된 배열을 병합하여 하나의 정렬된 배열로 만듭니다.
2. 특징
- 시간 복잡도:
- 최선/평균/최악: O(n log n)
- 공간 복잡도: O(n) (추가적인 배열이 필요함)
- 안정 정렬: 같은 값의 요소들의 상대적 순서가 유지됨.
3. 동작 원리
예시: 배열 [38, 27, 43, 3, 9, 82, 10]
- 분할: 배열을 나눔
- [38, 27, 43, 3]와 [9, 82, 10].
- 계속 나누면 [38], [27], [43], [3], [9], [82], [10].
- 정렬 및 병합:
- [38]과 [27] → [27, 38]
- [43]과 [3] → [3, 43]
- [9]과 [82] → [9, 82]
- ...
- 최종 병합:
- 모든 병합 완료 시 [3, 9, 10, 27, 38, 43, 82].
4. Java 구현
import java.util.Arrays;
public class MergeSort {
// Merge two subarrays
private static void merge(int[] arr, int left, int mid, int right) {
int n1 = mid - left + 1; // Size of left subarray
int n2 = right - mid; // Size of right subarray
// Temporary arrays
int[] leftArray = new int[n1];
int[] rightArray = new int[n2];
// Copy data to temporary arrays
for (int i = 0; i < n1; i++) {
leftArray[i] = arr[left + i];
}
for (int j = 0; j < n2; j++) {
rightArray[j] = arr[mid + 1 + j];
}
// Merge the temporary arrays back into the original array
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (leftArray[i] <= rightArray[j]) {
arr[k] = leftArray[i];
i++;
} else {
arr[k] = rightArray[j];
j++;
}
k++;
}
// Copy remaining elements of leftArray (if any)
while (i < n1) {
arr[k] = leftArray[i];
i++;
k++;
}
// Copy remaining elements of rightArray (if any)
while (j < n2) {
arr[k] = rightArray[j];
j++;
k++;
}
}
// Main function for Merge Sort
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2; // Avoid overflow
// Recursively sort both halves
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// Merge the sorted halves
merge(arr, left, mid, right);
}
}
public static void main(String[] args) {
int[] arr = {38, 27, 43, 3, 9, 82, 10};
System.out.println("Original Array: " + Arrays.toString(arr));
mergeSort(arr, 0, arr.length - 1);
System.out.println("Sorted Array: " + Arrays.toString(arr));
}
}
5. Python 구현
def merge_sort(arr):
if len(arr) > 1:
# Find the middle of the array
mid = len(arr) // 2
# Split the array into two halves
left_half = arr[:mid]
right_half = arr[mid:]
# Recursively sort both halves
merge_sort(left_half)
merge_sort(right_half)
# Merge sorted halves
i = j = k = 0
# Copy data to original array from left_half and right_half
while i < len(left_half) and j < len(right_half):
if left_half[i] < right_half[j]:
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1
# Check for any remaining elements
while i < len(left_half):
arr[k] = left_half[i]
i += 1
k += 1
while j < len(right_half):
arr[k] = right_half[j]
j += 1
k += 1
# Example usage
if __name__ == "__main__":
arr = [38, 27, 43, 3, 9, 82, 10]
print("Original Array:", arr)
merge_sort(arr)
print("Sorted Array:", arr)
6. 최적화
- Iterative Merge Sort: 재귀 호출 대신 반복문으로 구현하여 공간 복잡도를 O(1)O(1)로 줄일 수 있음.
- In-place Merge: 추가 배열을 사용하지 않고 정렬(하지만 구현이 복잡해짐).
7. 장단점
장점:
- 안정 정렬: 같은 값의 상대적인 순서가 유지됩니다.
- 시간 복잡도 보장: 최악의 경우에도 O(n log n)의 성능을 보장합니다.
단점:
- 추가 메모리 필요: 병합 과정에서 O(n) 크기의 배열이 필요합니다.
- 작은 데이터셋에 비효율적: 데이터가 적으면 삽입 정렬보다 느릴 수 있습니다.
8. 병합 정렬의 응용
병합 정렬은 추가 메모리를 허용할 수 있고 안정 정렬이 필요할 때 주로 사용됩니다. 예를 들어, 대규모 데이터의 외부 정렬(External Sorting)에서 효과적입니다.
반응형
'컴퓨터과학 > 알고리즘' 카테고리의 다른 글
정렬 알고리즘 (Sorting Algorithms) - 삽입 정렬 (Insertion Sort) (1) | 2024.12.27 |
---|---|
정렬 알고리즘 (Sorting Algorithms) - 선택 정렬 (Selection Sort) (1) | 2024.12.27 |
정렬 알고리즘 (Sorting Algorithms) - 퀵 정렬 (Quick Sort) (0) | 2024.12.26 |
정렬 알고리즘 (Sorting Algorithms) - 버블 정렬 (Bubble Sort) (0) | 2024.12.24 |
알고리즘(Algorithm) 개요 (0) | 2024.12.24 |