deba@464: /* -*- C++ -*- deba@464: * deba@464: * This file is a part of LEMON, a generic C++ optimization library deba@464: * deba@464: * Copyright (C) 2003-2008 deba@464: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@464: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@464: * deba@464: * Permission to use, modify and distribute this software is granted deba@464: * provided that this copyright notice appears in all copies. For deba@464: * precise terms see the accompanying LICENSE file. deba@464: * deba@464: * This software is provided "AS IS" with no warranty of any kind, deba@464: * express or implied, and with no claim as to its suitability for any deba@464: * purpose. deba@464: * deba@464: */ deba@464: deba@464: #ifndef RADIX_SORT_H deba@464: #define RADIX_SORT_H deba@464: deba@464: /// \ingroup auxalg deba@464: /// \file deba@464: /// \brief Radix sort deba@464: /// deba@464: /// Linear time sorting algorithms deba@464: deba@464: #include deba@464: #include deba@464: #include deba@464: #include deba@464: deba@464: namespace lemon { deba@464: deba@464: namespace _radix_sort_bits { deba@464: deba@464: template deba@464: struct Identity { deba@464: const Value& operator()(const Value& val) { deba@464: return val; deba@464: } deba@464: }; deba@464: deba@464: deba@464: template deba@464: Iterator radixSortPartition(Iterator first, Iterator last, deba@464: Functor functor, Value mask) { deba@464: while (first != last && !(functor(*first) & mask)) { deba@464: ++first; deba@464: } deba@464: if (first == last) { deba@464: return first; deba@464: } deba@464: --last; deba@464: while (first != last && (functor(*last) & mask)) { deba@464: --last; deba@464: } deba@464: if (first == last) { deba@464: return first; deba@464: } deba@464: std::iter_swap(first, last); deba@464: ++first; deba@464: if (!(first < last)) { deba@464: return first; deba@464: } deba@464: while (true) { deba@464: while (!(functor(*first) & mask)) { deba@464: ++first; deba@464: } deba@464: --last; deba@464: while (functor(*last) & mask) { deba@464: --last; deba@464: } deba@464: if (!(first < last)) { deba@464: return first; deba@464: } deba@464: std::iter_swap(first, last); deba@464: ++first; deba@464: } deba@464: } deba@464: deba@464: template deba@464: Iterator radixSortSignPartition(Iterator first, Iterator last, deba@464: Functor functor) { deba@464: while (first != last && functor(*first) < 0) { deba@464: ++first; deba@464: } deba@464: if (first == last) { deba@464: return first; deba@464: } deba@464: --last; deba@464: while (first != last && functor(*last) >= 0) { deba@464: --last; deba@464: } deba@464: if (first == last) { deba@464: return first; deba@464: } deba@464: std::iter_swap(first, last); deba@464: ++first; deba@464: if (!(first < last)) { deba@464: return first; deba@464: } deba@464: while (true) { deba@464: while (functor(*first) < 0) { deba@464: ++first; deba@464: } deba@464: --last; deba@464: while (functor(*last) >= 0) { deba@464: --last; deba@464: } deba@464: if (!(first < last)) { deba@464: return first; deba@464: } deba@464: std::iter_swap(first, last); deba@464: ++first; deba@464: } deba@464: } deba@464: deba@464: template deba@464: void radixIntroSort(Iterator first, Iterator last, deba@464: Functor functor, Value mask) { deba@464: while (mask != 0 && last - first > 1) { deba@464: Iterator cut = radixSortPartition(first, last, functor, mask); deba@464: mask >>= 1; deba@464: radixIntroSort(first, cut, functor, mask); deba@464: first = cut; deba@464: } deba@464: } deba@464: deba@464: template deba@464: void radixSignedSort(Iterator first, Iterator last, Functor functor) { deba@464: deba@464: Iterator cut = radixSortSignPartition(first, last, functor); deba@464: deba@464: Value mask; deba@464: int max_digit; deba@464: Iterator it; deba@464: deba@464: mask = ~0; max_digit = 0; deba@464: for (it = first; it != cut; ++it) { deba@464: while ((mask & functor(*it)) != mask) { deba@464: ++max_digit; deba@464: mask <<= 1; deba@464: } deba@464: } deba@464: radixIntroSort(first, cut, functor, 1 << max_digit); deba@464: deba@464: mask = 0; max_digit = 0; deba@464: for (it = cut; it != last; ++it) { deba@464: while ((mask | functor(*it)) != mask) { deba@464: ++max_digit; deba@464: mask <<= 1; mask |= 1; deba@464: } deba@464: } deba@464: radixIntroSort(cut, last, functor, 1 << max_digit); deba@464: } deba@464: deba@464: template deba@464: void radixUnsignedSort(Iterator first, Iterator last, Functor functor) { deba@464: deba@464: Value mask = 0; deba@464: int max_digit = 0; deba@464: deba@464: Iterator it; deba@464: for (it = first; it != last; ++it) { deba@464: while ((mask | functor(*it)) != mask) { deba@464: ++max_digit; deba@464: mask <<= 1; mask |= 1; deba@464: } deba@464: } deba@464: radixIntroSort(first, last, functor, 1 << max_digit); deba@464: } deba@464: deba@464: deba@464: template ::is_signed > deba@464: struct RadixSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { deba@464: radixSignedSort(first, last, functor); deba@464: } deba@464: }; deba@464: deba@464: template deba@464: struct RadixSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { deba@464: radixUnsignedSort(first, last, functor); deba@464: } deba@464: }; deba@464: deba@464: } deba@464: deba@464: /// \ingroup auxalg deba@464: /// deba@464: /// \brief Sorts the STL compatible range into ascending order. deba@464: /// deba@464: /// The \c radixSort sorts the STL compatible range into ascending deba@464: /// order. The radix sort algorithm can sort the items which mapped deba@464: /// to an integer with an adaptable unary function \c functor and the deba@464: /// order will be ascending by these mapped values. As function deba@464: /// specialization it is possible to use a normal function instead deba@464: /// of the functor object or if the functor is not given it will use deba@464: /// an identity function instead. deba@464: /// deba@464: /// This implemented radix sort is a special quick sort which pivot deba@464: /// value is choosen to partite the items on the next deba@464: /// bit. Therefore, let be \c c the maximal capacity and \c n the deba@464: /// number of the items in the container, the time complexity of the deba@464: /// algorithm is \f$ O(\log(c)n) \f$ and the additional space deba@464: /// complexity is \f$ O(\log(c)) \f$. deba@464: /// deba@464: /// \param first The begin of the given range. deba@464: /// \param last The end of the given range. deba@464: /// \param functor An adaptible unary function or a normal function deba@464: /// which maps the items to any integer type which can be either deba@464: /// signed or unsigned. deba@464: template deba@464: void radixSort(Iterator first, Iterator last, Functor functor) { deba@464: using namespace _radix_sort_bits; deba@464: typedef typename Functor::result_type Value; deba@464: RadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void radixSort(Iterator first, Iterator last, Value (*functor)(Key)) { deba@464: using namespace _radix_sort_bits; deba@464: RadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void radixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { deba@464: using namespace _radix_sort_bits; deba@464: RadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void radixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { deba@464: using namespace _radix_sort_bits; deba@464: RadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void radixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { deba@464: using namespace _radix_sort_bits; deba@464: RadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void radixSort(Iterator first, Iterator last) { deba@464: using namespace _radix_sort_bits; deba@464: typedef typename std::iterator_traits::value_type Value; deba@464: RadixSortSelector::sort(first, last, Identity()); deba@464: } deba@464: deba@464: namespace _radix_sort_bits { deba@464: deba@464: template deba@464: unsigned char valueByte(Value value, int byte) { deba@464: return value >> (std::numeric_limits::digits * byte); deba@464: } deba@464: deba@464: template deba@464: void counterIntroSort(Key *first, Key *last, Key *target, deba@464: int byte, Functor functor) { deba@464: const int size = deba@464: unsigned(std::numeric_limits::max()) + 1; deba@464: std::vector counter(size); deba@464: for (int i = 0; i < size; ++i) { deba@464: counter[i] = 0; deba@464: } deba@464: Key *it = first; deba@464: while (first != last) { deba@464: ++counter[valueByte(functor(*first), byte)]; deba@464: ++first; deba@464: } deba@464: int prev, num = 0; deba@464: for (int i = 0; i < size; ++i) { deba@464: prev = num; deba@464: num += counter[i]; deba@464: counter[i] = prev; deba@464: } deba@464: while (it != last) { deba@464: target[counter[valueByte(functor(*it), byte)]++] = *it; deba@464: ++it; deba@464: } deba@464: } deba@464: deba@464: template deba@464: void signedCounterIntroSort(Key *first, Key *last, Key *target, deba@464: int byte, Functor functor) { deba@464: const int size = deba@464: unsigned(std::numeric_limits::max()) + 1; deba@464: std::vector counter(size); deba@464: for (int i = 0; i < size; ++i) { deba@464: counter[i] = 0; deba@464: } deba@464: Key *it = first; deba@464: while (first != last) { deba@464: counter[valueByte(functor(*first), byte)]++; deba@464: ++first; deba@464: } deba@464: int prev, num = 0; deba@464: for (int i = size / 2; i < size; ++i) { deba@464: prev = num; deba@464: num += counter[i]; deba@464: counter[i] = prev; deba@464: } deba@464: for (int i = 0; i < size / 2; ++i) { deba@464: prev = num; deba@464: num += counter[i]; deba@464: counter[i] = prev; deba@464: } deba@464: while (it != last) { deba@464: target[counter[valueByte(functor(*it), byte)]++] = *it; deba@464: ++it; deba@464: } deba@464: } deba@464: deba@464: deba@464: template deba@464: void counterSignedSort(Iterator first, Iterator last, Functor functor) { deba@464: if (first == last) return; deba@464: typedef typename std::iterator_traits::value_type Key; deba@464: typedef std::allocator Allocator; deba@464: Allocator allocator; deba@464: deba@464: int length = std::distance(first, last); deba@464: Key* buffer = allocator.allocate(2 * length); deba@464: try { deba@464: bool dir = true; deba@464: std::copy(first, last, buffer); deba@464: for (int i = 0; i < int(sizeof(Value)) - 1; ++i) { deba@464: if (dir) { deba@464: counterIntroSort(buffer, buffer + length, buffer + length, deba@464: i, functor); deba@464: } else { deba@464: counterIntroSort(buffer + length, buffer + 2 * length, buffer, deba@464: i, functor); deba@464: } deba@464: dir = !dir; deba@464: } deba@464: if (dir) { deba@464: signedCounterIntroSort(buffer, buffer + length, buffer + length, deba@464: sizeof(Value) - 1, functor); deba@464: std::copy(buffer + length, buffer + 2 * length, first); deba@464: } else { deba@464: signedCounterIntroSort(buffer + length, buffer + 2 * length, buffer, deba@464: sizeof(Value) - 1, functor); deba@464: std::copy(buffer, buffer + length, first); deba@464: } deba@464: } catch (...) { deba@464: allocator.deallocate(buffer, 2 * length); deba@464: throw; deba@464: } deba@464: allocator.deallocate(buffer, 2 * length); deba@464: } deba@464: deba@464: template deba@464: void counterUnsignedSort(Iterator first, Iterator last, Functor functor) { deba@464: if (first == last) return; deba@464: typedef typename std::iterator_traits::value_type Key; deba@464: typedef std::allocator Allocator; deba@464: Allocator allocator; deba@464: deba@464: int length = std::distance(first, last); deba@464: Key *buffer = allocator.allocate(2 * length); deba@464: try { deba@464: bool dir = true; deba@464: std::copy(first, last, buffer); deba@464: for (int i = 0; i < int(sizeof(Value)); ++i) { deba@464: if (dir) { deba@464: counterIntroSort(buffer, buffer + length, deba@464: buffer + length, i, functor); deba@464: } else { deba@464: counterIntroSort(buffer + length, buffer + 2 * length, deba@464: buffer, i, functor); deba@464: } deba@464: dir = !dir; deba@464: } deba@464: if (dir) { deba@464: std::copy(buffer, buffer + length, first); deba@464: } else { deba@464: std::copy(buffer + length, buffer + 2 * length, first); deba@464: } deba@464: } catch (...) { deba@464: allocator.deallocate(buffer, 2 * length); deba@464: throw; deba@464: } deba@464: allocator.deallocate(buffer, 2 * length); deba@464: } deba@464: deba@464: deba@464: deba@464: template ::is_signed > deba@464: struct CounterSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { deba@464: counterSignedSort(first, last, functor); deba@464: } deba@464: }; deba@464: deba@464: template deba@464: struct CounterSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { deba@464: counterUnsignedSort(first, last, functor); deba@464: } deba@464: }; deba@464: deba@464: } deba@464: deba@464: /// \ingroup auxalg deba@464: /// deba@464: /// \brief Sorts stable the STL compatible range into ascending order. deba@464: /// deba@464: /// The \c counterSort sorts the STL compatible range into ascending deba@464: /// order. The counter sort algorithm can sort the items which deba@464: /// mapped to an integer with an adaptable unary function \c functor deba@464: /// and the order will be ascending by these mapped values. As deba@464: /// function specialization it is possible to use a normal function deba@464: /// instead of the functor object or if the functor is not given it deba@464: /// will use an identity function instead. deba@464: /// deba@464: /// The implemented counter sort use a radix forward sort on the deba@464: /// bytes of the integer number. The algorithm sorts the items deba@464: /// byte-by-byte, first it counts how many times occurs a byte value deba@464: /// in the containerm, and with the occurence number the container deba@464: /// can be copied to an other in asceding order in \c O(n) time. deba@464: /// Let be \c c the maximal capacity of the integer type and \c n deba@464: /// the number of the items in the container, the time complexity of deba@464: /// the algorithm is \f$ O(\log(c)n) \f$ and the additional space deba@464: /// complexity is \f$ O(n) \f$. deba@464: /// deba@464: /// The sorting algorithm is stable, i.e. the order of two equal deba@464: /// element remains the same. deba@464: /// deba@464: /// \param first The begin of the given range. deba@464: /// \param last The end of the given range. deba@464: /// \param functor An adaptible unary function or a normal function deba@464: /// which maps the items to any integer type which can be either deba@464: /// signed or unsigned. deba@464: template deba@464: void counterSort(Iterator first, Iterator last, Functor functor) { deba@464: using namespace _radix_sort_bits; deba@464: typedef typename Functor::result_type Value; deba@464: CounterSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void counterSort(Iterator first, Iterator last, Value (*functor)(Key)) { deba@464: using namespace _radix_sort_bits; deba@464: CounterSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void counterSort(Iterator first, Iterator last, Value& (*functor)(Key)) { deba@464: using namespace _radix_sort_bits; deba@464: CounterSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void counterSort(Iterator first, Iterator last, Value (*functor)(Key&)) { deba@464: using namespace _radix_sort_bits; deba@464: CounterSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void counterSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { deba@464: using namespace _radix_sort_bits; deba@464: CounterSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@464: void counterSort(Iterator first, Iterator last) { deba@464: using namespace _radix_sort_bits; deba@464: typedef typename std::iterator_traits::value_type Value; deba@464: CounterSortSelector::sort(first, last, Identity()); deba@464: } deba@464: deba@464: } deba@464: deba@464: #endif