Pijanističko takmičenje

Autor zadatka: Rade Radišić <radisic.rade@uns.ac.rs>

Pijanista takmičar predstavljen je preko strukture, pomoću sledećih polja:

  • ime (string, do 20 karaktera)

  • prezime (string, do 30 karaktera)

  • broj osvojenih poena (neoznačena, celobrojna vrednost)

Učitati takmičare iz ulazne datoteke u binarno stablo pretrage. Koristiti broj osvojenih poena kao ključno obeležje. U izlaznu datoteku ispisati ime i prezime takmičara, zajedno sa nagradom koju je osvojio sortirano, u opadajućem redosledu. Pravila za nagrađivanje su sledeća:

  • Ukoliko takmičar ima od 91-100 osvojenih poena, osvojio je prvu nagradu

  • Ukoliko takmičar ima od 81-90 osvojenih poena, osvojio je drugu nagradu

  • Ukoliko takmičar ima 80 i niže poena, osvojio je pohvalu

Kako više takmičara može osvojiti prvu i drugu nagradu, one se dodatno rangiraju u odnosu na osvojeni broj poena. Na primer, u slučaju da postoje dva takmičara, gde je jedan osvojio 99, a drugi 94 poena, prvi je osvojio prvu prvu, a drugi je osvojio prvu drugu nagradu. U slučaju da je takmičar osvojio prvu ili drugu nagradu, koristiti format ispisa "%-10s %-12s %d. %d.", dok u slučaju osvojene pohvale, koristiti "%-10s %-12s pohvala". Pogledati primer izlazne datoteke za detaljnije objašnjenje.

  • U slučaju nedovoljnog ili suvišnog broja argumenata, izaći iz programa sa kodom greške 1 (EXIT_FAILURE)

  • U slučaju da nije moguće dinamički zauzeti memoriju, izaći iz programa sa kodom greške 2

  • U slučaju neuspešnog otvaranja ulazne datoteke, izaći iz programa sa kodom greške 3

  • U slučaju neuspešnog otvaranja izlazne datoteke, izaći iz programa sa kodom greške 4

Primer ulaznog fajla takmicari.txt

Andja      Stankic     97
Aleksandra Novak       89
Ljubomir   Kovacevic   99
Pedja      Maric       78
Radmila    Loncar     100
Miljana    Jerkovic    85
Mileva     Pavlovic    93
Miljana    Zivkovic    95
Josif      Stojanovic  86
Mihajlo    Dragovic    72

Primer poziva programa:

./program takmicari.txt rezultati.txt

Primer izlazne datoteke rezultati.txt:

Radmila    Loncar       1. 1.
Ljubomir   Kovacevic    1. 2.
Andja      Stankic      1. 3.
Miljana    Zivkovic     1. 4.
Mileva     Pavlovic     1. 5.
Aleksandra Novak        2. 1.
Josif      Stojanovic   2. 2.
Miljana    Jerkovic     2. 3.
Pedja      Maric        pohvala
Mihajlo    Dragovic     pohvala

