/*************************************************************************
* File: RadixSort.hh
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* An implementation of the radix sort algorithm, which sorts numbers in
* ascending order by sorting one digit at a time. In particular, the
* algorithm first sorts values by their least-signficant bit, then their
* second-least significant bit, etc. until all of the numbers are in
* sorted order.
*
* This particular implementation works on unsigned integers and sorts
* them one bit at a time. It maintains two queues, one of integers
* with a 0 in the current bit position and one for integers with a 1
* in the current bit position, then scans over the main list of values
* putting each number in the proper queue. It then dequeues the zero
* queue, putting each element back into the array, then does the same
* on the one queue. Since this process preserves the relative ordering
* of elements, at each phase the elements are always in sorted order
* if one considers only the bits that have been visited so far.
*
* This implementation also allows for sorting of signed integers. This
* works by simply reversing the two queues when looking at the sign bit.
*/
#ifndef RadixSort_Included
#define RadixSort_Included
#include <climits> // For CHAR_BIT
#include <vector>
#include <iterator>
#include <algorithm>
#include <limits>
/**
* Function: RadixSort(RandomIterator begin, RandomIterator end);
* Usage: RadixSort(v.begin(), v.end());
* ------------------------------------------------------------------------
* Applies the radix sort algorithm to sort the specified list of numbers.
* It is assumes that the iterators are traversing a list of integral
* types, and will not function properly otherwise.
*/
template <typename RandomIterator>
void RadixSort(RandomIterator begin, RandomIterator end) {
/* Typedef defining the type of the elements being traversed. */
typedef typename std::iterator_traits<RandomIterator>::value_type T;
/* Two lists of values, one for zeros and one for ones. */
std::vector<T> bitQueues[2];
/* Traverse each bit from low to high until everything is sorted. */
for (size_t bit = 0; bit < CHAR_BIT * sizeof(T); ++bit) {
/* Traverse each element in the range, putting it into the proper
* queue.
*/
for (RandomIterator itr = begin; itr != end; ++itr) {
/* This next line is a bit cryptic. There are three main steps.
* 1. Compute a bitmask to read only one bit of the number. This
* is given by 1u << bit. The u here guarantees that the result
* is unsigned.
* 2. Bitwise AND this with the current element. This yields a large
* positive value if the bit is set, zero otherwise.
* 3. Based on whether this value is nonzero, add it either to the
* first queue or the second queue.
*/
bitQueues[(*itr & (1u << bit))? 1 : 0].push_back(*itr);
}
/* If this is the final bit and the representation of numbers is signed, then
* this is the sign bit. Consequently, we want to reverse the order of the
* comparison.
*/
if (std::numeric_limits<T>::is_signed && bit == CHAR_BIT * sizeof(T) - 1)
bitQueues[0].swap(bitQueues[1]);
/* Return the contents of the vectors to the array, with the zero
* queue coming before the one queue.
*/
std::copy(bitQueues[0].begin(), bitQueues[0].end(), begin);
/* Output location starts after all of the elements from the zero queue. */
std::copy(bitQueues[1].begin(), bitQueues[1].end(), begin + bitQueues[0].size());
/* Clear the two queues. */
bitQueues[0].clear();
bitQueues[1].clear();
}
}
#endif