You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
3.0 KiB
Java

package com.jwetherell.algorithms.sorts;
/**
* An American flag sort is an efficient, in-place variant of radix sort that
* distributes items into hundreds of buckets. Non-comparative sorting
* algorithms such as radix sort and American flag sort are typically used to
* sort large objects such as strings, for which comparison is not a unit-time
* operation.
*
* Family: Bucket.
* Space: In-place.
* Stable: False.
*
* Average case = O(n*k/d) Worst case = O(n*k/d) Best case = O(n*k/d)
* NOTE: n is the number of digits and k is the average bucket size
*
* http://en.wikipedia.org/wiki/American_flag_sort
*
* @author Justin Wetherell <phishman3579@gmail.com>
*/
public class AmericanFlagSort {
private static final int NUMBER_OF_BUCKETS = 10; // 10 for base 10 numbers
private AmericanFlagSort() { }
public static Integer[] sort(Integer[] unsorted) {
int numberOfDigits = getMaxNumberOfDigits(unsorted); // Max number of digits
int max = 1;
for (int i = 0; i < numberOfDigits - 1; i++)
max *= 10;
sort(unsorted, 0, unsorted.length, max);
return unsorted;
}
public static void sort(Integer[] unsorted, int start, int length, int divisor) {
// First pass - find counts
int[] count = new int[NUMBER_OF_BUCKETS];
int[] offset = new int[NUMBER_OF_BUCKETS];
int digit = 0;
for (int i = start; i < length; i++) {
int d = unsorted[i];
digit = getDigit(d, divisor);
count[digit]++;
}
offset[0] = start + 0;
for (int i = 1; i < NUMBER_OF_BUCKETS; i++) {
offset[i] = count[i - 1] + offset[i - 1];
}
// Second pass - move into position
for (int b = 0; b < NUMBER_OF_BUCKETS; b++) {
while (count[b] > 0) {
int origin = offset[b];
int from = origin;
int num = unsorted[from];
unsorted[from] = -1;
do {
digit = getDigit(num, divisor);
int to = offset[digit]++;
count[digit]--;
int temp = unsorted[to];
unsorted[to] = num;
num = temp;
from = to;
} while (from != origin);
}
}
if (divisor > 1) {
// Sort the buckets
for (int i = 0; i < NUMBER_OF_BUCKETS; i++) {
int begin = (i > 0) ? offset[i - 1] : start;
int end = offset[i];
if (end - begin > 1)
sort(unsorted, begin, end, divisor / 10);
}
}
}
private static int getMaxNumberOfDigits(Integer[] unsorted) {
int max = Integer.MIN_VALUE;
int temp = 0;
for (int i : unsorted) {
temp = (int) Math.log10(i) + 1;
if (temp > max)
max = temp;
}
return max;
}
private static int getDigit(int integer, int divisor) {
return (integer / divisor) % 10;
}
}