Primer rešenja

  1#include <stdio.h>
  2#include <string.h>
  3#include <stdlib.h>
  4
  5#define MAX_IME 21
  6#define MAX_PREZIME 31
  7
  8typedef struct takmicar_st {
  9    char ime[MAX_IME];
 10    char prezime[MAX_PREZIME];
 11    unsigned broj_ostvarenih_poena;
 12    struct takmicar_st *levi;
 13    struct takmicar_st *desni;
 14} TAKMICAR;
 15
 16FILE *safe_fopen(char *, char *, int);
 17void ucitaj_takmicare(FILE *, TAKMICAR **);
 18int ispisi_rezultate(FILE *, TAKMICAR *, int *);
 19
 20void inicijalizacija(TAKMICAR **);
 21TAKMICAR *napravi_cvor(char *, char *, unsigned);
 22void dodaj_u_stablo(TAKMICAR **, TAKMICAR *);
 23void obrisi_stablo(TAKMICAR **);
 24
 25int main(int argc, char **argv) {
 26    TAKMICAR *koren;
 27
 28    if(argc != 3) {
 29        printf("Primer poziva programa: %s takmicari.txt rezultati.txt\n", argv[0]);
 30        return EXIT_FAILURE;
 31    }
 32
 33    inicijalizacija(&koren);
 34
 35    FILE *ulazna = safe_fopen(argv[1], "r", 3);
 36    ucitaj_takmicare(ulazna, &koren);
 37    fclose(ulazna);
 38
 39    FILE *izlazna = safe_fopen(argv[2], "w", 4);
 40    int redni_broj = 0;     // Koristi nam da pratimo koje mesto u okviru nagrade je osvojio takmicar (prenosi se po referenci)
 41    
 42    // Mesto nam je potrebno samo dok prolazimo kroz stablo u rekurzivnim pozivima, necemo uzimati povratnu vrednost u main funkciji
 43    // Kada imamo takvu situaciju, odnosno pozivamo funkciju ciju povratnu vrednost necemo koristiti, 
 44    // u programskom jeziku C je dobra praksa je njen rezultat cast-ovati u void
 45    (void) ispisi_rezultate(izlazna, koren, &redni_broj);
 46    
 47    fclose(izlazna);
 48
 49    obrisi_stablo(&koren);
 50
 51    return EXIT_SUCCESS;
 52}
 53
 54FILE *safe_fopen(char *naziv, char *rezim, int kod_greske) {
 55    FILE *fp = fopen(naziv, rezim);
 56
 57    if(fp == NULL) {
 58        printf("Datoteka %s nije uspesno otvorena!\n", naziv);
 59        exit(kod_greske);
 60    }
 61
 62    return fp;
 63}
 64
 65void ucitaj_takmicare(FILE *ulazna, TAKMICAR **pkoren) {
 66    char tmp_ime[MAX_IME];
 67    char tmp_prezime[MAX_PREZIME];
 68    unsigned tmp_broj_ostvarenih_poena;
 69
 70    while(fscanf(ulazna, "%s %s %u", tmp_ime, tmp_prezime, &tmp_broj_ostvarenih_poena) != EOF) {
 71        TAKMICAR *novi = napravi_cvor(tmp_ime, tmp_prezime, tmp_broj_ostvarenih_poena);
 72        dodaj_u_stablo(pkoren, novi);
 73    }
 74}
 75
 76int ispisi_rezultate(FILE *izlazna, TAKMICAR *koren, int *predni_broj) {
 77    int mesto = 0;
 78
 79    if(koren != NULL) {
 80        int mesto_levi = ispisi_rezultate(izlazna, koren->desni, predni_broj);
 81        mesto = mesto_levi;    // mesto je uvek 0, tako da je bitno samo sta mesto_levi ima u sebi (moze biti 0 ili neki veci broj)
 82
 83        if(koren->broj_ostvarenih_poena >= 91 && koren->broj_ostvarenih_poena <= 100) {
 84            mesto = 1;
 85        } else if(koren->broj_ostvarenih_poena >= 81 && koren->broj_ostvarenih_poena <= 90) {
 86            if(mesto == 1) {
 87                *predni_broj = 0;   // reset rednog broja, jer smo izbrojali prve i prelazimo na druge nagrade
 88            }
 89            mesto = 2;
 90        } else {
 91            mesto = 3;  // pohvala (vrednost rednog broja nebitna)
 92        }
 93
 94        switch(mesto) {
 95        case 1:
 96        case 2:
 97            (*predni_broj)++;
 98            fprintf(izlazna, "%-10s %-12s %d. %d.\n", koren->ime, koren->prezime, mesto, *predni_broj);
 99            break;
100        case 3:
101            fprintf(izlazna, "%-10s %-12s pohvala\n", koren->ime, koren->prezime);
102            break;
103        }
104
105        int mesto_desni = ispisi_rezultate(izlazna, koren->levi, predni_broj);
106        if(mesto_desni > mesto) {
107            mesto = mesto_desni;
108        }
109    }
110
111    return mesto;
112}
113
114void inicijalizacija(TAKMICAR **pkoren) {
115    *pkoren = NULL;
116}
117
118TAKMICAR *napravi_cvor(char *ime, char *prezime, unsigned broj_ostvarenih_poena) {
119    TAKMICAR *novi = (TAKMICAR *)malloc(sizeof(TAKMICAR));
120
121    if(novi == NULL) {
122        printf("Greska prilikom zauzimanja memorije!\n");
123        exit(2);
124    }
125
126    strcpy(novi->ime, ime);
127    strcpy(novi->prezime, prezime);
128    novi->broj_ostvarenih_poena = broj_ostvarenih_poena;
129    novi->levi = NULL;
130    novi->desni = NULL;
131
132    return novi;
133}
134
135void dodaj_u_stablo(TAKMICAR **pkoren, TAKMICAR *novi) {
136    if(*pkoren == NULL) {
137        *pkoren = novi;
138    } else {
139        if((*pkoren)->broj_ostvarenih_poena > novi->broj_ostvarenih_poena) {
140            dodaj_u_stablo(&(*pkoren)->levi, novi);
141        } else {
142            dodaj_u_stablo(&(*pkoren)->desni, novi);
143        }
144    }
145}
146
147void obrisi_stablo(TAKMICAR **pkoren) {
148    if(*pkoren != NULL) {
149        obrisi_stablo(&(*pkoren)->levi);
150        obrisi_stablo(&(*pkoren)->desni);
151        free(*pkoren);
152        *pkoren = NULL;
153    }
154}
155