Ver Mensaje Individual
  #8 (permalink)  
Antiguo 07/04/2015, 00:39
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: arreglos y sus elementos repetidos

Cita:
Iniciado por lareto Ver Mensaje
Esta nueva versión es más rápida porque no hace nada. Pero de todos modos, si al corregirla conservas la idea, no será más rápida; las dos son de una complejidad O(log N) pero la "optimizada" tendría el doble de pendiente, demoraría el doble que mi versión.
Si y no... Es cierto que la versión que he puesto al final no funciona... cosas de montar el código directamente en el foro... pero no pasa nada, pongo un ejemplo completo, compilado y probado... ahora si puedo compilar :)

Código C++:
Ver original
  1. std::unordered_map<int, int> estilo_cpp1(std::vector< int > v)
  2. {
  3.     std::unordered_map<int, int> m;  // las funciones devuelven un map para
  4.                                      // no tener que mostrar con cout
  5.                                      // los miles de valores
  6.  
  7.  
  8.  
  9.     std::sort(std::begin(v), std::end(v));  // comienza el procese real
  10.  
  11.     int cont = 0;
  12.  
  13.     for(auto i=std::begin(v), j=std::end(v); i!=j; i+=cont) {
  14.         auto rango = std::equal_range(i, j, *i);
  15.         cont = std::distance(rango.first, rango.second);
  16.  
  17.         m[*i] = cont;
  18.     }
  19.  
  20.     return m;
  21. }
  22.  
  23. std::unordered_map<int, int> estilo_cpp2(std::vector< int > v)
  24. {
  25.     std::unordered_map<int, int> m;  // las funciones devuelven un map para
  26.                                      // no tener que mostrar con cout
  27.                                      // los miles de valores
  28.  
  29.     std::sort(std::begin(v), std::end(v));  // comienza el procese real
  30.     for( auto it = v.begin( ); it != v.end( ); ++it )
  31.       m[ *it ]++;
  32.  
  33.     return m;
  34. }
  35.  
  36. int main()
  37. {
  38.   using namespace std::chrono;
  39.   steady_clock::time_point t1;
  40.   duration<double> demora1, demora2;
  41.   std::unordered_map<int, int> m1, m2;
  42.  
  43.   std::minstd_rand0 generator;     // llena un vector con elementos al azar
  44.  
  45.   for(int n=1; n<30000000; n*=2)
  46.   {
  47.     std::cout << "n = " << n << '\n';
  48.     std::vector<int> v;
  49.     v.reserve( n );
  50.     for ( int i = 0; i < n; ++i )
  51.     v.push_back ( generator() % n );
  52.  
  53.     t1 = steady_clock::now();
  54.     m1 = estilo_cpp1(v);
  55.     demora1 = duration_cast<duration<double>>(steady_clock::now() - t1);
  56.  
  57.     t1 = steady_clock::now();
  58.     m2 = estilo_cpp2(v);
  59.     demora2 = duration_cast<duration<double>>(steady_clock::now()- t1);
  60.  
  61.     std::cout << std::setprecision(6) << std::fixed;
  62.     std::cout << "estilo_cpp1(): " << demora1.count() << " segundos\n";
  63.     std::cout << "estilo_cpp2(): " << demora2.count() << " segundos\n";
  64.     std::cout << "diferencia relativa = " << (demora1.count()-demora2.count())/demora2.count() * 100 << " %\n" << std::endl;
  65.   }
  66. }

...conseguimos exactamente la misma salida y con una mejora del rendimiento que varía... con pocos elementos he llegado a una mejora cercana al 2000% (poco fiable son procesos muy rápidos y cualquier interrupción dispara los tiempos) pero con cifras más altas la mejora se situa en torno al 12% - 15%.

Por cierto, he sacado la generación del vector fuera de las funciones por dos motivos:

1. Su generación no afecta a la medida de tiempos (medidas más precisas)
2. Ambas funciones van a trabajar con la misma colección de datos.

Sobre el motivo de usar el mapa... pues no se, como no podía probarlo tampoco tenía muy claro el impacto que podía tener con respecto a tu versión... esta mañana lo he probado y efectivamente rueda un 20% más lento (aprox.), cosas del directo.

Un saludo