|
Boost : |
From: Ross MacGregor (ross__macgregor_at_[hidden])
Date: 2003-10-12 15:58:56
The average application does not utilize randomization but some
diciplines use it extensively and are very interested in optimizing
these operations, like games and simulation programming for instance.
The partial_random_shuffle() algorithm would be useful when you have a
random access container filled with a large number of complex items and
you wish to select a random subset of elements from it.
Now you can do this in one of two ways utilizing
partial_random_shuffle() or the less efficient random_shuffle().
A) Shuffle the container
size_t elements_wanted = 25;
// Partially shuffle container
partial_random_shuffle(
thingies.begin(),
thingies.begin() + elements_wanted,
thingies.end());
// -OR- Shuffle entire container
//random_shuffle(
// thingies.begin(),
// thingies.end());
for_each(
thingies.begin(),
thingies.begin() + elements_wanted,
process_thingy);
B) Create a list of random indices or pointers
size_t elements_wanted = 25;
vector<size_t> indices;
for(size_t i = 0; i < thingies.size(); i++)
indices.push_back(i);
// Partially shuffle container
partial_random_shuffle(
indices.begin(),
indices.begin() + elements_wanted,
indices.end());
// -OR- Shuffle entire container
//random_shuffle(
// indices.begin(),
// indices.end());
for_each(
indices.begin(),
indices.begin() + elements_wanted,
process_indexed_thingy);
As I was saying it really is just an optimization because the standard
random_shuffle may be used in its place, but why not have a standard
implementation rather than having people reinvent the wheel for this
basic algorithm?
Paul, you are right. I should change the parameter names to (begin,
shuffle_end, end). This matches the specification for partial sort and
works the same way. The begin-end parameters indicate the range of
elements for the selection process and the begin-shuffle_end parameters
indicate the subset of elements to be randomized.
----------------REVISED CODE------------------
#define BOOST_PARTIAL_RANDOM_SHUFFLE_HPP_INCLUDED
#include <cstdlib>
namespace boost {
// This is a variation of the random_shuffle algorithm
// that allows you to partially shuffle an STL container.
// Elements from the subrange ("begin" to "shuffle_end") will
// be swapped with random elements from the entire range
// ("begin" to "end").
//
// Usage:
// // We have 1000 things to index
// vector<int> indices;
// for(int i=0; i<1000; i++) indices.push_back(i);
// // select 100 random indices
// partial_random_shuffle(
// indices.begin(),
// indices.begin() + 100,
// indices.end());
// indices.resize(100);
// Contributed by Ross MacGregor
template<class RandomAccessIter>
inline void
partial_random_shuffle(
RandomAccessIter begin,
RandomAccessIter shuffle_end,
RandomAccessIter end)
{
// our travelling iterator
RandomAccessIter & p = begin;
// find number of elements to the end
size_t range = std::distance(p, end);
// check for empty range
if( range != 0 )
{
// unable to swap last element
if( shuffle_end == end )
--shuffle_end;
// must have more than 1 element
// for swap operation to work
if( --range )
{
while( p != shuffle_end )
{
size_t n( rand() % range );
std::swap(*p,*(p + n));
--range;
++p;
}
}
}
}
template<class RandomAccessIter, class RandomNumberGenerator>
inline void
partial_random_shuffle(
RandomAccessIter begin,
RandomAccessIter shuffle_end,
RandomAccessIter end,
RandomNumberGenerator & rand_func)
{
// our travelling iterator
RandomAccessIter & p = begin;
// find number of elements to the end
size_t range = std::distance(p, end);
// check for empty range
if( range != 0 )
{
// unable to swap last element
if( shuffle_end == end )
--shuffle_end;
// must have more than 1 element
// for swap operation to work
if( --range )
{
while( p != shuffle_end )
{
size_t n( rand_func(range) );
std::swap(*p,*(p + n));
--range;
++p;
}
}
}
}
} // namespace boost
#endif // BOOST_PARTIAL_RANDOM_SHUFFLE_HPP_INCLUDED
Paul A. Bristow wrote:
> Looks sensible - but can you give example(s)/references where this would be
> useful in practice?
>
> Paul
>
> (Is p == shuffle_begin? Why are there not 4 parameters, thingys begin and end,
> and both shuffle_begin and shuffle_end?)
>
> Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK
> +44 1539 561830 Mobile +44 7714 33 02 04
> mailto:pbristow_at_[hidden]
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk