보통 이 문제는 범위가 좁아 계수 정렬(Counting Sort)로 풀지만, 저는 실무 활용도와 알고리즘 연습을 위해 기수 정렬을 선택했습니다.
가장 낮은 자릿수(1의 자리)부터 가장 높은 자릿수(10,000의 자리)까지 총 5번의 패스를 거치며 정렬합니다. 각 패스 내부에서는 계수 정렬(Counting Sort) 로직을 활용하여 해당 자릿수를 기준으로 정렬을 수행합니다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
public static void main(String[] args) throws Exception {
int N = nextInt();
// 10,000,000개의 데이터를 담을 배열 (약 40MB)
int[] nums = new int[N];
for (int i = 0; i < N; i++) {
nums[i] = nextInt();
}
// 기수 정렬 수행
radixSort(nums);
// 출력 최적화
StringBuilder sb = new StringBuilder();
for (int n : nums) {
sb.append(n).append("\n");
}
System.out.print(sb);
}
static void radixSort(int[] arr) {
int n = arr.length;
int[] temp = new int[n]; // 정렬 결과를 임시 저장할 배열
// 문제 조건: 숫자는 10,000보다 작거나 같은 자연수
// 1의 자리(1)부터 10,000의 자리(10000)까지 10배씩 증가하며 반복
for (int divisor = 1; divisor <= 10000; divisor *= 10) {
int[] count = new int[10]; // 0~9 자릿수 카운팅
// 1. 현재 자릿수 기준 빈도수 계산
for (int i = 0; i < n; i++) {
count[(arr[i] / divisor) % 10]++;
}
// 2. 누적합 계산 (Stable 정렬을 위한 인덱스 확보)
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 3. 뒤에서부터 순회하며 temp 배열에 배치 (안정성 유지)
for (int i = n - 1; i >= 0; i--) {
int digit = (arr[i] / divisor) % 10;
temp[count[digit] - 1] = arr[i];
count[digit]--;
}
// 4. 현재 자릿수 정렬 결과를 원본 배열에 복사
System.arraycopy(temp, 0, arr, 0, n);
}
}
static int nextInt() throws Exception {
while (st == null || !st.hasMoreTokens()) {
st = new StringTokenizer(br.readLine());
}
return Integer.parseInt(st.nextToken());
}
}