알고리즘(Algorithm)

퀵 정렬(Quick Sort) 및 병합 정렬(Merge Sort)

임베디드 친구 2025. 1. 20. 08:52
728x90
반응형

퀵 정렬(Quick Sort) 및 병합 정렬(Merge Sort)

퀵 정렬과 병합 정렬은 둘 다 "분할 정복(Divide and Conquer)" 전략을 사용하는 효율적인 정렬 알고리즘입니다. 이 글에서는 퀵 정렬과 병합 정렬의 원리와 구현 방법을 Java와 C로 함께 설명합니다.

퀵 정렬 (Quick Sort)

퀵 정렬은 주어진 배열을 기준 값(pivot)을 기준으로 두 부분으로 나누고, 각각의 부분 배열을 재귀적으로 정렬하는 방법을 사용합니다. 시간 복잡도는 평균적으로 $O(n \log n)$ 이지만, 최악의 경우 $O(n^2)$가 될 수 있습니다. 주로 "in-place"로 정렬이 이루어지기 때문에 메모리 사용이 효율적입니다.

퀵 정렬의 원리

  1. 배열에서 기준 값을 선택합니다 (일반적으로 첫 번째나 마지막 요소, 또는 중간 값).
  2. 기준 값을 기준으로 배열을 분할하여 작은 값들은 왼쪽에, 큰 값들은 오른쪽에 배치합니다.
  3. 분할된 두 부분 배열에 대해 재귀적으로 정렬을 수행합니다.

Java 코드 예제

public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pivotIndex = partition(arr, low, high);
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;
        return i + 1;
    }

    public static void main(String[] args) {
        int[] arr = { 34, 7, 23, 32, 5, 62 };
        quickSort(arr, 0, arr.length - 1);
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }
}

C 코드 예제

#include <stdio.h>

void quickSort(int arr[], int low, int high);
int partition(int arr[], int low, int high);

void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int pivotIndex = partition(arr, low, high);
        quickSort(arr, low, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, high);
    }
}

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = low - 1;
    for (int j = low; j < high; j++) {
        if (arr[j] <= pivot) {
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    return i + 1;
}

int main() {
    int arr[] = {34, 7, 23, 32, 5, 62};
    int n = sizeof(arr) / sizeof(arr[0]);
    quickSort(arr, 0, n - 1);
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

병합 정렬 (Merge Sort)

병합 정렬은 배열을 반으로 나누어 각각을 정렬한 후, 두 부분을 병합하여 정렬된 배열을 만드는 알고리즘입니다. 시간 복잡도는 항상 $O(n \log n)$을 보장하며, 안정적인 정렬 알고리즘입니다. 그러나 추가적인 메모리 공간이 필요하다는 단점이 있습니다.

병합 정렬의 원리

  1. 배열을 절반으로 나눕니다.
  2. 각 절반에 대해 병합 정렬을 재귀적으로 호출합니다.
  3. 나누어진 배열을 정렬하면서 병합합니다.

Java 코드 예제

public class MergeSort {
    public static void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            int middle = (left + right) / 2;
            mergeSort(arr, left, middle);
            mergeSort(arr, middle + 1, right);
            merge(arr, left, middle, right);
        }
    }

    private static void merge(int[] arr, int left, int middle, int right) {
        int n1 = middle - left + 1;
        int n2 = right - middle;

        int[] leftArray = new int[n1];
        int[] rightArray = new int[n2];

        for (int i = 0; i < n1; i++) {
            leftArray[i] = arr[left + i];
        }
        for (int j = 0; j < n2; j++) {
            rightArray[j] = arr[middle + 1 + j];
        }

        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++;
        }

        while (i < n1) {
            arr[k] = leftArray[i];
            i++;
            k++;
        }

        while (j < n2) {
            arr[k] = rightArray[j];
            j++;
            k++;
        }
    }

    public static void main(String[] args) {
        int[] arr = { 34, 7, 23, 32, 5, 62 };
        mergeSort(arr, 0, arr.length - 1);
        for (int num : arr) {
            System.out.print(num + " ");
        }
    }
}

C 코드 예제

#include <stdio.h>

void mergeSort(int arr[], int left, int right);
void merge(int arr[], int left, int middle, int right);

void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        int middle = left + (right - left) / 2;
        mergeSort(arr, left, middle);
        mergeSort(arr, middle + 1, right);
        merge(arr, left, middle, right);
    }
}

void merge(int arr[], int left, int middle, int right) {
    int n1 = middle - left + 1;
    int n2 = right - middle;

    int leftArray[n1], rightArray[n2];

    for (int i = 0; i < n1; i++) {
        leftArray[i] = arr[left + i];
    }
    for (int j = 0; j < n2; j++) {
        rightArray[j] = arr[middle + 1 + j];
    }

    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++;
    }

    while (i < n1) {
        arr[k] = leftArray[i];
        i++;
        k++;
    }

    while (j < n2) {
        arr[k] = rightArray[j];
        j++;
        k++;
    }
}

int main() {
    int arr[] = {34, 7, 23, 32, 5, 62};
    int n = sizeof(arr) / sizeof(arr[0]);
    mergeSort(arr, 0, n - 1);
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

정리

퀵 정렬과 병합 정렬은 둘 다 효율적인 정렬 알고리즘으로, 상황에 따라 적합한 알고리즘을 선택하여 사용할 수 있습니다. 퀵 정렬은 평균적으로 빠르고 메모리 사용이 적지만, 최악의 경우 시간이 오래 걸릴 수 있습니다. 병합 정렬은 안정적인 성능을 제공하지만 추가적인 메모리 공간이 필요합니다. Java와 C로 각각 구현해보면서 이들 알고리즘의 동작 원리를 이해하는 데 도움이 되었기를 바랍니다.

728x90
반응형