Tri d'un fichier

boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 - 19 juil. 2009 à 20:43
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 - 23 juil. 2009 à 15:09
Salut,

J'ai un fichier texte qui contient deux champs:
- cin de type entier
- indication de type chaine de carctère

la taille de deuxième champ est la même dans tout le fichier.
Ce fichier est appelé fich.txt, est le suivant:
10 110101
20 101101
30 111101
40 001101
55 001000
66 110101
79 110001
85 111010
99 010101
1000 100101

Je voudrais écrire un programme C sous Windows pour trier ce fichier selon le deuxième champ indication de sorte que le cin qui contient de plus de 1 dans son indication alors il sera placé en premier lieu.

par exemple:
le cin 10 possède quatre 1 dans son indication
le cin 30 possède cinq 1 dans son indication
et etc...

Donc le résultat il sera dans le même fichier ou autre fichier comme le suivant:
30 111101
85 111011
10 110101
20 101101
66 110101
40 001101
79 110001
99 010101
55 001000

Pouvez-vous m'aider comment je vais procéder ?

Merci.

15 réponses

boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
19 juil. 2009 à 20:56
Salut,

J'ai oublié de mettre la ligne 1000 100101
Donc,le résultat après le tri est :
30 111101
85 111011
10 110101
20 101101
66 110101
40 001101
79 110001
99 010101
1000 100101
55 001000
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
21 juil. 2009 à 16:18
Salut,

Le programme doit pouvoir gérer des gros fichier (>50 Mo) ? => Va falloire pas lire le fichier tout d'un coup -> compliqué.

Ou au contraire très peu de données ? (100 lignes...) -> bubble sort, très simple. Sinon Quick sort.

Ou entre les deux ?
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
22 juil. 2009 à 09:33
Salut,

Je trouve la fonction prédefinie qsort() dans le lien suivant:
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/

- C'est cette fonction que vous me parlez ?

- Est ce que cette fonction est implémenté par un tri rapide ou autre ?

- Cette fonction fait un tri croissant alors comment je vais la changer pour quelle puisse faire un tri décroissant ?

- Comment je vais utiliser cette fonction pour trier mon fichier comme est décrit au dessus ?

Merci.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
22 juil. 2009 à 10:02
C'est marrant, j'ai posé 50 questions et j'ai pas eu de réponses... Je devrais faire pareil : essayer de répondre à côté des questions.

[quote=boualiasma]- C'est cette fonction que vous me parlez ? /quote
Non mais celle là peut marcher aussi.

[quote=boualiasma]- Est ce que cette fonction est implémenté par un tri rapide ou autre ? /quote
Oui c'est bien un tri rapide (quicksort).


[quote=boualiasma]Cette fonction fait un tri croissant alors comment je vais la changer pour quelle puisse faire un tri décroissant ? /quote
Bin c'est facile, il suffit d'inverser la fonction de comparaison.
int compare (const void * a, const void * b)
{
  return ( *(int*)b - *(int*)a );
}


[quote=boualiasma]- Comment je vais utiliser cette fonction pour trier mon fichier comme est décrit au dessus ? /quote
Il y a deux différences majeures.
D'une part ta comparaison est un peu particulière et se fait sur du texte, alors que l'exemple se fait sur des entiers. Ensuite, cette fonction travaille sur un tableau de structures de taille fixe. Ce qui n'est pas le cas de ton fichier a priori. Le premier champs semble de taille variable. Donc il faudrait charger tout ça dans un tableau.

Donc faudrait par exemple que tu définisses une structure.
typedef struct _MY_DATA
{
  char lpField1[10];
  char lpField2[8];
}
MY_DATA;


Et faudrait que tu définisses un tableau de cette structure et que tu la remplisse avec fscanf.

MY_DATA lpFileContent[200];

i = 0;
while (fscanf(lpFile, "%s %s", lpFileContent[i]->lpField1, lpFileContent[i]->lpField2) == 2) i++;


Et enfin que tu appelles qsort.

qsort(lpFileContent, i, sizeof(MY_DATA), compare);


Avec une fonction compare qui compte les "1".
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
22 juil. 2009 à 11:02
Salut,

Tout d'abord je m'excuse car je n'est pas fait attention à vos questions.
je vais répondre:
Oui, je travaille sue des fichiers volumineux.

Oui, je voudrais utiliser le tri rapide.

Vous dites :
int compare (const void * a, const void * b)

{

return ( *(int*)b - *(int*)a );

}

Qu'est ce que je passe à cette fonction comme paramètre et c'est quoi son contenu ?

