Foros del Web » Programación para mayores de 30 ;) » C/C++ »

¿Se puede optimizar el siguiente codigo?

Estas en el tema de ¿Se puede optimizar el siguiente codigo? en el foro de C/C++ en Foros del Web. Hola amigos, he estado liado con el tema de verificar archivos por lotes usando un hash. El problema surgio cuando la aplicacion que probé me ...
  #1 (permalink)  
Antiguo 07/07/2016, 12:40
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
¿Se puede optimizar el siguiente codigo?

Hola amigos, he estado liado con el tema de verificar archivos por lotes usando un hash. El problema surgio cuando la aplicacion que probé me creaba un archivo con todos los md5 en un orden para un directorio y luego me creaba otro archivo con todos los md5 en otro orden para una copia del mismo directorio. No se porque hacia eso y no me los muestra todos ordenados pero me puse a crearme una solucion rapida en C que lo que hace es abrir el primer archivo y va buscando cada md5 en el segundo y los va poniendo en un tercer archivo en el mismo orden.
Ciertamente cada linea tiene el hash y al lado la ruta relativa al archivo con lo que lo que busco para ordenar es la ruta y no el md5 ya que este puede haber cambiado y no lo encontraria.
El caso es que aparentemente parece que funciona pero tarda para unas 70000 lineas como 5 minutos para ordenarlas en un tercer archivo. ¿Hay alguna manera de optimizarlo sin usar bases de datos?
Aqui el codigo:
Código C:
Ver original
  1. //---------------------------------------------------------------------------
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include <errno.h>
  7. #include <limits.h>
  8. #define SIZEMAX 1024
  9. //---------------------------------------------------------------------------
  10.  
  11. typedef enum {
  12.     STR2INT_SUCCESS,
  13.     STR2INT_OVERFLOW,
  14.     STR2INT_UNDERFLOW,
  15.     STR2INT_INCONVERTIBLE
  16. } str2int_errno;
  17.  
  18. int CheckFileError(FILE *fichero,char *fullpath)
  19. {
  20.     int error=0;
  21.  
  22.     if(fichero == NULL){
  23.         printf("No se pudo abrir el archivo %s. Asegurese de que la ruta y el nombre son correctos.\n",fullpath);
  24.         error=-1;
  25.     }
  26.     return error;
  27. }
  28. //---------------------------------------------------------------------------
  29.  
  30. void CerrarArchivos(FILE **origen1,FILE **origen2,FILE **destino2)
  31. {
  32.     if(*origen1 != NULL){
  33.         fclose(*origen1);
  34.         *origen1=NULL;
  35.         if(*origen2 != NULL){
  36.             fclose(*origen2);
  37.             *origen2=NULL;
  38.             if(*destino2 != NULL){
  39.                 fclose(*destino2);
  40.                 *destino2=NULL;
  41.             }
  42.         }
  43.     }
  44. }
  45. //---------------------------------------------------------------------------
  46.  
  47. int AbrirArchivos(FILE **origen1,FILE **origen2,FILE **destino2,char *pathOrigen1,char *pathOrigen2,char *pathDestino2)
  48. {
  49.     int error;
  50.  
  51.     *origen1=fopen(pathOrigen1,"r");
  52.     if((error=CheckFileError(*origen1,pathOrigen1))!=0){
  53.         CerrarArchivos(origen1,origen2,destino2);
  54.         system("pause");
  55.         return error;
  56.     }
  57.  
  58.     *origen2=fopen(pathOrigen2,"r");
  59.     if((error=CheckFileError(*origen2,pathOrigen2))!=0){
  60.         CerrarArchivos(origen1,origen2,destino2);
  61.         system("pause");
  62.         return error;
  63.     }
  64.  
  65.     *destino2=fopen(pathDestino2,"w");
  66.     if((error=CheckFileError(*destino2,pathDestino2))!=0){
  67.         CerrarArchivos(origen1,origen2,destino2);
  68.         system("pause");
  69.         return error;
  70.     }
  71.     return error;
  72. }
  73. //---------------------------------------------------------------------------
  74.  
  75. void clean(void)
  76. {
  77.     char a;
  78.     while(getchar()!='\n');
  79. }
  80. //---------------------------------------------------------------------------
  81.  
  82. void ObtenerRutas(char *pathOrigen1,char *pathOrigen2,char *pathDestino2,int *largoHash)
  83. {
  84.     int largo;
  85.  
  86.     printf("Introduce la ruta completa hacia el primer archivo:\n\t");
  87.     fgets(pathOrigen1,SIZEMAX,stdin);
  88.     largo=strlen(pathOrigen1);
  89.     if(pathOrigen1[largo-1]!='\n'){
  90.         clean();
  91.         printf("Ruta demasiado larga.\n");
  92.     }else{
  93.         pathOrigen1[largo-1]='\0';
  94.     }
  95.     printf("Introduce la ruta completa hacia el segundo archivo:\n\t");
  96.     fgets(pathOrigen2,SIZEMAX,stdin);
  97.     largo=strlen(pathOrigen2);
  98.     if(pathOrigen2[largo-1]!='\n'){
  99.         clean();
  100.         printf("Ruta demasiado larga.\n");
  101.     }else{
  102.         pathOrigen2[largo-1]='\0';
  103.     }
  104.     printf("Introduce la ruta completa para el archivo de salida:\n\t");
  105.     fgets(pathDestino2,SIZEMAX,stdin);
  106.     largo=strlen(pathDestino2);
  107.     if(pathDestino2[largo-1]!='\n'){
  108.         clean();
  109.         printf("Ruta demasiado larga.\n");
  110.     }else{
  111.         pathDestino2[largo-1]='\0';
  112.     }
  113.     printf("Introduce el numero de caracteres del hash: ");
  114.     scanf("%d",largoHash);
  115. }
  116. //---------------------------------------------------------------------------
  117.  
  118. //Para convertir el parametro del largo del hash de cadena a entero
  119. str2int_errno str2int(int *out, char *s, int base) {
  120.     char *end;
  121.     long l;
  122.    
  123.     if (s[0] == '\0' || isspace((unsigned char) s[0]))
  124.         return STR2INT_INCONVERTIBLE;
  125.     errno = 0;
  126.     l = strtol(s, &end, base);
  127.  
  128.     if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
  129.         return STR2INT_OVERFLOW;
  130.     if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
  131.         return STR2INT_UNDERFLOW;
  132.     if (*end != '\0')
  133.         return STR2INT_INCONVERTIBLE;
  134.     *out = l;
  135.     return STR2INT_SUCCESS;
  136. }
  137. //---------------------------------------------------------------------------
  138.  
  139. int CheckParams(int nParametros, char *parametros[], char *pathOrigen1,char *pathOrigen2,char *pathDestino2,int *largoHash)
  140. {
  141.     str2int_errno error_param_hash;
  142.     char mensaje[SIZEMAX];
  143.    
  144.     if(nParametros == 5){
  145.         strcpy(pathOrigen1,parametros[1]);
  146.         strcpy(pathOrigen2,parametros[2]);
  147.         strcpy(pathDestino2,parametros[3]);
  148.         error_param_hash=str2int(largoHash,parametros[4],10);
  149.         switch(error_param_hash){
  150.             case STR2INT_OVERFLOW:
  151.                 strcpy(mensaje,"STR2INT_OVERFLOW");
  152.             break;
  153.  
  154.             case STR2INT_UNDERFLOW:
  155.                 strcpy(mensaje,"STR2INT_UNDERFLOW");
  156.             break;
  157.  
  158.             case STR2INT_INCONVERTIBLE:
  159.                 strcpy(mensaje,"STR2INT_INCONVERTIBLE");
  160.             break;
  161.         }
  162.         if(error_param_hash != STR2INT_SUCCESS){
  163.             printf("Error en el parametro para el largo del hash. Error: %s\n",mensaje);
  164.             system("pause");
  165.             return -1;
  166.         }
  167.         if(*largoHash < 0){
  168.             printf("El valor asignado al largo del hash no puede ser menor que '0'.\nSi no hay hash ponga '0'.\n");
  169.             system("pause");
  170.             return -1;
  171.         }
  172.     }else if(nParametros > 1){
  173.         printf("parametros incorrectos.\n");
  174.         system("pause");
  175.         return -1;
  176.     }else{
  177.         ObtenerRutas(pathOrigen1,pathOrigen2,pathDestino2,largoHash);
  178.     }
  179.     return 0;
  180. }
  181. //---------------------------------------------------------------------------
  182.  
  183. void CrearFicheroOrdenado(char *pathOrigen1,char *pathOrigen2,char *pathDestino2,int largoHash)
  184. {
  185.     char buffer1[SIZEMAX];
  186.     char buffer2[SIZEMAX];
  187.     FILE *origen1=NULL,*origen2=NULL,*destino2=NULL;
  188.     int encontrado,largo,noEncontrados=0;
  189.  
  190.     if(AbrirArchivos(&origen1,&origen2,&destino2,pathOrigen1,pathOrigen2,pathDestino2)==0){
  191.         printf("Ha comenzado el proceso. No cierre esta ventana hasta que termine el proceso.");
  192.         while(!feof(origen1) && fgets(buffer1,sizeof(buffer1),origen1) != NULL){
  193.             encontrado=0;
  194.             rewind(origen2);
  195.             while(!feof(origen2) && fgets(buffer2,sizeof(buffer2),origen2) != NULL && encontrado == 0){
  196.                 largo=strlen(&buffer1[largoHash]);
  197.                 if(strncmp(&buffer1[largoHash],&buffer2[largoHash],largo)==0){
  198.                     encontrado=1;
  199.                     break;
  200.                 }
  201.             }
  202.             if(encontrado==1)
  203.                 fputs(buffer2,destino2);
  204.             else{
  205.                 fputs("\n",destino2);
  206.                 noEncontrados++;
  207.             }
  208.         }
  209.         CerrarArchivos(&origen1,&origen2,&destino2);
  210.         printf("Proceso finalizado.\n");
  211.         if(noEncontrados > 0)
  212.             printf("No se encontraron en \"%s\" %d entradas.\n",origen2,noEncontrados);
  213.         system("pause");
  214.     }
  215. }
  216. //---------------------------------------------------------------------------
  217.  
  218. //Se puede usar con parametros tambien
  219. int main(int argc, char* argv[])
  220. {
  221.     char pathOrigen1[SIZEMAX];
  222.     char pathOrigen2[SIZEMAX];
  223.     char pathDestino2[SIZEMAX];
  224.     int largoHash;
  225.  
  226.     if(CheckParams(argc,argv,pathOrigen1,pathOrigen2,pathDestino2,&largoHash) == 0)
  227.         CrearFicheroOrdenado(pathOrigen1,pathOrigen2,pathDestino2,largoHash);
  228.     return 0;
  229. }
  230. //---------------------------------------------------------------------------
