Programmazione I a.a. 2004/2005 (Canale P-Z)
R. Silvestri e I. Salvo
Prova scritta del 23 febbraio 2005
Per superare la prova è necessario (ma
non sufficiente) ottenere almeno 7 punti per la soluzione dell'esercizio
obbligatorio. Gli altri tre esercizi sono a scelta. Il voto è
la somma dei punti ottenuti.
Avvertenze: non usare variabili globali; definire tutte
le eventuali funzioni ausiliarie usate; è consentito usare
le
funzioni della libreria standard; se una
soluzione non è scritta in modo chiaro ed ordinato
non sarà presa
in considerazione.
Esercizio Obbligatorio (max 10 punti)
Si consideri il seguente tipo:
typedef
struct VStr {
long
val;
char *
str; //stringa allocata dinamicamente
struct VStr *next;
} VStr, *LStr;
Scrivere una funzione, con prototipo int
Comp(LStr L), che presa in input la lista L, ordinata in senso non decrescente
rispetto
al campo val, la modifica
in modo tale che elementi consecutivi che hanno lo stesso valore del campo
val sono sostituiti
da un
elemento il cui valore del campo val è lo stesso e il
campo str è la
stringa prodotta dalla concatenazione, nell'ordine, delle stringhe
degli elementi sostituiti. La funzione ritorna il numero massimo di elementi
con lo stesso valore del campo val. Inoltre la funzione
non deve modificare il puntatore al primo elemento. La memoria non più
usata deve essere rilasciata e i nuovi blocchi di memoria non
devono essere più grandi del necessario. Ad esempio se la lista
è
{5, "AA"} -> {5, "BBB"}
-> {7, "C"} -> {8, "D"} -> {8, "GG"} -> {8, "F"} allora
la funzione
la modifica così {5,
"AABBB"} -> {7, "C"} -> {8, "DGGF"} e ritorna 3.
Soluzione Esercizio Obbligatorio
int
Comp(LStr L)
{
int max = 0, count = 0;
LStr prev = NULL;
//Manterra' il puntatore al primo elemento
long val;
//di una sequenza
di elementi da sostituire.
while (L != NULL) {
if (prev
!= NULL && val == L->val) {
//Se e' un elemento di una sequenza
int newLen = strlen(prev->str)
+ strlen(L->str); //di elementi da sost.
prev->str = realloc(prev->str,
(newLen + 1)*sizeof(char));
strcat(prev->str, L->str);
//Rialloca un blocco
sufficiente per
prev->next
= L->next;
//mantenere la concatenazione.
free(L->str);
//Sgancia l'elemento dalla lista
e
free(L);
//rilascia
la memoria della stringa
L = prev->next;
//e dell'elemento.
count++;
} else
{
if (count > max) max = count;
count = 1;
val = L->val;
prev = L;
L = L->next;
}
}
if (count > max) max = count;
return max;
}
Esercizio 1 (max 9 punti)
Scrivere una funzione, con prototipo int
Cm(long A[], long
B[], int n), che ritorna il numero di
valori distinti che
sono presenti sia nel vettore A che nel vettore B (entrambi i vettori hanno
dimensione n). Ad esempio
se n = 7 e
A = [3,4,3,5,2,2,8] e B = [7,4,4,2,6,3,5] allora
la funzione ritorna 4.
Soluzione Esercizio 1
int
Cm(long A[], long
B[], int n)
{
int i, count = 0;
for (i = 0 ; i < n ;
i++) {
int
j = 0, found = 0;
while
(j < i && !found) {
//Controlla che sia la prima occorrenza
if (A[j] == A[i])
found = 1; //del valore A[i] nel vettore
A.
j++;
}
if (!found)
{
//Se e' la prima occcorrenza
controlla
j = 0;
//se e' presente anche in
B.
while (j < n && !found) {
if (B[j] == A[i]) {
count++;
found = 1;
}
j++;
}
}
}
return count;
}
Esercizio 2 (max 9 punti)
Scrivere una funzione, con prototipo long
Clean(char *srcF, char
*dstF), che preso in input un file di tipo testo, il cui
nome è nella stringa srcF, contenente una sequenza
di numeri interi separati da spazi, crea un nuovo file, il cui nome è
nella stringa
dstF, e vi scrive, nell'ordine,
i numeri del file srcF
ma senza ripetizioni. La funzione ritorna la somma dei numeri scritti nel
nuovo file.
La funzione non deve copiare in memoria il contenuto del file. Ad esempio
se il file srcF contiene 5 -3 11 5 8 8 -3 allora la
funzione scrive nel nuovo file 5 -3 11 8 e ritorna 21.
Soluzione Esercizio 2
/* Funzione ausiliaria che ritorna vero se nel file f
è presente l'intero n. */
short IsPresent(FILE
*f, int n)
{
rewind(f);
int k;
while (fscanf(f, "%d", &k) == 1)
if (k
== n) return 1;
return 0;
}
long Clean(char
*srcF, char *dstF)
{
FILE *src = fopen(srcF, "r");
//Apri il file in lettura
FILE *dst = fopen(dstF, "w+");
//Crea ed apri il nuovo file
long sum = 0;
int n;
while (fscanf(src, "%d", &n) == 1) {
//Leggi uno ad uno i numeri dal file
if (!IsPresent(dst,
n)) { //Se il numero
non e' gia' stato scritto
fseek(dst, 0, SEEK_END);
//Posizionati alla fine del nuovo file
fprintf(dst, "%d ", n); //Scrivi il numero
sum += n;
}
}
fclose(src);
fclose(dst);
return sum;
}
Esercizio 3 (max 12 punti)
Si consideri il seguente tipo:
typedef
struct Elem {
int
num;
struct Elem *next;
} Elem, *List;
Scrivere una funzione, con prototipo int SymDiff(List
*pA, List B), che modifica la lista *pA così che diventi
uguale
alla differenza simmetrica delle liste di partenza *pA e B. Vale a dire che la lista
modificata deve contenere esattamente quegli elementi
che appartenevano a *pA
ma non appartengono a B
uniti con quegli elementi che appartengono a B ma che non appartenevano
a *pA.
La funzione ritorna il numero di elementi che appartenevano ad entrambe
le liste di partenza. Si assuma che tutti gli elementi di *pA
sono distinti e che lo stesso valga per la lista B. La funzione non deve modificare
la lista B. La memoria
degli elementi eliminati deve
essere rilasciata. Ad esempio se la lista *pA è 8 -> 5 -> 2 -> 7 -> 9
e la lista B è 3 -> 8 -> 7 allora la
funzione
modifica la lista *pA
così 5 -> 2 -> 9
-> 3 (l'ordine non ha importanza) e ritorna 2.
Soluzione Esercizio 3
/* Funzione ausiliaria che ritorna vero se nella lista
L e' presente un elemento con
valore del campo num pari ad n.
*/
short IsPresent(List L, int n)
{
while (L != NULL && L->num != n) L = L->next;
return (L != NULL);
}
int SymDiff(List *pA, List B)
{
List BnoA = NULL;
List L = B;
int count = 0;
while (L != NULL) {
//Costruisci la lista degli elementi
if (!IsPresent(*pA,
L->num)) { //che appartengono a B ma che non
Elem *e = malloc(sizeof(Elem));
//appartengono a *pA.
e->num = L->num;
//Nel
comtempo conta gli elementi
e->next = BnoA;
//in comune tra le due liste.
BnoA = e;
} else
count++;
L = L->next;
}
List *p = pA;
while (*p != NULL) {
//Elimina
da *pA gli elementi che
if (IsPresent(B,
(*p)->num)) { //appartengono anche a B.
Elem *e = *p;
*p = (*p)->next;
free(e);
} else
p = &((*p)->next);
}
p = pA;
//Concatena cio' che
rimane di *pA
while (*p != NULL) p
= &((*p)->next); //con la lista precedentemente
*p = BnoA;
//costruita.
return count;
}