vous dites :
Avec une fonction compare qui compte les "1".

Mais, je vois que cette fonction compare deux constantes. C'est çà ?


Voici la fonction qui compte le nombre du caractère 1 dans le deuxième champ:

int compte( ch)
char ch[32]
{
int i,k=0;
for(i=0; i < strlen (ch) ; i++)
{
if (ch[i] = '1');
k++;
}
return (k);

}

avec "ch" est le deuxième champ du fichier.

Mais cette fonction compte le nombre de 1. Mais, elle ne fait pas la comparaison.

Avez-vous une solution ?

Merci.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
22 juil. 2009 à 11:54
Cette fonction prend en paramètre deux pointeurs sur des cases du tableau passé à sqsort.
Dans ton cas ce sera deux pointeurs sur des MY_DATA.

Donc ça fera quelque chose comme ça :

int compare (const void * a, const void * b)
{
  MY_DATA* dataA;
  MY_DATA* dataB;

  dataA = (MY_DATA*)a;
  dataB = (MY_DATA*)b;
  return (compte(dataB->lpField2) - compte(dataA->lpField2));
}
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
22 juil. 2009 à 14:00
Salut,

Voici une partie de programme :

typedef struct dataStruct
{
int cin;
char indication[32];
int nombre; //contient le nombre de 1 dans le deuxème champ indication donc je vais faireun tri décroissant sur ce nombre

} dataStruct;

int compare(const void* va,const void* vb)
{
dataStruct* a,b;
a = (dataStruct*)va;
b = (dataStruct*)vb;

return (b.nombre - a.nombre);

// ici, tu as 2 elements a et b, a toi de coder la comparaison : si a<b (selon ton critere) renvoie 1, sinon renvoie 0.

}

int main()
{

....
....
qsort(dataTabString,nCpt,sizeof(dataStruct),compare);


...

}


Après la compilation, j'ai le message d'erreur dans le fonction compare:

Error: incompatible types assignment
Error: request for member 'nombre' in something not a structure or union
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
22 juil. 2009 à 14:04
a et b sont des pointeurs.

return (b->nombre - a->nombre);
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
22 juil. 2009 à 15:46
Salut,

Je vous remercie pour vos aides.

Après le tri de fichier. Il me manque une partie concernant l'indexation du ce fichier.

Soit essai.txt le fichier trié:

3 1111
6 1111
1 1111
10 1011
9 0111
2 1011
4 0011

Ce fichier contient deux champs: cin (un entier) et indication (une chaine de caractère)

Je voudrais décomposer ce fichier en sous fichiers de manière que chaque sous ficher contient le même nombre du caractère 1 dans son deuxième champ appelé indication.
Puisque le fichier est trié dans le sens décroissant ceci nous aide pour faire ceci.

Après la décomposition, Je vais exécuter le même traitement sur chaque sous fichier obtenu.



Je dois obtenir le résultat suivant:
essai1.txt :
3 1111
6 1111
1 1111

essai2.txt :
10 1011
9 0111
2 1011

essai3.txt :
4 0011


Comme vous voyez le fichier essai1.txt contient les cin qui ont quatre 1 dans leurs indications,
le fichier essai2.txt contient les cin qui ont trois 1 dans leurs indications,
le fichier essai3.txt contient les cin qui ont deux 1 dans leurs indications.

S'il vous plaît, Avez-vous une idée comment je vais décomposer le fichier trié de grande taille en sous fichiers de taille moins ?

et comment je vais accéder après à ces sous fichiers ?


Merci.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
22 juil. 2009 à 16:26
Quelque chose dans ce genre là :
previousCount = -1;
fileIndex = 1;
lpFile = NULL;
while (fscanf(%s %s, blabla) == 2)
{
  currentCount = compte(blabla)
  if (currentCount != previousCount)
  {
    if (lpFile) fclose(lpFile);
    sprintf(fileName, "essai%d.txt", fileIndex);
    lpFile = fopen(fileName, "w");
    fileIndex++;
    previousCount = currentCount;
  }
  fprintf("%s %s\n", blabla);
}
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
23 juil. 2009 à 00:41
Salut,

Comment je vais accéder après au sous fichiers ?

Merci.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
23 juil. 2009 à 09:19
Bin soit tu listes proprement les fichier... Mais je crois pas qu'il y ait de méthode portable pour ça.

Unix/Linux-> opendir
Windows -> FindFirstFile

Ensuite avec un ifdef, tu peux avoir un code qui compile partout.

