Glasanje za pesmu Evrovizije

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

Napisati program koji izračunava ukupan broj glasova koji je određena država osvojila na Evroviziji. Iz ulazne datoteke učitati podatke u jednostruko spregnutu listu, gde se struktura sastoji iz sledećih polja:

  • naziv_drzave (jedna reč, do 30 karaktera)

  • glasovi_publike (neoznačena, celobrojna vrednost)

  • glasovi_zirija (neoznačena, celobrojna vrednost)

  • ukupno_glasova (neoznačena, celobrojna vrednost)

Struktura sadrži dodatna polja za pravilno formiranje jednostruko spregnute liste.

Program prima ime ulazne i izlazne datoteke kao argumente komandne linije. Naziv države i glasovi se učitavaju u jednostruko spregnutu listu, dok se ukupan broj glasova izračunava kao suma glasova žirija i publike:

\[ukupno\_glasova = glasovi\_publike + glasovi\_zirija\]

Prilikom učitavanja u listu, podaci se sortiraju na osnovu ukupnog broja osvojenih glasova. Ispisati podatke iz jednostruko spregnute liste u izlaznu datoteku u sledećem formatu: %2d. %-9s %3u %3u %3u, gde %d predstavlja redni broj države, dok su ostale vrednosti, redom, naziv države, ukupan broj glasova, glasovi publike i glasovi žirija.

Pronaći državu čija je razlika između glasova publike i glasova žirija najmanja:

\[razlika\_glasova = |glasovi\_publike - glasovi\_zirija|\]

Ispisati dobijeni rezultat nakon svih država u izlazni fajl u sledećem obliku:

Drzava ucesnica sa najmanjom razlikom izmedju glasova publike(<glasovi_publike>) i zirija(<glasovi_zirija>) je <naziv_države>.

U slučaju uspešnog izvršavanja programa, izaći sa status kodom 0 (EXIT_SUCCESS). Ukoliko program ne može da se izvrši do kraja usled sledećih nedostataka, izaći iz programa sa sledećim status kodovima:

  • U slučaju nedovoljnog ili suvišnog broj argumenata komandne linije, kao i nemogućnosti dinamičkog zauzeća memorije, izaći iz programa sa status kodom 1 (EXIT_FAILURE)

  • Ako program ne može da otvori ulazni fajl, izaći sa status kodom 2

  • Ako program ne može da otvori izlazni fajl, izaći sa status kodom 3

Primer poziva programa:

./prebrojavanje glasanje.txt rezulati.txt

Primer ulazne datoteke glasanje.txt:

Srbija    225  87
Grcka      57 158
Italija   110 158
Svedska   180 258
Britanija 183 283
Spanija   228 231
Portugal   36 171
Ukrajina  439 192
Norveska  146  36
Moldavija 239  14

Primer izlazne datoteke rezultati.txt:

 1. Ukrajina  631 439 192
 2. Britanija 466 183 283
 3. Spanija   459 228 231
 4. Svedska   438 180 258
 5. Srbija    312 225  87
 6. Italija   268 110 158
 7. Moldavija 253 239  14
 8. Grcka     215  57 158
 9. Portugal  207  36 171
10. Norveska  182 146  36

Drzava ucesnica sa najmanjom razlikom izmedju glasova publike(228) i zirija(231) je Spanija.

