Stampa di una lista al contrario

Consideriamo il problema di stampare una lista all'indietro, ossia partendo dall'ultimo elemento per arrivare a stampare il primo.

Questo problema si risolve banalmente in modo ricorsivo. Sappiamo che una lista o è vuota, oppure è composta da un elemento e da un resto (che è la lista composta dai restanti elementi). Stampare al contrario la lista vuota significa non stampare niente. Per l'altro caso (la lista ha un elemento e il resto), uso l'assunzione che la chiamata ricorsiva sul resto della lista stampi effettivamente il resto della lista al contrario.

Sia quindi void StampaListaRovesciata(TipoLista l) la intestazione della funzione. Sappiamo che la istruzione StampaListaRovesciata(l->next) stampa in ordine inverso il resto della lista. Dato che il resto della lista è composto da tutti gli elementi dal secondo fino all'ultimo, questa istruzione stampa prima l'ultimo elemento, poi il penultimo, ecc. fino al secondo. Dobbiamo ora fare in modo che venga stampata al contrario tutta la lista, incluso il primo elemento.

A questo punto, dovrebbe essere abbastanza evidente che, se StampaListaRovesciata(l->next) stampa dall'ultimo elemento al secondo, per stampare dal secondo al primo basta eseguire questa istruzione e poi una stampa del primo elemento con printf("%d ", l->val).

La funzione complessiva è quindi la seguente: se la lista è vuota, non si fa nulla. Se ci sono elementi, si stampa prima il resto della lista al contrario (con la chiamata ricorsiva) e poi il primo elemento. È facile verificare come i casi come quello di lista composta da un solo elemento vengono trattati correttamente. Il programma che contiene questa funzione, riportata qui sotto, è prntric.c

void StampaListaRovesciata(TipoLista l) {
  if(l==NULL)
    return;

  StampaListaRovesciata(l->next);
  printf("%d ", l->val);
}

Per simulare il comportamento della lista occorre tenere presenti i punti di ritorno. I record di attivazione hanno lo stesso contenuto di quelli del programma della pagina precedente (ricorsione su liste). L'unica differenza è che la stampa avviene solo dopo che la chiamata ricorsiva è terminata. In altre parole, prima si costruiscono tutti i record di attivazione. Quando ogni chiamata ricorsiva termina, la precedente fa la stampa e poi termina anch'essa. Questo produce effettivamente la stampa degli elementi della lista al contrario.