Docente: Giuseppe Scollo
Università di Catania, sede di Comiso (RG)
Facoltà di Scienze Matematiche, Fisiche e Naturali
Corso di Studi in Informatica applicata, AA 2007-8
problema: codificare una funzione che, dato il puntatore ad una lista, la modifichi invertendo l'ordine dei suoi nodi, e restituisca quindi il puntatore alla lista così invertita
y
va modificato y->next
, per farlo puntare al nodo precedente, eccetto che:
r
all'ultimo nodo elaborato (primo della porzione di lista
già invertita) e un puntatore y
al primo nodo della porzione di lista ancora da elaborare
nlink reverse (nlink x) { nlink y = x, r = 0, t; while (y != 0) { t = y->next; y->next = r; r = y; y = t; } return r; }
problema: codificare una funzione che, dato il puntatore ad una lista di interi non negativi, costruisca una lista di ugual dimensione, con gli stessi valori degli elementi ma ordinati per valori crescenti, e restituisca quindi il puntatore alla lista ordinata così costruita
node head(0,0)
invece di node head = node(0,0)
, e quindi il puntatore &head
nlink insord (nlink a) { node headb(0, 0); nlink t, x, b = &headb; for (t = a->next; t != 0; t = t->next) { for (x = b; x->next != 0; x = x->next) if (x->next->elem > t->elem) break; x->next = new node(t->elem, x->next); }; return b; }
come può constatarsi negli esempi precedenti, algoritmi diversi rendono convenienti convenzioni diverse per la rappresentazione della testa e della coda della lista:
next
nullo, oppure allo stesso nodo, oppure a nodo fittizio
in base a tali scelte:
t = t->next
, differisce nell'inizializzazione e nella
condizione di terminazione
per alcune applicazioni è utile poter scorrere una lista in entrambe le direzioni: nelle liste doppiamente concatenate, o liste doppie, ogni nodo ha un link al suo successore e uno al suo predecessore:
struct node { Elem elem; node *next; node *prev; }; typedef node *nlink;
la disponibilità dei due link permette la rimozione di un nodo specificando il suo puntatore:
x->prev->next = x->next; x->next->prev = x->prev ;
Lista.h :
typedef int Elem; struct node { Elem elem; node* next; }; typedef node* nlink; typedef nlink Node; void construct(int); Node newNode(Elem); void deleteNode(Node); void insert(Node, Node); Node remove(Node); Node next(Node); Elem elem(Node);
construct(N)
alloca la memoria per una lista di N
nodi (da costruire)
newNode
e deleteNode
potranno essere implementate usando le funzioni
di libreria new
e delete
, o in altro modo, senza dover modificare i client
next
con un parametro di newNode
: tale scelta è delegata all'implementazione
dell'interfaccia
ecco come si può riformulare il programma per il problema di Giuseppe Flavio usando l'interfaccia Lista.h:
#include <iostream> #include <cstdlib> #include "Lista.h" using namespace std; int main(int argc, char *argv[]) { int i, N = atoi(argv[1]), M = atoi(argv[2]); Node t, x; construct(N); for (i = 2, x = newNode(1); i <= N; i++) { t = newNode(i); insert(x, t); x = t; } // inserimento i-esimo nodo while (x != x->next) { // finché il nodo non punta a sé stesso: for (i = 1; i < M; i++) x = next(x); // scorrimento di M-1 nodi deleteNode(remove(x)); // cancellazione M-simo nodo } cout << elem(x) << endl; // output del superstite }
nlink reverse (nlink x) { nlink y = x, r = 0, t = x->next; while (y != 0) { y->next = r; r = y; y = t; t = y->next;} return r; }
insord
qui proposta
per l'ordinamento, e infine produca in output le due liste