 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Lawrence Lim Guest
|
Posted: Sat Jun 28, 2003 11:07 pm Post subject: Random Shuffle for List |
|
|
Does anyone here know a random_shuffle implementation for std::list? The
standard random_shuffle does not work on bidirectional iterators.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jeff Greif Guest
|
Posted: Sun Jun 29, 2003 11:32 am Post subject: Re: Random Shuffle for List |
|
|
copy to vector, shuffle, copy back.
Jeff
"Lawrence Lim" <thadeus (AT) shaw (DOT) ca> wrote
| Quote: | Does anyone here know a random_shuffle implementation for std::list? The
standard random_shuffle does not work on bidirectional iterators.
|
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
nick@byu.edu Guest
|
Posted: Sun Jun 29, 2003 11:35 am Post subject: Re: Random Shuffle for List |
|
|
Lawrence Lim wrote:
| Quote: | Does anyone here know a random_shuffle implementation for std::list?
The standard random_shuffle does not work on bidirectional
iterators.
|
If your lists are small enough, you could use an adapter to provide
random access iterators for it. (But it will be slow)
Better yet, write your own random_shuffle for list<>.
How about:
list<>::iterator begin = l.begin();
list<>::iterator end = l.end();
list<>::iterator p = begin;
for (int i = l.size(); i > 0; --i) {
for (int r = random(e); r > 0; --r) {
if (++p == end)
p = begin;
}
swap<>(*begin, *p);
}
That still has to walk it a bunch, but not nearly as much as a
random-access to bidi. iterator adapter would. Surely someone else
can improve it?
Nick
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
nick@byu.edu Guest
|
Posted: Sun Jun 29, 2003 11:37 am Post subject: Re: Random Shuffle for List |
|
|
In my previous post, I take back that my implementation is any faster
than an adapter. They're both O(n^2) afaict.
Nick
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Francis Glassborow Guest
|
Posted: Sun Jun 29, 2003 12:33 pm Post subject: Re: Random Shuffle for List |
|
|
In message <Gh7La.309503$ro6.7548585 (AT) news2 (DOT) calgary.shaw.ca>, Lawrence
Lim <thadeus (AT) shaw (DOT) ca> writes
| Quote: | Does anyone here know a random_shuffle implementation for std::list? The
standard random_shuffle does not work on bidirectional iterators.
|
I suspect that even if one was written it would be no more efficient
than creating a vector (possibly of pointers) from your list, calling
random_shuffle on that then using the result to build a list.
--
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow ACCU
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Andy Sawyer Guest
|
Posted: Sun Jun 29, 2003 2:03 pm Post subject: Re: Random Shuffle for List |
|
|
In article <Gh7La.309503$ro6.7548585 (AT) news2 (DOT) calgary.shaw.ca>,
on 28 Jun 2003 19:07:54 -0400,
Lawrence Lim <thadeus (AT) shaw (DOT) ca> wrote:
| Quote: | Does anyone here know a random_shuffle implementation for std::list?
The
standard random_shuffle does not work on bidirectional iterators.
|
You could try:
template<typename T>
void shuffle_list( std::list<T>& mylist )
{
std::vector<T> v( mylist.begin(), mylist.end() );
std::random_shuffle( v.begin(), v.end() );
mylist.assign( v.begin(), v.end() );
}
Or you might prefer:
template<typename BidirectionalIterator>
void random_shuffle_bidit( BidirectionalIterator begin,
BidirectionalIterator end )
{
typedef typename
std::iterator_traits<BidirectionalIterator>::value_type
value_type;
std::vector<value_type> v( begin, end );
std::random_shuffle( v.begin(), v.end() );
std::copy( v.begin(), v.end(), begin );
}
Regards,
Andy S
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there
first,
and is waiting for it." -- Terry Pratchett, Reaper Man
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Siemel Naran Guest
|
Posted: Sun Jun 29, 2003 10:20 pm Post subject: Re: Random Shuffle for List |
|
|
"Carl Barron" <cbarron3 (AT) ix (DOT) netcom.com> wrote
| Quote: | template <class T,class A
void random_shuffle_list(std::list
{
typedef std::list<T,A>::iterator iterator;
std::vector<iterator> index;
for(iterator it = data.begin(),it != data.end();++it)
index.push_back(it); // O(n)
std::random_shuffle(index.begin(),index.end());//O(n)
std:list<T,A> temp;
for(std::vector<iterator>::iterator it =
index.begin();it!=index.end();++it)
{
temp.splice(temp.end(),data,*it);
} // O(n)
data.swap(temp); // O(1);
}
|
Good. Can you accomplish the same without using temporary storage space
temp? Storage space index is OK.
I'm think of this, but too bad the standard does not have a function
list::swap(iterator,iterator)
| Quote: | for(std::vector<iterator>::iterator it =
index.begin();it!=index.end();++it)
{
temp.splice(temp.end(),data,*it);
} // O(n)
|
==>
assert(index.size()==data.size());
typedef std::vector<iterator>::iterator IndexIter;
IndexIter i = index.begin();
const IndexIter iend = index.end();
typedef std::list<T,A>::iterator Iter;
Iter d = data.begin();
const Iter dend = data.end();
for( ;i!=iend; ++i,++d)
{
data.swap(i,d);
} // O(n)
Can anyone help?
--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Siemel Naran Guest
|
Posted: Sun Jun 29, 2003 10:20 pm Post subject: Re: Random Shuffle for List |
|
|
"Andy Sawyer" <andys (AT) despammed (DOT) com> wrote in message
| Quote: | template<typename T
void shuffle_list( std::list
{
std::vector<T> v( mylist.begin(), mylist.end() );
std::random_shuffle( v.begin(), v.end() );
mylist.assign( v.begin(), v.end() );
}
|
Good if T is small, but what if T is big? The vector of iterators idea
by
Carl Barron seems better for the general case, though it seems to use
too
much storage space.
--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Carl Barron Guest
|
Posted: Mon Jun 30, 2003 9:40 am Post subject: Re: Random Shuffle for List |
|
|
Siemel Naran <SiemelNaran (AT) KILL (DOT) att.net> wrote:
| Quote: | "Andy Sawyer" <andys (AT) despammed (DOT) com> wrote in message
template<typename T
void shuffle_list( std::list
{
std::vector<T> v( mylist.begin(), mylist.end() );
std::random_shuffle( v.begin(), v.end() );
mylist.assign( v.begin(), v.end() );
}
Good if T is small, but what if T is big? The vector of iterators idea
by
Carl Barron seems better for the general case, though it seems to use
too
much storage space.
--
+++++++++++
Siemel Naran
Where is the too much space in my algorithm? Note that in my algorithm |
data.size()+temp.size() is a constant. Thst and efficiency was why I
chose list::splice() to do the rearranging,
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
nick@byu.edu Guest
|
Posted: Mon Jun 30, 2003 4:01 pm Post subject: Re: Random Shuffle for List |
|
|
Siemel Naran wrote:
| Quote: | "Andy Sawyer" <andys (AT) despammed (DOT) com> wrote in message
template<typename T
void shuffle_list( std::list
{
std::vector<T> v( mylist.begin(), mylist.end() );
std::random_shuffle( v.begin(), v.end() );
mylist.assign( v.begin(), v.end() );
}
Good if T is small, but what if T is big? The vector of iterators
idea by
Carl Barron seems better for the general case, though it seems to
use too
much storage space.
|
You can save storage space by using a sliding window of only i
iterators. You then have to do something like n/i passes in
alternating directions. Overlap may make this go back to O(n^2)
however--I'm not sure--anyone know?
Nick
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dave Harris Guest
|
Posted: Mon Jun 30, 2003 6:29 pm Post subject: Re: Random Shuffle for List |
|
|
[email]thadeus (AT) shaw (DOT) ca[/email] (Lawrence Lim) wrote (abridged):
| Quote: | Does anyone here know a random_shuffle implementation for
std::list? The standard random_shuffle does not work on
bidirectional iterators.
|
The O(N) copy-to-vector approach suggested by other people is
probably best.
I think there may be some O(N log N) algorithms. One idea is to
attach a random number to each item and sort using that item as
key. It still needs an extra N words of storage, but this is
non-contiguous and preallocated as part of the items, which may
be an advantage in some situations.
I think there is an O(N log N) algorithm which doesn't need extra
memory at all. Along the lines of a merge sort using a comparison
function which returns random results:
template <typename List, typename Compare>
void merge_sort( List &data, Compare comp ) {
// Left as an exercise. data.sort( comp ) might do.
}
template <typename T>
class random_compare {
bool operator()( const T &a, const T &b ) {
return (rand() & 0x1000) != 0; // Or whatever.
}
};
template <typename T, typename A>
void random_shuffle_list(std::list<T,A> &data) {
merge_sort( data, random_compare<T>() );
}
However, I haven't proven that this gives all permutations with
equal probability. Nor even tested it. It's something to
investigate if the copy-to-vector approach is too expensive in
memory.
-- Dave Harris, Nottingham, UK
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dhruv Guest
|
Posted: Mon Jun 30, 2003 6:34 pm Post subject: Re: Random Shuffle for List |
|
|
On Sat, 28 Jun 2003 19:07:54 -0400, Lawrence Lim wrote:
| Quote: | Does anyone here know a random_shuffle implementation for std::list? The
standard random_shuffle does not work on bidirectional iterators.
|
This algorithm is not really RANDOM, but it acomplishes the task to some
extent.
template <class I>
void list_random_shuffle (I _first, I _last)
{
I _front = _first;
I _back = --_last;
while (_front != _back)
{
if (rand()
{
std::swap (*_front, *_back);
++_front;
}
else if (rand()
{
std::swap (*_back, *_first);
--_back;
}
else
{
std::swap (*_back, *_last);
--_back;
}
}
}
-Dhruv.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
nick@byu.edu Guest
|
Posted: Tue Jul 01, 2003 7:50 am Post subject: Re: Random Shuffle for List |
|
|
Dhruv wrote:
| Quote: | On Sat, 28 Jun 2003 19:07:54 -0400, Lawrence Lim wrote:
Does anyone here know a random_shuffle implementation for
std::list? The standard random_shuffle does not work on
bidirectional iterators.
This algorithm is not really RANDOM, but it acomplishes the task to
some extent.
template
void list_random_shuffle (I _first, I _last)
{
I _front = _first;
I _back = --_last;
while (_front != _back)
{
if (rand()
{
std::swap (*_front, *_back);
++_front;
}
else if (rand()
{
std::swap (*_back, *_first);
--_back;
}
else
{
std::swap (*_back, *_last);
--_back;
}
}
}
|
I thought of something just like the above while considering a sliding
window approach. Closer analysis reveals that the above yields
extremely poor distribution--it doesn't even come close at all to
making all permutations reachable.
While it does 'mix it up' a bit, it'd probably be a misnomer to call
it a random shuffle (like you said). I guess my comment then, is
that 'to some extent' is actually "not very much at all".
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Siemel Naran Guest
|
Posted: Wed Jul 02, 2003 1:04 am Post subject: Re: Random Shuffle for List |
|
|
"Carl Barron" <cbarron3 (AT) ix (DOT) netcom.com> wrote
| Quote: | Siemel Naran <SiemelNaran (AT) KILL (DOT) att.net> wrote:
Good if T is small, but what if T is big? The vector of iterators idea
by
Carl Barron seems better for the general case, though it seems to use
too
much storage space.
Where is the too much space in my algorithm? Note that in my algorithm
data.size()+temp.size() is a constant. Thst and efficiency was why I
chose list::splice() to do the rearranging,
|
Yes, you're probably right. In your algorithm, please explain what is going
on with the following lines
temp.splice(temp.end(),data,*it);
template <class T,class A>
void random_shuffle_list(std::list<T,A> &data)
{
typedef std::list<T,A>::iterator iterator;
std::vector<iterator> index;
for(iterator it = data.begin(),it != data.end();++it)
index.push_back(it); // O(n)
std::random_shuffle(index.begin(),index.end());//O(n)
std:list<T,A> temp;
for(std::vector<iterator>::iterator it =
index.begin();it!=index.end();++it)
{
temp.splice(temp.end(),data,*it);
} // O(n)
data.swap(temp); // O(1);
}
--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Mirolyub Hristov Guest
|
Posted: Wed Jul 02, 2003 2:37 am Post subject: Re: Random Shuffle for List |
|
|
Hello,
"Siemel Naran" <SiemelNaran (AT) KILL (DOT) att.net> wrote
| Quote: | Good. Can you accomplish the same without using temporary storage space
temp? Storage space index is OK.
|
You could remove the temp list by using boost's indirect_iterator_generator:
#include <algorithm>
#include <boost/iterator_adaptors.hpp>
template<typename ForwardIter>
void forward_random_shuffle(ForwardIter first, ForwardIter last)
{
std::vector<ForwardIter> iterators;
for(ForwardIter current = first; current != last; ++current)
iterators.push_back(current);
typedef typename boost::indirect_iterator_generator<
std::vector::type indirect_iterator;
std::random_shuffle(
indirect_iterator(iterators.begin()),
indirect_iterator(iterators.end()));
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|