|
| 1 | +#include <algorithm> |
| 2 | +#include <cassert> |
| 3 | +#include <iostream> |
| 4 | +#include <iterator> |
| 5 | +#include <stack> |
| 6 | +#include <vector> |
| 7 | +// reference: |
| 8 | +// https://rosettacode.org/wiki/Sorting_algorithms/Patience_sort#C.2B.2B |
| 9 | +template <class E> |
| 10 | +struct pile_less { |
| 11 | + bool operator()(const std::stack<E> &pile1, |
| 12 | + const std::stack<E> &pile2) const { |
| 13 | + return pile1.top() < pile2.top(); |
| 14 | + } |
| 15 | +}; |
| 16 | + |
| 17 | +template <class E> |
| 18 | +struct pile_greater { |
| 19 | + bool operator()(const std::stack<E> &pile1, |
| 20 | + const std::stack<E> &pile2) const { |
| 21 | + return pile1.top() > pile2.top(); |
| 22 | + } |
| 23 | +}; |
| 24 | + |
| 25 | +template <class Iterator> |
| 26 | +void patienceSort(Iterator first, Iterator last) { |
| 27 | + typedef typename std::iterator_traits<Iterator>::value_type E; |
| 28 | + typedef std::stack<E> Pile; |
| 29 | + |
| 30 | + std::vector<Pile> piles; |
| 31 | + // sort into piles |
| 32 | + for (Iterator it = first; it != last; ++it) { |
| 33 | + E &x = *it; |
| 34 | + Pile newPile; |
| 35 | + newPile.push(x); |
| 36 | + typename std::vector<Pile>::iterator i = std::lower_bound( |
| 37 | + piles.begin(), piles.end(), newPile, pile_less<E>()); |
| 38 | + if (i != piles.end()) |
| 39 | + i->push(x); |
| 40 | + else |
| 41 | + piles.push_back(newPile); |
| 42 | + } |
| 43 | + |
| 44 | + // priority queue allows us to merge piles efficiently |
| 45 | + // we use greater-than comparator for min-heap |
| 46 | + std::make_heap(piles.begin(), piles.end(), pile_greater<E>()); |
| 47 | + for (Iterator it = first; it != last; ++it) { |
| 48 | + // moves the smallest to the end |
| 49 | + std::pop_heap(piles.begin(), piles.end(), pile_greater<E>()); |
| 50 | + Pile &smallPile = piles.back(); |
| 51 | + *it = smallPile.top(); |
| 52 | + smallPile.pop(); |
| 53 | + if (smallPile.empty()) |
| 54 | + piles.pop_back(); |
| 55 | + else |
| 56 | + // Inserts the element at the position end-1 into the min heap |
| 57 | + std::push_heap(piles.begin(), piles.end(), pile_greater<E>()); |
| 58 | + } |
| 59 | + assert(piles.empty()); |
| 60 | +} |
0 commit comments