DIPARTIMENTO DI
INFORMATICA Università di Torino | |
ESERCIZI (ALCUNI DEI QUALI CON SOLUZIONE) - ultimo aggiornamento 06/03/02Attenzione si consiglia di provare a fare questi esercizi e di confrontare in seguito la propria soluzione con l'eventuale soluzione fornita dal docente.Esercizi sulle liste linkate.ELENCO DEGLI ESERCIZI
SOLUZIONE (DI ALCUNI) DEGLI ESERCIZISoluzione all'esercizio 1Prima versioneATTENZIONE: la soluzione messa on-line il 14/02/02 (che ora ho tolto) era sbagliata: se una sola delle due liste era vuota il primo if deferenziava un puntatore a NULL.La seguente soluzione e' la versione corretta (si noti che la gestione dell'inserimento del primo nodo nella lista risultato richiede di considerare 4 casi distinti, per questo motivo e' preferibile la "Seconda versione" della soluzione). /* AI: l1 e l2 sono due liste di interi L1 e L2 ordinate (in ordine cresente) AF: Restituisce il merge di L1 e L2 (L1 e L2 non sono modificate) */ node *buildmergelis (node *l1, node *l2) { if ((l1==NULL) && (l2==NULL)) return NULL; node *head = newnode(); node *tail = head; if ((l1!=NULL) && (l2==NULL)) { tail->data = l1->data; l1 = l1->next; } else if ((l2!=NULL) && (l1==NULL)) { tail->data = l2->data; l2 = l2->next; } else if (l1->data <= l2->data) { tail->data = l1->data; l1 = l1->next; } else { tail->data = l2->data; l2 = l2->next; } /* IC: la lista head NON E' VUOTA e contiene il merge (delle copie) dei nodi di L1 dal primo fino al nodo puntato da l1 (escluso) e dei nodi di L2 dal primo fino al nodo puntato da l2 (escluso) tail contiene il puntatore all'ultimo nodo della lista head */ while ((l1 != NULL) && (l2 != NULL)) { tail->next = newnode(); tail = tail->next; if (l1->data <= l2->data) { tail->data = l1->data; l1 = l1->next; } else { tail->data = l2->data; l2 = l2->next; } } while (l1 != NULL) { tail->next = newnode(); tail = tail->next; tail->data = l1->data; l1 = l1->next; } while (l2 != NULL) { tail->next = newnode(); tail = tail->next; tail->data = l2->data; l2 = l2->next; } tail->next = NULL; return head; }La complessita' in tempo di questa funzione e' lineare nella somma delle lunghezze di L1 e L2. La giustificazione e' identica a quella data per la "Seconda versione" (vedi paragrafo successivo). Seconda versioneATTENZIONE: la soluzione messa on-line il 18/02/02 (che ora ho tolto) era sbagliata: se una sola delle due liste era vuota nel secondo o nel terzo while venivsa dfeferenziato un puntatore a NULL (il puntatore tail). La seguente soluzione e' la versione corretta: /* AI: l1 e l2 sono due liste di interi L1 e L2 ordinate (in ordine cresente) AF: Restituisce il merge di L1 e L2 (L1 e L2 non sono modificate) */ node *buildmergelis (node *l1, node *l2) { node *head = NULL; node *tail = NULL; node *temp = NULL; /* IC: la lista head, contiene il merge (delle copie) dei nodi di L1 dal primo fino al nodo puntato da l1 (escluso) e dei nodi di L2 dal primo fino al nodo puntato da l2 (escluso) tail contiene il puntatore all'ultimo nodo della lista head */ while ((l1 != NULL) && (l2 != NULL)) { temp = newnode(); temp->next = NULL; if (l1->data <= l2->data) { if (head == NULL) head = temp; else tail->next = temp; tail = temp; tail->data = l1->data; l1 = l1->next; } else { if (head == NULL) head = temp; else tail->next = temp; tail = temp; tail->data = l2->data; l2 = l2->next; } } while (l1 != NULL) { temp = newnode(); if (head == NULL) head = temp; else tail->next = temp; tail = temp; tail->data = l1->data; tail->next = NULL; l1 = l1->next; } while (l2 != NULL) { temp = newnode(); if (head == NULL) head = temp; else tail->next = temp; tail = temp; tail->data = l2->data; tail->next = NULL; l2 = l2->next; } return head; }La complessita' in tempo di questa funzione e' lineare nella somma delle lunghezze di L1 e L2. Giustificazione:
Soluzione all'esercizio 2Prima versioneATTENZIONE: la soluzione messa on-line il 14/02/02 (che ora ho tolto) era sbagliata: se una sola delle due liste era vuota il primo if deferenziava un puntatore a NULL.La seguente soluzione e' la versione corretta (si noti che la gestione dell'inserimento del primo nodo nella lista risultato richiede di considerare 4 casi distinti, per questo motivo sono preferibili la "Seconda versione" o la "Terza versione" della soluzione). /* AI: *pl1 e *pl2 sono due liste di interi L1 e L2 ordinate (in ordine cresente) AF: Restituisce il merge di L1 e L2 (L1 e L2 sono distrutte e *pl1 e *pl2 contengono NULL) */ node *mergelis (node **pl1, node **pl2) { if ((*pl1==NULL) && (*pl2==NULL) return NULL; node *head = NULL; node *tail = NULL; if ((*pl1!=NULL) && (*pl2==NULL) { head = *pl1; *pl1 = (*pl1)->next; } else if ((*pl1==NULL) && (*pl2!=NULL) { head = *pl2; *pl2 = (*pl2)->next; } else if ((*pl1)->data <= ((*pl2)->data) { head = *pl1; *pl1 = (*pl1)->next; } else { head = *pl2; *pl2 = (*pl2)->next; } tail = head; /* IC: la lista head NON E' VUOTA e contiene il merge dei nodi di L1 dal primo fino al nodo puntato da *pl1 (escluso) e dei nodi di L2 dal primo fino al nodo puntato da *pl2 (escluso) tail contiene il puntatore all'ultimo nodo della lista head */ while ((*pl1 != NULL) && (*pl2 != NULL)) { if ((*pl1)->data <= ((*pl2)->data) { tail->next = *pl1; *pl1 = (*pl1)->next; } else { tail->next = *pl2; *pl2 = (*pl2)->next; } tail = tail->next; } while (*pl1 != NULL) { tail->next = *pl1; *pl1 = (*pl1)->next; tail = tail->next; } while (*pl2 != NULL) { tail->next = *pl2; *pl2 = (*pl2)->next; tail = tail->next; } tail->next = NULL; return head; }La complessita' in tempo di questa funzione e' lineare nella somma delle lunghezze di L1 e L2. La giustificazione e' identica a quella data per la funzione precedente. Seconda versioneATTENZIONE: la soluzione messa on-line il 18/02/02 (che ora ho tolto) era sbagliata: se una sola delle due liste era vuota nel secondo nel terzo while veniva deferenziato un puntatore a NULL (il puntatore tsail).La seguente soluzione e' la versione corretta: /* AI: *pl1 e *pl2 sono due liste di interi L1 e L2 ordinate (in ordine cresente) AF: Restituisce il merge di L1 e L2 (L1 e L2 non distrutte e *pl1 e *pl2 contengono NULL) */ node *mergelis (node **pl1, node **pl2) { node *head = NULL; node *tail = NULL; /* IC: la lista head, contiene il merge dei nodi di L1 dal primo fino al nodo puntato da *pl1 (escluso) e dei nodi di L2 dal primo fino al nodo puntato da *pl2 (escluso) tail contiene il puntatore all'ultimo nodo della lista head */ while ((*pl1 != NULL) && (*pl2 != NULL)) { if ((*pl1)->data <= (*pl2)->data) { if (head == NULL) head = *pl1; else tail->next = *pl1; tail = *pl1; *pl1 = (*pl1)->next; } else { if (head == NULL) head = *pl2; else tail->next = *pl2; tail =*pl2; *pl2 = (*pl2)->next; } } while (*pl1 != NULL) { if (head == NULL) head = *pl21 else tail->next = *pl1; tail = *pl1; *pl1 = (*pl1)->next; } while (l2 != NULL) { if (head == NULL) head = *pl2; else tail->next = *pl2; tail = *pl2; *pl2 = (*pl2)->next; } return head; La giustificazione e' identica a quella data per la funzione precedente.
Terza versione (FARE MOLTA ATTENZIONE)/* AI: *pl1 e *pl2 sono due liste di interi L1 e L2 ordinate (in ordine cresente) AF: Restituisce il merge di L1 e L2 (L1 e L2 non sono distrutte e *pl1 e *pl2 contengono NULL) */ node *mergelis (node **l1, node **l2) { node *head = NULL; node **pend = &head; /* IC: la lista head, contiene il merge dei nodi di L1 dal primo fino al nodo puntato da *pl1 (escluso) e dei nodi di L2 dal primo fino al nodo puntato da *pl2 (escluso) pend contiene l'indirizzo della locazione che memorizza il puntatore (di valore NULL) che termina la lista head (ovvero: l'indirizzo di head o l'indirizzo del campo next del penultimo nodo della lista head) */ while ((*pl1 != NULL) && (*pl2 != NULL)) { if ((*pl1)->data <= ((*pl2)->data) { *pend = *pl1; pend = &((*pl1)->next); *pl1 = (*pl1)->next; } else { *pend = *pl2; pend = &((*pl2)->next); *pl2 = (*pl2)->next; } } while (*pl1 != NULL) { *pend = *pl1; pend = &((*pl1)->next); *pl1 = (*pl1)->next; } while (*pl2 != NULL) { *pend = *pl2; pend = &((*pl2)->next); *pl1 = (*pl2)->next; } *pend = NULL; return head; }Notate che se la funzione avesse restituito il risultato in un terzo parametro, ovvero se avesse avuto prototipo: /* AI: *pl1 e *pl2 sono due liste di interi L1 e L2 ordinate (in ordine cresente) AF: Restituisce il merge di L1 e L2 (L1 e L2 sono distrutte e *pl1 e *pl2 contengono NULL) nel parametro (PASSATO PER REFERENZA) *pl3 */ void mergelisp (node **pl1, node **pl2, **pl3)si sarebbe potuto evitare dichiarare la variabile head, e usare *pl3 al posto di head. |
Last update: Mar 06, 2002 | |