Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1822 connectés 

  FORUM HardWare.fr
  Programmation
  C

   choix du structure des données

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

choix du structure des données

n°1936798
msedirim
Posté le 01-11-2009 à 16:32:26  profilanswer
 


Bonjour,
 
Je vais refaire une grande partie de mon travail car j'ai mal choisi les structures des données car les accès fichiers sont plus coûteux. Tout mon travail se base sur les fichiers même les résultats
intermédiaires. Le but de mon travail est de trouver une solution à mon problème mais de plus minimiser le plus possible le temps d'exécution (le mesure le temps en utilisant la fonction 'clock()'.
 
Mais, lorsque j'ai testé le temps de l'exécution concernant la comparaison de deux fichiers selon les critères bien définis alors j'ai remarqué que le temps est devenir très longue si nous avons des fichiers avec des centaines lignes. On va lire chaque ligne de fichier 1 et le compare avec tous les lignes de fichier 2. C'est très couteux.
 
D'après vous :
- Avec quelles structures des données ces deux fichiers seront remplacés ?
 
- En général,quelle est la structure des données la moins couteuse en
mémoire et donc temps d'exécution le plus inférieur possible ?
 
Je souhaite que vous m'aidez.
 
Merci.

mood
Publicité
Posté le 01-11-2009 à 16:32:26  profilanswer
 

n°1936804
Joel F
Real men use unique_ptr
Posté le 01-11-2009 à 16:58:05  profilanswer
 

je comprends rien, tu pourrais pas donner encore moins de details ?

n°1936818
msedirim
Posté le 01-11-2009 à 17:43:27  profilanswer
 

Bonjour,
 
Dans mon programme C, la fonction de comparaison est :

Code :
  1. *rets = compare_files("f.txt", "f2.txt" );


 
 
Je passe deux fichiers "f.txt" et "f2.txt" à la fonction 'compare_files'
la taille de "f.txt" est toujours plus grande que "f2.txt".
chaque ligne de deux fichiers contient une chaine de caractère.
 
Je cherche les lignes qui appartiennent à "f.txt" et non pas "f2.txt"
C'est une sorte de différence lignes de "f.txt" moins lignes de "f2.txt"
à condition:
Une ligne de "f.txt" est identique à une ligne de "f2.txt"
si les deux lignes ont la même valeur et le même nombre des mots qui forment les deux lignes quelque soit l'ordre des mots puisque l'ordre des mots n'est pas important dans mon problème.
le plus important c'est : la même valeur et le même nombre
 
Sinon c'est à dire les deux lignes n'ont pas la même valeur et le même nombre des mots alors dans ce cas les deux lignes sont différentes.
 
par exemple:
"nom prenom age" = "nom age prenom"
 
Sachant que chaque ligne du deux fichiers "f.txt" et "f2.txt" est composé d'un seul champ (une chaine de caractères)
 
Soit le premier fichier fichier "f.txt":
nom prenom
nom age
prenom age
prenom emploi
nom prenom age
nom emploi
age emploi
prenom age emploi
nom age emploi
nom prenom emploi
nom prenom age emploi
 
Soit le deuxième fichier "f2.txt":
 
nom
prenom
age
emploi
age nom
nom age prenom
nom emploi
age emploi
prenom age emploi
nom prenom emploi
 
On applique le principe de comparaison alors on obtient ce résultat intermédiaire:
nom prenom
nom age emploi
nom prenom age emploi
 
Puis, on garde de ce résultat que les chaines qui ne contiennent pas autre chaine de ce résultat.
ici, on ne garde pas la chaine "nom prenom age emploi" car elle contienne la chaine "nom prenom"
Le résultat final souhaité obtenu est :
nom prenom
nom age emploi
 
