Fondamenti di Programmazione     a.a. 2011-2012
Prova scritta - 24 febbraio 2012
Avvertenze: non usare variabili globali; definire tutte le funzione ausiliarie usate; è consentito usare le funzioni della libreria standard; se una soluzione non è scritta in modo chiaro ed ordinato non sarà presa in considerazione.
Per chi fa solamente una parte: i punteggi degli esercizi sono da intendersi raddoppiati.
Per chi fa entrambe le parti: per raggiungere la sufficienza deve ottenere almeno 8 punti sulla Prima Parte e almeno 8 punti sulla Seconda Parte.

PRIMA PARTE
Esercizio 1 (max 6 punti)
Diciamo che una sequenza di interi x1, x2,..., xm è k-smooth se le differenze delle coppie di interi consecutivi sono in valore assoluto limitate da k (cioè, |xixi+1| ≤ k per i = 1,2,...,m−1). Scrivere una funzione int smooth(int S[], int n, int k) che ritorna la lunghezza del più lungo sottovettore del vettore S (di n interi) che è k-smooth. Ad es. se S = {4,2,1,1,0,-1,0,2,2,3} (n = 10) e k = 1 allora la funzione ritorna 6 (la lunghezza del sottovettore dall'indice 1 all'indice 6); se invece k = 0, ritorna 2 (la lunghezza del sottovettore dall'indice 2 all'indice 3).
Esercizio 2 (max 8 punti)
Scrivere una funzione int lcs(char *s1, char *s2, int *start1, int *start2) che ritorna la lunghezza della più lunga sottostringa comune alle stringhe s1 e s2 e restituisce in *start1 l'indice d'inizio in s1 e in *start2 l'indice d'inizio in s2. Se tale lunghezza è zero, *start1 e *start2 sono lasciati invariati. Ad es. se s1 = "Longest Common Substring" e s2 = "The longest common Subsequence", la funzione ritorna 10 e in *start1 restituisce 9 e in *start2 restituisce 13.
Esercizio 3 (max 10 punti)
Scrivere una funzione char *comstr(char **sA1, char **sA2, int n) che ritorna in una stringa, allocata dinamicamente, la concatenazione delle stringhe, separate dal carattere ';', dell'array di stringhe sA1 che sono anche contenute nell'array di stringhe sA2; entrambi gli array contengono n stringhe. Se non ci sono stringhe di sA1 contenute anche in sA2, ritorna NULL. Ad es. se sA1 = {"Red","Green","Blue","Red","Blue"} e sA2 = {"Brown","Green","Green","Red","Black"}, ritorna "Red;Green;Red"; se invece sA2 = {"a","a","Green","Green","b"}, ritorna "Green".
SECONDA PARTE
Esercizio 4 (max 6 punti)
Si consideri il tipo:
typedef struct Point {
    int           x, y;         //coordinate di un punto del piano
    struct Point *next;
} Point, *PList;
Scrivere una funzione PList rect(PList L, int x1, int y1, int x2, int y2, PList *out) che modifica la lista L eliminando tutti i punti che sono esterni al rettangolo individuato dai due vertici opposti (x1, y1), (x2, y2) e ritorna il puntatore alla lista modificata, inoltre se out non è NULL, i punti eliminati sono posti in una lista il cui puntatore è restituito in *out, se invece out è NULL, la memoria dei punti eliminati è rilasciata. Si assume che x1x2 e y1y2. L'ordine degli elementi nelle liste restituite non ha importanza. Ad es. se L = (0,1) (1,1) (7,7) (5,9) (2,7) (8,0), dopo la chiamata rect(L,1,1,6,9,&out) si ha L = (1,1) (5,9) (2,7) e out = (8,0) (7,7) (0,1).
Esercizio 5 (max 8 punti)
Si consideri il tipo:
typedef struct {
    char     spec[62];    //contiene una stringa di lunghezza < 62
    short    first;
} Rec;
Scrivere una funzione int mfirst(char *fname) che preso in input il nome fname di un file binario contenente una sequenza di record di tipo Rec, modifica ogni record r in modo tale che il campo first è posto a 1 se non c'è un record che precede r che ha lo stesso valore del campo spec e altrimenti è posto a 0. La funzione ritorna il numero di record il cui campo first è stato posto a 1, se il file non esiste ritorna -1. Il file può essere molto grande quindi la funzione non deve mantenere in memoria l'intero file. Ad es.
{"SA",2}{"SA",2}{"SA1",2}{"SB",2}{"SA1",2}{"SA",2}   Il file, prima e
{"SA",1}{"SA",0}{"SA1",1}{"SB",1}{"SA1",0}{"SA",0}   dopo la chiamata a mfirst
Esercizio 6 (max 10 punti)
Si consideri il tipo:
typedef struct Elem {
    int          count;
    struct Elem *next;
} Elem, *List;
Una lista circolare è una lista in cui l'"ultimo" elemento non punta a NULL ma al "primo" elemento. Una sottolista (una sequenza di elementi consecutivi) è uniforme se ha almeno due elementi e tutti hanno lo stesso valore del campo count. Scrivere una funzione List clist(List C) che presa in input una lista circolare C la modifica in modo tale che la più lunga sottolista uniforme (se c'è) è sostituita da un solo elemento il cui campo count ha valore uguale alla somma dei valori dei campi count degli elementi della sottolista. La funzione ritorna il puntatore a un elemento qualsiasi della lista (eventualmente) modificata. La memoria degli elementi eliminati deve essere rilasciata. Se ci sono più sottoliste uniformi di massima lunghezza, una qualunque di queste è sostituita. Esempi:
5→5→1→1→1→5→5    ====>     20→1→1→1
↑___________|              ↑______|

4→4→4            ====>     12
↑___|                      ↑_|

1→2→3→4          ====>     1→2→3→4
↑_____|                    ↑_____|