Here's a perhaps naive but simple implementation of Radix sort in Java. It works with any radix, and both positive and negative numbers.
import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class RadixSortWithDivision { public static final int DEFAULT_RADIX = 10; public static void sort(int[] arr) { sort(arr, DEFAULT_RADIX); } public static void sort(int[] arr, int radix) { int maxDigits = 1 + (int) (Math.log(max(arr)) / Math.log(radix)); int divisor = 1; for (int pos = 0; pos < maxDigits; ++pos) { List<List<Integer>> buckets = splitToBuckets(arr, divisor, radix); flattenBuckets(arr, buckets); divisor *= radix; } List<List<Integer>> buckets = splitBySign(arr); flattenBuckets(arr, buckets); } private static List<List<Integer>> splitToBuckets(int[] arr, int divisor, int radix) { List<List<Integer>> buckets = new ArrayList<>(); for (int i = 0; i < radix; ++i) { buckets.add(new LinkedList<>()); } for (int num : arr) { int bucketIndex = Math.abs(num) / divisor % radix; buckets.get(bucketIndex).add(num); } return buckets; } private static List<List<Integer>> splitBySign(int[] arr) { List<Integer> positive = new LinkedList<>(); List<Integer> negative = new LinkedList<>(); for (int num : arr) { if (num >= 0) { positive.add(num); } else { negative.add(0, num); } } return Arrays.asList(negative, positive); } private static void flattenBuckets(int[] arr, List<? extends List<Integer>> buckets) { int i = 0; for (List<Integer> bucket : buckets) { for (int num : bucket) { arr[i++] = num; } } } private static int max(int[] arr) { int max = Integer.MIN_VALUE; for (int num : arr) { if (num > max) { max = num; } } return max; } }
Unit tests:
import org.junit.Test; import java.util.Arrays; import java.util.Random; import static org.junit.Assert.assertArrayEquals; public abstract class SortTest { abstract void sort(int[] arr); private int[] newRandomArray(int num) { Random random = new Random(0); int[] arr = new int[num]; for (int i = 0; i < arr.length; ++i) { arr[i] = random.nextInt(); } return arr; } private void sortAndVerify(int[] arr) { int[] copy = arr.clone(); Arrays.sort(copy); sort(arr); assertArrayEquals(copy, arr); } @Test public void test_empty() { sortAndVerify(new int[0]); } @Test public void test_1() { sortAndVerify(new int[]{1}); } @Test public void test_1_2() { sortAndVerify(new int[]{1, 2}); } @Test public void test_2_1() { sortAndVerify(new int[]{2, 1}); } @Test public void test_1_2_3() { sortAndVerify(new int[]{1, 2, 3}); } @Test public void test_3_2_1() { sortAndVerify(new int[]{3, 2, 1}); } @Test public void test_random_10() { sortAndVerify(newRandomArray(10)); } @Test public void test_random_1000() { sortAndVerify(newRandomArray(1000)); } } public class RadixSortWithDivisionTest extends SortTest { @Override void sort(int[] arr) { RadixSortWithDivision.sort(arr); } }
How would you improve this?
How would you improve the unit test cases?