2021. 12. 31. 16:18ㆍMajor`/자료구조
계수 정렬 (Counting Sort)

Stable sort
- 비교하지 않는 정렬 알고리즘
- 좁은 범위의 Data를 정렬할 때 효과적
- 입력받는 수의 범위가 한정되어 있을 때 사용
총 배열 3개가 필요 (정렬할 배열 A, 누적 합 배열 C, 최종 정렬된 배열 result)
- 추가 배열 C
- 배열 A에 존재하는 각 요소들의 등장횟수를 오름차순으로 저장하고, 배열 C의 맨 앞 인덱스부터 차례대로 값들을 누적해서 저장
- 배열 C는 결국 배열 A의 각 요소들의 인덱스를 저장
시간복잡도
- O(n + k) → k = 배열의 최댓값
장점
- O(n)의 매우 빠른 속도로 정렬 가능
단점
- 음수/실수는 정렬 못함
- 추가적인 메모리 공간이 필요하고 값의 분포에 따라 메모리 낭비가 심해질 수 있다
과정
- 정렬할 배열 A, 배열 A의 요소에 대한 누적 합 배열 C, 최종 정렬완료 배열 result 생성
- 배열 A의 각 요소들의 등장횟수를 오름차순으로 배열 C에 저장
- 배열 C에 저장된 각 요소들의 등장횟수를 앞에서부터 차례대로 누적해서 더한 값들로 업데이트
- 배열 A의 끝에서부터 역순으로 순회하면서, 각 요소의 인덱스를 배열 C로부터 확인해서 배열 result의 해당 인덱스에 저장
- 저장하면 배열 C의 해당 인덱스는 -1을 해준다
※ Example
과정 1 ~ 3
배열 A
→ {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
배열 C
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
등장 횟수 | 3 | 2 | 2 | 3 | 3 | 3 |
↓
배열 C (앞에서부터 누적)
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 3 | 5 | 7 | 10 | 13 | 16 |
과정 4 ~ 5
배열 A : {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
→ 배열 C에서 요소 0의 인덱스 = 3
→ result배열의 인덱스3에 0 저장
→ 배열 C에서 요소 0의 인덱스 -1
result index |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
0 |
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 2 | 5 | 7 | 10 | 13 | 16 |
배열 A : {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
→ 배열 C에서 요소 3의 인덱스 = 10
→ result배열의 인덱스10에 3 저장
→ 배열 C에서 요소 3의 인덱스 -1
result index |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
0 | 3 |
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 2 | 5 | 7 | 9 | 13 | 16 |
배열 A : {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
→ 배열 C에서 요소 2의 인덱스 = 7
→ result배열의 인덱스7에 2 저장
→ 배열 C에서 요소 2의 인덱스 -1
result index |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
0 | 2 | 3 |
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 2 | 5 | 6 | 9 | 13 | 16 |
배열 A : {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
→ 배열 C에서 요소 4의 인덱스 = 13
→ result배열의 인덱스13에 4 저장
→ 배열 C에서 요소 4의 인덱스 -1
result index |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
0 | 2 | 3 | 4 |
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 2 | 5 | 6 | 9 | 12 | 16 |
배열 A : {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
→ 배열 C에서 요소 2의 인덱스 = 6
→ result배열의 인덱스6에 2 저장
→ 배열 C에서 요소 2의 인덱스 -1
result index |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
0 | 2 | 2 | 3 | 4 |
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 2 | 5 | 5 | 9 | 12 | 16 |
배열 A : {5, 5, 3 ,4, 5, 1, 0, 4, 1, 3, 0, 2, 4, 2, 3, 0}
→ 배열 C에서 요소 5의 인덱스 = 14
→ result배열의 인덱스14에 5 저장
→ 배열 C에서 요소 5의 인덱스 -1
result index |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
0 | 0 | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 3 | 4 | 4 | 4 | 5 | 5 | 5 |
A의 각 요소 | 0 | 1 | 2 | 3 | 4 | 5 |
인덱스 | 0 | 3 | 5 | 7 | 10 | 13 |
Counting_Sort Code
static void counting_sort(int [] A, int[] C, int [] result){ for(int i=0; i<A.length; i++) C[A[i]]++; // A의 각 요소 등장횟수를 C의 해당 인덱스 저장 for(int i=1; i<C.length; i++){ C[i] += C[i-1]; // C 앞에서부터 차례대로 누적 합 저장 accumulate } for(int i=A.length-1; i>=0; i--){ int value = A[i]; // 배열 A의 마지막 요소 확인 C[value]--; // 해당 요소의 인덱스 -1 result[C[value]] = value; // 해당 요소를 result 인덱스(배열 C에서의 해당 요소 인덱스)에 저장 } }
Full Code
package Sort; import java.util.Calendar; public class Counting_Sort_1 { public static void main(String[] args){ int [] A = new int[100]; // 정렬할 배열 A int [] C = new int[51]; // A의 요소들에 대한 등장횟수, 차례대로 누적 합 int [] result = new int[100]; // A의 최종 정렬 배열 저장 for(int i=0; i<A.length; i++) A[i] = (int)(Math.random()*51); // 0~50 // 정렬 전 A 출력 System.out.print("A[]"); for(int i=0; i<A.length; i++){ if(i%20==0) System.out.println(); System.out.print(A[i] + "\t"); } System.out.println("\n"); counting_sort(A, C, result); } static void counting_sort(int [] A, int[] C, int [] result){ Calendar before = Calendar.getInstance(); for(int i=0; i<A.length; i++) C[A[i]]++; // A의 각 요소 등장횟수를 C의 해당 인덱스 저장 System.out.print("C[] (각 요소 등장횟수)"); for(int i=0; i<C.length; i++){ if(i%20==0) System.out.println(); System.out.print(C[i] + "\t"); } System.out.println("\n"); for(int i=1; i<C.length; i++){ C[i] += C[i-1]; // C 앞에서부터 차례대로 누적 합 저장 accumulate } System.out.print("C[] (각 요소 차례대로 누적 합)"); for(int i=0; i<C.length; i++){ if(i%20==0) System.out.println(); System.out.print(C[i] + "\t"); } System.out.println("\n"); for(int i=A.length-1; i>=0; i--){ int value = A[i]; // 배열 A의 마지막 요소 확인 C[value]--; // 해당 요소의 인덱스 -1 result[C[value]] = value; // 해당 요소를 result 인덱스(배열 C에서의 해당 요소 인덱스)에 저장 } Calendar after = Calendar.getInstance(); // A의 각 요소 count 저장한 배열 C 출력 System.out.print("C[] (Counting_Sort 후 최종 Count)"); for(int i=0; i<C.length; i++){ if(i%20==0) System.out.println(); System.out.print(C[i] + "\t"); } System.out.println("\n"); // 정렬 후 최종 result 배열 출력 System.out.print("result[]"); for(int i=0; i<result.length; i++){ if(i%20==0) System.out.println(); System.out.print(result[i] + "\t"); } System.out.println("\n"); int time = after.get(Calendar.MILLISECOND) - before.get(Calendar.MILLISECOND); System.out.println("걸린 시간 : " + time + "ms"); } }


