Red vožnje¶
Autor zadatka: Rade Radišić <radisic.rade@uns.ac.rs>
Napisati program koji na osnovu spiska polazaka sa autobuske stanice formira red vožnje. Iz ulazne datoteke učitati u binarno stablo pretrage sledeće podatke:
odredište
(jedna reč, do 20 karaktera)vreme_polaska
(jedna reč, u formatu sat, dva karaktera, tačka, minut, dva karaktera)prevoznik
(jedna reč, do 30 karaktera)cena_karte
(realan broj)
Stablo se formira na osnovu vrednosti polja vreme_polaska
.
Program prima ime ulazne, izlazne datoteke, odredište i vreme kao argumente komandne linije.
U izlaznu datoteku potrebno je ispisati podatke iz ulazne datoteke, sortirane po vremenima polaska u rastućem redosledu.
Prilikom ispisa u izlaznu datoteku, koristiti format "%9s %5s %-15s %7.2lf\n"
.
Na standardni izlaz ispisati najjeftiniji polazak za zadato mesto do naznačenog vremena polaska (uključujući i vreme polaska). Ukoliko postoji, ispisati:
Polazak pre <zadato-vreme> casova za mesto <zadato-mesto> sa najjeftinijom kartom je:
zajedno sa informacijama o polasku. Prilikom formatiranja jedino zaokružiti cenu karte na dve decimale. Ukoliko ne postoji, ispisati poruku sledeće sadržine:
Ne postoji polazak za mesto <zadato-mesto> pre <zadato-vreme> casova.
zadato-mesto
i zadato-vreme
predstavljaju vrednosti argumenata komandne linije.
Uraditi validaciju argumenta komandne linije koji predstavlja zadato vreme na sledeći način:
Iskontrolisati dužinu stringa tako da u njega stane format, po dve cifre za čas i za minut, sa tačkom između (proveriti i njeno postojanje)
Izdvojiti iz stringa čas i minut, pretvoriti u celobrojne vrednosti i iskontrolisati da li se nalaze u validnom opsegu
Čas je vrednost između 0 i 23
Minut je vrednost između 0 i 59
Radi jednostavnosti, pretpostaviti da se na mestima rezervisanim za časove i minute mogu naći samo cifre.
U slučaju sledećih grešaka prilikom rada programa, izaći sa odgovarajućim kodom greške:
Nedovoljan ili suvišan broj argumenata, kod greške
1
(EXIT_FAILURE)Neuspešna validacija zadatog vremena, kod greške
2
Neuspešno otvaranje ulazne datoteke, kod greške
3
Neuspešno otvaranje izlazne datoteke, kod greške
4
Nije moguće dinamički zauzeti memoriju, kod greške
5
Program realizovati tako da sve funkcije koje imaju veze isključivo sa stablom (inicijalizacija, dodavanje, brisanje...) budu odvojene u jedan par datoteka koje predstavljaju zaglavlje i implementaciju.
Primer ulazne datoteke polasci.txt
:
Beograd 08.55 Lasta 801.50
Beograd 10.00 Jugoprevoz 821.50
Beograd 11.35 Severtrans 821.50
Beograd 12.20 SaobracajZabalj 671.50
Becej 09.50 BecejPrevoz 632.50
Becej 12.10 BecejPrevoz 632.50
Becej 13.15 BecejPrevoz 632.50
Becej 13.45 Lasta 572.50
Subotica 08.25 Lasta 971.50
Subotica 10.35 NisEkspres 1211.50
Subotica 12.25 SaobracajZabalj 971.50
Subotica 13.50 NisEkspres 1381.50
Zrenjanin 08.58 BanatTrans 471.50
Zrenjanin 09.30 AsTours 461.50
Zrenjanin 10.30 StupVrsac 521.50
Zrenjanin 11.50 BanatTrans 471.50
Za primer poziva programa:
./a.out polasci.txt red-voznje.txt Zrenjanin 13.00
Očekivani ispis na standardnom izlazu je:
Polazak pre 13.00 casova za mesto Zrenjanin sa najjeftinijom kartom je: Zrenjanin 09.30 AsTours 461.50
Dok je za poziv sledeći poziv programa:
./a.out polasci.txt red-voznje.txt Zrenjanin 08.00
Očekivani ispis na standardnom izlazu:
Ne postoji polazak za mesto Zrenjanin pre 08.00 casova.
U oba slučaja, sadržaj izlazne datoteke red-voznje.txt
je sledeći:
Subotica 08.25 Lasta 971.50
Beograd 08.55 Lasta 801.50
Zrenjanin 08.58 BanatTrans 471.50
Zrenjanin 09.30 AsTours 461.50
Becej 09.50 BecejPrevoz 632.50
Beograd 10.00 Jugoprevoz 821.50
Zrenjanin 10.30 StupVrsac 521.50
Subotica 10.35 NisEkspres 1211.50
Beograd 11.35 Severtrans 821.50
Zrenjanin 11.50 BanatTrans 471.50
Becej 12.10 BecejPrevoz 632.50
Beograd 12.20 SaobracajZabalj 671.50
Subotica 12.25 SaobracajZabalj 971.50
Becej 13.15 BecejPrevoz 632.50
Becej 13.45 Lasta 572.50
Subotica 13.50 NisEkspres 1381.50
Primer rešenja¶
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include "stablo.h"
5
6POLAZAK *najjeftiniji_pre_vremena(POLAZAK *, char *, char *);
7FILE *safe_fopen(char *, char *, int);
8void ucitaj_polaske(FILE *, POLAZAK **);
9void ispisi_polaske(FILE *, POLAZAK *);
10
11int validacija_vremena(char *);
12
13int main(int argc, char **argv) {
14 POLAZAK *koren;
15
16 if(argc != 5) {
17 printf("Primer poziva programa: %s polasci.txt red-voznje.txt Zrenjanin 13.00\n", argv[0]);
18 exit(1);
19 }
20
21 if(!validacija_vremena(argv[4])) {
22 printf("Pogresan format vremena, primer dobrog formata: 13.00\n");
23 exit(2);
24 }
25
26 inicijalizacija(&koren);
27
28 FILE *ulazna = safe_fopen(argv[1], "r", 3);
29 ucitaj_polaske(ulazna, &koren);
30 fclose(ulazna);
31
32 FILE *izlazna = safe_fopen(argv[2], "w", 4);
33 ispisi_polaske(izlazna, koren);
34 fclose(izlazna);
35
36 POLAZAK *najjeftiniji = najjeftiniji_pre_vremena(koren, argv[3], argv[4]);
37 if(najjeftiniji) {
38 printf("Polazak pre %s casova za mesto %s sa najjeftinijom kartom je: %s %s %s %.2lf\n",
39 argv[4], argv[3], najjeftiniji->odrediste, najjeftiniji->vreme_polaska,
40 najjeftiniji->prevoznik, najjeftiniji->cena_karte);
41 } else {
42 printf("Ne postoji polazak za mesto %s pre %s casova.\n", argv[3], argv[4]);
43 }
44
45 return 0;
46}
47
48POLAZAK *najjeftiniji_pre_vremena(POLAZAK *koren, char *odrediste, char *vreme) {
49 POLAZAK *najjeftiniji = NULL;
50
51 if(koren != NULL) {
52 if(strcmp(koren->odrediste, odrediste) == 0 &&
53 strcmp(koren->vreme_polaska, vreme) <= 0) {
54 najjeftiniji = koren;
55 }
56
57 POLAZAK *najjeftiniji_levi = najjeftiniji_pre_vremena(koren->levi, odrediste, vreme);
58 if(najjeftiniji == NULL ||
59 (najjeftiniji_levi != NULL && najjeftiniji_levi->cena_karte < najjeftiniji->cena_karte)) {
60 najjeftiniji = najjeftiniji_levi;
61 }
62
63 POLAZAK *najjeftiniji_desni = najjeftiniji_pre_vremena(koren->desni, odrediste, vreme);
64 if(najjeftiniji == NULL ||
65 (najjeftiniji_desni != NULL && najjeftiniji_desni->cena_karte < najjeftiniji->cena_karte)) {
66 najjeftiniji = najjeftiniji_desni;
67 }
68 }
69
70 return najjeftiniji;
71}
72
73FILE *safe_fopen(char *ime, char *rezim, int kod_greske) {
74 FILE *fp = fopen(ime, rezim);
75
76 if(fp == NULL) {
77 printf("Greska prilikom otvaranja %s datoteke!\n", ime);
78 exit(kod_greske);
79 }
80
81 return fp;
82}
83
84void ucitaj_polaske(FILE *pulazna, POLAZAK **pkoren) {
85 char tmp_odrediste[MAX_ODREDISTE];
86 char tmp_vreme_polaska[MAX_VREME_POLASKA];
87 char tmp_prevoznik[MAX_PREVOZNIK];
88 double tmp_cena_karte;
89
90 while(fscanf(pulazna, "%s %s %s %lf",
91 tmp_odrediste,
92 tmp_vreme_polaska,
93 tmp_prevoznik,
94 &tmp_cena_karte) != EOF) {
95 POLAZAK *novi = napravi_cvor(
96 tmp_odrediste,
97 tmp_vreme_polaska,
98 tmp_prevoznik,
99 tmp_cena_karte);
100 dodaj_u_stablo(pkoren, novi);
101 }
102
103}
104
105void ispisi_polaske(FILE *izlazna, POLAZAK *koren) {
106 if(koren != NULL) {
107 ispisi_polaske(izlazna, koren->levi);
108 fprintf(izlazna, "%9s %5s %-15s %7.2lf\n",
109 koren->odrediste,
110 koren->vreme_polaska,
111 koren->prevoznik,
112 koren->cena_karte);
113 ispisi_polaske(izlazna, koren->desni);
114 }
115}
116
117int validacija_vremena(char *vreme) {
118 int sat, minut;
119
120 if(strlen(vreme) != 5 || vreme[2] != '.') return 0;
121
122 sat = (vreme[0] - '0') * 10;
123 sat += vreme[1] - '0';
124
125 if(sat >= 24) return 0;
126
127 minut = (vreme[3] - '0') * 10;
128 minut += vreme[4] - '0';
129
130 if(minut >= 60) return 0;
131
132 return 1;
133}
1#ifndef STABLO_H
2#define STABLO_H
3
4#define MAX_ODREDISTE 21
5#define MAX_PREVOZNIK 31
6#define MAX_VREME_POLASKA 6
7
8typedef struct polazak_st {
9 char odrediste[MAX_ODREDISTE];
10 char vreme_polaska[MAX_VREME_POLASKA];
11 char prevoznik[MAX_PREVOZNIK];
12 double cena_karte;
13 struct polazak_st *levi;
14 struct polazak_st *desni;
15} POLAZAK;
16
17void inicijalizacija(POLAZAK **);
18POLAZAK *napravi_cvor(char *, char *, char *, double);
19void dodaj_u_stablo(POLAZAK **, POLAZAK *);
20void obrisi_stablo(POLAZAK **);
21
22#endif
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include "stablo.h"
5
6void inicijalizacija(POLAZAK **pkoren) {
7 *pkoren = NULL;
8}
9
10POLAZAK *napravi_cvor(char *odrediste, char *vreme_polaska, char *prevoznik, double cena_karte) {
11 POLAZAK *novi = (POLAZAK *)malloc(sizeof(POLAZAK));
12
13 if(novi == NULL) {
14 printf("Greska prilikom zauzimanja memorije!\n");
15 exit(5);
16 }
17
18 strcpy(novi->odrediste, odrediste);
19 strcpy(novi->vreme_polaska, vreme_polaska);
20 strcpy(novi->prevoznik, prevoznik);
21 novi->cena_karte = cena_karte;
22 novi->levi = NULL;
23 novi->desni = NULL;
24
25 return novi;
26}
27
28void dodaj_u_stablo(POLAZAK **pkoren, POLAZAK *novi) {
29 if(*pkoren == NULL) {
30 *pkoren = novi;
31 } else {
32 if(strcmp(novi->vreme_polaska, (*pkoren)->vreme_polaska) < 0) {
33 dodaj_u_stablo(&(*pkoren)->levi, novi);
34 } else {
35 dodaj_u_stablo(&(*pkoren)->desni, novi);
36 }
37 }
38}
39
40void obrisi_stablo(POLAZAK **pkoren) {
41 if(*pkoren != NULL) {
42 obrisi_stablo(&(*pkoren)->levi);
43 obrisi_stablo(&(*pkoren)->desni);
44 free(*pkoren);
45 *pkoren = NULL;
46 }
47}
1.PHONY: clean
2a.out: stablo.o resenje.o
3 gcc stablo.o resenje.o
4resenje.o: resenje.c
5 gcc -c resenje.c
6stablo.o: stablo.c
7 gcc -c stablo.c
8clean:
9 rm *.o a.out