# Liste 3
# 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);
}
```
---
# Eliminazione di un Elemento in Posizione $i$
Scrivere una funzione che elimina un singolo elemento nella lista in poisizione $i$ (sia in modo iterativo che ricorsivo).
## Iterativo
```c=
pNode eliminaPosIterativo(pNode head, int pos) {
// Caso base: posizione non valida
if (pos < 0) {
printf("Posizione non valida\n");
return head;
}
// Caso: lista vuota
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;
}
// Altri casi: scorro la lista per trovare il nodo precedente a quello da eliminare
pNode curr = head, prev = NULL;
int index = 0;
while (curr != NULL && index < pos) {
prev = curr;
curr = curr->next;
index++;
}
// Se la posizione è fuori dai limiti
if (curr == NULL) {
printf("Posizione %d fuori dai limiti\n", pos);
return head;
}
// Elimino il nodo
prev->next = curr->next;
free(curr);
return head;
}
```
## Ricorsivo
```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;
}
```
---
# 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;
}
```
---
# Inserimento Ordinato con Ricorsione
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;
}
```
---
# 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;
}
```
---
# Eliminazione degli Elementi Duplicati
Scrivere una funzione che elimina gli elementi duplicati da una lista (in modo iterativo e ricorsivo).
## Iterativo
```c=
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;
}
```
## Ricorsivo
```c=
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;
}
```
---
# Costruzione Liste Compresse
Si considerino le seguenti definizioni:
```c=
// Lista di interi
typedef struct el {
int data;
struct el * next;
} Node;
typedef Node * pNode;
// Lista compressa di interi
typedef struct c_el{
int data, count;
struct c_el * next;
} CNode;
typedef CNode * pCNode;
```
Le liste compresse rappresentano le classiche liste con nodi in cui appare il valore e il numero di volte che appare nella lista originale.
Ad esempio:
2->1->3->2->1->3->3->4 = (2,2)->(1,2)->(3,3)->(4,1)
Scrivere una funzione che prende una lista e costruisce la sua rappresentazione compressa.
==**Bonus:** fare in modo che la lista compressa risultante sia ordinata (per `->data`) senza modificare la lista originale.==
## Soluzione 1
```c=
pCNode inserisciCodaCompresso(pCNode head, int new_data, int new_count){
// Alloco il nuovo nodo
pCNode new = (pCNode)malloc(sizeof(CNode));
if(new == NULL){
printf("Errore di allocazione\n");
return head;
}
new->data = new_data;
new->count = new_count;
new->next = NULL;
// Verifico che la lista sia allcocata, altrimenti il nuovo nodo è il primo
if(head == NULL) return new;
// Scorro la lista fino alla fine
pCNode curr = head;
while(curr->next != NULL) curr = curr->next;
// curr è l'ultimo elemento, quindi attacco new
curr->next = new;
return head;
}
int contaOccorrenze(pNode head, int value){
int count = 0;
pNode curr = head;
while(curr != NULL){
if(curr->data == value) count++;
curr = curr->next;
}
return count;
}
int cercaElemento(pCNode head, int value){
int found = 0;
pCNode curr = head;
while(curr != NULL && !found){
if(curr->data == value) found = 1;
curr = curr->next;
}
return found;
}
pCNode comprimiLista(pNode head, pCNode c_head){
if(head == NULL) return c_head;
pNode curr = head;
int tmp_count;
while(curr != NULL){
if(!cercaElemento(c_head, curr->data)){
tmp_count = contaOccorrenze(curr, curr->data);
c_head = inserisciCodaCompresso(c_head, curr->data, tmp_count);
}
curr = curr->next;
}
return c_head;
}
```
## Soluzione 2
```c=
pCNode inserisciCodaCompresso(pCNode head, int new_data, int new_count){
// Alloco il nuovo nodo
pCNode new = (pCNode)malloc(sizeof(CNode));
if(new == NULL){
printf("Errore di allocazione\n");
return head;
}
new->data = new_data;
new->count = new_count;
new->next = NULL;
// Verifico che la lista sia allcocata, altrimenti il nuovo nodo è il primo
if(head == NULL) return new;
// Scorro la lista fino alla fine
pCNode curr = head;
while(curr->next != NULL) curr = curr->next;
// curr è l'ultimo elemento, quindi attacco new
curr->next = new;
return head;
}
pCNode aggiornaListaCompressa(pCNode head, int value){
// Se la lista compressa è vuota, aggiungo l'elemento
if(head == NULL) return inserisciCodaCompresso(head, value, 1);
// Scorro la lista compressa, se trovo l'elemento aggiorno il counter
pCNode curr = head;
while(curr != NULL){
if(curr->data == value){
curr->count += 1;
return head;
}
curr = curr->next;
}
// Se siamo qui, l'elelemento non è presente
return inserisciCodaCompresso(head, value, 1);
}
pCNode comprimiListaBase(pNode head, pCNode c_head){
if(head == NULL) return c_head;
pNode curr = head;
while(curr != NULL){
c_head = aggiornaListaCompressa(c_head, curr->data);
curr = curr->next;
}
return c_head;
}
```
---
# Rete di Ricercatori
Si definisca una struttura dati Ricercatore con i seguenti campi: nome, citazioni, h index, numero di articoli pubblicati e vettore di articoli.
Si definisca una struttura articolo con i campi: titolo, numero di autori e vettore di nome degli autori.
Si usi una lista di tutti i ricercatori.
Si definisca una lista contenente le liste di tutti i coatuori per ogni autore.
Si definisca una funzione per incrementare il numero di citazioni di un articolo dato solo il titolo, la funzione deve incrementare il numero di citazioni di ogni autore dell'articolo e, nel caso, si aggiorni anche l'h index.
==**Nota:** un autore ha un h-index uguale a N se ha almeno N articoli con N citazioni.==
```c=
// TODO
```