Ver Mensaje Individual
  #5 (permalink)  
Antiguo 06/04/2015, 12:31
lareto
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: arreglos y sus elementos repetidos

No quiero complicarle la vida a JarolGarcia con una versión más compleja que la que pueda asimilar, pero me parece que puede resultar interesante hacer una comparación entre una solución relativamente simple y artesanal, en estilo C (para lo que tomo como ejemplo y acomodando un poco la respuesta de eferion), y otra en estilo C++.

Yo creo que el estilo C++ tiene una ventaja inmediata: es mucho más fácil pensar en una solución y esa solución es muy fácil de hacer eficiente, mientras que la solución en estilo C puede no ser difícil de pergeniar, pero es más difícil de hacer eficiente o, por lo menos, se necesita bastante más esfuerzo y reinventar varios paraguas para conseguir una solución equivalente. Mi idea es que para obtener una solución eficiente en C++ no hace falta ser demasiado inteligente, sólo estudiar un poco más.

Va el ejemplo de comparación, que espero pueda servirle a alguien.

Para el que quiera compilar y ejecutar el programa, va a necesitar un compilador conforme con el estándar C++11 y un poco de paciencia, porque la prueba así como está en mi máquina se demora casi un minuto entero.

Código C++:
Ver original
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <utility>
  4. #include <unordered_map>
  5. #include <chrono>
  6. #include <iomanip>
  7. #include <cstdlib>
  8.  
  9.  
  10. std::unordered_map<int, int> estilo_cpp(int N)
  11. {
  12.     std::unordered_map<int, int> m;  // las funciones devuelven un map para
  13.                                      // no tener que mostrar con cout
  14.                                      // los miles de valores
  15.  
  16.  
  17.     std::minstd_rand0 generator;     // llena un vector con elementos al azar
  18.  
  19.     std::vector<int> v;
  20.     v.reserve(N);
  21.     for(int i=0; i<N; ++i) {
  22.         v.push_back(generator()%N);
  23.     }
  24.     std::sort(std::begin(v), std::end(v));  // comienza el procese real
  25.  
  26.     int cont = 0;
  27.  
  28.     for(auto i=std::begin(v), j=std::end(v); i!=j; i+=cont) {
  29.         auto rango = std::equal_range(i, j, *i);
  30.         cont = std::distance(rango.first, rango.second);
  31.  
  32.         m[*i] = cont;
  33.     }
  34.  
  35.     return m;
  36. }
  37.  
  38.  
  39. std::unordered_map<int, int> estilo_c(int N)
  40. {
  41.     int cont, pasar;
  42.     int i, j;
  43.     std::unordered_map<int, int> m;  // lo mismo que en la función de arriba
  44.  
  45.     std::minstd_rand0 generator;
  46.  
  47.     int* a = new int[N];
  48.     for(int i=0; i<N; ++i) {
  49.         a[i] = generator()%N;     // llena el array con valores al azar
  50.     }
  51.  
  52.     for ( i = 0; i < N; i++ ) {   // comienza el proceso real
  53.         pasar = 0;
  54.         for ( j = i; j-- && !pasar; )
  55.             pasar = a[i] == a[j];
  56.  
  57.         if( !pasar ) {
  58.             for( j=i, cont=0; j < N; ++j )
  59.                 cont += a[i] == a[j];
  60.  
  61.             m[i] = cont;
  62.         }
  63.     }
  64.  
  65.     delete[] a;
  66.     return m;
  67. }
  68.  
  69.  
  70. int main()
  71. {
  72.     using namespace std::chrono;
  73.     steady_clock::time_point t1;
  74.     duration<double> demora1, demora2;
  75.     std::unordered_map<int, int> m1, m2;
  76.  
  77.     for(int n=1; n<300000; n*=2) {
  78.         std::cout << "n = " << n << '\n';
  79.  
  80.         t1 = steady_clock::now();
  81.         m1 = estilo_c(n);
  82.         demora1 = duration_cast<duration<double>>(steady_clock::now() - t1);
  83.  
  84.         t1 = steady_clock::now();
  85.         m2 = estilo_cpp(n);
  86.         demora2 = duration_cast<duration<double>>(steady_clock::now()- t1);
  87.  
  88.         std::cout << std::setprecision(6) << std::fixed;
  89.         std::cout << "estilo_c()  : " << demora1.count() << " segundos\n";
  90.         std::cout << "estilo_cpp(): " << demora2.count() << " segundos\n";
  91.         std::cout << "diferencia relativa = " << (demora1.count()-demora2.count())/demora2.count() * 100 << " %\n" << std::endl;
  92.         // a partir de 128 elementos las diferencias relativas aumentan proporcionalmente con n.
  93.         // más allá de 32.000 elementos, estilo_c() se hace inviable.
  94.     }
  95.  
  96. }

Última edición por lareto; 06/04/2015 a las 12:41