고급 정렬 알고리즘: 병합 정렬, 퀵 정렬

2024-10-25 16:41:31 | 조회수 73


고급 정렬 알고리즘 개요

고급 정렬 알고리즘은 단순 정렬 알고리즘에 비해 더 복잡하지만, 대규모 데이터에서 효율적인 성능을 발휘합니다. 이 글에서는 대표적인 고급 정렬 알고리즘인 병합 정렬퀵 정렬의 원리, 구현 방식 및 시간 복잡도 등을 다룹니다.

1. 병합 정렬 (Merge Sort)

병합 정렬은 데이터를 절반으로 나눈 뒤, 각 부분을 재귀적으로 정렬하고 다시 합쳐서 전체를 정렬하는 **분할정복(Divide and Conquer)** 방식의 정렬 알고리즘입니다. 주로 $$O(N \log N)$$의 시간 복잡도를 가지며 안정적인 정렬을 보장합니다.

작동 원리

  • 주어진 배열을 절반으로 나누어 두 개의 부분 배열로 분할합니다.
  • 각각의 부분 배열을 재귀적으로 병합 정렬을 수행하여 정렬합니다.
  • 정렬된 두 부분 배열을 하나의 배열로 병합하여 전체 배열을 정렬합니다.

병합 과정

병합 정렬의 핵심은 두 개의 정렬된 배열을 효율적으로 하나의 배열로 병합하는 것입니다. 병합 과정에서는 두 배열의 첫 요소를 비교하여 작은 요소를 결과 배열에 추가하고, 해당 배열의 다음 요소로 이동하여 비교를 반복합니다.

시간 복잡도

병합 정렬은 $$O(N \log N)$$의 시간 복잡도를 가지며, 최악의 경우에도 동일한 성능을 보입니다. 그러나 추가 메모리를 필요로 하기 때문에 공간 복잡도는 $$O(N)$$입니다.

Python 코드 예제:
def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    left_half = merge_sort(arr[:mid])
    right_half = merge_sort(arr[mid:])
    return merge(left_half, right_half)

def merge(left, right):
    sorted_arr = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            sorted_arr.append(left[i])
            i += 1
        else:
            sorted_arr.append(right[j])
            j += 1
    sorted_arr.extend(left[i:])
    sorted_arr.extend(right[j:])
    return sorted_arr
                

설명: merge_sort 함수는 배열을 반으로 나누고, merge 함수를 통해 두 개의 정렬된 배열을 병합합니다. 각 병합 단계에서 요소를 순서대로 추가하여 결과 배열을 완성합니다.

2. 퀵 정렬 (Quick Sort)

퀵 정렬은 피벗(pivot)이라는 기준 요소를 설정하고, 이를 기준으로 좌우로 분할하여 정렬하는 분할정복 방식의 알고리즘입니다. 평균적으로 $$O(N \log N)$$의 시간 복잡도를 가지지만, 특정 상황에서는 $$O(N^2)$$까지 증가할 수 있습니다.

작동 원리

  • 배열에서 피벗을 선택합니다. 일반적으로 첫 번째 요소, 마지막 요소, 중간 요소 중 하나를 선택할 수 있습니다.
  • 피벗을 기준으로 배열을 분할합니다. 피벗보다 작은 값은 왼쪽, 큰 값은 오른쪽에 배치합니다.
  • 좌우로 분할된 배열에 대해 재귀적으로 퀵 정렬을 수행하여 정렬합니다.

분할 과정

퀵 정렬에서 피벗을 기준으로 배열을 분할하는 과정이 핵심입니다. 피벗보다 작은 요소는 왼쪽에, 큰 요소는 오른쪽에 배치하며, 이를 반복하여 전체 배열을 정렬합니다.

시간 복잡도

퀵 정렬의 평균 시간 복잡도는 $$O(N \log N)$$이지만, 최악의 경우 $$O(N^2)$$까지 증가할 수 있습니다. 최악의 경우는 피벗이 항상 가장 크거나 작은 값을 선택하여 분할이 제대로 이루어지지 않을 때 발생합니다.

Python 코드 예제:
def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quick_sort(left) + middle + quick_sort(right)
                

설명: quick_sort 함수는 중간 요소를 피벗으로 선택하여 배열을 분할하고, 재귀적으로 정렬을 수행하여 결과 배열을 반환합니다. 이 과정에서 좌우로 분할된 배열을 병합하여 정렬이 완료됩니다.

병합 정렬과 퀵 정렬의 비교

병합 정렬과 퀵 정렬은 모두 $$O(N \log N)$$의 시간 복잡도를 가진 효율적인 고급 정렬 알고리즘이지만, 특성과 상황에 따라 선택이 달라질 수 있습니다.

특성 병합 정렬 퀵 정렬
시간 복잡도 (평균) $$O(N \log N)$$ $$O(N \log N)$$
시간 복잡도 (최악) $$O(N \log N)$$ $$O(N^2)$$
공간 복잡도 $$O(N)$$ $$O(\log N)$$
안정성 안정적 불안정적
사용 메모리 추가 메모리 필요 인플레이스(in-place) 가능

비교 요약: 병합 정렬은 안정적이고 최악의 경우에도 $$O(N \log N)$$의 성능을 보이지만, 추가적인 메모리 공간이 필요합니다. 반면 퀵 정렬은 인플레이스 정렬이 가능하며 평균적으로 효율적이지만, 최악의 경우 $$O(N^2)$$의 시간 복잡도가 발생할 수 있습니다.

이번 글에서는 고급 정렬 알고리즘인 병합 정렬퀵 정렬의 원리와 구현, 두 알고리즘의 차이점을 학습했습니다. 다양한 상황에서 적절한 알고리즘을 선택하여 효율적으로 문제를 해결할 수 있도록 연습해 보세요.


고급 정렬 알고리즘: 병합 정렬, 퀵 정렬 - 알고리즘닷컴 19 개의 글