Voici le code de la fonction 'compare_files'
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #define OUTPUT_NAME "finalresult.txt"
  6. /* Nom du fichier dans lequel le resultat est stocké */
  7. #define MAX_SIZE 1024
  8. /* Taille maximale d'une ligne du fichier */
  9. /** Teste le retour de realloc et quitte le programme si besoin */
  10. void * xrealloc(void * prec, size_t len)
  11. {
  12.     void *ret = realloc(prec, len);
  13.     if(!ret) /* Equivaut à if(ret == NULL) */
  14.         exit(0xDEAD);
  15.     return ret;
  16. }
  17. /** Copie n caractère de str dans une nouvelle chaine alloué dynamiquement, et renvoie cette chaine */
  18. char * mstrndup(const char *str, size_t n)
  19. {
  20.     char *ret = malloc((n+1) * sizeof(char));
  21.     if (!ret)
  22.         exit(0xDEAD);
  23.     strncpy(ret, str, n); /* Copie n caractère de str dans n */
  24.     ret[n] = 0; /* 0 == '\0' */
  25.     return ret;
  26. }
  27. /** Libère le tableau de chaine de caractère t de len chaine de caractère */
  28. void free_tab(char **t, size_t len)
  29. {
  30.     if (t)
  31.     {
  32.         size_t i;
  33.         for (i = 0; i < len; i++)
  34.             free(t[i]);
  35.         free(t);
  36.     }
  37. }
  38. /** Libère le tableau de chaine de caractère t et s'arrête lorsqu'un pointeur NULL est rencontré */
  39. void free_tab2(char **t)
  40. {
  41.     size_t i = 0;
  42.     while (t && t[i])
  43.         free(t[i++]);
  44.     free(t);
  45. }
  46. /** Compte le nombre de mot dans str (un mot correspond à une suite de lettre et s'arrête dès qu'un caractère autre est rencontré */
  47. size_t count_word(const char *str)
  48. {
  49.     size_t n = 0;
  50.     int a;
  51.     while (*str) /* Equivaut à while(*str != '\0') */
  52.     {
  53.         a = 0; /* Cette variable sert à indiquer si au moins une lettre a été trouvé (pour éviter les lignes vides) */
  54.         while (isalpha((unsigned char) *str) && *str) str++, a = 1; /* Tant que c'est une lettre et que ce n'est pas la fin de la chaine, on parcourt la chaine
  55.         et on met a à 1 pour indiquer qu'on a trouvé au moins une lettre */
  56.         if (a) n++; /* Si on a trouvé au moins une lettre, on augmente le nombre de mot */
  57.         while (!isalpha((unsigned char) *str) && *str) str++; /* On saute tous les caractères qui ne sont pas des lettres */
  58.     }
  59.     return n;
  60. }
  61. /** copie les mots de la chaine str dans le tableau de chaine de caractère tab */
  62. void get_word(char **tab, const char *str)
  63. {
  64.     const char* p = str;
  65.     int a, i = 0;
  66.     /* Le fonctionnement est le même que pour la fonction count_word mais ici on enregistre la chaien dans un tableau. On pourrait le faire en une seule
  67.     fonction mais il faudrai à chaque fois réallouer de la mémoire et ce n'est pas très propre */
  68.     while (*str)
  69.     {
  70.         a = 0;
  71.         while (isalpha((unsigned char) *p) && *p) p++, a = 1;
  72.         if (a)
  73.             tab[i++] = mstrndup(str, p-str); /* Si on a trouvé un mot, on met dans tab[i] le mot (la suite de lettre trouvé) et on incrémente i.
  74.             p-str correspond à la taille du mot, c'est l'adresse du caractère suivant le dernier caractère moins l'adresse du premier caractère */
  75.         while (!isalpha((unsigned char) *p) && *p) p++;
  76.         str = p;
  77.     }
  78. }
  79. /** Compare deux tableaux de mots, renvoie 1 si ces tableaux sont identiques sans tenir compte de l'ordre ni du nombre de mot, 0 sinon (En fait, il renvoie 1
  80.     si chaque ligne de t1 existe dans t2) */
  81. int compareline(char **t1, size_t size1, char **t2, size_t size2)
  82. {
  83.     int ret = 1;
  84.     size_t i, j;
  85.     int a;
  86.     /* Pour chaque ligne de t1, on compare avec chaque ligne de t2. Si à un moment on ne trouve pas la ligne, alors les tableaux ne sont pas identiques */
  87.     for (i = 0; i < size1; i++)
  88.     {
  89.         a = 0;
  90.         for (j = 0; j < size2; j++)
  91.             if (!strcmp(t1[i], t2[j]))
  92.             {
  93.                 a = 1;
  94.                 break; /* Dès que la ligne est trouvé, on peux arrêter de comparer pour cette valeur du tableau */
  95.             }
  96.         if (!a)
  97.         {
  98.             ret = 0;
  99.             break; /* Dès qu'une ligne manque, on peux arrêter la comparaison */
  100.         }
  101.     }
  102.     return ret;
  103. }
  104. /** Compare deux chaines de caractère, si comparesize vaut 1 alors la première doit contenir la seconde, et renvoie 1 si elles sont identiques sans tenir
  105.     compte de l'ordre des mots */
  106. int is_same(const char *s1, const char *s2, int comparesize)
  107. {
  108.     char **t1, **t2;
  109.     size_t size1 = count_word(s1), size2 = count_word(s2);
  110.     int ret = 0;
  111.     if (!comparesize || (size1 > size2)) /* Si comparesize vaut 0, on ne compare pas la taille, si comparesize vaut 1 alors il faut que size1 > size 2 */
  112.     {
  113.         t1 = malloc(size1 * sizeof(char*));
  114.         t2 = malloc(size2 * sizeof(char*));
  115.         if (t1 && t2)
  116.         {
  117.             get_word(t1, s1);
  118.             get_word(t2, s2);
  119.             ret = comparesize? compareline(t2, size2, t1, size1) : compareline(t1, size1, t2, size2);
  120.             free_tab(t1, size1), free_tab(t2, size2);
  121.         }
  122.         else
  123.             exit(0xDEAD);
  124.     }
  125.     return ret;
  126. }
  127. /** Compare deux fichiers er renvoie le résultat de la comparaison */
  128. char ** compare_files(const char *filename1, const char *filename2)
  129. {
  130.     FILE *f = fopen(filename1, "r" ), *f2 = fopen(filename2, "r" );
  131.     char s[MAX_SIZE], s2[MAX_SIZE];
  132.     int a, retsize = 0;
  133.     char **ret = NULL;
  134.     if (f && f2) /* Si les fichiers sont bien ouverts */
  135.     {
  136.         while (fgets(s, MAX_SIZE, f)) /* C'est la même principe que dans la fonction compareline en fait */
  137.         {
  138.             a = 0;
  139.             rewind(f2);
  140.             while (fgets(s2, MAX_SIZE, f2))
  141.                 if (is_same(s, s2, 0))
  142.                 {
  143.                     a = 1;
  144.                     break;
  145.                 }
  146.             if (!a)
  147.             {
  148.                 ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On alloue une case de plus au tableau de string, puis on ajoute la chaine à la fin du tableau */
  149.                 ret[retsize-1] = mstrndup(s, strlen(s));
  150.             }
  151.         }
  152.         fclose(f), fclose(f2);
  153.         ret = xrealloc(ret, (++retsize) * sizeof(char*)); /* On ajoute un dernier pointeur sur NULL pour savoir quand le tableau se termine */
  154.         ret[retsize-1] = NULL;
  155.     }
  156.     else /* Si un fichier n'a pas pu être ouvert, on ferme eventuellement le fichier qui a pu être ouvert */
  157.     {
  158.         if (f) fclose(f);
  159.         if (f2) fclose(f2);
  160.     }
  161.     return ret;
  162. }
  163. /** Ecrit le tableau de len chaines de caractère dans le flux f */
  164. void write_tab(FILE *f, char **t, size_t len)
  165. {
  166.     size_t i;
  167.     for (i = 0; t && i < len; i++)
  168.         if (t[i])
  169.             fprintf(f, t[i]);
  170. }
  171. void disp_tab(char **t)
  172. {
  173.     size_t i;
  174.     for (i = 0; t && t[i]; i++)
  175.         printf(t[i]);
  176. }
  177. int main(void)
  178. {
  179. #define MAXFILE 3
  180. /* Le nombre de fichier à comparer, on compare f.txt à f1.txt, f2.txt etc... */
  181. #define MAXTMP 10
  182. /* La taille maximum du nom de fichier */
  183. #define N 4
  184.     char **rets[MAXFILE] = {NULL}, tmp[MAXTMP];
  185.     char **interret = NULL;
  186.     size_t interret_size = 0;
  187.     int i,j,k;
  188.     int a, b;
  189.     int equN = 0, equN1 = 0, equothr = 0, equi = 0;
  190.     FILE *output;
  191.     *rets = compare_files("f.txt", "f1.txt" );
  192.     i = 0;
  193.     while(*rets && (*rets)[i]) /* On teste toutes les lignes */
  194.     {
  195.         a = count_word((*rets)[i]); /* On récupère le nombre de mot */
  196.         if(a == N) /* Si il vaut N, on augmente le "compteur de N" et on enregistre la position de la chaine, pour pouvoir la supprimer ensuite sans avoir
  197.         à reparcourir la tableau (gain de temps) */
  198.           equN++, equi = i;
  199.         else if (a == (N-1)) /* S'il vaut N-1, on augmente le "compteur de N-1" */
  200.           equN1++;
  201.         else if (a < (N-1))
  202.           equothr = 1; /* S'il y a une ligne qui comporte moins de N-1 mot, alors on utilise la méthode classique */
  203.         i++;
  204.     }
  205.     if(equN == 1 && !equothr) /* S'il y a exactement 1 ligne avec N mots et pas de ligne comportant moins de (N-1) mot*/
  206.     {
  207.         if(equN1) /* S'il y a au moins 1 ligne de (N-1) mots (s'il n'y en a pas 0 en fait) */
  208.         {
  209.             interret = *rets; /* Le resultat final est la premiere comparaison */
  210.             interret_size = i; /* La taille du tableau */
  211.             free((*rets)[equi]), (*rets)[equi] = NULL; /* On supprime la ligne contenant N mots */
  212.         }
  213.         else /* Sinon, on ne récupère que la premiere ligne */
  214.         {
  215.           interret = *rets;
  216.           interret_size = 1;
  217.           for(i = 1; rets[0][i]; i++)
  218.             free(rets[0][i]), rets[0][i] = NULL;
  219.         }
  220.     }
  221.     else
  222.     {
  223.       for (i = 1; i < MAXFILE; i++) /* Pour chaque fichier */
  224.       {
  225.           sprintf(tmp, "f%d.txt", i+1);
  226.           rets[i] = compare_files("f.txt", tmp); /* On comparer f.txt avec f%d.txt où %d est un nombre de 1 à MAXFILE */
  227.           /*disp_tab(rets[i]);
  228.           getchar();*/
  229.       }
  230.       i = 0;
  231.       while (rets[0] && rets[0][i]) /* Tant que ça ne vaut pas NULL */
  232.       {
  233.           a = b = 0;
  234.           for (j = 1; j < MAXFILE; j++) /* On compare le premier avec tous les autres */
  235.           {
  236.               k = 0;
  237.               while (rets[j] && rets[j][k]) /* On parcourt le tableau en entier (je rappelle qu'il est terminé par NULL */
  238.               {
  239.                   if (!strcmp(rets[0][i], rets[j][k])) /* Si on trouve une ligne identique */
  240.                   {
  241.                       a = 1; /* On met a à 1, c'est à dire que la ligne rets[0][i] existe dans ret[j] */
  242.                       break;
  243.                   }
  244.                   k++;
  245.               }
  246.               if (!a) /* Si on a pas trouvé la ligne, alors on met b à 1, ça veux dire que la ligne du tableau n'existe pas dans tous les autres tableaux */
  247.               {
  248.                   b = 1;
  249.                   break;
  250.               }
  251.           }
  252.           if (!b) /* Si b vaut 0 (on a trouvé la ligne ret[0][i] dans tous les tableaux ret[j] avec 0 < j < MAXFILE) */
  253.           {
  254.               interret = xrealloc(interret, (++interret_size) * sizeof(char*));
  255.               interret[interret_size-1] = mstrndup(rets[0][i], strlen(rets[0][i])); /* On recopie la ligne dans un nouveau tableau */
  256.           }
  257.           i++;
  258.       }
  259.       for (i = 0; i < MAXFILE; i++) /* On nettoie les tableaux issus des comparaison maistenant que l'intersection a été faite */
  260.           free_tab2(rets[i]);
  261.       for (i = 0; i < interret_size; i++) /* Pour chaque case du tableau... */
  262.       {
  263.           for (j = 0; interret[i] && j < interret_size; j++) /* On compare avec toutes les cases tant que la case actuelle ne vaut pas NULL */
  264.           {
  265.               if (interret[j] && j != i) /* Si la case qu'on veux comparer ne vaut pas NULL et que i est différent de j (sinon on compare la même case!) */
  266.                   if (is_same(interret[i], interret[j], 1)) /* Si interret[j] est inclu dans interret[i] */
  267.                   {
  268.                       free(interret[i]), interret[i] = NULL; /* On supprime la case */
  269.                       break;
  270.                   }
  271.           }
  272.       }
  273.     }
  274.     if((output = fopen(OUTPUT_NAME, "w+" )) != NULL) /* On ouvre le fichier et on écrit le résultat si le fichier a bien été ouvert */
  275.     {
  276.         write_tab(output, interret, interret_size);
  277.         fclose(output);
  278.     }
  279.     free_tab(interret, interret_size); /* On nettoie le dernier tableau */
  280.     return 0;
  281. }


 
