c++ - resueltos - que es una matriz en programacion
¿Cómo asegurar que dos vectores diferentes se mezclan en el mismo orden en C++? (8)
Esta pregunta ya tiene una respuesta aquí:
Tengo dos vectores:
vector1 = [1 2 3 4 5 6 7 8 9]
vector2 = [1 2 3 4 5 6 7 8 9]
Quiero asegurarme de que, cuando mezclo los dos al azar con random_shuffle, se deben barajar en el mismo orden correspondiente. Por ejemplo:
La salida después de barajar debe ser como:
vector1 = [1 9 3 4 2 7 8 5 6]
vector2 = [1 9 3 4 2 7 8 5 6]
Pero estoy obteniendo salida como:
vector1 = [5 1 7 4 2 3 9 8 6]
vector2 = [3 4 1 9 8 2 5 7 6]
Aquí está mi código:
int main ()
{
std::srand ( unsigned ( std::time(0) ) );
std::vector<int> vector1, vector2;
// set some values:
for (int i=1; i<10; ++i)
{
vector1.push_back(i);
vector2.push_back(i);
}
// using built-in random generator:
std::random_shuffle ( vector1.begin(), vector1.end() );
std::random_shuffle ( vector2.begin(), vector2.end() );
// print out content:
std::cout << "vector1 contains:";
for ( std::vector<int>::iterator it1 = vector1.begin(); it1 != vector1.end(); ++it1 )
std::cout << '' '' << *it1;
std::cout << ''/n'';
std::cout << ''/n'';
std::cout << "vector2 contains:";
for ( std::vector<int>::iterator it2 = vector2.begin(); it2 != vector2.end(); ++it2 )
std::cout << '' '' << *it2;
std::cout << ''/n'';
std::cout << ''/n'';
return 0;
}
EDITAR Este es un caso de ejemplo que traté de implementar. En la práctica, tengo un vector de imágenes y un vector de etiquetas correspondientes. Necesito que se barajen de la misma manera. ¿Alguien por favor ayuda ... muchas gracias!
¿Por qué no escribes tu propio shuffle?
for( size_t i = 0 ; i < numitems; ++i )
{
size_t next = random() % numitems ;
swap( v1[i], v1[next] );
swap( v2[i], v2[next] );
}
Asegúrate de usar la misma semilla para ambas llamadas a random_shuffle()
:
auto seed = unsigned ( std::time(0) );
// ...
std::srand ( seed );
std::random_shuffle ( vector1.begin(), vector1.end() );
std::srand ( seed );
std::random_shuffle ( vector2.begin(), vector2.end() );
Sin embargo, random_shuffle()
que la Norma no especifica que random_shuffle()
debe usar la función rand()
para generar una permutación aleatoria; esto está definido por la implementación. Por lo tanto, srand()
no afectará el resultado de random_shuffle()
en implementaciones que no usan rand()
.
El párrafo 25.3.12 / 4 de la norma C ++ 11 en random_shuffle()
especifica:
Observaciones : En la medida en que la implementación de estas funciones haga uso de números aleatorios, la implementación deberá utilizar las siguientes fuentes de aleatoriedad:
La fuente subyacente de números aleatorios para la primera forma de la función está definida por la implementación. Una implementación puede usar la función
rand
de la biblioteca C estándar. [...]
Por lo tanto, si desea asegurarse de que está escribiendo un código portátil, use la versión de random_shuffle()
que acepta un generador de números aleatorios como un tercer argumento, para que tenga control sobre la selección.
Como han demostrado otros, volver a sembrar con la misma semilla debería permitirte replicar el mismo orden aleatorio varias veces. Sin embargo, si puede usar C ++ 11, recomendaría implementar esto sin usar srand()
y random_shuffle()
; en su lugar, debe usar la biblioteca <random>
con std::shuffle
.
Primero, si es posible, se debe evitar el rand
. Aparte del hecho de que no suele ser un pRNG muy bueno, también tiene problemas con la seguridad de subprocesos debido al estado compartido. La biblioteca <random>
soluciona estos dos problemas al darle al programador un control explícito sobre el estado de pRNG y al ofrecer varias opciones con características de calidad, rendimiento y rendimiento garantizados.
En segundo lugar, random_shuffle
no está realmente especificado para usar rand
por lo que es teóricamente legal para volver a sembrar usando srand
no para tener el efecto que deseas. Para obtener resultados garantizados con random_shuffle
tienes que escribir tu propio generador. Pasando a las shuffle
, ya que puede utilizar directamente motores estándar.
#include <algorithm> // shuffle, copy
#include <iostream> // cout
#include <iterator> // begin, end, ostream_iterator
#include <numeric> // iota
#include <random> // default_random_engine, random_device
#include <vector> // vector
int main() {
std::vector<int> v1(10);
std::iota(begin(v1), end(v1), 1);
auto v2 = v1;
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
// create two random engines with the same state
std::mt19937 eng1(seed);
auto eng2 = eng1;
std::shuffle(begin(v1), end(v1), eng1);
std::shuffle(begin(v2), end(v2), eng2);
std::copy(begin(v1), end(v1), std::ostream_iterator<int>(std::cout, " "));
std::cout << "/n/n";
std::copy(begin(v2), end(v2), std::ostream_iterator<int>(std::cout, " "));
std::cout << "/n/n";
}
Desafortunadamente, si usamos srand cambiamos el valor de semilla interno. Quiero decir, los siguientes números aleatorios serán predeterminados. Y, primera decisión:
std::srand ( 42 );
std::random_shuffle ( vector1.begin(), vector1.end() );
std::srand ( 42 );
std::random_shuffle ( vector2.begin(), vector2.end() );
std::srand ( unsigned ( std::time(0) ) );
// Post-code.
Para guardar rand para post-code.
Segunda decisión: es la solución de Mark Ransom: no se llama std :: srand (y, acabo de notar, tiene un rendimiento más alto).
En lugar de mezclar los propios vectores, mezcle un vector de índices en los otros vectores. Dado que utilizará los mismos índices para ambos, se garantiza que están en el mismo orden.
std::vector<int> indexes;
indexes.reserve(vector1.size());
for (int i = 0; i < vector1.size(); ++i)
indexes.push_back(i);
std::random_shuffle(indexes.begin(), indexes.end());
std::cout << "vector1 contains:";
for ( std::vector<int>::iterator it1 = indexes.begin(); it1 != indexes.end(); ++it1 )
std::cout << '' '' << vector1[*it1];
Puede crear un iterador de acceso aleatorio que, si se anula, devuelve un std :: tuple a las referencias de los elementos de los vectores correspondientes. Así que podrías barajarlos en el lugar. O te fijas en la versión boost . Entonces debería verse algo como esto:
std::random_shuffle(
boost::make_zip_iterator(
boost::make_tuple(vector1.begin(), vector2.begin())
),
boost::make_zip_iterator(
boost::make_tuple(vector1.end(), vector2.end()
),
);
Esto baraja tus datos en el lugar, funciona con más de dos vectores y se auto documenta si sabes lo que hace make_zip_iterator
. Por supuesto, debería ser más rápido que mezclar dos veces o usar un tercer vector.
Si ambos tienen que tener el mismo orden, ¿por qué son vectores separados? La solución lógica sería algo como:
struct ImageData
{
Image myImage;
std::string myLabel;
// ...
};
Entonces tienes un único vector de ImageData
que ImageData
.
Siembre el generador de números pseudoaleatorios con un valor reproducible antes de cada orden aleatoria.
std::srand ( 42 );
std::random_shuffle ( vector1.begin(), vector1.end() );
std::srand ( 42 );
std::random_shuffle ( vector2.begin(), vector2.end() );