Avatar billede tchami Nybegynder
07. oktober 2003 - 18:40 Der er 20 kommentarer og
1 løsning

Sortere fil indhold

Hej,

I mit forsøg på at lære C (ANSI C) er jeg stødt på et problem med at sortere indholdet af en fil alfabetisk. Jeg går ud fra at jeg skal have læst indholdet af filen ned i et array og derefter sortere arrayet. Det sidste kan formentlig også godt lade sig gøre, men jeg kan ikke få smidt indholdet ned i et array. Indholdet af filen ser f.eks. således ud:

Name: Allan    Grade: 3
Name: Mette    Grade: 6
Name: Thomas    Grade: 4
Name: Jacob    Grade: 2

Det skal altså sorteres alfabetisk så indholdet af filen kommer til at se således ud istedet:

Name: Allan    Grade: 3
Name: Mette    Grade: 6
Name: Jacob    Grade: 2
Name: Thomas    Grade: 4

Så 200 point til vedkommende der kan kode en løsning i ANSI C og kommentere den så jeg også kan forstå hvad der sker.
Avatar billede tchami Nybegynder
07. oktober 2003 - 18:42 #1
Doh, output skal selvfølgelig se således ud:

Name: Allan    Grade: 3
Name: Jacob    Grade: 2
Name: Mette    Grade: 6
Name: Thomas    Grade: 4

:)
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:44 #2
Har jeg ikke lavet den en gang ?
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:44 #3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct info
{
  char *name;
  int grade;
};

void qs_help(int n1,int n2,struct info *a)
{
  struct info tmp;
  int l = n1;
  int r = n2;
  int pivot = a[(n1+n2)/2].grade;
  do {
      while(a[l].grade<pivot) l++;
      while(a[r].grade>pivot) r--;
      if(l<=r) {
        tmp = a[l];
        a[l] = a[r];
        a[r] = tmp;
        l++;
        r--;
      }
  } while(l<=r);
  if(n1<r) qs_help(n1,r,a);
  if(l<n2) qs_help(l,n2,a);
  return;
}

void qs(int n,struct info *a)
{
  qs_help(0,n-1,a);
  return;
}

#define KEY1 "Name:"
#define KEY2 "Grade:"

int main()
{
  int i,n;
  char line[133],*p1,*p2;
  struct info data[5000];
  FILE *fp,*fp2;
  fp = fopen("list.dat", "r");
  n=0;
  while(!feof(fp)) {
      if(fgets(line,sizeof(line),fp))
      {
          p1 = strstr(line,KEY1) + strlen(KEY1);
          while(*p1==' ') p1++;
          p2 = strchr(p1,' ');
          data[n].name = (char *)malloc(p2-p1);
          strncpy(data[n].name,p1,p2-p1);
          data[n].name[p2-p1] = '\0';
          data[n].grade = atoi(strstr(line,KEY2)+strlen(KEY2));
          n++;
      }
  }
  fclose(fp);
  qs(n,data);
  fp2 = fopen("sortlist.dat", "w");
  for(i=0;i<n;i++)
  {
      fprintf(fp2,"%s %s %s %d\n",KEY1,data[i].name,KEY2,data[i].grade);
  }
  fclose(fp2);
  return 0;
}
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:45 #4
Nå du vil have sorteret efter name i.s.f. grade ?

Stay tuned !
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:50 #5
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct info
{
  char *name;
  int grade;
};

void qs_help(int n1,int n2,struct info *a)
{
  struct info tmp;
  char pivot[33];
  int l = n1;
  int r = n2;
  strcpy(pivot,a[(n1+n2)/2].name);
  do {
      while(strcmp(a[l].name,pivot) < 0) l++;
      while(strcmp(a[r].name,pivot) > 0) r--;
      if(l<=r) {
        tmp = a[l];
        a[l] = a[r];
        a[r] = tmp;
        l++;
        r--;
      }
  } while(l<=r);
  if(n1<r) qs_help(n1,r,a);
  if(l<n2) qs_help(l,n2,a);
  return;
}

void qs(int n,struct info *a)
{
  qs_help(0,n-1,a);
  return;
}

#define KEY1 "Name:"
#define KEY2 "Grade:"

int main()
{
  int i,n;
  char line[133],*p1,*p2;
  struct info data[5000];
  FILE *fp,*fp2;
  fp = fopen("list.dat", "r");
  n=0;
  while(!feof(fp)) {
      if(fgets(line,sizeof(line),fp))
      {
          p1 = strstr(line,KEY1) + strlen(KEY1);
          while(*p1==' ') p1++;
          p2 = strchr(p1,' ');
          data[n].name = (char *)malloc(p2-p1);
          strncpy(data[n].name,p1,p2-p1);
          data[n].name[p2-p1] = '\0';
          data[n].grade = atoi(strstr(line,KEY2)+strlen(KEY2));
          n++;
      }
  }
  fclose(fp);
  qs(n,data);
  fp2 = fopen("sortlist.dat", "w");
  for(i=0;i<n;i++)
  {
      fprintf(fp2,"%s %s %s %d\n",KEY1,data[i].name,KEY2,data[i].grade);
  }
  fclose(fp2);
  return 0;
}
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:50 #6
Output:

