Seguendo la metafora variabile <=> scatola, questi costrutti corrispondono
ad avere un certo numero di quelle scatole di cartone smontabili, che vengono vendute
appiatite.
Quando si abbisogna una nuova scatola, si richiede ad un montatore di
montare una nuova scatola e di ritonare un modo per identificarla,
cioè un nome di scatola (informaticamente un puntatore).
Potrebbe succedere che non vi siano più scatole da montare, e
quindi la richiesta risulta in un fallimento.
Quando una di quese scatole smontabili non serve più è
possibile rilasciarla, essa verrà smontata e sarà disponibile
per future richieste.
Per usare le operazioni presentate sopra occorre
premettere al programma
#include <stdlib.h>.
struct REC { int F1; ... int Fn; REC F; };questo non è accettato dal C e dagli altri linguaggi similari (es. Pascal, Ada); mentre se usiamo i puntatori nel seguente modo diventa accettabile
struct REC { int F1; ... int Fn; REC * F; };infatti in questo caso, la componente F sara semplicemente un puntatore ad (indirizzo di) una cella che conterrà un valore di tipo REC.
typedef struct INS *INSIEME; struct INS { float ELEMENTO; INS * PROSSIMO; } ;quindi un insieme è un puntatore che punta all'inzio della lista dei suoi elementi.
Le costanti e le operazioni principali del tipo di dato sono presentate di seguito.
const INSIEME Vuoto = NULL; /* l'insieme vuoto*/ int Appartiene(float x, INSIEME s) /* controlla se x appartiene ad s */ { int app = FALSE; while( (s != NULL) && (! app) ) if( x == s ->ELEMENTO ) app = TRUE; else s = s -> PROSSIMO; return app; } int Contenuto(INSIEME s1, INSIEME s2) /* controlla se s1 e' contenuto in s2 */ { int cont = TRUE; while( (s1 != NULL) && cont ) if( Appartiene(s1 -> ELEMENTO, s2) ) s1 = s1 -> PROSSIMO; else cont = FALSE; return cont; } INSIEME Singleton (float x) /* ritorna l'insieme il cui unico elemento e' x */ { INSIEME s = (INSIEME)malloc(sizeof(struct INS)); s -> PROSSIMO = NULL; s -> ELEMENTO = x; return s; } INSIEME Aggiungi_Elemento(float x, INSIEME s) /*aggiunge x all'insieme s*/ { INSIEME primo; primo = Singleton(x); primo -> PROSSIMO = s; return primo; } INSIEME Togli_Elemento(float x, INSIEME s) /*toglie x dall'insieme s, modifica s*/ { if(s == NULL) return s; else if(x == s -> ELEMENTO) return Togli_Elemento(x, s -> PROSSIMO); else{ s -> PROSSIMO = Togli_Elemento(x, s -> PROSSIMO); return s; }; } INSIEME safeTogli_Elemento(float x, INSIEME s) /*toglie x dall'insieme s, non modifica s*/ { if(s == NULL) return s; else if(x == s -> ELEMENTO) return safeTogli_Elemento(x, s -> PROSSIMO); else return Aggiungi_Elemento(s -> ELEMENTO, safeTogli_Elemento(x, s -> PROSSIMO)); }; INSIEME safeUnione(INSIEME s1, INSIEME s2) /* non usa s1 ed s2*/ { if(s1 == NULL) return Fai_Copia(s2); else return Aggiungi_Elemento(s1->ELEMENTO, safeUnione( s1 -> PROSSIMO, s2)); } INSIEME safeIntersezione(INSIEME s1, INSIEME s2) /* non usa s1 ed s2*/ { if(s1 == NULL) return NULL; else if(Appartiene(s1 -> ELEMENTO,s2)) return Aggiungi_Elemento(s1->ELEMENTO, safeIntersezione( s1 -> PROSSIMO, s2)); else return safeIntersezione( s1 -> PROSSIMO, s2); }Notare le due versioni della funzione per togliere un elemento, quella sicura e l'altra. Questo è dovuto all'uso dei puntatori, utilizzando le versioni sicure siamo certi che gli argomenti non sono modificati; quando invece vogliamo proprio modificare gli argomenti si deve usare l'atra versione.
INSIEME Fai_Copia(INSIEME s) /*ritorna una copia dell'insieme s*/ { INSIEME copia = NULL, aux = s, aux2; while(aux != NULL){ aux2 = Singleton(aux -> ELEMENTO); aux2 -> PROSSIMO = copia; copia = aux2; aux = aux -> PROSSIMO; }; return copia; }ed una per eliminare (disallocare) un dato, come
void Elimina(INSIEME s) /* dissalloca s */ { INSIEME aux; while(s != NULL){ aux = s; s = s -> PROSSIMO; free(aux); }; }Le funzioni per leggere e scrivere gli elementi del tipo di dato sono
INSIEME Leggi_S(void) { char answer = 'S'; float el; INSIEME s = NULL; do{ printf("\nC\'e\' ancora un elemento? (S/N)\n"); do scanf("%c", &answer); while(answer=='\n'); if(answer=='S'){ printf("Darlo\n"); scanf("%f", &el); s = Aggiungi_Elemento(el,s); } } while(answer == 'S'); return s; } void Stampa_Insieme(INSIEME s) { printf("{ "); while(s != NULL){ if(! Appartiene(s -> ELEMENTO,s -> PROSSIMO)){ printf("%f",s -> ELEMENTO); if(s -> PROSSIMO != NULL) printf(" , "); }; s = s -> PROSSIMO; }; printf(" }"); }
INSIEME safeTogli_Elemento(float x, INSIEME s) /*toglie x dall'insieme s, non modifica s*/ { return Togli_Elemento(x, Fai_Copia(S)); }Discutere le differenze con la versione data precedentemente.
int Appartiene0(float x, INSIEME s) /* controlla se x appartiene ad s */ { if( s == NULL ) return FALSE; else if(x == s -> ELEMENTO) return TRUE; else return Appartiene0(x,s -> PROSSIMO); }è la versione ricorsiva di Appartiene.
int Appartiene1(float x, INSIEME s) /* controlla se x appartiene ad s */ { while((s != NULL) && x != s ->ELEMENTO ) s = s -> PROSSIMO; return s != NULL; }è la versione C-oriented di Appartiene.
#define MAX_CARD 100 struct INSIEME { float ELEMENTI[MAX_CARD]; /*gli elementi dell'insieme sono allocati nelle componenti dell'array ELEMENTI da quella di indice 0 a quella di indice LIBERA -1 Si assume che non vi siano ripetizioni. */ int LIBERA; /*indice della prima casella libera*/ } ; const INSIEME Vuoto = { { 0 }, 0 }; /* l'insieme vuoto*/ int Appartiene(float x, INSIEME s) /* controlla se x appartiene ad s */ { int app = FALSE, i; for(i = 0; i < s.LIBERA && ! app; i++) if( x == s.ELEMENTI[i] ) app = TRUE; return app; } void Stampa_Insieme(INSIEME s) { int i; printf("{ "); for(i = 0; i < s.LIBERA -1; i++){ printf("%f",s.ELEMENTI[i]); printf(" , "); }; if(s.LIBERA > 0) printf("%f",s.ELEMENTI[s.LIBERA-1]); printf(" }"); } int Contenuto(INSIEME s1, INSIEME s2) /* controlla se s1 e' contenuto in s2 */ { int cont = TRUE, i; for(i = 0; i < s1.LIBERA && cont; i++) if( !Appartiene(s1.ELEMENTI[i], s2) ) cont = FALSE; return cont; } INSIEME Singleton (float x) /* ritorna l'insieme il cui unico elemento e' x */ { INSIEME s = { { x }, 1 }; return s; } INSIEME Aggiungi_Elemento(float x, INSIEME s) /*aggiunge x all'insieme s*/ { if(!Appartiene(x,s)) if(s.LIBERA == MAX_CARD) printf("ERRORE: non c\'e\' piu\' spazio\n"); else { s.ELEMENTI[s.LIBERA] = x; s.LIBERA ++; }; return s; } INSIEME Togli_Elemento(float x, INSIEME s) /*toglie x dall'insieme s*/ { int i; for(i = 0; i < s.LIBERA; i++) if(s.ELEMENTI[i] == x){ s.ELEMENTI[i] = s.ELEMENTI[s.LIBERA-1]; i = s.LIBERA = s.LIBERA-1; }; return s; } INSIEME Unione(INSIEME s1, INSIEME s2) { int i; for(i = 0; i < s1.LIBERA; i++) s2 = Aggiungi_Elemento(s1.ELEMENTI[i], s2); return s2; } INSIEME Intersezione(INSIEME s1, INSIEME s2) { int i; INSIEME s = Vuoto; for(i = 0; i < s1.LIBERA; i++) if(Appartiene(s1.ELEMENTI[i],s2)) s = Aggiungi_Elemento(s1.ELEMENTI[i], s); return s; } INSIEME Leggi_S(void) { char answer = 'S'; float el; INSIEME s = Vuoto; do{ printf("\nC\'e\' ancora un elemento? (S/N)\n"); do scanf("%c", &answer); while(answer == '\n'); if(answer == 'S'){ printf("Darlo\n"); scanf("%f", &el); s = Aggiungi_Elemento(el,s); } } while(answer == 'S'); return s; }