ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 정렬 알고리즘 (9): 버킷 정렬 (Bucket Sort)
    알고리즘 2025. 2. 20. 16:00

    1. 버킷 정렬이란?

    버킷 정렬(Bucket Sort)은 데이터를 여러 개의 버킷(bucket)으로 나누어 정렬하는 비교 기반이 아닌 정렬 알고리즘이다. 각 버킷은 일정한 범위를 가지며, 데이터가 해당 범위에 따라 버킷에 배정된 후 개별적으로 정렬되고, 이후 병합되어 최종적으로 정렬된 배열을 얻는다.

    이 알고리즘은 입력 데이터가 고르게 분포된 경우 매우 효율적으로 동작하며, 평균적으로 O(n + k)의 시간 복잡도를 가진다. 일반적으로 삽입 정렬, 병합 정렬 또는 퀵 정렬을 보조적으로 사용하여 개별 버킷을 정렬한다.

    2. 버킷 정렬의 동작 원리

    버킷 정렬은 다음과 같은 과정을 거쳐 데이터를 정렬한다.

    2.1 정렬 과정

    1. 입력 배열의 최댓값과 최솟값을 찾는다.
    2. 범위를 기반으로 여러 개의 버킷을 생성한다.
    3. 각 요소를 해당하는 버킷에 배치한다.
    4. 각 버킷을 개별적으로 정렬한다.
    5. 모든 버킷을 병합하여 최종적으로 정렬된 배열을 만든다.

    2.2 예제 코드 (Java)

    import java.util.*;
    
    public class BucketSort {
        // 버킷 정렬을 수행하는 메서드
        public static void bucketSort(float[] arr, int bucketSize) {
            if (arr.length == 0) return;
            
            // 최댓값과 최솟값 찾기
            float minValue = arr[0];
            float maxValue = arr[0];
            for (float num : arr) {
                if (num < minValue) minValue = num;
                if (num > maxValue) maxValue = num;
            }
            
            // 버킷 개수 결정
            int bucketCount = (int) Math.ceil((maxValue - minValue) / bucketSize) + 1;
            List<List<Float>> buckets = new ArrayList<>(bucketCount);
            for (int i = 0; i < bucketCount; i++) {
                buckets.add(new ArrayList<>());
            }
            
            // 각 숫자를 해당하는 버킷에 배치
            for (float num : arr) {
                int bucketIndex = (int) ((num - minValue) / bucketSize);
                buckets.get(bucketIndex).add(num);
            }
            
            // 각 버킷을 개별적으로 정렬
            for (List<Float> bucket : buckets) {
                Collections.sort(bucket);
            }
            
            // 정렬된 요소를 원본 배열에 병합
            int index = 0;
            for (List<Float> bucket : buckets) {
                for (float num : bucket) {
                    arr[index++] = num;
                }
            }
        }
    
        // 메인 메서드: 버킷 정렬 실행 및 결과 출력
        public static void main(String[] args) {
            float[] data = {0.42f, 0.32f, 0.33f, 0.52f, 0.37f, 0.47f, 0.51f};
            System.out.println("정렬 전: " + Arrays.toString(data));
            
            bucketSort(data, 10);
            
            System.out.println("정렬 후: " + Arrays.toString(data));
        }
    }

    3. 버킷 정렬의 성능 분석

    버킷 정렬의 시간 및 공간 복잡도를 분석하면 다음과 같다.

    3.1 시간 복잡도

    • 최선의 경우 (Best Case): O(n) → 데이터가 고르게 분포된 경우
    • 평균의 경우 (Average Case): O(n + k) → k는 버킷 개수
    • 최악의 경우 (Worst Case): O(n²) → 모든 요소가 하나의 버킷에 배치될 경우

    3.2 공간 복잡도

    • 공간 복잡도: O(n + k) → 추가적인 버킷 배열이 필요하므로 메모리 사용량이 증가할 수 있음.

    4. 버킷 정렬의 장점과 단점

    4.1 장점

    • 비교 기반 정렬 알고리즘보다 빠를 수 있음 (특히 데이터가 균등하게 분포된 경우).
    • O(n) 또는 O(n + k)로 동작할 가능성이 높아 매우 빠른 성능을 보일 수 있음.
    • 안정 정렬(Stable Sort)이며, 동일한 값의 상대적 순서를 유지할 수 있음.

    4.2 단점

    • 추가적인 메모리 공간이 필요하여 공간 복잡도가 증가할 수 있음.
    • 데이터가 균등하게 분포되지 않은 경우 최악의 경우 O(n²)의 성능을 가질 수 있음.
    • 버킷의 크기와 개수를 적절하게 설정해야 최적의 성능을 낼 수 있음.

    5. 버킷 정렬의 활용 및 개선 방법

    5.1 활용 사례

    • 부동소수점 데이터를 정렬할 때 유용함.
    • 데이터가 균등하게 분포된 경우 빠르게 정렬할 수 있음.
    • 대량의 데이터를 정렬해야 하는 경우 효율적으로 사용할 수 있음.

    5.2 개선 방법

    • 적절한 버킷 크기 선택: 버킷 크기가 너무 작거나 크면 성능이 저하될 수 있음.
    • 보조 정렬 알고리즘 사용: 각 버킷을 정렬할 때 삽입 정렬이나 퀵 정렬을 혼합하여 최적화 가능.
    • 동적 버킷 크기 조정: 데이터 분포를 분석하여 버킷 크기를 조정하면 성능을 개선할 수 있음.

    6. 결론

    버킷 정렬은 정수뿐만 아니라 실수 데이터를 정렬할 때 매우 효율적인 알고리즘이다. 비교 기반 정렬보다 빠를 수 있으며, 데이터가 균등하게 분포된 경우 O(n) 성능을 기대할 수 있다. 하지만 메모리 사용량이 증가할 수 있고, 데이터 분포에 따라 성능이 저하될 수도 있으므로 적절한 상황에서 사용하는 것이 중요하다.

Designed by Tistory.