Name: Allan Grade: 3
Name: Jacob Grade: 2
Name: Mette Grade: 6
Name: Thomas Grade: 4
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:51 #7
Svar
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:51 #8
Men lad mig gætte: forklaringer ønskes !
Avatar billede arne_v Ekspert
07. oktober 2003 - 18:52 #9
Hvad mangler du forklaring til:
  - brug af array af struct
  - indlæsning af linier fra fil
  - parsning af linie
  - quick sort (ufffff)
  - udskrivning af linier til fil
?
Avatar billede tchami Nybegynder
07. oktober 2003 - 19:00 #10
Jo du har lavet den en gang, bortset fra at denne gang skal der sorteres alfabetisk :)

Mht. forklaring. Jeg er helt med på hvordan du åbner filen, men er lidt i tvivl om hvordan resten fungerer. Ud fra ovenstående kan jeg dog godt se hvordan du skriver linierne til filen, men resten må du meget meget gerne forklare. Håber ikke det er alt for meget at bede om.
Avatar billede arne_v Ekspert
07. oktober 2003 - 19:05 #11
fp = fopen("list.dat", "r");  /* åben fil */
  n=0;
  while(!feof(fp)) { /* så længe vi ikke har nået enden af filen */
      if(fgets(line,sizeof(line),fp)) /* læs en linie */
      {
          p1 = strstr(line,KEY1) + strlen(KEY1); /* find slut på "Name:" */
          while(*p1==' ') p1++; /* skip eventuelle blanke således at vi er ved start af navn */
          p2 = strchr(p1,' '); /* find mellemrum efter navn */
          data[n].name = (char *)malloc(p2-p1); /* kopier navn udfra start og slut */
          strncpy(data[n].name,p1,p2-p1);
          data[n].name[p2-p1] = '\0';
          data[n].grade = atoi(strstr(line,KEY2)+strlen(KEY2)); /* find tart på karakter og konverter til int */
          n++;
      }
  }
  fclose(fp); /* luk filen */
Avatar billede arne_v Ekspert
07. oktober 2003 - 19:07 #12
QuickSort er mere vanskelig at forklare.

Det er en meget hurtig sortering.

Den er rekursiv.

Den bygger på et princip om at man:
  - vælger en element
  - så putter man alle dem mindre på den ene side og alle dem større på den anden side
  - så sorterer man de 2 halvdele på samme måde
Avatar billede arne_v Ekspert
07. oktober 2003 - 19:08 #13
Prøv og stil uddybende spørgsmål om det du ikke forstår ?
Avatar billede dilleberg Nybegynder
07. oktober 2003 - 19:29 #14
Der er ikke nogen grund til at skrive en QuickSort selv. Det er en ANSI C funktion.
arne_v's kald af funktionen 'qs' kan erstattes med

  qsort(a,n,sizeof(struct info),compareNameUp);

hvor compareNameUp er den funktion der sammenligner to elementer.

int compareGradeUp(const void *data1, const void *data2)
{
  return ((struct info*)data1)->grade - ((struct info*)data2)->grade;
}

Hvis du hellere vil sortere i faldende orden:

int compareGradeUp(const void *data1, const void *data2)
{
  return ((struct info*)data2)->grade - ((struct info*)data1)->grade;
}

db
Avatar billede dilleberg Nybegynder
07. oktober 2003 - 19:32 #15
Og hvis man vil sortere efter name

int compareNameUp(const void *data1, const void *data2)
{
  return strcmp(((struct info*)data1)->name,((struct info*)data2)->name);
}

db
Avatar billede dilleberg Nybegynder
07. oktober 2003 - 19:33 #16
Hmmm, jeg roder vist lidt rundt i funktionsnavnene, men det skulle være til at forstå alligevel :-)
Avatar billede arne_v Ekspert
07. oktober 2003 - 19:37 #17
Der er 2 grunde til at jeg bruger en custom quick sort:
  - den er hurtigere på simple data typer
  - jeg ved at det ikke er første eller sidste element der bliver brugt
    pivot element (jeg er ikke sikker på at ANSI C definerer at det ikke
    være tilfældet)

Men i dette tilfælde er det måske upædagogisk fordi quick sort ikke
bare lig er noget man forstå.

Så kunne man lige så godt have brugt qsort.

Eller måske have lavet en god gammel bobbel sort.
Avatar billede arne_v Ekspert
10. oktober 2003 - 21:41 #18
OK ?
Avatar billede tchami Nybegynder
11. oktober 2003 - 00:51 #19
Beklager jeg ikke har svaret tidligere (har haft frygteligt meget om ørene), men ja, det ser ud til at give mening. Eneste lille spørgsmål er din brug af struct, hvad er det helt præcist du bruger den til?
Avatar billede arne_v Ekspert
11. oktober 2003 - 08:35 #20
Jeg gemmer hver linie en en struct (struktur) som indeholder både
navn og karakter. Så kan man nemlig arbejde på hele linier.
Avatar billede tchami Nybegynder
14. oktober 2003 - 21:46 #21
Takker mange gange for hjælp Arne.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester