Counting 정렬 (Counting Sort)
Counting Sort는 특정 조건에서 효율적인 정렬 알고리즘으로, 비교 기반 정렬 알고리즘이 아닙니다. 배열의 각 항목의 빈도를 기반으로 정렬하며, 원소의 범위가 제한적이고 양의 정수인 경우 매우 효율적입니다.
1. 작동 원리
- 범위 설정: 정렬할 배열에서 가장 큰 값을 찾아, 모든 값을 표현할 수 있는 범위를 설정합니다.
- 빈도 계산: 각 원소의 빈도를 저장하는 count 배열을 만듭니다.
- 누적 계산: count 배열을 기반으로 누적합을 계산하여 정렬된 배열에서 각 원소의 최종 위치를 결정합니다.
- 결과 저장: 정렬된 값을 새로운 배열에 저장합니다.
2. 특징
- 시간 복잡도: O(n + k)
- n: 입력 배열의 크기
- k: 데이터의 범위 (최대값 - 최소값)
- 공간 복잡도: O(n + k) (추가 공간 필요)
- 제한 사항:
- 정수 또는 정수로 표현 가능한 데이터에만 사용 가능.
- 데이터 범위가 크면 비효율적.
- 안정성: 원소의 순서를 유지하기 때문에 안정 정렬입니다.
3. 단계별 예제
입력 배열: [4, 2, 2, 8, 3, 3, 1]
- 빈도 계산:
- count 배열 생성: [0, 1, 2, 2, 1, 0, 0, 0, 1]
- 각 인덱스는 숫자, 값은 빈도.
- count 배열 생성: [0, 1, 2, 2, 1, 0, 0, 0, 1]
- 누적합 계산:
- count 배열 누적합: [0, 1, 3, 5, 6, 6, 6, 6, 7]
- 누적합은 원소가 최종적으로 위치할 인덱스 정보를 제공합니다.
- count 배열 누적합: [0, 1, 3, 5, 6, 6, 6, 6, 7]
- 정렬 배열 생성:
- 입력 배열을 역순으로 순회하며 정렬된 배열에 저장:
- 결과: [1, 2, 2, 3, 3, 4, 8]
- 입력 배열을 역순으로 순회하며 정렬된 배열에 저장:
4. 장점과 단점
장점:
- 선형 시간 복잡도: 비교 기반 정렬보다 빠른 성능 (O(n)).
- 안정 정렬: 원소의 상대적인 순서를 유지.
단점:
- 추가 메모리 사용량: 데이터 범위가 클수록 많은 메모리 필요.
- 제한적인 데이터: 정수 또는 정수형으로 매핑 가능한 값에만 사용.
5. Java 구현
import java.util.Arrays;
public class CountingSort {
public static void countingSort(int[] arr) {
if (arr.length == 0) {
return;
}
// Step 1: Find the range of the array
int max = Arrays.stream(arr).max().getAsInt();
int min = Arrays.stream(arr).min().getAsInt();
int range = max - min + 1;
// Step 2: Create count array and output array
int[] count = new int[range];
int[] output = new int[arr.length];
// Step 3: Count occurrences of each number
for (int num : arr) {
count[num - min]++;
}
// Step 4: Compute cumulative count
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// Step 5: Place elements into output array in sorted order
for (int i = arr.length - 1; i >= 0; i--) {
output[count[arr[i] - min] - 1] = arr[i];
count[arr[i] - min]--;
}
// Step 6: Copy sorted array back to the original array
System.arraycopy(output, 0, arr, 0, arr.length);
}
public static void main(String[] args) {
int[] arr = {4, 2, 2, 8, 3, 3, 1};
System.out.println("Original Array: " + Arrays.toString(arr));
countingSort(arr);
System.out.println("Sorted Array: " + Arrays.toString(arr));
}
}
6. Python 구현
def counting_sort(arr):
if not arr:
return arr
# Step 1: Find the range of the array
min_val = min(arr)
max_val = max(arr)
range_val = max_val - min_val + 1
# Step 2: Create count array and output array
count = [0] * range_val
output = [0] * len(arr)
# Step 3: Count occurrences of each number
for num in arr:
count[num - min_val] += 1
# Step 4: Compute cumulative count
for i in range(1, len(count)):
count[i] += count[i - 1]
# Step 5: Place elements into output array in sorted order
for num in reversed(arr):
output[count[num - min_val] - 1] = num
count[num - min_val] -= 1
return output
# Example usage
if __name__ == "__main__":
arr = [4, 2, 2, 8, 3, 3, 1]
print("Original Array:", arr)
sorted_arr = counting_sort(arr)
print("Sorted Array:", sorted_arr)
7. 활용 사례
- 데이터 범위가 제한적이고 양의 정수인 경우:
- 예: 성적 분포 정렬, 특정 범위의 로그 데이터를 정렬.
- 빠른 정렬이 필요한 경우:
- 데이터의 크기는 크지만 값의 범위가 작을 때 효과적.
- 실시간 시스템:
- 예측 가능한 실행 시간이 중요한 응용 프로그램.
Counting 정렬은 효율적이지만, 메모리와 데이터 유형의 제약으로 인해 특정 상황에서만 유용합니다.
반응형
'컴퓨터과학 > 알고리즘' 카테고리의 다른 글
정렬 알고리즘 (Sorting Algorithms) - 버킷 정렬 (Bucket Sort) (1) | 2025.01.07 |
---|---|
정렬 알고리즘 (Sorting Algorithms) - 기수 정렬 (Radix Sort) (0) | 2025.01.07 |
정렬 알고리즘 (Sorting Algorithms) - 삼분 병합 정렬 (3-Way Merge Sort) (0) | 2025.01.07 |
정렬 알고리즘 (Sorting Algorithms) - 사이클 정렬 (Cycle Sort) (0) | 2025.01.07 |
정렬 알고리즘 (Sorting Algorithms) - 힙 정렬 (Heap Sort) (0) | 2024.12.28 |