Primer rešenja

  1#include <stdio.h>
  2#include <string.h>
  3#include <stdlib.h>
  4
  5#define MAX_NIZ 30
  6
  7#define MAX_SIROVINA 31
  8
  9typedef struct glas_st {
 10    char naziv_drzave[MAX_SIROVINA];
 11    unsigned glasovi_publike;
 12    unsigned glasovi_zirija;
 13    unsigned ukupno_glasova;
 14    struct glas_st *sledeci;
 15} GLAS;
 16
 17FILE *safe_fopen(char *naziv, char *rezim, int kod_greske);
 18void ucitaj_glasove(FILE *ulazna, GLAS **pglava);
 19void ispisi_konacne_rezultate(FILE *izlazna, GLAS *glava);
 20
 21void inicijalizacija(GLAS **pglava);
 22GLAS *napravi_cvor(char *naziv_drzave, unsigned glasovi_publike, unsigned glasovi_zirija);
 23void dodaj_sortirano(GLAS **pglava, GLAS *novi);
 24GLAS *najmanja_razlika_izmedju_glasova(GLAS *);
 25void obrisi_listu(GLAS **pglava);
 26
 27int main(int argc, char **argv) {
 28    GLAS *glava;
 29
 30    if(argc != 3) {
 31        printf("Primer poziva programa: %s glasanje.txt rezultati.txt\n", argv[0]);
 32        exit(EXIT_FAILURE);
 33    }
 34
 35    inicijalizacija(&glava);
 36
 37    FILE *ulazna = safe_fopen(argv[1], "r", 2);
 38    ucitaj_glasove(ulazna, &glava);
 39    fclose(ulazna);
 40
 41    FILE *izlazna = safe_fopen(argv[2], "w", 3);
 42    ispisi_konacne_rezultate(izlazna, glava);
 43
 44    GLAS *najmanja_razlika_cvor = najmanja_razlika_izmedju_glasova(glava);
 45    fprintf(izlazna,
 46            "\nDrzava ucesnica sa najmanjom razlikom izmedju glasova publike(%u) i zirija(%u) je %s.\n",
 47            najmanja_razlika_cvor->glasovi_publike,
 48            najmanja_razlika_cvor->glasovi_zirija,
 49            najmanja_razlika_cvor->naziv_drzave
 50    );
 51
 52    fclose(izlazna);
 53
 54    obrisi_listu(&glava);
 55
 56    return EXIT_SUCCESS;
 57}
 58
 59FILE *safe_fopen(char *naziv, char *rezim, int kod_greske) {
 60    FILE *fp = fopen(naziv, rezim);
 61
 62    if(fp == NULL) {
 63        printf("Datoteka %s nije uspesno otvorena!\n", naziv);
 64        exit(kod_greske);
 65    }
 66
 67    return fp;
 68}
 69
 70void ucitaj_glasove(FILE *pulazna, GLAS **pglava) {
 71    char tmp_naziv_drzave[MAX_SIROVINA];
 72    unsigned tmp_glasovi_publike;
 73    unsigned tmp_glasovi_zirija;
 74
 75    while(fscanf(pulazna, "%s %u %u",
 76                 tmp_naziv_drzave,
 77                 &tmp_glasovi_publike,
 78                 &tmp_glasovi_zirija) != EOF) {
 79        GLAS *novi = napravi_cvor(tmp_naziv_drzave, tmp_glasovi_publike, tmp_glasovi_zirija);
 80        dodaj_sortirano(pglava, novi);
 81    }
 82}
 83
 84void ispisi_konacne_rezultate(FILE *izlazna, GLAS *glava) {
 85    GLAS *tekuci = glava;
 86    int brojac = 1;
 87
 88    while(tekuci != NULL) {
 89        fprintf(izlazna, "%2d. %-9s %3u %3u %3u\n", brojac, tekuci->naziv_drzave, 
 90                tekuci->ukupno_glasova, tekuci->glasovi_publike, tekuci->glasovi_zirija);
 91
 92        tekuci = tekuci->sledeci;
 93        brojac++;
 94    }
 95}
 96
 97void inicijalizacija(GLAS **pglava) {
 98    *pglava = NULL;
 99}
100
101GLAS *napravi_cvor(char *naziv_drzave, unsigned glasovi_publike, unsigned glasovi_zirija) {
102    GLAS *novi = (GLAS *)malloc(sizeof(GLAS));
103
104    if(novi == NULL) {
105        printf("Greska prilikom zauzimanja memorije!\n");
106        exit(EXIT_FAILURE);
107    }
108
109    strcpy(novi->naziv_drzave, naziv_drzave);
110    novi->glasovi_publike = glasovi_publike;
111    novi->glasovi_zirija = glasovi_zirija;
112    novi->ukupno_glasova = glasovi_publike + glasovi_zirija;
113    novi->sledeci = NULL;
114
115    return novi;
116}
117
118void dodaj_sortirano(GLAS **pglava, GLAS *novi) {
119    if(*pglava == NULL || (*pglava)->ukupno_glasova < novi->ukupno_glasova) {
120        novi->sledeci = *pglava;
121        *pglava = novi;
122    } else {
123        GLAS *tekuci = *pglava;
124
125        while(tekuci->sledeci != NULL &&
126              novi->ukupno_glasova < tekuci->sledeci->ukupno_glasova) {
127            tekuci = tekuci->sledeci;
128        }
129
130        novi->sledeci = tekuci->sledeci;
131        tekuci->sledeci = novi;
132    }
133}
134
135GLAS *najmanja_razlika_izmedju_glasova(GLAS *glava) {
136    GLAS *tekuci = glava;
137    GLAS *najmanja_razlika_cvor = glava;
138    unsigned najmanja_razlika = abs(glava->glasovi_publike - glava->glasovi_zirija);
139    unsigned tekuci_razlika;
140
141    while(tekuci != NULL) {
142        tekuci_razlika = abs(tekuci->glasovi_publike - tekuci->glasovi_zirija);
143
144        if(tekuci_razlika < najmanja_razlika) {
145            najmanja_razlika = tekuci_razlika;
146            najmanja_razlika_cvor = tekuci;
147        }
148
149        tekuci = tekuci->sledeci;
150    }
151
152    return najmanja_razlika_cvor;
153}
154
155void obrisi_listu(GLAS **pglava) {
156    GLAS *tmp;
157
158    while(*pglava != NULL) {
159        tmp = *pglava;
160        *pglava = (*pglava)->sledeci;
161        tmp->sledeci = NULL;
162        free(tmp);
163    }
164}
165