El caso es que si está mas o menos ordenado al empezar pues cuanto mas avance mas tardará en encontrar el siguiente y asi hasta el final y si es muy largo el archivo pues se puede hacer eterno jajaja.
  #2 (permalink)  
Antiguo 07/07/2016, 23:39
 
Fecha de Ingreso: abril-2016
Mensajes: 31
Antigüedad: 8 años, 7 meses
Puntos: 5
Respuesta: ¿Se puede optimizar el siguiente codigo?

Hola. Sin intención de ofender, por favor, pero para hacer el universo de respuestas un poco más manejables yo cambiaría la pregunta por "¿hay alguna forma de hacerlo peor?" Si el archivo origen1 tuviera 70.000 líneas, igual que el archivo origen2, este sorprendente algoritmo necesitaría 4.900 millones de comparaciones. Extraordinario.

Una primera intención: ¿el archivo origen2 puede cargarse en memoria? Si fuera posible: qsort para ordenarlo y búsqueda binaria.

Si origen2 no cupiera en memoria: segunda intención: [URL="https://en.wikipedia.org/wiki/External_sorting"]External sorting[/URL] y la búsqueda binaria sobre el archivo ordenado.

Y bueno, cualquier otra solución que se te ocurra que incluya "orden" entre sus premisas, no puede resultar peor que las 4.900 millones de comparaciones :)
  #3 (permalink)  
