diff -r e9c203fb003d -r 994c7df296c9 lemon/radix_sort.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/radix_sort.h Thu Dec 10 17:05:35 2009 +0100 @@ -0,0 +1,487 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2009 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef RADIX_SORT_H +#define RADIX_SORT_H + +/// \ingroup auxalg +/// \file +/// \brief Radix sort +/// +/// Linear time sorting algorithms + +#include +#include +#include +#include + +namespace lemon { + + namespace _radix_sort_bits { + + template + struct Identity { + const Value& operator()(const Value& val) { + return val; + } + }; + + + template + Iterator radixSortPartition(Iterator first, Iterator last, + Functor functor, Value mask) { + while (first != last && !(functor(*first) & mask)) { + ++first; + } + if (first == last) { + return first; + } + --last; + while (first != last && (functor(*last) & mask)) { + --last; + } + if (first == last) { + return first; + } + std::iter_swap(first, last); + ++first; + if (!(first < last)) { + return first; + } + while (true) { + while (!(functor(*first) & mask)) { + ++first; + } + --last; + while (functor(*last) & mask) { + --last; + } + if (!(first < last)) { + return first; + } + std::iter_swap(first, last); + ++first; + } + } + + template + Iterator radixSortSignPartition(Iterator first, Iterator last, + Functor functor) { + while (first != last && functor(*first) < 0) { + ++first; + } + if (first == last) { + return first; + } + --last; + while (first != last && functor(*last) >= 0) { + --last; + } + if (first == last) { + return first; + } + std::iter_swap(first, last); + ++first; + if (!(first < last)) { + return first; + } + while (true) { + while (functor(*first) < 0) { + ++first; + } + --last; + while (functor(*last) >= 0) { + --last; + } + if (!(first < last)) { + return first; + } + std::iter_swap(first, last); + ++first; + } + } + + template + void radixIntroSort(Iterator first, Iterator last, + Functor functor, Value mask) { + while (mask != 0 && last - first > 1) { + Iterator cut = radixSortPartition(first, last, functor, mask); + mask >>= 1; + radixIntroSort(first, cut, functor, mask); + first = cut; + } + } + + template + void radixSignedSort(Iterator first, Iterator last, Functor functor) { + + Iterator cut = radixSortSignPartition(first, last, functor); + + Value mask; + int max_digit; + Iterator it; + + mask = ~0; max_digit = 0; + for (it = first; it != cut; ++it) { + while ((mask & functor(*it)) != mask) { + ++max_digit; + mask <<= 1; + } + } + radixIntroSort(first, cut, functor, 1 << max_digit); + + mask = 0; max_digit = 0; + for (it = cut; it != last; ++it) { + while ((mask | functor(*it)) != mask) { + ++max_digit; + mask <<= 1; mask |= 1; + } + } + radixIntroSort(cut, last, functor, 1 << max_digit); + } + + template + void radixUnsignedSort(Iterator first, Iterator last, Functor functor) { + + Value mask = 0; + int max_digit = 0; + + Iterator it; + for (it = first; it != last; ++it) { + while ((mask | functor(*it)) != mask) { + ++max_digit; + mask <<= 1; mask |= 1; + } + } + radixIntroSort(first, last, functor, 1 << max_digit); + } + + + template ::is_signed > + struct RadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + radixSignedSort(first, last, functor); + } + }; + + template + struct RadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + radixUnsignedSort(first, last, functor); + } + }; + + } + + /// \ingroup auxalg + /// + /// \brief Sorts the STL compatible range into ascending order. + /// + /// The \c radixSort sorts an STL compatible range into ascending + /// order. The radix sort algorithm can sort items which are mapped + /// to integers with an adaptable unary function \c functor and the + /// order will be ascending according to these mapped values. + /// + /// It is also possible to use a normal function instead + /// of the functor object. If the functor is not given it will use + /// the identity function instead. + /// + /// This is a special quick sort algorithm where the pivot + /// values to split the items are choosen to be 2k + /// for each \c k. + /// Therefore, the time complexity of the algorithm is O(log(c)*n) and + /// it uses O(log(c)) additional space, where \c c is the maximal value + /// and \c n is the number of the items in the container. + /// + /// \param first The begin of the given range. + /// \param last The end of the given range. + /// \param functor An adaptible unary function or a normal function + /// which maps the items to any integer type which can be either + /// signed or unsigned. + /// + /// \sa stableRadixSort() + template + void radixSort(Iterator first, Iterator last, Functor functor) { + using namespace _radix_sort_bits; + typedef typename Functor::result_type Value; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value (*functor)(Key)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { + using namespace _radix_sort_bits; + RadixSortSelector::sort(first, last, functor); + } + + template + void radixSort(Iterator first, Iterator last) { + using namespace _radix_sort_bits; + typedef typename std::iterator_traits::value_type Value; + RadixSortSelector::sort(first, last, Identity()); + } + + namespace _radix_sort_bits { + + template + unsigned char valueByte(Value value, int byte) { + return value >> (std::numeric_limits::digits * byte); + } + + template + void stableRadixIntroSort(Key *first, Key *last, Key *target, + int byte, Functor functor) { + const int size = + unsigned(std::numeric_limits::max()) + 1; + std::vector counter(size); + for (int i = 0; i < size; ++i) { + counter[i] = 0; + } + Key *it = first; + while (first != last) { + ++counter[valueByte(functor(*first), byte)]; + ++first; + } + int prev, num = 0; + for (int i = 0; i < size; ++i) { + prev = num; + num += counter[i]; + counter[i] = prev; + } + while (it != last) { + target[counter[valueByte(functor(*it), byte)]++] = *it; + ++it; + } + } + + template + void signedStableRadixIntroSort(Key *first, Key *last, Key *target, + int byte, Functor functor) { + const int size = + unsigned(std::numeric_limits::max()) + 1; + std::vector counter(size); + for (int i = 0; i < size; ++i) { + counter[i] = 0; + } + Key *it = first; + while (first != last) { + counter[valueByte(functor(*first), byte)]++; + ++first; + } + int prev, num = 0; + for (int i = size / 2; i < size; ++i) { + prev = num; + num += counter[i]; + counter[i] = prev; + } + for (int i = 0; i < size / 2; ++i) { + prev = num; + num += counter[i]; + counter[i] = prev; + } + while (it != last) { + target[counter[valueByte(functor(*it), byte)]++] = *it; + ++it; + } + } + + + template + void stableRadixSignedSort(Iterator first, Iterator last, Functor functor) { + if (first == last) return; + typedef typename std::iterator_traits::value_type Key; + typedef std::allocator Allocator; + Allocator allocator; + + int length = std::distance(first, last); + Key* buffer = allocator.allocate(2 * length); + try { + bool dir = true; + std::copy(first, last, buffer); + for (int i = 0; i < int(sizeof(Value)) - 1; ++i) { + if (dir) { + stableRadixIntroSort(buffer, buffer + length, buffer + length, + i, functor); + } else { + stableRadixIntroSort(buffer + length, buffer + 2 * length, buffer, + i, functor); + } + dir = !dir; + } + if (dir) { + signedStableRadixIntroSort(buffer, buffer + length, buffer + length, + sizeof(Value) - 1, functor); + std::copy(buffer + length, buffer + 2 * length, first); + } else { + signedStableRadixIntroSort(buffer + length, buffer + 2 * length, + buffer, sizeof(Value) - 1, functor); + std::copy(buffer, buffer + length, first); + } + } catch (...) { + allocator.deallocate(buffer, 2 * length); + throw; + } + allocator.deallocate(buffer, 2 * length); + } + + template + void stableRadixUnsignedSort(Iterator first, Iterator last, + Functor functor) { + if (first == last) return; + typedef typename std::iterator_traits::value_type Key; + typedef std::allocator Allocator; + Allocator allocator; + + int length = std::distance(first, last); + Key *buffer = allocator.allocate(2 * length); + try { + bool dir = true; + std::copy(first, last, buffer); + for (int i = 0; i < int(sizeof(Value)); ++i) { + if (dir) { + stableRadixIntroSort(buffer, buffer + length, + buffer + length, i, functor); + } else { + stableRadixIntroSort(buffer + length, buffer + 2 * length, + buffer, i, functor); + } + dir = !dir; + } + if (dir) { + std::copy(buffer, buffer + length, first); + } else { + std::copy(buffer + length, buffer + 2 * length, first); + } + } catch (...) { + allocator.deallocate(buffer, 2 * length); + throw; + } + allocator.deallocate(buffer, 2 * length); + } + + + + template ::is_signed > + struct StableRadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + stableRadixSignedSort(first, last, functor); + } + }; + + template + struct StableRadixSortSelector { + template + static void sort(Iterator first, Iterator last, Functor functor) { + stableRadixUnsignedSort(first, last, functor); + } + }; + + } + + /// \ingroup auxalg + /// + /// \brief Sorts the STL compatible range into ascending order in a stable + /// way. + /// + /// This function sorts an STL compatible range into ascending + /// order according to an integer mapping in the same as radixSort() does. + /// + /// This sorting algorithm is stable, i.e. the order of two equal + /// elements remains the same after the sorting. + /// + /// This sort algorithm use a radix forward sort on the + /// bytes of the integer number. The algorithm sorts the items + /// byte-by-byte. First, it counts how many times a byte value occurs + /// in the container, then it copies the corresponding items to + /// another container in asceding order in O(n) time. + /// + /// The time complexity of the algorithm is O(log(c)*n) and + /// it uses O(n) additional space, where \c c is the + /// maximal value and \c n is the number of the items in the + /// container. + /// + + /// \param first The begin of the given range. + /// \param last The end of the given range. + /// \param functor An adaptible unary function or a normal function + /// which maps the items to any integer type which can be either + /// signed or unsigned. + /// \sa radixSort() + template + void stableRadixSort(Iterator first, Iterator last, Functor functor) { + using namespace _radix_sort_bits; + typedef typename Functor::result_type Value; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { + using namespace _radix_sort_bits; + StableRadixSortSelector::sort(first, last, functor); + } + + template + void stableRadixSort(Iterator first, Iterator last) { + using namespace _radix_sort_bits; + typedef typename std::iterator_traits::value_type Value; + StableRadixSortSelector::sort(first, last, Identity()); + } + +} + +#endif