package lbms.plugins.mldht.utils;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import lbms.plugins.mldht.kad.Key;
import lbms.plugins.mldht.kad.Prefix;
public class RadixSort {
public final static void radixSort(final Radixable[] toSort) {
radixSort(toSort, 0, toSort.length, 0);
}
private final static void radixSort(final Radixable[] toSort, final int startIdx, final int endIdx, final int depth)
{
final int bins = 256;
int[] count = new int[bins];
int lowestBin = bins;
int highestBin = 0;
boolean ascendingRun = true;
int prevRadix = -1;
for(int i=startIdx;i<endIdx;i++)
{
int radix = toSort[i].getRadix(depth);
if(lowestBin > radix)
lowestBin = radix;
if(highestBin < radix)
highestBin = radix;
if(prevRadix > radix)
ascendingRun = false;
prevRadix = radix;
count[radix]++;
}
if(ascendingRun)
{
// shortcut
int bucketStart = startIdx;
for(int i=lowestBin;i<=highestBin;i++)
{
int bucketLength = count[i];
int bucketEnd = bucketStart + bucketLength;
doRecursion(toSort, bucketStart, bucketEnd, depth);
bucketStart = bucketEnd;
}
return;
}
int[] startIndices = new int[bins];
// we'll overwrite this one on the fly
int[] endIndices = count;
startIndices[lowestBin] = startIdx;
for(int i=lowestBin+1;i<=highestBin;i++)
{
startIndices[i] = count[i-1] + startIndices[i-1];
endIndices[i-1] = startIndices[i-1];
}
endIndices[highestBin] = startIndices[highestBin];
int currentBin = lowestBin;
for(int currentPointer=startIdx;currentPointer<endIdx;)
{
Radixable current = toSort[currentPointer];
int radix, target = -1;
// do a swapping dance through the array until we find something that fits into the current bin
while((radix = current.getRadix(depth)) != currentBin)
{
target = endIndices[radix];
Radixable newCurrent = toSort[target];
toSort[target] = current;
endIndices[radix] = target+1;
current = newCurrent;
}
// only write current element if we did any swapping
if(target != -1)
toSort[currentPointer] = current;
// advance the current pointer to the next element
endIndices[ currentBin ] = ++currentPointer;
// make sure that invariants hold
boolean needsUpdate = false;
while(currentBin < bins-1 && endIndices[ currentBin ] == startIndices[ currentBin +1 ])
{
int bin = currentBin++;
needsUpdate = true;
// recurse inside the loop to exploit cache locality in mostly sorted arrays
//doRecursion(toSort,startIndices[bin],endIndices[bin],depth);
// fudge pointers so we don't recurse into this bucket again
//startIndices[bin] = endIndices[bin];
}
// skip over anything we have already completed in the swapping phase
if(needsUpdate)
currentPointer = Math.max(currentPointer, endIndices[ currentBin ]);
}
for(int recursionBin = lowestBin;recursionBin<=highestBin;recursionBin++)
doRecursion(toSort,startIndices[recursionBin ],endIndices[recursionBin ],depth);
}
private final static void doRecursion(final Radixable[] toSort, final int startIdx, final int endIdx, final int depth)
{
int inBin = endIdx - startIdx;
if(inBin < 2)
return;
if(inBin > 32)
radixSort(toSort,startIdx,endIdx,depth+1);
else
Arrays.sort(toSort, startIdx, endIdx);
}
public static void main(String[] args) {
Prefix p = Prefix.WHOLE_KEYSPACE;
for(int i=0;i<64;i++)
p = p.splitPrefixBranch(false);
Key[] values = new Key[5000000];
for(int i=0;i<values.length;i++)
values[i] = p.createRandomKeyFromPrefix();
Comparator<Key> k = new Key.DistanceOrder(Key.createRandomKey());
//Arrays.sort(values);
Collections.shuffle(Arrays.asList(values));
for(int i=0;i<200;i++)
{
System.gc();
Key[] toSort = values.clone();
long start = System.nanoTime();
radixSort(toSort);
//Arrays.sort(toSort);
System.out.println((System.nanoTime()-start)/1000/1000);
for(int j=1;j<toSort.length;j++)
if(toSort[j-1].compareTo(toSort[j]) > 1)
System.out.println("error");
}
}
}