alpar@465: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@464: * alpar@465: * This file is a part of LEMON, a generic C++ optimization library. deba@464: * alpar@467: * Copyright (C) 2003-2009 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) { alpar@465: return val; deba@464: } deba@464: }; deba@464: deba@464: deba@464: template alpar@465: Iterator radixSortPartition(Iterator first, Iterator last, alpar@465: Functor functor, Value mask) { deba@464: while (first != last && !(functor(*first) & mask)) { alpar@465: ++first; deba@464: } deba@464: if (first == last) { alpar@465: return first; deba@464: } deba@464: --last; deba@464: while (first != last && (functor(*last) & mask)) { alpar@465: --last; deba@464: } deba@464: if (first == last) { alpar@465: return first; deba@464: } deba@464: std::iter_swap(first, last); deba@464: ++first; deba@464: if (!(first < last)) { alpar@465: return first; deba@464: } deba@464: while (true) { alpar@465: while (!(functor(*first) & mask)) { alpar@465: ++first; alpar@465: } alpar@465: --last; alpar@465: while (functor(*last) & mask) { alpar@465: --last; alpar@465: } alpar@465: if (!(first < last)) { alpar@465: return first; alpar@465: } alpar@465: std::iter_swap(first, last); alpar@465: ++first; deba@464: } deba@464: } deba@464: deba@464: template alpar@465: Iterator radixSortSignPartition(Iterator first, Iterator last, alpar@465: Functor functor) { deba@464: while (first != last && functor(*first) < 0) { alpar@465: ++first; deba@464: } deba@464: if (first == last) { alpar@465: return first; deba@464: } deba@464: --last; deba@464: while (first != last && functor(*last) >= 0) { alpar@465: --last; deba@464: } deba@464: if (first == last) { alpar@465: return first; deba@464: } deba@464: std::iter_swap(first, last); deba@464: ++first; deba@464: if (!(first < last)) { alpar@465: return first; deba@464: } deba@464: while (true) { alpar@465: while (functor(*first) < 0) { alpar@465: ++first; alpar@465: } alpar@465: --last; alpar@465: while (functor(*last) >= 0) { alpar@465: --last; alpar@465: } alpar@465: if (!(first < last)) { alpar@465: return first; alpar@465: } alpar@465: std::iter_swap(first, last); alpar@465: ++first; deba@464: } deba@464: } deba@464: deba@464: template alpar@465: void radixIntroSort(Iterator first, Iterator last, alpar@465: Functor functor, Value mask) { deba@464: while (mask != 0 && last - first > 1) { alpar@465: Iterator cut = radixSortPartition(first, last, functor, mask); alpar@465: mask >>= 1; alpar@465: radixIntroSort(first, cut, functor, mask); alpar@465: 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) { alpar@465: while ((mask & functor(*it)) != mask) { alpar@465: ++max_digit; alpar@465: mask <<= 1; alpar@465: } 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) { alpar@465: while ((mask | functor(*it)) != mask) { alpar@465: ++max_digit; alpar@465: mask <<= 1; mask |= 1; alpar@465: } 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) { alpar@465: while ((mask | functor(*it)) != mask) { alpar@465: ++max_digit; alpar@465: mask <<= 1; mask |= 1; alpar@465: } deba@464: } deba@464: radixIntroSort(first, last, functor, 1 << max_digit); deba@464: } deba@464: deba@464: alpar@465: template ::is_signed > deba@464: struct RadixSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { alpar@465: 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) { alpar@465: 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: /// alpar@465: /// The \c radixSort sorts an STL compatible range into ascending alpar@465: /// order. The radix sort algorithm can sort items which are mapped alpar@465: /// to integers with an adaptable unary function \c functor and the alpar@465: /// order will be ascending according to these mapped values. deba@464: /// alpar@465: /// It is also possible to use a normal function instead alpar@465: /// of the functor object. If the functor is not given it will use alpar@465: /// the identity function instead. alpar@465: /// alpar@465: /// This is a special quick sort algorithm where the pivot kpeter@606: /// values to split the items are choosen to be 2k kpeter@606: /// for each \c k. kpeter@606: /// Therefore, the time complexity of the algorithm is O(log(c)*n) and kpeter@606: /// it uses O(log(c)) additional space, where \c c is the maximal value kpeter@606: /// and \c n is the number of the items in the container. 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. alpar@465: /// deba@466: /// \sa stableRadixSort() 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@466: void stableRadixIntroSort(Key *first, Key *last, Key *target, deba@466: int byte, Functor functor) { alpar@465: const int size = alpar@465: unsigned(std::numeric_limits::max()) + 1; deba@464: std::vector counter(size); deba@464: for (int i = 0; i < size; ++i) { alpar@465: counter[i] = 0; deba@464: } deba@464: Key *it = first; deba@464: while (first != last) { alpar@465: ++counter[valueByte(functor(*first), byte)]; alpar@465: ++first; deba@464: } deba@464: int prev, num = 0; deba@464: for (int i = 0; i < size; ++i) { alpar@465: prev = num; alpar@465: num += counter[i]; alpar@465: counter[i] = prev; deba@464: } deba@464: while (it != last) { alpar@465: target[counter[valueByte(functor(*it), byte)]++] = *it; alpar@465: ++it; deba@464: } deba@464: } deba@464: deba@464: template deba@466: void signedStableRadixIntroSort(Key *first, Key *last, Key *target, deba@466: int byte, Functor functor) { alpar@465: const int size = alpar@465: unsigned(std::numeric_limits::max()) + 1; deba@464: std::vector counter(size); deba@464: for (int i = 0; i < size; ++i) { alpar@465: counter[i] = 0; deba@464: } deba@464: Key *it = first; deba@464: while (first != last) { alpar@465: counter[valueByte(functor(*first), byte)]++; alpar@465: ++first; deba@464: } deba@464: int prev, num = 0; deba@464: for (int i = size / 2; i < size; ++i) { alpar@465: prev = num; alpar@465: num += counter[i]; alpar@465: counter[i] = prev; deba@464: } deba@464: for (int i = 0; i < size / 2; ++i) { alpar@465: prev = num; alpar@465: num += counter[i]; alpar@465: counter[i] = prev; deba@464: } deba@464: while (it != last) { alpar@465: target[counter[valueByte(functor(*it), byte)]++] = *it; alpar@465: ++it; deba@464: } deba@464: } deba@464: alpar@465: deba@464: template deba@466: void stableRadixSignedSort(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 { alpar@465: bool dir = true; alpar@465: std::copy(first, last, buffer); alpar@465: for (int i = 0; i < int(sizeof(Value)) - 1; ++i) { alpar@465: if (dir) { deba@466: stableRadixIntroSort(buffer, buffer + length, buffer + length, deba@466: i, functor); alpar@465: } else { deba@466: stableRadixIntroSort(buffer + length, buffer + 2 * length, buffer, deba@466: i, functor); alpar@465: } alpar@465: dir = !dir; alpar@465: } alpar@465: if (dir) { deba@466: signedStableRadixIntroSort(buffer, buffer + length, buffer + length, deba@466: sizeof(Value) - 1, functor); alpar@465: std::copy(buffer + length, buffer + 2 * length, first); alpar@465: } else { alpar@467: signedStableRadixIntroSort(buffer + length, buffer + 2 * length, deba@466: buffer, sizeof(Value) - 1, functor); alpar@465: std::copy(buffer, buffer + length, first); alpar@465: } deba@464: } catch (...) { alpar@465: allocator.deallocate(buffer, 2 * length); alpar@465: throw; deba@464: } deba@464: allocator.deallocate(buffer, 2 * length); deba@464: } deba@464: deba@464: template alpar@467: void stableRadixUnsignedSort(Iterator first, Iterator last, deba@466: 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 { alpar@465: bool dir = true; alpar@465: std::copy(first, last, buffer); alpar@465: for (int i = 0; i < int(sizeof(Value)); ++i) { alpar@465: if (dir) { deba@466: stableRadixIntroSort(buffer, buffer + length, deba@466: buffer + length, i, functor); alpar@465: } else { deba@466: stableRadixIntroSort(buffer + length, buffer + 2 * length, deba@466: buffer, i, functor); alpar@465: } alpar@465: dir = !dir; alpar@465: } alpar@465: if (dir) { alpar@465: std::copy(buffer, buffer + length, first); alpar@465: } else { alpar@465: std::copy(buffer + length, buffer + 2 * length, first); alpar@465: } deba@464: } catch (...) { alpar@465: allocator.deallocate(buffer, 2 * length); alpar@465: throw; deba@464: } deba@464: allocator.deallocate(buffer, 2 * length); deba@464: } deba@464: deba@464: deba@464: alpar@465: template ::is_signed > deba@466: struct StableRadixSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { deba@466: stableRadixSignedSort(first, last, functor); deba@464: } deba@464: }; deba@464: deba@464: template deba@466: struct StableRadixSortSelector { deba@464: template deba@464: static void sort(Iterator first, Iterator last, Functor functor) { deba@466: stableRadixUnsignedSort(first, last, functor); deba@464: } deba@464: }; deba@464: deba@464: } deba@464: deba@464: /// \ingroup auxalg deba@464: /// alpar@465: /// \brief Sorts the STL compatible range into ascending order in a stable alpar@465: /// way. deba@464: /// alpar@465: /// This function sorts an STL compatible range into ascending alpar@465: /// order according to an integer mapping in the same as radixSort() does. deba@464: /// alpar@465: /// This sorting algorithm is stable, i.e. the order of two equal deba@466: /// elements remains the same after the sorting. alpar@465: /// alpar@465: /// This sort algorithm use a radix forward sort on the deba@464: /// bytes of the integer number. The algorithm sorts the items alpar@465: /// byte-by-byte. First, it counts how many times a byte value occurs alpar@465: /// in the container, then it copies the corresponding items to kpeter@606: /// another container in asceding order in O(n) time. deba@464: /// kpeter@606: /// The time complexity of the algorithm is O(log(c)*n) and kpeter@606: /// it uses O(n) additional space, where \c c is the alpar@465: /// maximal value and \c n is the number of the items in the alpar@465: /// container. deba@464: /// alpar@465: 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. alpar@465: /// \sa radixSort() deba@464: template deba@466: void stableRadixSort(Iterator first, Iterator last, Functor functor) { deba@464: using namespace _radix_sort_bits; deba@464: typedef typename Functor::result_type Value; deba@466: StableRadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@466: void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key)) { deba@464: using namespace _radix_sort_bits; deba@466: StableRadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@466: void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { deba@464: using namespace _radix_sort_bits; deba@466: StableRadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@466: void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { deba@464: using namespace _radix_sort_bits; deba@466: StableRadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@466: void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { deba@464: using namespace _radix_sort_bits; deba@466: StableRadixSortSelector::sort(first, last, functor); deba@464: } deba@464: deba@464: template deba@466: void stableRadixSort(Iterator first, Iterator last) { deba@464: using namespace _radix_sort_bits; deba@464: typedef typename std::iterator_traits::value_type Value; deba@466: StableRadixSortSelector::sort(first, last, Identity()); deba@464: } deba@464: deba@464: } deba@464: deba@464: #endif