// Laboratorio 2 - Esercizio 3 // Matteo Schiff - s295565 #include #include #include #include #include #define MAX_LEN 30 const int MAXL = 50; typedef struct Time { unsigned int hours; unsigned int minutes; unsigned int seconds; } time; typedef struct Date { unsigned int year; unsigned int month; unsigned int day; } date; typedef struct Corsa { char codice_tratta[MAX_LEN]; char partenza[MAX_LEN]; char destinazione[MAX_LEN]; date data; time ora_partenza; time ora_arrivo; unsigned int ritardo; } corsa; typedef struct Raccolta { int N; corsa **corse_data; corsa **corse_codice; corsa **corse_partenza; corsa **corse_arrivo; corsa **temp; } raccolta; typedef enum { k_codice_tratta, k_partenza, k_destinazione, k_data } corsa_keys; typedef enum { r_stampa, r_ordina_data, r_ordina_codice, r_ordina_partenza, r_ordina_destinazione, r_ricerca_partenza, r_carica, r_fine } t_comandi; // Trasforma in lowercase tutti i caratteri di una stringa char *toLower(char *s) { for (char *p = s; *p; p++) *p = tolower(*p); return s; } t_comandi leggiComando() { t_comandi c; char cmd[MAXL]; char tabella[9][20] = { "stampa", "ordina_data", "ordina_codice", "ordina_partenza", "ordina_destinazione", "ricerca", "carica", "fine"}; printf("comando (stampa/ordina_data/ordina_codice"); printf("/ordina_partenza/ordina_destinazione/ricerca/carica/fine): "); scanf("%s", cmd); toLower(cmd); c = r_stampa; while (c < 9 && strcmp(cmd, tabella[c]) != 0) c++; return (c); } corsa_keys interpreta_tratta(char *tratta) { corsa_keys c; char cmd[MAXL]; char tabella[8][20] = { "codice\n", "partenza\n", "destinazione\n", "data\n"}; c = k_codice_tratta; while (c < 8 && strcmp(tratta, tabella[c]) != 0) c++; return (c); } // restituisce true se la prima data è successiva o coincidente alla seconda int confronta_data_ora(corsa *a, corsa *b) { if (a->data.year > b->data.year) return true; else if (a->data.year < b->data.year) return false; if (a->data.month > b->data.month) return true; else if (a->data.month < b->data.month) return false; if (a->data.day > b->data.day) return true; else if (a->data.day < b->data.day) return false; if (a->ora_partenza.hours > b->ora_partenza.hours) return true; else if (a->ora_partenza.hours < b->ora_partenza.hours) return false; if (a->ora_partenza.minutes > b->ora_partenza.minutes) return true; else if (a->ora_partenza.minutes < b->ora_partenza.minutes) return false; if (a->ora_partenza.seconds >= b->ora_partenza.seconds) return true; return false; } int confronta_codice(corsa *a, corsa *b) { return strcmp(a->codice_tratta, b->codice_tratta); } int confronta_partenza(corsa *a, corsa *b) { return strcmp(a->partenza, b->partenza) >= 0; } int confronta_arrivo(corsa *a, corsa *b) { return strcmp(a->destinazione, b->destinazione) >= 0; } int confronta_chiave(corsa *a, corsa *b, corsa_keys chiave) { switch (chiave) { case k_codice_tratta: return confronta_codice(a, b); case k_destinazione: return confronta_arrivo(a, b); case k_partenza: return confronta_partenza(a, b); case k_data: return confronta_data_ora(a, b); } } int freeVettori(raccolta * rac) { for (int i = 0; i < rac->N; i++) { free(rac->corse_codice[i]); } free(rac->corse_data); free(rac->corse_partenza); free(rac->corse_arrivo); free(rac->corse_codice); free(rac->temp); } int loadFile(raccolta * rac, char *filename, int callFree) { FILE *fp_read; unsigned int i; if ((fp_read = fopen(filename, "r")) == NULL) { puts("Impossibile aprire il file"); return 1; } if (callFree) { // chiamo free solo dopo aver controllato che il file esista // se il file non esiste rimangono caricati i dati precedenti freeVettori(rac); } fscanf(fp_read, "%u\n", &(rac->N)); rac->corse_data = malloc(rac->N * sizeof(corsa *)); rac->corse_partenza = malloc(rac->N * sizeof(corsa *)); rac->corse_arrivo = malloc(rac->N * sizeof(corsa *)); rac->corse_codice = malloc(rac->N * sizeof(corsa *)); rac->temp = malloc(rac->N * sizeof(corsa *)); for (i = 0; i < rac->N; i++) { corsa * nuova = malloc(sizeof(corsa)); int num_read = fscanf(fp_read, "%30s %30s %30s %4u/%2u/%2u %2u:%2u:%2u %2u:%2u:%2u %u\n", nuova->codice_tratta, nuova->partenza, nuova->destinazione, &(nuova->data.year), &(nuova->data.month), &(nuova->data.day), &(nuova->ora_partenza.hours), &(nuova->ora_partenza.minutes), &(nuova->ora_partenza.seconds), &(nuova->ora_arrivo.hours), &(nuova->ora_arrivo.minutes), &(nuova->ora_arrivo.seconds), &(nuova->ritardo)); if (num_read != 13) { // la stringa è mal formattata printf("File non formattato correttamente. Errore a linea %d\n", i + 1); fclose(fp_read); return 1; } rac->corse_data[i] = nuova; rac->corse_partenza[i] = nuova; rac->corse_arrivo[i] = nuova; rac->corse_codice[i] = nuova; } fclose(fp_read); return 0; } int min(int x, int y) { return (x < y) ? x : y; } void merge(corsa **A, corsa ** temp, int low, int mid, int high, corsa_keys chiave) { int i, j, k; // Merge the temp arrays i = low; j = mid+1; k = 0; while (i <= mid && j <= high) { if (!confronta_chiave(A[i], A[j], chiave)) { temp[k] = A[i]; i++; } else { temp[k] = A[j]; j++; } k++; } // Copy the remaining elements of L[] while (i <= mid) { temp[k] = A[i]; i++; k++; } // Copy the remaining elements of R[] while (j <= high) { temp[k] = A[j]; j++; k++; } for (i = 0; i <= high - low; i++) { A[i+low] = temp[i]; } } void mergesort_by_key(corsa **A, corsa ** temp, int low, int high, corsa_keys key) { if (low >= high) return; // Finding mid element int mid = low + (high - low) / 2; // Recursively sorting both the halves mergesort_by_key(A, temp, low, mid, key); mergesort_by_key(A, temp, mid + 1, high, key); // Merge the array merge(A, temp, low, mid, high, key); } void stampa_corsa(corsa corsa) { printf(" - %s %s %s, data: %4u/%02u/%02u, ora di partenza: %02u:%02u:%02u, ora di arrivo: %02u:%02u:%02u, ritardo %d minuto\n", corsa.codice_tratta, corsa.partenza, corsa.destinazione, corsa.data.year, corsa.data.month, corsa.data.day, corsa.ora_partenza.hours, corsa.ora_partenza.minutes, corsa.ora_partenza.seconds, corsa.ora_arrivo.hours, corsa.ora_arrivo.minutes, corsa.ora_arrivo.seconds, corsa.ritardo); } void stampa_corse_vettore(corsa **corse, int N) { for (int i = 0; i < N; i++) { stampa_corsa(*(corse[i])); } } void stampa_corse_scelta(char *argomenti, raccolta * rac) { argomenti++; // salta lo spazio switch (interpreta_tratta(argomenti)) { case k_codice_tratta: puts("Corse ordinate per codice:"); stampa_corse_vettore(rac->corse_codice, rac->N); break; case k_data: puts("Corse ordinate per data:"); stampa_corse_vettore(rac->corse_data, rac->N); break; case k_destinazione: puts("Corse ordinate per destinazione:"); stampa_corse_vettore(rac->corse_arrivo, rac->N); break; case k_partenza: puts("Corse ordinate per partenza:"); stampa_corse_vettore(rac->corse_partenza, rac->N); break; default: puts("Errore. La sintassi è 'stampa [codice/partenza/destinazione/data]'"); break; } } void ordina_data(char *argomenti, raccolta * rac) { puts("Ordino le corse per data\n"); mergesort_by_key(rac->corse_data, rac->temp, 0, rac->N - 1, k_data); } void ordina_codice(char *argomenti, raccolta * rac) { puts("Ordino le corse per codice tratta\n"); mergesort_by_key(rac->corse_codice, rac->temp, 0, rac->N - 1, k_codice_tratta); } void ordina_partenza(char *argomenti, raccolta * rac) { puts("Ordino le corse per partenza\n"); mergesort_by_key(rac->corse_partenza, rac->temp, 0, rac->N - 1, k_partenza); } void ordina_arrivo(char *argomenti, raccolta * rac) { puts("Ordino le corse per destinazione\n"); mergesort_by_key(rac->corse_arrivo, rac->temp, 0, rac->N - 1, k_destinazione); } void ricerca_dicotomica(corsa **corse, char *partenza, int partenza_len, int N) { int s = 0, e = N - 1, i = (e + s) / 2, res = strncmp(partenza, corse[i]->partenza, partenza_len); while (res != 0) { if (e-s <= 0) { //nothing found puts("Nessun risultato"); return; } if (res > 0) { s = i+1; } else { e = i-1; } i = (e + s) / 2; res = strncmp(partenza, corse[i]->partenza, partenza_len); } s = i; e = i; while (s > 0 && !strncmp(partenza, corse[s - 1]->partenza, partenza_len)) s--; while (e < (N - 1) && !strncmp(partenza, corse[e + 1]->partenza, partenza_len)) e++; for (i = s; i <= e; i++) { stampa_corsa(*(corse[i])); } } void ricerca_lineare(corsa **corse, char *partenza, int partenza_len, int N) { for (int i = 0; i < N; i++) { if (!strncmp(partenza, corse[i]->partenza, partenza_len)) stampa_corsa(*(corse[i])); } } void ricerca_partenza(char *argomenti, raccolta * rac) { char partenza[30], tipo[30], partenza_len; if (sscanf(argomenti, " %30s %30s", tipo, partenza) != 2) { puts("Partenza non valida. La sintassi è 'partenza [dicotomica/lineare] '"); return; } partenza_len = strlen(partenza); puts("Risultati della ricerca per stazione di partenza:"); if (!strcmp(tipo, "dicotomica")) { ricerca_dicotomica(rac->corse_partenza, partenza, partenza_len, rac->N); } else { ricerca_lineare(rac->corse_partenza, partenza, partenza_len, rac->N); } } void carica_file(char *argomenti, raccolta * rac) { char filename[30], partenza_len; if (sscanf(argomenti, " %30s", filename) != 1) { puts("Sintassi non valida. La sintassi è 'carica '"); return; } puts("Carico il nuovo file..."); loadFile(rac, filename, true); } void menuParola(raccolta * rac) { t_comandi comando; char argomenti[MAXL]; int i, continua = 1; while (continua) { comando = leggiComando(); fgets(argomenti, MAXL, stdin); /* resto della riga */ switch (comando) { case r_stampa: stampa_corse_scelta(argomenti, rac); break; case r_ordina_data: ordina_data(argomenti, rac); break; case r_ordina_codice: ordina_codice(argomenti, rac); break; case r_ordina_destinazione: ordina_arrivo(argomenti, rac); break; case r_ordina_partenza: ordina_partenza(argomenti, rac); break; case r_ricerca_partenza: ricerca_partenza(argomenti, rac); break; case r_carica: carica_file(argomenti, rac); break; case r_fine: continua = 0; break; default: puts("Comando non valido\n"); } } } int main() { raccolta rac; if (loadFile(&rac, "./corse.txt", false)) { return 1; } menuParola(&rac); freeVettori(&rac); return 0; }