Antiguo 08/07/2016, 00:45
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Se puede optimizar el siguiente codigo?

Un hash de digamos 64 caracteres mas una ruta de digamos 500 caracteres, en 70.000 líneas nos daría un consumo aproximado de 38MB (que será menos si conviertes el hash a entero), no veo qué problema puede presentar leer dos ficheros de esas características en memoria y realizar la ordenación directamente en memoria, como te está proponiendo enrieto.

Para ordenar desde el fichero puedes optar por crearte un índice en memoria que te indique en qué posición empieza cada línea del fichero a ordenar e iterar sobre dicho índice. Usar el índice te permite ir al inicio de cada registro directamente sin tener que hacer cálculos repetitivos. Cada vez que ordenas un elemento eliminas dicha entrada del índice (o lo marcas como usado) y te ahorras futuras comprobaciones sobre dicho elemento.

Opciones hay bastantes unas más rápidas pero más complejas de implementar y otras más lentas pero con una algorítmica más sencilla.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #4 (permalink)  
Antiguo 08/07/2016, 01:13
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

A ver, pensé en hacer una búsqueda binaria y qsort pero me encontré con un problema. Lo que comparo no son valores numéricos sino ruta a archivos y son cadenas ¿como puedo saber si una ruta es mayor o menor que otra para poder hacer una búsqueda binaria?
  #5 (permalink)  
Antiguo 08/07/2016, 02:54
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Se puede optimizar el siguiente codigo?

strcmp permite comparar cadenas. ¿Cómo lo hace? algo así:
Código C:
Ver original
  1. int strcmp(const char* cad1, const char* cad2)
  2. {
  3.   int ret = 0;
  4.   for( int i=0; ret==0 && cad1[i] != 0; i++)
  5.     ret = cad1[i] - cad2[i];
  6.   return ret;
  7. }

Es decir, recorre las dos cadenas y realiza una resta del valor de los caracteres en cada posición. Si las dos cadenas son iguales la resta dará 0 mientras que en caso contrario el resultado será un valor positivo si cad1 es mayor o más larga que cad2 o negativo en caso contrario.

Puedes aprovechar ese mismo principio para ordenar los ficheros.

Otra cosa es que desees un orden determinado. En ese caso te tocará introducir algunos cambios para adaptar la ordenación a tus necesidades.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #6 (permalink)  
Antiguo 08/07/2016, 03:11
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

