Krafton Jungle/3. TIL

[WEEK01] 합병 정렬

munsik22 2025. 3. 18. 15:22

합병 정렬(Merge Sort)분할 정복(Divide and Conquer) 알고리즘으로, 배열을 점차적으로 두 부분으로 나누고, 각각을 정렬한 후 합병(merge)하는 방식으로 동작한다.

🚀 동작 과정

1. 배열을 재귀적으로 나눈다

배열을 계속 반으로 나누며, 더 이상 나누어질 수 없을 때까지 반복한다.

[38, 27, 43, 3, 9, 82, 10]
→ [38, 27, 43, 3]  [9, 82, 10]
→ [38, 27] [43, 3]   [9, 82] [10]
→ [38] [27] [43] [3] [9] [82] [10]

2. 나누어진 배열을 합병하며 정렬한다

각각의 작은 배열을 정렬하면서 합친다.

[38] [27] → [27, 38]
[43] [3] → [3, 43]
[9] [82] → [9, 82]
[10] → [10]

3. 합병하면서 정렬

각각의 부분 배열을 합병하면서 정렬된 상태로 유지한다.

[27, 38] [3, 43] → [3, 27, 38, 43]
[9, 82] [10] → [9, 10, 82]
[3, 27, 38, 43] [9, 10, 82] → [3, 9, 10, 27, 38, 43, 82]

결국, 최종적으로 배열은 정렬된 상태가 된다.

💻 코드 구현

def merge(a, left, right):
    if left < right:
        center = (left + right) // 2
        merge(a, left, center)
        merge(a, center+1, right)

        p = j = 0
        i = k = left

        while i <= center:
            buff[p] = a[i]
            p += 1
            i += 1

        while i <= right and j < p:
            if buff[j] <= a[i]:
                a[k] = buff[j]
                j += 1
            else:
                a[k] = a[i]
                i += 1
            k += 1

        while j < p:
            a[k] = buff[j]
            k += 1
            j += 1

def merge_sort(a):
    n = len(a)
    buff = [None] * n
    merge(a, 0, n-1)
    del buff

🔍 코드 분석

1. merge 함수 (배열 합병)

  • merge(a, left, right):
    • a: 정렬할 배열
    • left, right: 배열의 왼쪽오른쪽 구간의 인덱스
    • center: 배열을 절반으로 나누는 중앙 인덱스
  • 재귀적으로 배열을 두 개의 부분 배열로 나누고, 각 부분 배열을 정렬한 후 다시 합병하는 과정

2. 배열을 나누는 부분

  • 배열을 두 부분으로 나누어 재귀적으로 호출함
    • merge(a, left, center) → 왼쪽 절반 정렬
    • merge(a, center+1, right) → 오른쪽 절반 정렬

3. 배열을 합병하는 부분

  • p, j: 임시 배열 buff에 데이터를 복사하는 데 사용
  • i, k: 배열 a에서 데이터를 병합하는 데 사용

4. buff 배열에 왼쪽 부분 복사

  • i <= center까지 왼쪽 절반 배열(a[left ... center])의 값을 buff 배열에 복사함

5. 두 부분 배열을 병합하는 부분

  • buff 배열과 a 배열을 병합
  • 두 배열에서 가장 작은 값을 비교하여 배열 a에 넣음 (buff는 왼쪽 절반, a는 오른쪽 절반)
  • 비교한 후, 해당 값을 배열 a[k]에 넣고, 인덱스를 증가시킴

6. 남은 값 복사

  • 왼쪽 절반 배열(buff)에 남아있는 값들이 있으면, 그것을 a[k]에 그대로 복사함
  • 이 단계는 a 배열의 오른쪽 절반이 다 처리된 후에 남은 값들을 처리함

7. merge_sort 함수 (메인 함수)

  • merge_sort(a) 함수는 전체 배열을 합병 정렬하는 함수
  • buff는 임시 배열로, 각 부분 배열을 합병할 때 사용됨
    • buff는 원본 배열을 수정하지 않고 임시로 데이터를 저장하는 공간
  • merge(a, 0, n-1)는 배열 전체를 합병 정렬하는 함수 호출
  • 마지막에 del buff를 사용해 buff 배열을 메모리에서 제거함

🕓 시간 복잡도

  • 시간 복잡도:
    • 배열을 계속 반으로 나누는 데 O(log n) 시간이 걸리고, 나눈 배열을 합병하는 데 O(n) 시간이 걸리므로 전체 시간 복잡도는 O(n log n)
  • 공간 복잡도:
    • O(n) : buff 배열을 추가로 사용하기 때문에 배열의 크기만큼 공간이 필요함

📌 정리

  • 합병 정렬(Merge Sort)은 분할 정복 알고리즘을 사용하여 배열을 두 부분으로 나누고, 각각을 정렬한 후 합병하는 방식으로 동작한다.
  • 이 알고리즘은 안정 정렬(stable sort)으로, 같은 값의 요소들이 원래 배열에서의 순서를 유지한다.
  • O(n log n)의 시간 복잡도를 가지며, 병합 작업을 위한 추가적인 메모리 공간이 필요하다.