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