Muy bien, siguiendo vuestros consejos estoy intentando reconducir el codigo y de momento estoy probando con esto:
Código C:
Ver original
  1. /* funcion para comparar strings de C para qsort */
  2. int cstring_cmp(const void *a, const void *b)
  3. {
  4.     const char **ia = (const char **)a;
  5.     const char **ib = (const char **)b;
  6.     return strcmp(*ia, *ib);
  7. }
  8. //---------------------------------------------------------------------------
  9.  
  10. //Se puede usar con parametros tambien
  11. int main(int argc, char* argv[])
  12. {
  13.     char pathOrigen1[SIZEMAX];
  14.     char pathOrigen2[SIZEMAX];
  15.     char pathDestino2[SIZEMAX];
  16.     char **buffer;
  17.     int largoHash,nElementos;
  18.     FILE *origen1=NULL,*origen2=NULL,*destino2=NULL;
  19.  
  20.     if(CheckParams(argc,argv,pathOrigen1,pathOrigen2,pathDestino2,&largoHash) == 0){
  21.         if((nElementos=CargarFicheroEnMemoria(origen2,pathOrigen2,&buffer)) > 0){
  22.             qsort(buffer, nElementos, sizeof(char *), cstring_cmp);
  23.         }
  24.     }
  25.     return 0;
  26. }
Me encuentro con 2 problemas:
1- En la funcion CargarFicheroEnMemoria realloc falla porque hago algo mal y no doy con la tecla.
2- En la funcion que compara las strings el problema es que no quiero comparar las dos cadenas enteras, o sea, querria comparar ambas cadenas a partir de la posicion 32 de cada una por ejemplo y tampoco se como indicarle eso. Se me ocurre ponerlo asi pero no se si es correcto y hasta que no solucione el primer problema no podre probarlo:
Código C:
Ver original
  1. /* funcion para comparar strings de C para qsort */
  2. int cstring_cmp(const void *a, const void *b)
  3. {
  4.     const char **ia = (const char **)a;
  5.     const char **ib = (const char **)b;
  6.     return strcmp(&(*ia[32]), &(*ib[32]));
  7. }
  #7 (permalink)  
Antiguo 08/07/2016, 03:17
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Se puede optimizar el siguiente codigo?

Código C:
Ver original
  1. int cstring_cmp(const void *a, const void *b)
  2. {
  3.     const char **ia = (const char **)a;
  4.     const char **ib = (const char **)b;
  5.     return strcmp(*ia, *ib);
  6. }

¿por qué tanto odio en esa función? ¿No te valía con usar punteros simples?

Código C:
Ver original
  1. int cstring_cmp(const void *a, const void *b)
  2. {
  3.     const char *ia = (const char *)a;
  4.     const char *ib = (const char *)b;
  5.     return strcmp(ia, ib);
  6. }

Aparte que convertir un void* en un char** o, lo que es lo mismo, un puntero simple en uno doble, no parece buena idea.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #8 (permalink)  
Antiguo 08/07/2016, 03:46
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

Cita:
Iniciado por eferion Ver Mensaje
Código C:
Ver original
  1. int cstring_cmp(const void *a, const void *b)
  2. {
  3.     const char **ia = (const char **)a;
  4.     const char **ib = (const char **)b;
  5.     return strcmp(*ia, *ib);
  6. }

¿por qué tanto odio en esa función? ¿No te valía con usar punteros simples?

Código C:
Ver original
  1. int cstring_cmp(const void *a, const void *b)
  2. {
  3.     const char *ia = (const char *)a;
  4.     const char *ib = (const char *)b;
  5.     return strcmp(ia, ib);
  6. }

Aparte que convertir un void* en un char** o, lo que es lo mismo, un puntero simple en uno doble, no parece buena idea.
La verdad es que para ello tuve que buscar info por internet y en todas partes veo que lo hacen asi y me basé en este codigo: http://www.anyexample.com/programmin...nd_structs.xml
  #9 (permalink)  
Antiguo 08/07/2016, 03:51
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Se puede optimizar el siguiente codigo?

El problema es que has intentado innovar y has puesto un doble puntero donde ellos usan un puntero simple:

Copiado del enlace que facilitas:
Código C:
Ver original
  1. /* qsort int comparison function */
  2. int int_cmp(const void *a, const void *b)
  3. {
  4.     const int *ia = (const int *)a; // casting pointer types
  5.     const int *ib = (const int *)b;
  6.     return *ia  - *ib;
  7.     /* integer comparison: returns negative if b > a
  8.     and positive if a > b */
  9. }
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #10 (permalink)  
Antiguo 08/07/2016, 04:00
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

Esa función que pones es la que usa para comparar enteros. Si miras la que usa para comparar cadenas veras que es diferente.
  #11 (permalink)  
Antiguo 08/07/2016, 04:24
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Se puede optimizar el siguiente codigo?

Ya no recordaba la de putadas que se hacían en C con los tipos.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #12 (permalink)  
Antiguo 08/07/2016, 05:00
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