Que proposez vous ?
 
Merci.


Message édité par msedirim le 01-11-2009 à 17:45:28
n°1936825
Joel F
Real men use unique_ptr
Posté le 01-11-2009 à 17:53:39  profilanswer
 

Deja ecris des fonctions au lieu de bananer tout dans un main imbitable.
Et quel est l'itneret de tes fonctions qui wrappe la libc ?

n°1936832
GrosBocdel
Posté le 01-11-2009 à 18:31:02  profilanswer
 

C'est lent comment?
Tes fichiers sont gros comment? Est ce que tu peux les faire tenir en mémoire plutot que de les relire n1*n2 fois?
Est-ce que tu ne pourrais pas remplacer tes chaines de caractères par des trucs qui les représenteraient de façon unique (des checksums peut-être???) et dont la comparaison serait plus rapide? (faut demander à quelqu'un d'autre que moi pour ces aspects)
 

n°1936867
msedirim
Posté le 01-11-2009 à 21:08:25  profilanswer
 

Citation :

C'est lent comment?


Lorsque je mesure le temps d'exécution de ce traitement de comparaison en utilisant la fonction 'clock()' alors j'obtiens un temps plus élevé même des milliers de secondes pour un fichier de centaines des lignes.

Code :
  1. debut = clock();
  2. //comparaison entre deux fichiers
  3. fin = clock();
  4. fprintf(stderr, "temps : %f\n", (double)(fin-debut) / (double) CLOCKS_PER_SEC);


 
 

