Algorithm Implementation/Sorting/Patience sort
From Wikibooks, open books for an open world
< Algorithm Implementation | Sorting(Redirected from Algorithm implementation/Sorting/Patience sort)
C++ [edit]
Given a generic STL-style input iterator to a sequence, we shall call its elements' value type card_type, and assume that we have some container of cards PileType (an example could be vector<card_type>), and a container of piles TableType (which, again, could be just a vector of piles).
In this case, one can define the patience sorting as follows:
/**
* Patience sort algorithm as per Aldous and Diaconis,
* using binary search to select the leftmost heap for a new card.
* Compares cards using operator<
*
* TableType requirements
* -# whatever lower_bound needs
* -# begin(), end(): ForwardIterator of piles
*
* PileType requirements
* -# default constructible
* -# constructible from a single card const reference
* typedef typename PileType::value_type card_type;
* -# push_back(const card_type&)
* -# assignable, lightweight on a singleton pile
* -# whatever lower_bound needs
* -# back() implemented or an appropriate pile_less specialization
*/
template < typename PileType, typename TableType, typename InputIterator >
void patience_sort(TableType& table, InputIterator first, InputIterator last) {
typedef PileType pile_type;
typedef typename PileType::value_type card_type;
typedef TableType table_type;
typedef typename table_type::iterator iterator;
while (first != last) {
pile_type new_pile(*first); // read *first only once! (input iterator)
// find the leftmost heap with the top card greater
// than *first , to push *first on it
iterator pile_p = std::lower_bound(
table.begin(), table.end(), new_pile,
pile_less<pile_type>() );
if (pile_p != table.end()) {
pile_p->push_back(new_pile.back());
}
// ...or allocate a new heap on the right with *first
else {
table.push_back(new_pile);
}
first++;
}
}
For the std::lower_bound algorithm to work, a tiny utility comparator functor is needed:
/** * Comparator for two piles according to their top card values. * Compares cards using operator< */ template < typename pile_type > struct pile_less : std::binary_function<pile_type, pile_type, bool> { bool operator()(const pile_type& x, const pile_type& y) const { return x.back() < y.back(); } }; /** * When the algorithm is run with the sole purpose to discover the length of the longest increasing subsequence, * one doesn't need to store any cards in the piles beneath the topmost one, since only the topmost card's value * is ever used by the algorithm above, and the length of the longest increasing subsequence is equal to the number of piles on the * table, * i.e., ''table.size()'': */ /** * A class representing a pile that is sticky, i.e., once a card * is put onto its top, it's glued forever. This way, only * the top card is actually remembered (O(1) memory per heap). * Used by longest_increasing_subsequence(). * * Unfortunately, such heap is impossible to use in more advanced * algorithms, such as the Bespamyatnykh and Segal one, for the * actual longest increasing subsequence recovery. */ template< typename Card > struct StickyPile { // cards stick together when put here :-) typedef Card value_type; typedef const value_type& const_reference; StickyPile(const Card& _card) : card(_card) {} void push_back(const Card& _card) { card = _card; } const_reference back() const { return card; } private: Card card; }; /** Find the length of the longest increasing subsequence * given by the given iterator range, using patience_sort(). * Compares cards using operator< */ template< typename InputIterator > size_t longest_increasing_subsequence( InputIterator first, InputIterator last) { typedef typename std::iterator_traits<InputIterator>::value_type Card; typedef StickyPile<Card> pile_type; typedef std::vector< pile_type > table_type; table_type table; patience_sort<pile_type>(table, first, last); return table.size(); } /* The above GPL code is based on excerpts from [[http://www.tarunz.org/~vassilii/pub/c++/patience_sort.hpp patience_sort.hpp]], which also provides versions of the same functionality parametrized by any given comparator (rather than using operator< ). */
Java [edit]
import java.util.*; public class PatienceSort { public static <E extends Comparable<? super E>> void sort (E[] n) { List<Pile<E>> piles = new ArrayList<Pile<E>>(); // sort into piles for (E x : n) { Pile<E> newPile = new Pile<E>(); newPile.push(x); int i = Collections.binarySearch(piles, newPile); if (i < 0) i = ~i; if (i != piles.size()) piles.get(i).push(x); else piles.add(newPile); } System.out.println("longest increasing subsequence has length = " + piles.size()); // priority queue allows us to retrieve least pile efficiently PriorityQueue<Pile<E>> heap = new PriorityQueue<Pile<E>>(piles); for (int c = 0; c < n.length; c++) { Pile<E> smallPile = heap.poll(); n[c] = smallPile.pop(); if (!smallPile.isEmpty()) heap.offer(smallPile); } assert(heap.isEmpty()); } private static class Pile<E extends Comparable<? super E>> extends Stack<E> implements Comparable<Pile<E>> { public int compareTo(Pile<E> y) { return peek().compareTo(y.peek()); } } }
Python [edit]
import bisect, heapq def sort(seq): piles = [] for x in seq: new_pile = [x] i = bisect.bisect_left(piles, new_pile) if i != len(piles): piles[i].insert(0, x) else: piles.append(new_pile) print "longest increasing subsequence has length =", len(piles) # priority queue allows us to retrieve least pile efficiently for i in xrange(len(seq)): small_pile = piles[0] seq[i] = small_pile.pop(0) if small_pile: heapq.heapreplace(piles, small_pile) else: heapq.heappop(piles) assert not piles foo = [4, 65, 2, 4, -31, 0, 99, 1, 83, 782, 1] sort(foo) print foo