자바
[자바] 계수정렬(Counting sort) 개념과 구현
imcoding
2022. 7. 6. 12:47
계수정렬
Counting sort
계수정렬
별도의 메모리공간을 만들어서 각 원소값 만큼의 index에 해당 원소의 갯수를 채운 뒤 기존 배열의 값을 재설정하는 방식이다.
예를들어, 특정 값이 10만이라고 하면 해당 원소는 index 100,000에 채워지므로 메모리공간의 최대 길이는 10만까지 늘어나서 비효율적이다.
하지만 최대값의 크기가 적당하다면 효율적으로 사용할 수 있겠다.
시간복잡도는 O(n + k)이다. 여기서 k는 위에서 말한 최대 원소값을 뜻한다.
하지만 메모리공간을 HashMap으로 할당함으로써 워스트케이스에 어느정도 대처할 수 있다.
정렬방식
이와같이 별도의 메모리공간을 만들고, 각 원소 크기에 해당하는 index를 찾아 해당 원소 갯수만큼 채워넣는다.
모든 값을 채워넣었다면 최종적으로 기존 배열값을 재설정해준다.
코드구현
메모리공간을 배열로 생성
import java.util.*;
public class 계수정렬 {
public static void countingSort(int[] arr) {
int max = Arrays.stream(arr).max().getAsInt(); // 메모리공간의 크기를 경정할 배열 내에 최댓값을 찾는다.
int[] cnt = new int[max + 1]; // 각 원소의 갯수만큼 해당 원소값에 해당하는 index에서 cnt를 늘려간다.
for (int i = 0; i < arr.length; i++) {
cnt[arr[i]]++;
}
int idx = 0;
for (int i = 0; i < cnt.length; i++) {
while (cnt[i] > 0) {
arr[idx++] = i;
cnt[i]--;
}
}
}
public static void main(String[] args) {
int[] arr = {10, 32, 10, 27, 32, 17, 99, 56}; // 출력: [10, 10, 17, 27, 32, 32, 56, 99]
countingSort(arr);
System.out.println(Arrays.toString(arr));
}
}
위 방법은 메모리공간으로 배열을 만들었다.
단점으로는 최댓값에 따라 시간복잡도가 커져서 비효율적이 될 수 있다.
이번에는 HashMap을 메모리공간으로 할당하여 이 단점을 어느정도 커버해보겠다.
메모리공간을 HashMap으로 생성
import java.util.*;
public class 계수정렬 {
public static void countingSort(int[] arr) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int item: arr) {
map.put(item, map.getOrDefault(item, 0) + 1);
}
int idx2 = 0;
ArrayList<Integer> list = new ArrayList<>(map.keySet());
Collections.sort(list);
for (int i = 0; i < list.size(); i++) {
while (map.get(list.get(i)) > 0) {
arr[idx2++] = list.get(i);
map.put(list.get(i), map.get(list.get(i)) - 1);
}
}
}
public static void main(String[] args) {
int[] arr = {10, 32, 10, 27, 32, 17, 99, 56}; // 출력: [10, 10, 17, 27, 32, 32, 56, 99]
countingSort(arr);
System.out.println(Arrays.toString(arr));
}
}
HashMap에 데이터를 채워넣으면, 최댓값만큼 메모리공간을 늘리지 않아도 된다.
최댓값의 크기에 따라 배열, HashMap 중 선택해서 사용하는 것을 권장드린다.
지금까지 계수정렬의 개념과 구현을 알아보았다.