Citation :

Tes fichiers sont gros comment? Est ce que tu peux les faire tenir en mémoire plutot que de les relire n1*n2 fois?


Le fichier peut contenir des centaines de lignes et chaque ligne contient une chaine de caractère (ensemble des mots).
Je voulais les  les faire tenir en mémoire mais comment faire ceci ? et avec quelle structure des données on peut faire ceci?
 

Citation :

Est-ce que tu ne pourrais pas remplacer tes chaines de caractères par des trucs qui les représenteraient de façon unique (des checksums peut-être???) et dont la comparaison serait plus rapide?


n°1936908
GrosBocdel
Posté le 02-11-2009 à 07:48:56  profilanswer
 

regarde peut-être du coté des listes chainées?


Message édité par GrosBocdel le 02-11-2009 à 07:49:06
n°1937161
msedirim
Posté le 03-11-2009 à 09:51:20  profilanswer
 

Bonjour,
 
J'ai trouvé sur le net que le tableau est plus rapide que la liste chainée au niveau accès.
C'est vraie ? Sinon, pourquoi ?

n°1937394
GrosBocdel
Posté le 03-11-2009 à 20:07:36  profilanswer
 

msedirim a écrit :

Bonjour,
 
J'ai trouvé sur le net que le tableau est plus rapide que la liste chainée au niveau accès.
C'est vraie ? Sinon, pourquoi ?


 
Oh, ptet bien.
Si tu veux accéder à n'importe quel élément de ton ensemble de données, le tableau sera plus rapide car on y accède directement par tab[i], alors que pour ta liste chainée, il faut parcourir tous les éléments qui le précèdent
 
Seulement là:  
-Tu ne connais pas le nombre d'éléments de ton fichier1 et de ton fichier2, alors tu leur donnes quelle taille initiale à tes tableaux?
-Tu cherches des doublons dans tes données : avec ta liste chainée, tu peux les supprimer, tes comparaisons s'accélèrent au fur et à mesure puisqu'il y a moins d'éléments, et à la fin de ton algo, il ne te reste que tes éléments uniques.
-Tu dois de toute façon regarder tous tes éléments un par un.
 
Ptet bien autre chose.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

   choix du structure des données

 

Sujets relatifs
intégrer une base de données .txt a eclispeChoix d'un langage pour production GUI
Choix language pour projetMes données ne s'inscrivent pas dans ma BDD :'(
Rajout d'une structureLien vers une base de données local
[Résolu] Choix d'un schéma d'une tableInsérer des données dans un fichier PDF avec PHP
Faire le lien entre les données d'un array 
Plus de sujets relatifs à : choix du structure des données


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR