Sortowanie struktur i wyszukiwanie elementów.

1

Witam,
mam na jutro do napisania program w [C] i z niektórymi rzeczami mam problem. Ogólnie program ma wczytywać z pliku *.txt bazę danych o filmach, zapisać to wszystko do poszczególnych tablic i następnie na kilka sposobów przetwarzać. Część rzeczy już zrobiłem, ale część nie chce mi wyjść, m.in. :

  1. Sortowanie w strukturze, funkcja mi działa, ale chcąc wyświetlić część posortowaną i do tego nazwę oryginalnie przypisaną do tej daty to wyświetla mi nazwy w oryginalnej kolejności, tzn np mając filmy:
    Iron man 3 2013
    Iron man 2008
    Iron man 2 2010
    gdy to posortuję wg dat to nazwy zostają w takiej samej kolejności, a lata będą 2008,2010 i 2013. Jest coś nie tak z indeksowaniem i nie wiem jak to poprawić.

  2. Wyszukiwanie elementu w tablicy. Chodzi np o wyszukanie wszystkich filmów akcji i wyświetlenie ich. Próbowałem przez wyszukanie zwykłym for'em i dopisanie do nowej tablicy ale nie wyszło mi to.

  3. Menu wyboru. Jakoś nie za bardzo mogę ogarnąć polecenie switch i case.

Wszystkie wskazówki i uwagi będą bardzo cenne i z góry dziękuję za pomoc :)
Dorzucam kod tego, co mi się do tej pory udało zrobić i część pliku tekstowego.

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
struct dane 
{
       char tytul[100];
       char rezyser[100];
       char rok[100];
       char gatunek[100];
       char ocena[100];
       char a[100];     
};
struct dane tab[100];


void sortujrok( struct dane tabela[], int rozmiar )
{
     int i, j;
     char bufor[100];
 
   for(j=0;j<rozmiar;j++)
    {
     
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].rok,tabela[i+1].rok)>0)
       {
        strcpy(bufor,tabela[i+1].rok);
        strcpy(tabela[i+1].rok,tabela[i].rok);
        strcpy(tabela[i].rok,bufor);
       }
      }
}}

void sortujocena( struct dane tabela[], int rozmiar )
{
     int i, j;
     char bufor[100];
 
   for(j=0;j<rozmiar;j++)
    {
     
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].ocena,tabela[i+1].ocena)>0)
       {
        strcpy(bufor,tabela[i+1].ocena);
        strcpy(tabela[i+1].ocena,tabela[i].ocena);
        strcpy(tabela[i].ocena,bufor);
       }
      }
}}

void sortujgatunek( struct dane tabela[], int rozmiar )
{
     int i, j;
     char bufor[100];
 
   for(j=0;j<rozmiar;j++)
    {
     
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].gatunek,tabela[i+1].gatunek)>0)
       {
        strcpy(bufor,tabela[i+1].gatunek);
        strcpy(tabela[i+1].gatunek,tabela[i].gatunek);
        strcpy(tabela[i].gatunek,bufor);
       }
      }
}}
int main ()
{ 
     int i=0, j, k, size=0, wiersz=1, pomoc;
     char rok[100];
     char b;
  
    
     FILE *file = fopen("baza.txt", "r");
     FILE *file2 =fopen("x.txt", "w");
          
     while(!feof(file))
     {
                        fscanf(file,"%[^;]%*c%[^;]%*c%[^;]%*c%[^;]%*c%[^;]%*c%*c", tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
                        ++size;
                        fprintf(file2,"%d %s %s %s %s %s \n", wiersz, tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
                        ++wiersz;
     }
     fclose(file);
     fclose(file2);
      


  

  FILE *file3 = fopen("z.txt", "w");
  wiersz=1;
  fprintf(file3, "Lp  Tytul  Rezyser  Rok produkcji  Gatunek  Ocena(1-10)\n\n");    
  for(i=0;i<size;i++)
  {
   fprintf(file3, "%d %s %s %s %s %s \n", wiersz, tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
  ++wiersz;}
  fclose(file3);


  
  system("PAUSE");	
  return 0;
}

W taki sposób mam przygotowaną bazę filmów (przykładowe 3):

Iron Man 3;Shane Black;2013;Akcja,Sci-Fi;7,8;
Zielona mila;Frank Darabont;1999;Dramat;8,7;
Forrest Gump;Robert Zemeckis;1994;Dramat;8,6;

Pozdrawiam i liczę na szybką pomoc :)

1
  1. Sortowanie. Musisz zamieniać elementy tablicy a nie składową, według której sortujesz. Przykładowo dla funkcji sortującej według roku:
void sortujrok( struct dane tabela[], int rozmiar )
{
     int i, j;
     struct dane tmp;

   for(j=0;j<rozmiar;j++)
    {
 
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].rok,tabela[i+1].rok)>0)
       {
	//lepszym rozwiązaniem byłaby tablica wskaźników do struktury dane 
        tmp = tabela[i];
        tabela[i] = tabela[i+1];
        tabela[i+1] = tmp;
       }
      }
}}
  1. Wyszukiwanie. Podobnie do sortowania funkcją strcmp(). Wymaga to ustalenia, które pole ma być przeszukiwane lub napisania osobnej funkcji dla każdego z pól:
void wyswietl( struct dane ofilmie)
{
    //trzeba zamplementować w zależności od tego co ma być wyświetlane
}

void szukajgatunek( struct dane tabela[], int rozmiar, char* gatunek)
{
     int j, znaleziono;
     
   znaleziono = 0;
   for(j=0;j<rozmiar;j++)
    {
     if(strcmp(tabela[j].gatunek,gatunek)==0)
     {
      wyswietl(tabela[j]);//do zrobienia!
      ++znaleziono;
     }
    }
   if(znaleziono == 0)
    fprint("Nie znaleziono filmow w podanym gatunku");
} 
  1. Menu. Masz przykładowo 2 polecenia do wyboru: 1. sortuj wg roku 2. szukaj gatunku.
    Użytkownik podaje numer pozycji:
switch(numer)
{
    case 1:
        sortujrok(tab, rozmiar);
    break;
    case 2:
        //najpierw pobierasz informacje o poszukiwanym gatunku
        szukajgatunek(tab, rozmiar, gatunek);
    break;
    default:
        fprint("Nie ma takiego polecenia");
} 
0

Dzięki wielkie za odpowiedź, ale:

  1. Teraz to nie za bardzo sortuje, zamienia tylko niektóre wiersze i tyle. Myślę, że coś nie tak jest z tą całą pętlą.
  2. Tutaj nie rozumiem jak to ma działać co podałeś, możesz wytłumaczyć dokładniej ?
  3. Nie patrzę nawet dopóki reszty nie zrobię
0
  1. Sortuje. (Jest to bardzo primitywne i co za tym idzie nieefektywne sortowanie.)
    Zastanawiam się czy ma co sortować. Zwarzywszy jak wczytujesz dane:

fscanf(file,"%[;]%*c%[;]%*c%[;]%*c%[;]%*c%[^;]%*c%*c", tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);

gdy plik zawiera:

Iron Man 3;Shane Black;2013;Akcja,Sci-Fi;7,8;
Zielona mila;Frank Darabont;1999;Dramat;8,7;
Forrest Gump;Robert Zemeckis;1994;Dramat;8,6;

  • chyba nie.
  1. W pętli jest przeszukiwana cała tabela.
    Gdy pole gatunek sprawdzanego elementu zawiera taki sam tekst jak zmienna gatunek (strcmp() zwróci wówczas 0) to elemnet jest wypisywany i zwiększana jest zmienna znaleziono.
    Jeżeli nic nie znaleziono (zmienna znaleziono == 0) wypisywany jest odpowiedni komunikat (oczywiście funkcją printf() a nie jak błędnie napisałem fprint).
    Teraz widzę, że dla tego pola trzeba będzie użuć bardziej złożonego wyszukiwania z uwagi na to że film może należeć do kilku gatunków (Iron Man 3).
0
  1. Wydaje mi się, że ma co sortować, bo samo sortowanie czy to po roku, po tytule czy ocenie wykonuje dobrze. Problem jest gdy chcę wyświetlić do tego tytuł. A czy cała pętla sortowania jest dobrze zrobiona? Jakoś ten "for" dla 'j' mi nie do końca pasuje ..
    Ogólnie celem takiego wczytywania było to, aby program przypisał sobie wszystkie tytuły do jednej tablicy, i tak każdy parametr oddzielnie, ale żeby mieć wszystkie tytuły razem.

  2. Okej, rozumiem już. Akurat podwójne gatunki to nie problem, można wywalić ;p

0

Problem jest gdy chcę wyświetlić do tego tytuł.

Nie bardzo rozumiem.
Poniżej funkcja wyświetlająca zawartość jednego elementu tablicy (ta brakująca):

void wyswietl(struct dane ofilmie)
{
    printf(" %s %s %s %s %s\n", ofilmie.tytul, ofilmie.rezyser, ofilmie.rok, ofilmie.gatunek, ofilmie.ocena);
} 

A czy cała pętla sortowania jest dobrze zrobiona?

Są różne metody sortowania. Bąbelkowe ma kilka odmian. Gotowe implementacje znajdziesz bez problemu w internecie.

0
  1. Jeśli mówisz, że jest to nieefektywny sposób sortowania to może jakiś inny byłby wygodniejszy ?
    Z tym tytułem chodzi o to, o czym mówiłem w 1 poście, lata sortuje ale tytuły zostają w tej samej kolejności.
    Zaraz poszukam jeszcze raz implementacji sortowania.
    Może masz jakiś lepszy sposób na samo wczytanie tych danych ?

  2. Przy wywołaniu funkcji czym jest 3cia zmienna ? Wydaje mi się, że to ten gatunek jaki szukamy, ale jak to wywołać dokładnie?

0

Punkt 2. już mi ładnie działa także bardzo dziękuję. Niestety z 1szym mam nadal problemy, mogę prosić o pomoc? Nie za bardzo mogę ogarnąć jak to posortować dokładnie aby program poukładał lata produkcji rosnaco, ale tytuły wyświetlił te odpowiednie dla daty a nie w wejściowej kolejności. Kod który podawał Rekman kompiluje się, ale niestety nie sortuje, wydaje mi się, że jest coś nie tak z pętlą.

0

Jeśli mówisz, że jest to nieefektywny sposób sortowania to może jakiś inny byłby wygodniejszy ?

Wygodniejszy dla tego co implementuje na pewno nie. Ten jest najprostszy. Najszybszy to Quicksort. Nawet nie musisz go nimplementować. W biblotece języka C jest funkcja qsort(). Wystarczy napisać funkcję porównującą.

Nie za bardzo mogę ogarnąć jak to posortować dokładnie aby program poukładał lata produkcji rosnaco, ale tytuły wyświetlił te odpowiednie dla daty a nie w wejściowej kolejności.

Poprawiona przeze mnie funkcja sortujrok() sortuje całe rekordy rosnąco według pola rok. I na pewno robi to dobrze (pomijam jakość algorytmu). Więc nie tu leży przyczyna ich mieszania.

Może masz jakiś lepszy sposób na samo wczytanie tych danych ?

Możesz to zrobić za pomocą funkcji fread().
Wymaga to odpowiedniego przygotowania pliku z danymi. Wczytaj tak jak obecnie (fscanf()) i zapisz dane z tablicy funkcją fwrite() do nowego pliku (na wszelki wypadek). Następnie tak utworzony plik odczytaj funkcją fread().

0

Dosłownie 10 minut temu wszystko zaczęło mi już działać w taki sposób jak miałem, dlatego postaram się to poukładać i wrzucę końcowy kod. Dziękuję Ci bardzo za pomoc :)

0

Pewnie nie spodoba Ci się jak to wygląda, bo na pewno można by to zrobić o wiele prościej, praktyczniej i krócej no ale to jednak mój pierwszy poważniejszy program.

Dla przypomnienia wczytywana baza danych wygląda w notatniku tak:

Iron Man 3;Shane Black;2013;Akcja;7,8;
Zielona mila;Frank Darabont;1999;Dramat;8,7;
Forrest Gump;Robert Zemeckis;1994;Dramat;8,6;
Cast Away - poza swiatem;Robert Zemeckis;2000;Dramat;7,6;

A kod wygląda tak:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

struct dane 
{
       char tytul[100];
       char rezyser[100];
       char rok[100];
       char gatunek[100];
       char ocena[100];
       char a[100];     
};
struct dane tab[100];

void sortujrok( struct dane tabela[], int rozmiar )
{
     int i, j;
     struct dane tmp;
 
   for(j=0;j<rozmiar;j++)
    {
 
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].rok,tabela[i+1].rok)>0)
       {
        tmp = tabela[i];
        tabela[i] = tabela[i+1];
        tabela[i+1] = tmp;
       }
      }
}}

void sortujtytul( struct dane tabela[], int rozmiar )
{
     int i, j;
     struct dane tmp;
 
   for(j=0;j<rozmiar;j++)
    {
 
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].tytul,tabela[i+1].tytul)>0)
       {
        tmp = tabela[i];
        tabela[i] = tabela[i+1];
        tabela[i+1] = tmp;
       }
      }
}}

void sortujocena( struct dane tabela[], int rozmiar )
{
     int i, j;
     struct dane tmp;
 
   for(j=0;j<rozmiar;j++)
    {
 
     for(i=0;i<rozmiar-1;i++)
      {
       if(strcmp(tabela[i].ocena,tabela[i+1].ocena)>0)
       {
        tmp = tabela[i];
        tabela[i] = tabela[i+1];
        tabela[i+1] = tmp;
       }
      }
}}

void wyswietl(struct dane ofilmie)
{ 
    printf("%s     %s     %s     %s\n", ofilmie.tytul, ofilmie.rezyser, ofilmie.rok, ofilmie.ocena);
} 

void szukajgatunek( struct dane tabela[], int rozmiar, char gatunek[])
{
     int i, znaleziono;
 
   znaleziono = 0;
   for(i=0;i<rozmiar;i++)
    {
     if(strcmp(tabela[i].gatunek,gatunek)==0)
     {
      wyswietl(tabela[i]);
      ++znaleziono;
     }
    }
   if(znaleziono == 0)
    printf("Nie znaleziono filmow w podanym gatunku.\n\n");
} 


 void szukajocena( struct dane tabela[], int rozmiar, char ocena[])
{
     int i, znaleziono=0;
 
    for(i=0;i<rozmiar;i++)
    {
     if(strcmp(tabela[i].ocena,ocena)>0)
     {
      wyswietl(tabela[i]);
      ++znaleziono;
     }
    }
   if(znaleziono == 0)
    printf("Nie znaleziono filmow powyzej takiej oceny.\n\n");
}







int main ()
{ 

     int i=0, j, size=0, wiersz=1;
	 int wybor;
     char gat[200]; char oc[100];
	
    
     FILE *file = fopen("baza.txt", "r");
     FILE *file2 =fopen("x.txt", "w");
          
     while(!feof(file))
     {
                        fscanf(file,"%[^;]%*c%[^;]%*c%[^;]%*c%[^;]%*c%[^;]%*c%*c", tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
                        ++size;
                        fprintf(file2,"%d %s %s %s %s %s \n", wiersz, tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
                        ++wiersz;
     }
     fclose(file);
     fclose(file2);
  
   while(wybor!=6){
   
   
   printf(" 1.Sortowanie wg tytulu\n 2.Sortowanie wg roku produkcji\n 3.Sortowanie wg oceny\n 4.Znajdz wszystkie filmy podanego gatunku\n 5.Znajdz wszystkie filmy powyzej podanej oceny\n 6.Wyjscie\n");
   printf("Wybierz opcje: ");scanf("%d", &wybor); 
       
   switch (wybor) 
   {   	
   	
   case 1: 
   
   sortujtytul(tab, size);
    wiersz=1;
    printf("\nFilmy posortowane wg tytulu:\n\n");
  for(i=0;i<size;i++)
  {
   printf("%d. %s   %s   %s   %s   %s \n", wiersz, tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
  ++wiersz;}
   printf("\n\n");
     break;     
     
   case 2:    
   
   sortujrok(tab, size);
    wiersz=1;
    printf("\nFilmy posortowane wg roku produkcji:\n\n");
  for(i=0;i<size;i++)
  {
   printf("%d1 %s   %s   %s   %s   %s \n", wiersz, tab[wiersz-1].rok, tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].gatunek, tab[wiersz-1].ocena);
  ++wiersz;}
   printf("\n\n");
     break;     
     
   case 3:    
   
   sortujocena(tab, size);
    wiersz=1;
    printf("\nFilmy posortowane wg ocena:\n\n");
  for(i=0;i<size;i++)
  {
   printf("%d. %s   %s   %s   %s   %s \n", wiersz, tab[wiersz-1].ocena, tab[wiersz-1].tytul, tab[wiersz-1].rezyser, tab[wiersz-1].rok, tab[wiersz-1].gatunek);
  ++wiersz;}
   printf("\n\n");
     break;     
     
   case 4: 
      
   printf("Gatunki: Akcja, Dramat, Sci-Fi, Wojenny, Sportowy, Katastroficzny, Biograficzny.");
   printf("\nPodaj gatunek filmu do wyszukania : "); scanf("%s", &gat); 
    printf( "\nWszystkie filmy z gatunku %s:\n\n", gat); 
    szukajgatunek(tab, size, gat);
   printf("\n\n");
     break;
          
   case 5:    
   
   printf("Podaj ocene filmu od ktorej maja byc wyszukane filmy(na przyklad 7,8): "); scanf("%s", &oc); 
    printf( "\nWszystkie filmy z ocena powyzej %s:\n\n", oc); 
	szukajocena(tab, size, oc);
     printf("\nOceny filmow pochodza z serwisu www.filmweb.pl\n\n");
   printf("\n\n");
     break;     
     
    case 6:     
    
   printf("\n\nWyjscie z programu\n\n");
     break;     
     
   default:    
   
   printf("\nPodaj prawidlowy numer opcji.\n\n\n");
   break;
 }
}    
  system("PAUSE");	
  return 0;
}
0
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
typedef enum ETYP {TYTUL, REZYSER, ROK, GATUNEK, OCENA, A} TYP;
 
struct Dane {
    char dane[6][100];
};
 
struct Dane moje_dane[100];
 
void sortuj(struct Dane tabela[], int rozmiar, TYP klucz) {
    int i, j;
    struct Dane tmp;
 
    for(j=0;j<rozmiar;j++) {
        for(i=0;i<rozmiar-1;i++) {
            if(strcmp(tabela[i].dane[klucz],tabela[i+1].dane[klucz])>0) {
                tmp = tabela[i];
                tabela[i] = tabela[i+1];
                tabela[i+1] = tmp;
            }
        }
    }
}
 
int szukaj(struct Dane tabela[], int rozmiar, TYP klucz, char szukana[]) {
    int i, znaleziono = 0;
 
    for(i=0;i<rozmiar;i++) {
        if(!(strcmp(tabela[i].dane[klucz], szukana))) {
            ++znaleziono;
        }
    }
    
    return znaleziono;
}
 
void wyswietl(struct Dane d, FILE* fp) {
    int i;
    for(i=0;i<6;++i) {
        fprintf(fp, "%s\t", d.dane[(TYP)i]);
    }
    fprintf(fp, "\n");
}
 
int main () { 
    int i=0, size, wiersz=0, wybor, posortowac, poszukac, n=0;
    char klucz_napis[6][20] = {
        "Tytul",
        "Rezyser",
        "Rok",
        "Gatunek",
        "Ocena",
        "A"
    };
    
    char szukana[100];
 
    FILE *file  = fopen("baza.txt", "r");
    FILE *file2 = fopen("x.txt", "w");
 
    while(!feof(file)) {
        fscanf (
            file,
            "%[^;]%*c%[^;]%*c%[^;]%*c%[^;]%*c%[^;]%*c%*c",
            moje_dane[wiersz].dane[TYTUL],
            moje_dane[wiersz].dane[REZYSER],
            moje_dane[wiersz].dane[ROK],
            moje_dane[wiersz].dane[GATUNEK],
            moje_dane[wiersz].dane[OCENA]
        );
        wyswietl(moje_dane[wiersz], file2);
        ++wiersz, ++size;
    }
    fclose(file);
    fclose(file2);
 
    while(wybor) {
        printf (
            "0.Wyjscie\n"
            "1.Sortowanie wg tytulu\n"
            "2.Sortowanie wg roku produkcji\n"
            "3.Sortowanie wg oceny\n"
            "4.Znajdz wszystkie filmy podanego gatunku\n"
            "5.Znajdz wszystkie filmy powyzej podanej oceny\n"
        );
        
        printf("Wybierz opcje: ");
        scanf("%d", &wybor); 
     
        posortowac = poszukac = -1;
     
        switch (wybor) {      
            case 0: {
                printf("\n\nWyjscie z programu\n\n");
            } break;
     
            case 1: {
                posortowac = TYTUL;
            } break; 
     
            case 2: {
                posortowac = ROK;
            } break;     
     
            case 3: {
                posortowac = OCENA;
            } break;     
     
            case 4: {
                poszukac = GATUNEK;
            } break;
     
            case 5: {
                poszukac = OCENA;
            } break;          
     
            default: {
                printf("\nPodaj prawidlowy numer opcji.\n\n\n");
            } break;
        }
        
        if(posortowac != -1) {
            sortuj(moje_dane, size, posortowac);
            printf("\nFilmy posortowane wg %s:\n\n", klucz_napis[posortowac]);
            for(i=0;i<size;++i) {
                wyswietl(moje_dane[i], stdout);
            }
            printf("\n\n");
        } else if(poszukac != -1) {
            scanf("%99s", szukana);
            n=szukaj(moje_dane, size, poszukac, szukana);
            printf("Znaleziono %d wartosci\n\n\n", n);
        }
    }
    
    return 0;
}

O cos mniej-wiecej takiego mi chodzilo. Mozna to oczywiscie skrocic, ale juz nie chcialem Ci zmieniac calego kodu.

Dopisze jeszcze co mozna by poprawic:

  1. Menu: tablica struktur {wiadomosc, wskaznik na funkcje};
  2. Caly ten zapis/odczyt z pliku nie bardzo mi sie podoba.
  3. Zrobienie tego dynamicznie dla dowolnej liczby struktur.
  4. Wszelakie identyfikatory maja nazwy do kitu :P
0

No rzeczywiście, przeanalizowałem sobie to wszystko no i można było to zrobić łatwiej i lepiej no ale chciałem to zrobić tak, jak to widziałem. Jest już za późno na zmianę, bo wysłałem program do oceny ale na pewno mi się to przyda, zapamiętam sobie to także dzięki wielkie :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1