C++ has a function that shuffles the random_shuffle ()
sequence. Typically, it is used with two arguments.
However, there is a three-argument version.
How to use it with these three arguments?
The third argument is the “random number generator function”. In theory, this third argument is a functor. Just which one? The instructions say that this functor should return for n
elements a value in the range [0, n]
.
I tried to write something like a functor. Compiles but doesn’t work. Runtime error. Here is the code:
using namespace std;
template & lt; class T & gt;
class Func {
T num;
public:
Func (T & amp; a)
: num (a)
{}
T & amp; operator () (T & amp; x)
{x = (T) ((rand ())% (int) x);
return x;}
};
const int NUM = 12;
int main (void)
{
int sz = NUM;
vector & lt; int & gt; vec;
int i = 0;
for (i = 0; i & lt; NUM; ++ i)
vec.push_back (rand ());
int g = sz-1;
Func & lt; int & gt; f (g);
random_shuffle (vec.begin (), vec.end (), f);
// A runtime error occurs here.
return 0;
}
Showing what I did
{
# include & lt; iostream & gt;
# include & lt; vector & gt;
# include & lt; set & gt;
# include & lt; ctime & gt;
# include & lt; algorithm & gt;
# include & lt; functional & gt;
using namespace std;
// Functor (undercut). But a worker !!!
// This is a BAD Functor !!!
// It CANNOT be applied WITHOUT MANDATORY
// specifying the Argument.
template & lt; class T & gt;
class Func_1 {
T num;
public:
Func_1 (const T & amp; a)
: num (a)
{}
T operator () (const T & amp; x) {return rand ()% x;}
// IT WORKED!!!
};
// This Functor works ONLY for TYPE "int" !!!
class Func_2
{
public:
int operator () (const int & amp; x)
{
return rand ()% x;
}
};
// This is how a NORMAL Functor should look like !!!
template & lt; class T & gt;
class Func_3: unary_function & lt; T, T & gt;
{
public:
T operator () (T & amp; x)
{
return (T) rand ()% x;
}
};
// Constant for the NUMBER of Cycles.
const int NUM = 12;
int main (void)
{
cout & lt; & lt; "\ n \ n \ tBEGIN !!! \ n \ n" & lt; & lt; endl;
srand ((int) time (0));
vector & lt; int & gt; vec_base, vec_1, vec_2, vec_3;
set & lt; int & gt; s_temp;
while (s_temp.size () & lt; NUM + 1)
s_temp.insert (rand ()% 100);
set & lt; int & gt; :: iterator sb = s_temp.begin ();
while (sb! = s_temp.end ())
{
vec_base.push_back (* sb);
vec_1.push_back (* sb);
vec_2.push_back (* sb);
vec_3.push_back (* sb);
++ sb;
}
cout & lt; & lt; "\ n \ tSORT VEC_base: \ n" & lt; & lt; endl;
vector & lt; int & gt; :: iterator vb = vec_base.begin ();
int v = 0;
for (v = 0; v & lt; NUM; ++ v)
{
cout & lt; & lt; "\ t" & lt; & lt; v + 1 & lt; & lt; "." & lt; & lt; * vb & lt; & lt; endl;
++ vb;
}
cout & lt; & lt; "\ t \ tRANDOM_SHUFFLE (1,2): \ n \ n" & lt; & lt; endl;
cout & lt; & lt; "\ n \ n \ tNOT SORT VEC_base: \ n" & lt; & lt; endl;
random_shuffle (vec_base.begin (), vec_base.end ());
vb = vec_base.begin ();
v = 0;
for (v = 0; v & lt; NUM; ++ v)
{
cout & lt; & lt; "\ t" & lt; & lt; v + 1 & lt; & lt; "." & lt; & lt; * vb & lt; & lt; endl;
++ vb;
}
cout & lt; & lt; "\ n \ t \ tRANDOM_SHUFFLE (1,2,3): \ n" & lt; & lt; endl;
// This should only be done for a BAD Functor !!!
// This BAD Functor DEMANDS an Argument !!!
int g = NUM;
Func_1 & lt; int & gt; f (g);
// This will not work !!!
// NORMAL Functors MUST NOT be their own Arguments !!!
// Their Arguments are initialized by Algorithms !!!
// Func_2ft (g);
// Func_3 & lt; int & gt; fn (g);
// This is a BAD Functor. It cannot be applied without an argument !!!
random_shuffle (vec_1.begin (), vec_1.end (), Func_1 & lt; int & gt; (g));
// Normal Functors should be used WITHOUT Argument !!!
random_shuffle (vec_2.begin (), vec_2.end (), Func_2 ());
random_shuffle (vec_3.begin (), vec_3.end (), Func_3 & lt; int & gt; ());
vb = vec_1.begin ();
cout & lt; & lt; "\ n \ n \ tNOT SORT VEC_1: \ n" & lt; & lt; endl;
v = 0;
for (v = 0; v & lt; NUM; ++ v)
{
cout & lt; & lt; "\ t" & lt; & lt; v + 1 & lt; & lt; "." & lt; & lt; * vb & lt; & lt; endl;
++ vb;
}
vb = vec_2.begin ();
cout & lt; & lt; "\ n \ n \ tNOT SORT VEC_2: \ n" & lt; & lt; endl;
v = 0;
for (v = 0; v & lt; NUM; ++ v)
{
cout & lt; & lt; "\ t" & lt; & lt; v + 1 & lt; & lt; "." & lt; & lt; * vb & lt; & lt; endl;
++ vb;
}
vb = vec_3.begin ();
cout & lt; & lt; "\ n \ n \ tNOT SORT VEC_3: \ n" & lt; & lt; endl;
v = 0;
for (v = 0; v & lt; NUM; ++ v)
{
cout & lt; & lt; "\ t" & lt; & lt; v + 1 & lt; & lt; "." & lt; & lt; * vb & lt; & lt; endl;
++ vb;
}
v = 0;
cout & lt; & lt; "\ n \ n \ tEND !!! \ n \ n" & lt; & lt; endl;
return (0);
}
}
Answer 1, authority 100%
According to documentation , the implementation of the random_shuffle
function might look like like this:
template & lt; class RandomAccessIterator, class RandomNumberGenerator & gt;
void random_shuffle (RandomAccessIterator first, RandomAccessIterator last,
RandomNumberGenerator & amp; gen)
{
iterator_traits & lt; RandomAccessIterator & gt; :: difference_type i, n;
n = (last-first);
for (i = n-1; i & gt; 0; --i) {
swap (first [i], first [gen (i + 1)]);
}
}
From this example it follows that the function (functor class) gen
should have approximately the following signature:
int your_function (int) // function
class Your_class // functor
{
public:
int operator () (int);
}
The function takes as input the maximum possible position of the element – i.e. the size of the collection, and returns the new position, which must have a value between 0 and the value of the accepted argument.
In its simplest form, the implementation is as follows:
int myrandom (int i) {return rand ()% i;}
Answer 2
My problem was that I was trying to assign my own argument to the functor, while the algorithm using the functor does it on its own.
BY THE WAY. The random_shuffle () algorithm not only shuffles the sequence, but also changes the value of one of its members. IT’S WEIRD.