## Esercizio 00: Operazioni Base su Liste di Interi ==Qui trovate l'implementazione delle funzioni base su liste di interi. Le soluzioni agli esercizi seguenti fanno riferimento a questo codice, e questo va complementato con l'esercizio 00 della prima parte delle liste (Liste 1)== ```c // Librerie #include <stdio.h> #include <stdlib.h> // !!! // Dati typedef struct NodeStruct { int data; struct NodeStruct * next; } Node; typedef Node * pNode; pNode inserisciOrdinatoNoRip(pNode, int); pNode eliminaPos(pNode, int); pNode eliminaElementiValore(pNode, int); // altre eventuali funzioni nella scorsa esercitazione // Main int main() { pNode head = NULL; // Inizializzazione della lista int err; printf("Creazione lista con inserimento in testa:\n"); head = inserisciTesta(head, 10); head = inserisciTesta(head, 20); head = inserisciTesta(head, 30); stampaLista(head); printf("\nInserimento in coda:\n"); head = inserisciCoda(head, 40); head = inserisciCoda(head, 50); stampaLista(head); printf("\nInserimento in posizione:\n"); head = inserisciPos(head, 25, 2); // Inserisce 25 alla posizione 2 stampaLista(head); printf("\nInserimento ordinato senza duplicati:\n"); head = inserisciOrdinatoNoRip(head, 35); // Inserisce ordinato head = inserisciOrdinatoNoRip(head, 10); // Tentativo duplicato stampaLista(head); printf("\nCalcolo della lunghezza e media della lista:\n"); int len = listaLen(head); float media = listaMedia(head, &err); if (!err) { printf("Lunghezza: %d, Media: %.2f\n", len, media); } else { printf("Errore nel calcolo della media (lista vuota).\n"); } printf("\nRicerca di un elemento nella lista:\n"); int val = 25; if (cercaElemento(head, val)) { printf("Elemento %d trovato nella lista.\n", val); } else { printf("Elemento %d non trovato.\n", val); } printf("\nEliminazione del nodo in posizione 3:\n"); head = eliminaPos(head, 3); // Elimina il nodo alla posizione 3 stampaLista(head); printf("\nEliminazione di tutti i nodi con valore 40:\n"); head = eliminaElementiValore(head, 40); // Elimina tutti i nodi con valore 40 stampaLista(head); printf("\nLiberazione della lista:\n"); eliminaLista(head); head = NULL; stampaLista(head); // Verifica che la lista sia vuota return 0; } pNode inserisciOrdinatoNoRip(pNode head, int new_data) { // Alloco il nuovo nodo pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } new_node->data = new_data; new_node->next = NULL; // Controllo se il valore è già presente pNode curr = head, prec = NULL; while (curr != NULL && new_data > curr->data) { prec = curr; curr = curr->next; } // Se il valore è già presente, non inserisco nulla if (curr != NULL && curr->data == new_data) { printf("Valore %d già presente, non inserito.\n", new_data); free(new_node); return head; } // Inserimento in testa (prec == NULL) if (prec == NULL) { new_node->next = curr; head = new_node; } // Inserimento tra prec e curr else { prec->next = new_node; new_node->next = curr; } return head; } pNode eliminaPos(pNode head, int index) { // Controllo se l'indice è valido if (index < 0) { printf("Indice %d non valido\n", index); return head; } // Lista vuota if (head == NULL) { printf("Lista vuota, impossibile eliminare.\n"); return head; } // Eliminazione della testa if (index == 0) { pNode temp = head; head = head->next; free(temp); return head; } // Altri casi: scorro la lista pNode curr = head, prec = NULL; int pos = 0; while (curr != NULL && pos < index) { prec = curr; curr = curr->next; pos++; } // Controllo se l'indice è fuori dai limiti if (curr == NULL) { printf("Indice %d fuori dai limiti.\n", index); return head; } // Rimuovo il nodo corrente prec->next = curr->next; free(curr); return head; } pNode eliminaElementiValore(pNode head, int value){ pNode curr = head, prec = NULL, tmp; // Elimino in testa while(curr != NULL && curr->data == value){ tmp = curr; curr = curr->next; free(tmp); } // Aggiorno la testa head = curr; // Elimino non in testa while(curr != NULL){ if(curr->data == value){ tmp = curr; prec->next = curr->next; curr = curr->next; free(tmp); } else{ prec = curr; curr = curr->next; } } return head; } ``` ## Esercizio 00: Operazioni Base su Liste di Stringhe ==Qui trovate l'implementazione delle funzioni base su liste di stringhe. Le soluzioni agli esercizi seguenti fanno riferimento a questo codice.== ```c // Librerie #include <stdio.h> #include <stdlib.h> #include <string.h> // Per funzioni su stringhe // Macro #define LEN 100 // Tipo Stringa typedef char Stringa[LEN]; // Dati typedef struct NodeStruct { Stringa data; struct NodeStruct *next; } Node; typedef Node *pNode; // Prototipi void stampaLista(pNode); pNode inserisciCoda(pNode, Stringa); pNode inserisciTesta(pNode, Stringa); pNode inserisciPos(pNode, Stringa, int); pNode inserisciOrdinatoNoRip(pNode, Stringa); int listaLen(pNode); int cercaElemento(pNode, Stringa); void eliminaLista(pNode); pNode eliminaPos(pNode, int); pNode eliminaElementiValore(pNode, Stringa); // Main int main() { pNode head = NULL; // Inizializzazione della lista Stringa s; printf("Creazione lista con inserimento in testa:\n"); strcpy(s, "Ciao"); head = inserisciTesta(head, s); strcpy(s, "Mondo"); head = inserisciTesta(head, s); strcpy(s, "Test"); head = inserisciTesta(head, s); stampaLista(head); printf("\nInserimento in coda:\n"); strcpy(s, "Esempio"); head = inserisciCoda(head, s); stampaLista(head); printf("\nInserimento ordinato senza duplicati:\n"); strcpy(s, "Alpha"); head = inserisciOrdinatoNoRip(head, s); strcpy(s, "Test"); // Tentativo duplicato head = inserisciOrdinatoNoRip(head, s); stampaLista(head); printf("\nRicerca di un elemento nella lista:\n"); strcpy(s, "Test"); if (cercaElemento(head, s)) { printf("Elemento '%s' trovato nella lista.\n", s); } else { printf("Elemento '%s' non trovato.\n", s); } printf("\nEliminazione del nodo in posizione 1:\n"); head = eliminaPos(head, 1); // Elimina il nodo alla posizione 1 stampaLista(head); printf("\nEliminazione di tutti i nodi con valore 'Alpha':\n"); strcpy(s, "Alpha"); head = eliminaElementiValore(head, s); // Elimina tutti i nodi con valore 'Alpha' stampaLista(head); printf("\nLiberazione della lista:\n"); eliminaLista(head); head = NULL; stampaLista(head); // Verifica che la lista sia vuota return 0; } // Funzioni void stampaLista(pNode head) { if (head == NULL) { printf("Lista vuota!\n"); } else { pNode curr = head; while (curr != NULL) { printf("%s -> ", curr->data); curr = curr->next; } printf("NULL\n"); } } pNode inserisciCoda(pNode head, Stringa new_data) { pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } strcpy(new_node->data, new_data); new_node->next = NULL; if (head == NULL) return new_node; pNode curr = head; while (curr->next != NULL) curr = curr->next; curr->next = new_node; return head; } pNode inserisciTesta(pNode head, Stringa new_data) { pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } strcpy(new_node->data, new_data); new_node->next = head; return new_node; } pNode inserisciPos(pNode head, Stringa new_data, int index) { if (index < 0) { printf("Indice %d non valido\n", index); return head; } if (index == 0) return inserisciTesta(head, new_data); pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } strcpy(new_node->data, new_data); int pos = 0; pNode curr = head, prec = NULL; while (curr != NULL && pos < index) { prec = curr; curr = curr->next; pos++; } if (pos != index) { printf("Indice %d fuori dai limiti.\n", index); free(new_node); return head; } prec->next = new_node; new_node->next = curr; return head; } pNode inserisciOrdinatoNoRip(pNode head, Stringa new_data) { pNode curr = head, prec = NULL; while (curr != NULL && strcmp(new_data, curr->data) > 0) { prec = curr; curr = curr->next; } if (curr != NULL && strcmp(new_data, curr->data) == 0) { printf("Valore '%s' già presente, non inserito.\n", new_data); return head; } pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } strcpy(new_node->data, new_data); new_node->next = curr; if (prec == NULL) { return new_node; } else { prec->next = new_node; } return head; } int listaLen(pNode head) { int len = 0; pNode curr = head; while (curr != NULL) { curr = curr->next; len++; } return len; } int cercaElemento(pNode head, Stringa value) { pNode curr = head; while (curr != NULL) { if (strcmp(curr->data, value) == 0) return 1; curr = curr->next; } return 0; } void eliminaLista(pNode head) { pNode curr; while (head != NULL) { curr = head; head = head->next; free(curr); } } pNode eliminaPos(pNode head, int index) { if (index < 0) { printf("Indice %d non valido\n", index); return head; } if (head == NULL) return head; if (index == 0) { pNode temp = head; head = head->next; free(temp); return head; } pNode curr = head, prec = NULL; int pos = 0; while (curr != NULL && pos < index) { prec = curr; curr = curr->next; pos++; } if (curr == NULL) return head; prec->next = curr->next; free(curr); return head; } pNode eliminaElementiValore(pNode head, Stringa value) { pNode curr = head, prec = NULL, tmp; while (curr != NULL && strcmp(curr->data, value) == 0) { tmp = curr; curr = curr->next; free(tmp); } head = curr; while (curr != NULL) { if (strcmp(curr->data, value) == 0) { tmp = curr; prec->next = curr->next; curr = curr->next; free(tmp); } else { prec = curr; curr = curr->next; } } return head; } ``` --- ## Esercizio 04: Copia Elemento in una Posizione Specifica (Lista di Interi) Date due liste di interi e un indice, scrivere una funzione che copia l’elemento della prima lista nella posizione data nella seconda lista, alla stessa posizione. **Nota**: la soluzione va integrata con il codice di “Operazione Base su Liste di Interi” ```c // Prototipo int copiaPos(pNode, pNode, int); // Funzione int copiaPos(pNode h1, pNode h2, int pos) { // Controllo variabile pos if (pos < 0) { printf("Errore: posizione non valida (%d).\n", pos); return 0; } // Variabili di controllo pNode curr1 = h1, curr2 = h2; int index = 0; // Scorro entrambe le liste while (curr1 != NULL && curr2 != NULL) { // Controllo se ho raggiunto la posizione desiderata if (index == pos) { curr2->n = curr1->n; // Copio il valore return 1; // Successo } // Avanzo nelle liste curr1 = curr1->next; curr2 = curr2->next; index++; } // Se arrivo qui, non ho trovato la posizione printf("Errore: posizione %d fuori dai limiti delle liste.\n", pos); return 0; } ``` --- ## Esercizio 05: Copia Elementi Pari (Lista di Interi) Data una lista di interi, scrivere una funzione che cerca nella lista il tutti gli elementi pari e li copia in coda ad una nuova lista. **Nota**: la soluzione va integrata con il codice di “Operazione Base su Liste di Interi” ```c // Prototipo pNode copiaPari(pNode, pNode); // Funzione pNode copiaPari(pNode head1, pNode head2) { if (head1 == NULL) { printf("La lista da cui copiare è vuota.\n"); return head2; // Restituisco head2 (potrebbe essere già popolata) } pNode curr = head1; // Copio i numeri pari da head1 a head2 while (curr != NULL) { if (curr->data % 2 == 0) { head2 = inserisciCoda(head2, curr->data); } curr = curr->next; } return head2; } ``` ==**Nota**: in questo modo scorro ogli volta la lista fino all'ultimo elemento, si può fare di meglio? (modificare la funzione inserisciCoda).== --- ## Esercizio 07: Trova Stringa di Lunghezza Minima (Lista di Stringhe) Data una lista di stringhe, scrivere una funzione che trova e restituisce la stringa di lunghezza minima. **Nota**: la soluzione va integrata con il codice di “Operazione Base su Liste di Stringhe” ```c // Prototipo void trovaStringaMin(pNode, Stringa, int*); // Funzione void trovaStringaMin(pNode head, Stringa res, int *err) { // Inizializzo errore a 0 *err = 0; // Caso lista vuota if (head == NULL) { printf("Lista vuota.\n"); *err = 1; strcpy(res, ""); // Resetta `res` a una stringa vuota return; } // Inizializzo `res` con la stringa del primo nodo strcpy(res, head->data); // Scorro la lista per trovare la stringa più corta pNode curr = head->next; // Parto dal secondo nodo while (curr != NULL) { if (strlen(res) > strlen(curr->data)) { strcpy(res, curr->data); } curr = curr->next; } } ``` --- ## Esercizio 08: Copia Stringhe per Prefisso (Liste di Stringhe) Date due liste di stringhe e una stringa prefisso, scrivere una funzione che trova nella prima lista le stringhe che iniziano per il prefisso dato e copiarle in coda alla seconda lista. Scrivere una funzione separata per controllare che una stringa inizi con un certo suffisso. **Nota**: la soluzione va integrata con il codice di “Operazione Base su Liste di Stringhe” ```c // Prototipi int controllaPrefisso(Stringa, Stringa); pNode copiaStringhePerPrefisso(pNode, pNode, Stringa); // Funzioni int controllaPrefisso(Stringa s, Stringa prefix) { int len_prefix = strlen(prefix); // Il prefisso non può essere più lungo della stringa if (strlen(s) < len_prefix) return 0; // Confronta caratteri all'inizio for (int i = 0; i < len_prefix; i++) { if (s[i] != prefix[i]) return 0; } return 1; // È un prefisso } pNode copiaStringhePerPrefisso(pNode head1, pNode head2, Stringa prefix) { if (head1 == NULL) { printf("Lista vuota.\n"); return head2; } pNode curr = head1; // Scorri la lista `head1` e copia i nodi con il prefisso richiesto while (curr != NULL) { if (controllaPrefisso(curr->data, prefix)) { head2 = inserisciCoda(head2, curr->data); } curr = curr->next; } return head2; } ``` ==**Nota**: in questo modo scorro ogli volta la lista fino all'ultimo elemento, si può fare di meglio? (modificare la funzione inserisciCoda).== --- ## Esercizio 11: Catena di Stringhe CCTSF (Liste di Stringhe) (TDE 19.02.2007) **Richiesta 1.** Data una lista di stringhe, scrivere una funzione che restituisce 1 se la lista rappresenta una catena di parole CCTSF (i.e., compatibile col telefono senza fili). Una catena di parole si dice CCTSF se è composta da parole adiacenti simili (ovvero con al più due caratteri diversi). Si supponga di poter utilizzare una funzione con prototipo **int simili(char * s1, char * s2);** che restituisce 1 se le stringhe s1 e s2 sono simili, zero altrimenti. ```c= typedef struct Elem { char * data; struct Elem * next; } Nodo; typedef Nodo * pNode; ``` ### Versione Iterativa (parte 1) ```c= // Prototipo int stringheCCTSF(pNode head); int simili(char * s1, char * s2); // Funzione int stringheCCTSF(pNode head){ if(head == NULL || head->next == NULL) return 1; pNode curr = head; while(curr->next != NULL){ if(!simili(curr->data, curr->next->data)) return 0; curr = curr->next; } return 1; } ``` ### Versione Ricorsiva (parte 1) ```c= // Prototipo int stringheCCTSF(pNode head); int simili(char * s1, char * s2); // Funzione int stringheCCTSF(pNode head){ if(head == NULL || head->next == NULL) return 1; if(!simili(curr->data, curr->next->data)) return 0; return stringheCCTSF(head->next); } ``` --- ## Esercizio 12: Eliminazione di Tutta la Lista Scrivere una funzione che elimina tutta la lista (sia in modo iterativo che ricorsivo). ==:warning: fare attenzione al valore che assume il puntatore `head` nel main! Come si può fare per farlo modificare in automatico nelle funzioni sottostanti?== ### Iterativo ```c= void eliminaListaIterativa(pNode head) { pNode curr; while (head != NULL) { curr = head; // Salva il nodo corrente head = head->next; // Passa al nodo successivo free(curr); // Libera la memoria del nodo corrente } printf("Lista eliminata (iterativa).\n"); } ``` ### Ricorsivo ```c= void eliminaListaRicorsiva(pNode head) { // Caso base: lista vuota if (head == NULL) { printf("Lista eliminata (ricorsiva).\n"); return; } // Passo ricorsivo: libera il resto della lista eliminaListaRicorsiva(head->next); // Libera il nodo corrente free(head); } ``` --- ## Esercizio 13: Eliminazione di un Elemento in Posizione $i$ Scrivere una funzione che elimina un singolo elemento nella lista in poisizione $i$ in modo ricorsivo (iterativo visto nelle funzioni base). ```c= pNode eliminaPosRicorsivo(pNode head, int pos) { // Caso base: posizione non valida o lista vuota if (pos < 0) { printf("Posizione non valida\n"); return head; } if (head == NULL) { printf("Lista vuota\n"); return head; } // Caso: eliminazione del primo nodo if (pos == 0) { pNode tmp = head; head = head->next; free(tmp); return head; } // Passo ricorsivo: procedo alla posizione successiva head->next = eliminaPosRicorsivo(head->next, pos - 1); return head; } ``` --- ## Esercizio 14: Eliminazione di Tutti gli Elementi Minori di un Valore Dato Scrivere una funzione che elimina tutti gli elementi nella lista che sono minori di un certo valore dato (sia in modo iterativo che ricorsivo). ### Iterativo ```c= pNode eliminaMinoriIterativo(pNode head, int val) { // Elimino tutti i nodi in testa che soddisfano la condizione while (head != NULL && head->data < val) { pNode tmp = head; head = head->next; free(tmp); } // Se la lista è vuota dopo aver eliminato i nodi in testa if (head == NULL) return NULL; // Scorro il resto della lista pNode curr = head, prec = NULL; while (curr != NULL) { if (curr->data < val) { // Elimina il nodo corrente pNode tmp = curr; prec->next = curr->next; curr = curr->next; free(tmp); } else { // Avanza prec = curr; curr = curr->next; } } return head; } ``` ### Ricorsivo ```c= pNode eliminaMinoriRicorsivo(pNode head, int val) { // Caso base: lista vuota if (head == NULL) return NULL; // Se il nodo corrente deve essere eliminato if (head->data < val) { pNode tmp = head; head = eliminaMinoriRicorsivo(head->next, val); // Passo ricorsivo free(tmp); return head; } // Nodo corrente non soddisfa la condizione, passo al prossimo head->next = eliminaMinoriRicorsivo(head->next, val); return head; } ``` --- ## Esercizio 15: Inserimento Ordinato con Ripetizione Scrivere una funzione ricorsiva che inserisce un nodo in modo ordinato (anche con ripetizioni). ### Iterativo ```c= pNode inserisciOrdinatoIterativo(pNode head, int new_data) { // Alloco il nuovo nodo pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } new_node->data = new_data; new_node->next = NULL; // Caso: lista vuota o nuovo nodo da inserire in testa if (head == NULL || new_data < head->data) { new_node->next = head; return new_node; } // Trovo la posizione in cui inserire il nuovo nodo pNode curr = head; while (curr->next != NULL && curr->next->data < new_data) { curr = curr->next; } // Inserisco il nodo tra curr e curr->next new_node->next = curr->next; curr->next = new_node; return head; } ``` ### Ricorsivo ```c= pNode inserisciOrdinatoRicorsivo(pNode head, int new_data) { // Caso base: lista vuota o inserimento in testa if (head == NULL || new_data < head->data) { pNode new_node = (pNode)malloc(sizeof(Node)); if (new_node == NULL) { printf("Errore di allocazione\n"); return head; } new_node->data = new_data; new_node->next = head; return new_node; } // Passo ricorsivo: scorro la lista head->next = inserisciOrdinatoRicorsivo(head->next, new_data); return head; } ``` --- ## Esercizio 16: Eliminazione dei Primi $N$ Elementi Scrivere una funzione che elimini i primi $N$ elementi di una lista (in modo iterativo e ricorsivo). ### Iterativo ```c= pNode eliminaPrimiElementiIterativo(pNode head, int n) { // Lista vuota o n non valido if (head == NULL || n <= 0) return head; // Scorro ed elimino i primi `n` elementi pNode curr; while (head != NULL && n > 0) { // Salvo il nodo corrente (head) curr = head; // Avanzo nella lista head = head->next; // Libero il nodo corrente free(curr); // Decremento il contatore n--; } // Restituisco la nuova testa della lista return head; } ``` ### Ricorsivo ```c= pNode eliminaPrimiElementiRicorsivo(pNode head, int n) { // Lista vuota o n non valido if (head == NULL || n <= 0) return head; // Passo ricorsivo: elimino il primo nodo pNode new_head = eliminaPrimiElementiRicorsivo(head->next, n - 1); // Libero il nodo corrente free(head); // Restituisco la nuova testa return new_head; } ``` --- ## Esercizio 17: Eliminazione degli Elementi Duplicati Scrivere una funzione che elimina gli elementi duplicati da una lista (in modo iterativo e ricorsivo). **Dai dubbi emersi durante la lezione:** 1. Attenzione: non è come eliminare gli elementi di un dato valore a priori, perché il valore è dato da ogni elemento della lista. 2. Per questo motivo: a. Scorro la lista fino alla fine in modo ricorsivo b. Quando ritorno dall'ultimo elemento, ricorsivamente uso quel valore per eliminare (a partire dal nodo successivo) gli elementi con quel valore :::warning :warning: Riporto sia le funzioni di interesse, che il codice completo per poterlo provare. Le funzioni di interesse sono commentate di più per poterci focalizzare su quelle ::: ### Iterativo - solo funzione Idea: Scorro la lista, ed a partire da ogni elemento la scorro di nuovo fino alla fine per vedere se trovo un valore uguale al nodo di partenza. ```c pNode eliminaDuplicatiIterativo(pNode head) { // Lista vuota o con un solo elemento // serve per evitare che l'utente chiami questa funzione su una lista vuota if (head == NULL || head->next == NULL) return head; pNode curr = head; // Scorro la lista esterna while (curr != NULL) { pNode runner = curr; // Runner per scorrere il resto della lista while (runner->next != NULL) { if (runner->next->data == curr->data) { // Nodo duplicato trovato pNode tmp = runner->next; runner->next = runner->next->next; // Salta il duplicato free(tmp); // Libera il nodo duplicato } else { runner = runner->next; // Avanza } } curr = curr->next; // Avanza nella lista esterna } return head; } ``` ### Ricorsivo - solo funzione Idea: - Scorro la lista fino alla fine ricorsivamente - Man mano che torno indietro partendo dal fondo - Ri-scorro fino alla fine partendo dal prossimo nodo per eliminare gli elementi uguali, aggiornando i `next` Possibili domande emerse: - Perché non elimino man mano che vado in fondo? - è più facile impostare la ricorsione così, provate a fare il contrario e capirete perché ```c= pNode eliminaElementiUguali(pNode head, int value) { // elimina in una lista che parte da head, il valore value // idea: se head->data non è uguale a value, ritorno head (il chiamante ha chiamato per assegnare next). // altrimenti, ritorno il primo che ha un valore non uguale a quello passato come value // Caso base: lista vuota if (head == NULL) return NULL; // Caso: il nodo corrente contiene `value` // in questo caso elimino head e trovo la nuova head chiamando ricorsivamente la // funzione. if (head->data == value) { pNode tmp = head; // Salvo il nodo corrente head = eliminaElementiUguali(head->next, value); // Elimino il resto dei nodi con `value` free(tmp); // Libero il nodo corrente // ora NON punto più al nodo che mi è stata passato dal chiamante tramite head, ma tornerò // il puntatore che mi ritorna la chiamata ricorsiva. Nel caso in cui quella ricorsiva non // trovasse un elemento uguale subito dopo dopo, ritornerebbe il puntatore al successivo (rispetto alla lista originale). // // se c'è una catena di valori uguali, continuo ad entrare in questo if e ritorno un puntatore // al primo nodo diverso return head; } // Caso: il nodo corrente non contiene `value`, lo tengo buono // (ovvero tengo la head passata dal chiamante) ed eventualmente aggiorno il next nella // chiamata successiva. head->next = eliminaElementiUguali(head->next, value); return head; } pNode eliminaDuplicatiRicorsivo(pNode head) { // Caso base: lista vuota o con un solo elemento if (head == NULL || head->next == NULL) return head; // Elimino ricorsivamente i duplicati dalla lista // partendo dalla lista che inizia un elemento dopo head->next = eliminaDuplicatiRicorsivo(head->next); // Elimino ricorsivamente tutti i nodi uguali al dato di head partendo dall'elemento successivo // questa viene chiamata partendo dal fondo della lista head->next = eliminaElementiUguali(head->next, head->data); return head; } ``` ### Iterativo - codice completo Qui trovate tutto il codice per eseguire effettivamente le funzioni sopra :::warning :warning: il codice delle funzioni qui contiene solo commenti base. Una versione più commentata la trovate [qui](#Iterativo---solo-funzione), nella sezione "Iterativo - solo funzione" ::: ```c // include #include <stdio.h> #include <stdlib.h> // Dati typedef struct NodeStruct { int data; struct NodeStruct *next; } Node; typedef Node *pNode; // Prototipo void stampaLista(pNode); pNode inserisciTesta(pNode, int); pNode eliminaDuplicatiIterativo(pNode); int main() { // inizializzo la lista int n = 2; // Numero di elementi da eliminare pNode head = NULL; head = inserisciTesta(head, 20); head = inserisciTesta(head, 10); head = inserisciTesta(head, 10); head = inserisciTesta(head, 703); // lista: 703 -> 10 -> 10 -> 20 printf("Lista creata:\n"); stampaLista(head); printf("\n"); // elimino i primi n elementi head = eliminaDuplicatiIterativo(head); printf("Lista dopo eliminazione dei duplicati:\n"); stampaLista(head); return 0; } pNode eliminaDuplicatiIterativo(pNode head) { // Lista vuota o con un solo elemento if (head == NULL || head->next == NULL) return head; pNode curr = head; // Scorro la lista esterna while (curr != NULL) { pNode runner = curr; // Runner per scorrere il resto della lista while (runner->next != NULL) { if (runner->next->data == curr->data) { // Nodo duplicato trovato pNode tmp = runner->next; runner->next = runner->next->next; // Salta il duplicato free(tmp); // Libera il nodo duplicato } else { runner = runner->next; // Avanza } } curr = curr->next; // Avanza nella lista esterna } return head; } // Funzioni void stampaLista(pNode head){ if(head == NULL){ printf("Lista vuota!\n"); } else{ pNode curr = head; // Stampo fino al penultimo while(curr->next != NULL){ printf("%d ->", curr->data); curr = curr->next; } // stampo l'ultimo printf("%d\n", curr->data); } } pNode inserisciTesta(pNode head, int new_data){ // Alloco il nuovo nodo pNode new = (pNode)malloc(sizeof(Node)); if(new == NULL){ printf("Errore di allocazione\n"); return head; } new->data = new_data; new->next = NULL; // Bisogna che il nuovo nodo sia la testa e bisogna restituire la testa new->next = head; return new; } ``` ### Ricorsivo - codice completo Qui trovate tutto il codice per eseguire effettivamente le funzioni sopra. :::warning :warning: il codice delle funzioni qui contiene solo commenti base. Una versione più commentata la trovate [qui](#Ricorsivo---solo-funzione), nella sezione "Ricorsivo - solo funzione" ::: ```c // include #include <stdio.h> #include <stdlib.h> // Dati typedef struct NodeStruct { int data; struct NodeStruct *next; } Node; typedef Node *pNode; // Prototipo void stampaLista(pNode); pNode inserisciTesta(pNode, int); pNode eliminaDuplicatiRicorsivo(pNode); pNode eliminaElementiUguali(pNode, int); int main() { // inizializzo la lista pNode head = NULL; head = inserisciTesta(head, 20); head = inserisciTesta(head, 10); head = inserisciTesta(head, 10); head = inserisciTesta(head, 703); // lista: 703 -> 10 -> 10 -> 20 printf("Lista creata:\n"); stampaLista(head); printf("\n"); // elimino i duplicati head = eliminaDuplicatiRicorsivo(head); printf("Lista dopo eliminazione dei duplicati:\n"); stampaLista(head); return 0; } pNode eliminaElementiUguali(pNode head, int value) { // Caso base: lista vuota if (head == NULL) return NULL; // Caso: il nodo corrente contiene `value` if (head->data == value) { pNode tmp = head; // Salvo il nodo corrente head = eliminaElementiUguali(head->next, value); // Elimino il resto dei nodi con `value` free(tmp); // Libero il nodo corrente return head; } // Caso: il nodo corrente non contiene `value` head->next = eliminaElementiUguali(head->next, value); return head; } pNode eliminaDuplicatiRicorsivo(pNode head) { // Caso base: lista vuota o con un solo elemento if (head == NULL || head->next == NULL) return head; // Elimino ricorsivamente i duplicati del resto della lista head->next = eliminaDuplicatiRicorsivo(head->next); // Elimino ricorsivamente tutti i nodi uguali al dato di head head->next = eliminaElementiUguali(head->next, head->data); return head; } // Funzioni void stampaLista(pNode head){ if(head == NULL){ printf("Lista vuota!\n"); } else{ pNode curr = head; // Stampo fino al penultimo while(curr->next != NULL){ printf("%d ->", curr->data); curr = curr->next; } // stampo l'ultimo printf("%d\n", curr->data); } } pNode inserisciTesta(pNode head, int new_data){ // Alloco il nuovo nodo pNode new = (pNode)malloc(sizeof(Node)); if(new == NULL){ printf("Errore di allocazione\n"); return head; } new->data = new_data; new->next = NULL; // Bisogna che il nuovo nodo sia la testa e bisogna restituire la testa new->next = head; return new; } ``` ---