I improved the chmike algorithm. This feature is consistent with it for all 11! permutations (0..10) passed as a reordering vector. Also, it does not change the reordering vector.
template< class T > void reorder(vector<T> &v, vector<size_t> const &order ) { for ( int s = 1, d; s < order.size(); ++ s ) { for ( d = order[s]; d < s; d = order[d] ) ; if ( d == s ) while ( d = order[d], d != s ) swap( v[s], v[d] ); } }
Here's a version of the STL style that I put a little more effort into. This is about 47% faster (i.e., almost twice as fast (0.10)!), Because he makes all swaps as early as possible, and then returns. The reordering vector consists of several orbits, and each orbit is reordered upon reaching its first term. This is faster if the last few elements do not contain an orbit.
template< typename order_iterator, typename value_iterator > void reorder( order_iterator order_begin, order_iterator order_end, value_iterator v ) { typedef typename iterator_traits< value_iterator >::value_type value_t; typedef typename iterator_traits< order_iterator >::value_type index_t; typedef typename iterator_traits< order_iterator >::difference_type diff_t; diff_t remaining = order_end - 1 - order_begin; for ( index_t s = index_t(), d; remaining > 0; ++ s ) { for ( d = order_begin[s]; d > s; d = order_begin[d] ) ; if ( d == s ) { -- remaining; value_t temp = v[s]; while ( d = order_begin[d], d != s ) { swap( temp, v[d] ); -- remaining; } v[s] = temp; } } }
And finally, just to answer the question once and for all, an option that destroys the reordering vector. (It fills -1.) This is about 16% faster than the previous version. This one uses the ugly type, but handle it. It spans 11! ~ = 40 mil permutations of 11 characters in 4.25 seconds, not counting the overhead, on my 2.2 GHz laptop.
template< typename order_iterator, typename value_iterator > void reorder_destructive( order_iterator order_begin, order_iterator order_end, value_iterator v ) { typedef typename iterator_traits< value_iterator >::value_type value_t; typedef typename iterator_traits< order_iterator >::value_type index_t; typedef typename iterator_traits< order_iterator >::difference_type diff_t; diff_t remaining = order_end - 1 - order_begin; for ( index_t s = index_t(); remaining > 0; ++ s ) { index_t d = order_begin[s]; if ( d == (diff_t) -1 ) continue; -- remaining; value_t temp = v[s]; for ( index_t d2; d != s; d = d2 ) { swap( temp, v[d] ); swap( order_begin[d], d2 = (diff_t) -1 ); -- remaining; } v[s] = temp; } }
Potatoswatter Aug 12 '09 at 18:26 2009-08-12 18:26
source share