Pour des exemples utiliser google.

Soit tu fais des fopen où tu tests le retour.

FILE* lpFile;
char lpFileName[20];
for (i = 0; i <=6; i++)
{
  sprintf(lpFileName, "essai%d.txt", fileIndex);
  lpFile = fopen(lpFileName, "r");
  if (lpFile)
  {
    ...
    fclose(lpFile);
  }
}


Après je ne sais pas vraiment ce que tu entends par "accéder".

Mais il aurait peut être été plus simple de faire des fichiers :
essaiN.txt ou N est le nombre de 1 dans le champ 2.
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
23 juil. 2009 à 11:31
Salut,

- J'ai dit "accéder" pour dire ouvrir et lire.
- Merci. le dernier code marche bien.

J'ai un petit problème dans la suite de mon travail :

- La fonction compte permet de compter les 1 pour chaque deuxième champ dans le fichier après le tri.
Mais de plus, moi je cherche les positions communes dans chaque chaine de caractère (le deuxième champ) qui contiennent le caractère '0'.
Ce traitement doit être fait avant le tri.
Si je vais appliquer la fonction compte sur le fichier non trié "essai.txt" suivant:
1 110101
2 100101
3 110101
4 000101
5 000000
6 110101
7 110101
8 000000
9 010101
10 100101

Voici la fonction qui compte les '1' où j'ai ajouté un tableau dynamique pour stoker les positions communes de '0':

int compte(ch)
char ch[32];
{
     int *tabPos;
     int i,p=0,k=0,m;
tabPos = (int *) malloc(sizeof(int));
     for(i=0; i < strlen(ch) ; i++)
     {

                if (ch[i] == '1')

                    k=k+1;

                else
                {
              tabPos[p]=i;
              p++;
                }

    }
    printf("\\\\\\\\\\\\\\***\n");
    for(m=0;m<p;m++)
    printf("%d : ",tabPos[m]);
    printf("///////////\n");
  free(tabPos);
  return (k);

}


- J'ai remarqué que on stocke à chaque fois les positions de caractère '0' de deuxième champ (chaine caractère) du chaque ligne du fichier dans un tableau dynamique.
pour chaque deuxième champ de chaque ligne du fichier, on aura un tableau
des positions 0. Mais, ce tableau il sera effacer dans l'itération
suivant car on travaille sur le même tableau.
C'est juste ou non ?

par exemple, pour la première ligne :
1 110101
on aura un tableau qui contient les positions 2 et 4
2 100101 on aura un tableau qui contient les positions 1,2 et 4.
etc

- Mais le résultat souhaité est d'obtenir un seul tableau (ou un seul fichier) qui
contient les positions 2 et 4 dans notre exemple.
je ne sais pas le mieux d'utiliser un tableau ou un fichier pour stocker les positions 2 et 4 car je vais parcourir ce tableau ou ce
fichier pour utiliser après dans mon programme ?

- Pouvez-vous savoir et afficher les positions communes des '0' pour
chaque deuxième champ de chaque ligne du fichier ?
Où vous allez faire une modification dans mon programme pour faire ceci ?

Merci.
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
23 juil. 2009 à 13:41
Pourquoi allouer dynamiquement un tableau dont tu connais la taille ?
Pourquoi le dimensionner de sizeof(int) (Non, c'est pas assez !) ?

Si tu veux que la fonction se souvienne du tableau d'un appel sur l'autre, déclare le en statique.

Pour voir les correspondance, suffit de comparer avec le dernier...

Tu lis la ligne :
1 110101

Tu mets dans ton tableau:
110101

Puis tu lis la ligne :
2 100101

Bin tu compares avec ton tableau, et tu constates que ils n'ont que deux et 4 en communs donc dans ton tableau, tu mets :
110101

Et ainsi de suite.
0
boualiasma Messages postés 393 Date d'inscription lundi 22 juin 2009 Statut Membre Dernière intervention 23 décembre 2011 5
23 juil. 2009 à 15:09
Salut,

J'alloue dynamiquement un tableau car je ne sais pas en avance le nombre de caractère '0'dans le deuxième champ(présenter par une chaine de caractère).

on ne mit pas dans la chaine de caractère commune. Mais, ce tableau doit contenir seulement les positions de la chaine de caractère de deuxième champ où cette position contient le caractère '0'.

On doit obtenir à la fin un tableau de deux cases dans notre exemple:
tabPos[0]=2 et tabPos[1]=4;

S'il vous plaît aidez-moi.
0
Rejoignez-nous