Jajaja.
Lo más urgente ahora es resolver el problema que tengo al reservar la memoria para volcar el archivo. Lo otro cuando funcione esto ya veremos si hay que llamar a los artificieros para que no explote el pc jijiji.
He hecho esta modificacion porque he leido que si falla realloc se produciria una fuga de memoria como yo lo estaba haciendo y que habia que usar un puntero auxiliar asi que asi lo he dejado:
Código C:
Ver original
  1. void LiberarMemoria(char ***buffer,int nlines)
  2. {
  3.     int index;
  4.  
  5.     if(buffer != NULL && *buffer != NULL){
  6.         for(index=0;index < nlines;index++)
  7.             free(*buffer[index]);
  8.         free(*buffer);
  9.     }
  10. }
  11. //---------------------------------------------------------------------------
  12.  
  13. int CargarFicheroEnMemoria(FILE *origen, char *path,char ***pbuffer)
  14. {
  15.     int nlines=0,largo;
  16.     char aux[SIZEMAX];
  17.     char **paux;
  18.  
  19.     origen=fopen(path,"r");
  20.  
  21.     if(origen != NULL){
  22.         *pbuffer=NULL;
  23.         while(!feof(origen)){
  24.             memset(aux,'\0',SIZEMAX);
  25.             fgets(aux,SIZEMAX,origen);
  26.             largo=strlen(aux);
  27.             nlines++;
  28.             paux=(char**)realloc(*pbuffer,nlines*sizeof(char**));
  29.             if(paux != NULL){
  30.                 *pbuffer=paux;
  31.                 *pbuffer[nlines-1]=(char*)malloc(sizeof(char*)*largo);
  32.                 strcpy(*pbuffer[nlines-1],aux);
  33.             }else{
  34.                 printf("No hay suficiente memoria disponible para volcar el archivo.\n");
  35.                 LiberarMemoria(pbuffer,nlines-1);
  36.             }
  37.         }
  38.     }
  39.     return nlines;
  40. }
Sigue teniendo el mismo fallo y es porque no hago bien el trabajo de punteros y no se que hago mal al respecto. ¿podeis ayudarme?

Última edición por aguml; 08/07/2016 a las 06:09
  #13 (permalink)  
Antiguo 08/07/2016, 12:52
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

Bueno, al final he encontrado una manera de codear lo que quiero y optimizando muy mucho el tiempo aunque ocupando mas memoria. Este es el codigo:
Código C:
Ver original
  1. //---------------------------------------------------------------------------
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include <errno.h>
  7. #include <limits.h>
  8. #define SIZEMAX 1024
  9.  
  10.  
  11. typedef enum {
  12.     STR2INT_SUCCESS,
  13.     STR2INT_OVERFLOW,
  14.     STR2INT_UNDERFLOW,
  15.     STR2INT_INCONVERTIBLE
  16. } str2int_errno;
  17.  
  18. int largoHash;
  19. //---------------------------------------------------------------------------
  20.  
  21. void clean(void)
  22. {
  23.     char a;
  24.     while(getchar()!='\n');
  25. }
  26. //---------------------------------------------------------------------------
  27.  
  28. void ObtenerRutas(char *pathOrigen1,char *pathOrigen2,char *pathDestino2,int *largoHash)
  29. {
  30.     int largo;
  31.  
  32.     printf("Introduce la ruta completa hacia el primer archivo:\n\t");
  33.     fgets(pathOrigen1,SIZEMAX,stdin);
  34.     largo=strlen(pathOrigen1);
  35.     if(pathOrigen1[largo-1]!='\n'){
  36.         clean();
  37.         printf("Ruta demasiado larga.\n");
  38.     }else{
  39.         pathOrigen1[largo-1]='\0';
  40.     }
  41.     printf("Introduce la ruta completa hacia el segundo archivo:\n\t");
  42.     fgets(pathOrigen2,SIZEMAX,stdin);
  43.     largo=strlen(pathOrigen2);
  44.     if(pathOrigen2[largo-1]!='\n'){
  45.         clean();
  46.         printf("Ruta demasiado larga.\n");
  47.     }else{
  48.         pathOrigen2[largo-1]='\0';
  49.     }
  50.     printf("Introduce la ruta completa para el archivo de salida:\n\t");
  51.     fgets(pathDestino2,SIZEMAX,stdin);
  52.     largo=strlen(pathDestino2);
  53.     if(pathDestino2[largo-1]!='\n'){
  54.         clean();
  55.         printf("Ruta demasiado larga.\n");
  56.     }else{
  57.         pathDestino2[largo-1]='\0';
  58.     }
  59.     printf("Introduce el numero de caracteres del hash: ");
  60.     scanf("%d",largoHash);
  61. }
  62. //---------------------------------------------------------------------------
  63.  
  64. //Para convertir el parametro del largo del hash de cadena a entero
  65. str2int_errno str2int(int *out, char *s, int base) {
  66.     char *end;
  67.     long l;
  68.  
  69.     if (s[0] == '\0' || isspace((unsigned char) s[0]))
  70.         return STR2INT_INCONVERTIBLE;
  71.     errno = 0;
  72.     l = strtol(s, &end, base);
  73.  
  74.     if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
  75.         return STR2INT_OVERFLOW;
  76.     if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
  77.         return STR2INT_UNDERFLOW;
  78.     if (*end != '\0')
  79.         return STR2INT_INCONVERTIBLE;
  80.     *out = l;
  81.     return STR2INT_SUCCESS;
  82. }
  83. //---------------------------------------------------------------------------
  84.  
  85. int CheckParams(int nParametros, char *parametros[], char *pathOrigen1,char *pathOrigen2,char *pathDestino2,int *largoHash)
  86. {
  87.     str2int_errno error_param_hash;
  88.     char mensaje[SIZEMAX];
  89.  
  90.     if(nParametros == 5){
  91.         strcpy(pathOrigen1,parametros[1]);
  92.         strcpy(pathOrigen2,parametros[2]);
  93.         strcpy(pathDestino2,parametros[3]);
  94.         error_param_hash=str2int(largoHash,parametros[4],10);
  95.         switch(error_param_hash){
  96.             case STR2INT_OVERFLOW:
  97.                 strcpy(mensaje,"STR2INT_OVERFLOW");
  98.             break;
  99.  
  100.             case STR2INT_UNDERFLOW:
  101.                 strcpy(mensaje,"STR2INT_UNDERFLOW");
  102.             break;
  103.  
  104.             case STR2INT_INCONVERTIBLE:
  105.                 strcpy(mensaje,"STR2INT_INCONVERTIBLE");
  106.             break;
  107.         }
  108.         if(error_param_hash != STR2INT_SUCCESS){
  109.             printf("Error en el parametro para el largo del hash. Error: %s\n",mensaje);
  110.             return -1;
  111.         }
  112.         if(*largoHash < 0){
  113.             printf("El valor asignado al largo del hash no puede ser menor que '0'.\nSi no hay hash ponga '0'.\n");
  114.             return -2;
  115.         }
  116.     }else if(nParametros > 1){
  117.         printf("parametros incorrectos.\n");
  118.         return -3;
  119.     }else{
  120.         ObtenerRutas(pathOrigen1,pathOrigen2,pathDestino2,largoHash);
  121.     }
  122.     return 0;
  123. }
  124. //---------------------------------------------------------------------------
  125.  
  126. void DescartarElemento(char **buffer,int pos,int *nElementos)
  127. {
  128.     int i;
  129.  
  130.     for(i=pos; i < *nElementos-1; i++){
  131.         buffer[i]=buffer[i+1];
  132.     }
  133.     (*nElementos)--;
  134. }
  135. //---------------------------------------------------------------------------
  136.  
  137. int CrearFicheroOrdenado(char **bufferFile1,char **bufferFile2,char *pathDestino,int largoHash,int nElementosBufferFile1,int nElementosBufferFile2)
  138. {
  139.     FILE *destino=NULL;
  140.     int encontrado,noEncontrados=0;
  141.     int i,j,retval=0;
  142.     char **arrayAuxiliar;
  143.  
  144.     destino=fopen(pathDestino,"w");
  145.  
  146.     if(destino == NULL)
  147.         return -1;
  148.  
  149.     printf("Ha comenzado el proceso. No cierre esta ventana hasta que termine el proceso.\n");
  150.     arrayAuxiliar=malloc(nElementosBufferFile2 * sizeof(char**));
  151.  
  152.     if(arrayAuxiliar == NULL){
  153.         fclose(destino);
  154.         remove(pathDestino);
  155.         return -2;
  156.     }
  157.  
  158.     memcpy(arrayAuxiliar,bufferFile2,nElementosBufferFile2 * sizeof(char**));
  159.  
  160.     for(i=0; i < nElementosBufferFile1; i++){
  161.         encontrado=0;
  162.         for(j=0; j < nElementosBufferFile2; j++){
  163.             if(strcmp(bufferFile1[i],arrayAuxiliar[j])==0){
  164.                 encontrado=1;
  165.                 break;
  166.             }
  167.         }
  168.         if(encontrado==1){
  169.             fputs(arrayAuxiliar[j],destino);
  170.             DescartarElemento(arrayAuxiliar,j,&nElementosBufferFile2);
  171.         }else{
  172.             fputs("\n",destino);
  173.             noEncontrados++;
  174.         }
  175.     }
  176.     free(arrayAuxiliar);
  177.     fclose(destino);
  178.  
  179.     if(noEncontrados > 0)
  180.         retval=noEncontrados;
  181.  
  182.     return retval;
  183. }
  184. //---------------------------------------------------------------------------
  185.  
  186. void LiberarMemoria(char **buffer,int nlines)
  187. {
  188.     int index;
  189.  
  190.     if(buffer != NULL){
  191.         for(index=0;index < nlines;index++)
  192.             free(buffer[index]);
  193.         free(buffer);
  194.         buffer=NULL;
  195.     }
  196. }
  197. //---------------------------------------------------------------------------
  198.  
  199. char** CargarFicheroEnMemoria(char *path,int *nlines)
  200. {
  201.     int largo;
  202.     char aux[SIZEMAX];
  203.     char **pbuffer,**paux;
  204.     FILE *origen;
  205.     origen=fopen(path,"r");
  206.  
  207.     *nlines=0;
  208.     if(origen != NULL){
  209.         pbuffer=NULL;
  210.         do{
  211.             memset(aux,'\0',SIZEMAX);
  212.             fgets(aux,SIZEMAX,origen);
  213.             if(!feof(origen)){
  214.                 largo=strlen(aux);
  215.                 (*nlines)++;
  216.                 paux=(char**)realloc(pbuffer,*nlines*sizeof(char**));
  217.                 if(paux != NULL){
  218.                     pbuffer=paux;
  219.                     pbuffer[*nlines-1]=(char*)malloc(sizeof(char*)*largo);
  220.                     strcpy(pbuffer[*nlines-1],aux);
  221.                 }else{
  222.                     printf("No hay suficiente memoria disponible para volcar el archivo.\n");
  223.                     LiberarMemoria(pbuffer,*nlines-1);
  224.                 }
  225.             }
  226.         }while(!feof(origen));
  227.         fclose(origen);
  228.     }
  229.     return pbuffer;
  230. }
  231. //---------------------------------------------------------------------------
  232.  
  233. /* funcion para comparar strings de C para qsort */
  234. int cstring_cmp(const void *a, const void *b)
  235. {
  236.     const char **ia = (const char **)a;
  237.     const char **ib = (const char **)b;
  238.     return strcmp(*ia+largoHash, *ib+largoHash);
  239. }
  240. //---------------------------------------------------------------------------
  241.  
  242. //Se puede usar con parametros tambien
  243. int main(int argc, char* argv[])
  244. {
  245.     char pathOrigen1[SIZEMAX];
  246.     char pathOrigen2[SIZEMAX];
  247.     char pathDestino[SIZEMAX];
  248.     char **bufferFile1,**bufferFile2;
  249.     int nElementosFile1,nElementosFile2,retval;
  250.  
  251.     if(CheckParams(argc,argv,pathOrigen1,pathOrigen2,pathDestino,&largoHash) == 0){
  252.         if((bufferFile1=CargarFicheroEnMemoria(pathOrigen1,&nElementosFile1)) > 0){
  253.             if((bufferFile2=CargarFicheroEnMemoria(pathOrigen2,&nElementosFile2)) > 0){
  254.                 //Ordeno los elementos
  255.                 qsort(bufferFile2, nElementosFile2, sizeof(char *), cstring_cmp);
  256.                 retval=CrearFicheroOrdenado(bufferFile1,bufferFile2,pathDestino,largoHash,nElementosFile1,nElementosFile2);
  257.  
  258.                 switch(retval){
  259.                     case 0:
  260.                         printf("Proceso finalizado correctamente.\n");
  261.                         break;
  262.                     case -1:
  263.                         printf("Proceso finalizado con errores.\n");
  264.                         printf("No se pudo abrir el archivo \"%s\".\n",pathOrigen2);
  265.                         break;
  266.                     case -2:
  267.                         printf("Proceso finalizado con errores.\n");
  268.                         printf("No se pudo obtener memoria suficiente.\n");
  269.                         break;
  270.                     default:
  271.                         printf("Proceso finalizado.\n");
  272.                         printf("No se encontraron %d entradas en \"%s\".\n",retval,pathOrigen2);
  273.                 }
  274.                 //Libero la memoria solicitada para guardar el archivo en ella
  275.                 LiberarMemoria(bufferFile2,nElementosFile2);
  276.             }
  277.             LiberarMemoria(bufferFile1,nElementosFile1);
  278.         }
  279.     }
  280.     system("pause");
  281.     return 0;
  282. }
  283. //---------------------------------------------------------------------------
  #14 (permalink)  
Antiguo 08/07/2016, 12:52
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

La unica pega que tengo es que he tenido que colocar la variable largoHash como global porque tengo que usarla en la funcion cstring_cmp que es la que le paso como parametro a qsort y si intento ponerle otro parametro no me deja asi que si alguien tiene una sugerencia para no tener que ponerla como global soy todo oidos jejeje.
Por otro lado acepto criticas constructivas para mejorar el codigo y mi aptitud a la hora de codear pero por favor, criticas del estilo "¿se puede hacer peor?" no aportan nada y pueden desmoralizar a aquellos que empezamos y que, mas que ese tipo de criticas, necesitamos apoyo para no desanimarnos y acabar abandonando. A mi no me ha molestado eso aunque despues de varias horas codeando y esforzandome a tope por intentar hacerlo lo menor posible, ese comentario me cayó como un jarro de agua fria y la verdad es que me ha desanimado bastante y casi acabo borrando el codigo y olvidarme de el pero soy muy cabezon y me gusta mucho esto como para dejarlo de lado.
Al margen de eso, el tiempo ha mejorado de tardar unos 5 minutos a tardar unos 10 segundos .
  #15 (permalink)  
Antiguo 08/07/2016, 15:37
 
Fecha de Ingreso: abril-2016
Mensajes: 31
Antigüedad: 8 años, 7 meses
Puntos: 5
Respuesta: ¿Se puede optimizar el siguiente codigo?

Hola; lamento que mi comentario te haya desmoralizado; releyendo veo que quedó bastante rudo, pero no fue intencional.
Como comentaste que estás empezando, permitime sugerirte que aproveches este mismo programa como incentivo y caso de estudio para el tema "ordenación y búsqueda", que creo que te va a resultar interesante.
Por ejemplo, yo te había sugerido (Thug Life mode) ordenar primero y "bsearch" después. Una búsqueda binaria sobre la segunda lista en memoria seguramente va a mejorar mucho. Te dejo un link básico, que tiene un ejemplo:
http://pubs.opengroup.org/onlinepubs/009695399/functions/bsearch.html
(básico, no trivial, claro; a partir de ahí podés buscar otros ejemplos y explicaciones).
Y como comentario medio irresponsable, porque no me puse a analizar tu código como si fuera para entregar mañana, se me ocurren un par de cosas mucho menos relevantes que hacer una búsqueda binaria antes que n x n secuenciales, como que me parece que sólo necesitas cargar en memoria y ordenar el segundo archivo, y el primero podés ir leyéndolo línea por línea así como está.
Otra cosa que puede mejorar los tempos un poquito más es tratar de evitar los realloc, lo más posible. Por ejemplo, quizá puedas leer las líneas del segundo archivo y ponerlas en un array de tamaño predeterminado; la cantidad de líneas la podés obtener dividiendo el largo del archivo por la longitud de cada línea. Ese arrya de cadenas pude ocupar un poco más de memoria, pero por un lado estarías cargando en memoria un solo archivo y no dos, y por el otro, la diferencia vale la pena en términos de "performance".

Si se tratara de mis prioridades y mis tiempos, yo dedicaría: dos días al tema "ordenación y búsqueda" (lecturas, desarrollo de ejemplos, comparaciones); un día para acomodar mi programa a lo nuevo que haya aprendido; un día para corregir y optimizar; 2 horas más para anotar y comentar mis conclusiones. Y con eso, y un par de oportunidades donde aplicar lo aprendido, ya me quedaría en paz con el tema hasta la próxima oportunidad.
  #16 (permalink)  
Antiguo 08/07/2016, 18:26
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Se puede optimizar el siguiente codigo?

Te comento algunos detalles:
No sabia de la existencia de qsort y bsearch y me parecen geniales. Sólo tengo una duda ¿que tan eficientes son? Lo digo porque, por ejemplo entre usar memset y un bucle, el bucle es más rápido y en temas de fuerza bruta es mejor evitar memset y no se si estas funciones adolecen del mismo problema. Otra cosa que he visto es que bsearch dice que si hay elementos duplicados el resultado es impredecible.
El tema de leer el archivo entero y obtener el número de elementos dividiendo por un tamaño determinado... creo que no es posible ya que no es un archivo secuencial y cada línea tiene un tamaño diferente.
Lo de leer el primer archivo línea a línea sin volcarlo en memoria, ciertamente ya lo leo línea a línea y no se porque lo metí en memoria jajaja. Tendré que probar ese cambio a ver que pasa.
Me parece que la mejora que ha tenido en tiempo es brutal y sabia que era más eficiente trabajar con memoria que con archivos pero no me esperaba tanta diferencia.
También tengo entendido que en eficiencia el único lenguaje capaz de plantar cara a C y ganarle es ASM ¿es cierto eso?
  #17 (permalink)  
Antiguo 08/07/2016, 18:46
 
Fecha de Ingreso: abril-2016
Mensajes: 31
Antigüedad: 8 años, 7 meses
Puntos: 5
Respuesta: ¿Se puede optimizar el siguiente codigo?

qsort y bsearch
Cita:
¿que tan eficientes son?
Creo que es el patrón más eficiente incluido en la biblioteca estándar del C. bsearch implementa el concepto de búsqueda binaria sobre una secuencia ordenada. Información razonable acá:
https://en.wikipedia.org/wiki/Binary_search_algorithm

Cita:
Me parece que la mejora que ha tenido en tiempo es brutal
Si usaras una búsqueda binaria tendrías que llegar a los milisegundos.

Cita:
el único lenguaje capaz de plantar cara a C y ganarle es ASM ¿es cierto eso?
No, no lo creo; el C++ es casi siempre más eficiente que el C, y en el peor de los casos es igual. Por ejemplo, el std::sort del C++ es entre 2 o 3 veces más rápido que qsort.

Ah, me olvidaba
Cita:
bsearch dice que si hay elementos duplicados el resultado es impredecible
Código C:
Ver original
  1. void *bsearch(const void *key, const void *base, size_t nel,
  2.        size_t width, int (*compar)(const void *, const void *));
bseach devuelve un puntero al valor en "base" que se corresponde con la "key"; si "base" tuviera valores repetidos, bsearch va a devolver un puntero a uno de esos, que puede ser el primero en la secuencia o no, no sabremos cuál.

Última edición por enrieto; 08/07/2016 a las 19:18

Etiquetas: char, int, numero, siguiente
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:32.