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