La lista di elementi concatenate semplici sono un insieme di nodi dove ogni nodo è inteso come elemento della lista.
Lista della spesa su carta
Se prendiamo una tipica lista della spesa scritta a penna su un foglio di carta, potrebbe apparire come segue. Consideriamo la penna perchè i prodotti che scriviamo sulla carta vogliamo trattarli come non cancellabili dal foglio di carta stesso, ma piuttosto depennabili.
Lista spesa
- acqua
- caffe
- sapone
- ecc…
Rapportando la lista sopra alla lista di elementi concatenati che andremo a trattare, ogni elemento della lista spesa (esempio il caffè) è un nodo della lista concatenata.
Il termine concatenato fa riferimento al fatto che il prodotto corrente sulla carta è disposto in modo da avere un prodotto predecente al corrente e uno successivo: il prodotto precedente a caffè è acqua mentre il successivo è sapone. Ovviamente esiste il caso in cui il primo prodotto (acqua) non ha un precedente e che l’ultimo prodotto (sapone) non ha un successivo.
Di seguito alcune azioni che possiamo compiere sulla lista scritta a penna su carta:
per aggiungere un prodotto, prendiamo la penna e lo scriviamo inserendolo a fine lista.
per cancellare un prodotto lo depenniamo (tiriamo una riga sul prodotto) e lo sostituiamo scrivendo un nuovo prodotto al suo fianco.
oppure è possibile cancellare il prodotto (depennandolo) e basta.
ecc…
Tenendo a mente queste “azioni” eseguibili sulla lista scritta su foglio di carta, andiamo a trattare la lista con elementi concatenati scritta in C
.
Lista concatenata in C
.
Si parte dal presupposto che la lista concatenata deve far uso delle strutture. Le strutture usate per creare la lista e i suoi elementi possono essere modellate in modi diversi. Questo aspetto sarà chiaro più avanti.
//librerire usate da alcune funzioni
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
//dichiarazione struttura secondaria
struct node_t{
int value;
struct node_t *next;
};
//dichiarazione struttura principale
struct list_t{
struct node_t *head; //deve essere già dichiarata la struct node_t
};
Si dichiara la struttura principale struct list_t
formata da una variabile che dovrà contenere un indirizzo di memoria (quindi è una variabile puntatore). Possiamo vedere che la struttura principale è in seconda posizione rispetto alla struttura secondaria. Questo perchè struct list_t
contiene il puntatore *head
di tipo struct node_t
.
struct node_t
che deve esser già dichiarato per essese usato da struct list_t
. Diversamente si ha un errore di compilazione.
//firme funzioni
struct list_t *new_list();
void insert_on_head(struct list_t *list, int value);
void insert_on_tail(struct list_t *list, int value);
bool contains(struct list_t *list, int value);
void remove_from_list(struct list_t *list, int value);
void print(struct list_t *list);
void empty_list(struct list_t *list);
void free_list(struct list_t *list);
Guardando le firme delle funzioni possiamo vedere che ogni funzione riceve la lista per indirizzo.
//funzione principale
void main(){
//dichiaro un puntatore di tipo struct list_t
struct list_t *list = new_list();
int v;
for(v = 0; v < 10; v++){
insert_on_head(list, v);
}
print(list);
for(v = 11; v < 20; v++){
insert_on_tail(list, v);
}
print(list);
if(contains(list, 5)){
printf("list contains the value 5\n");
}
else{
printf("list does not contain the value 5\n");
}
if(contains(list, 30)){
printf("list contains the value 30\n");
}
else{
printf("list does not contain the value 30\n");
}
remove_from_list(list, 5);
print(list);
if(contains(list, 5)){
printf("list contains the value 5\n");
}
else{
printf("list does not contain the value 5\n");
}
empty_list(list);
print(list);
insert_on_tail(list, 5);
print(list);
remove_from_list(list, 5);
print(list);
free_list(list);
};
struct list_t *new_list(){
struct list_t *list = (struct list_t *)malloc(sizeof(struct list_t));
list->head = NULL;
return list;
};
void insert_on_head(struct list_t *list, int value){
struct node_t *node = (struct node_t *)malloc(sizeof(struct node_t));
node->value = value;
node->next = list->head;
list->head = node;
};
void insert_on_tail(struct list_t *list, int value){
if(list->head == NULL){
insert_on_head(list, value);
}
else{
struct node_t *current = list->head;
while(current->next != NULL){
current = current->next;
}
struct node_t *node = (struct node_t *)malloc(sizeof(struct node_t));
node->value = value;
node->next = NULL;
current->next = node;
}
};
bool contains(struct list_t *list, int value){
struct node_t *current = list->head;
while(current != NULL){
if(current->value == value){
return true;
}
current = current->next;
}
return false;
};
void remove_from_list(struct list_t *list, int value){
struct node_t *current = list->head;
struct node_t *previous = NULL;
while(current != NULL){
if(current->value == value){
if(current == list->head){
list->head = current->next;
free(current);
}
else{
previous->next = current->next;
free(current);
}
return;
}
previous = current;
current = current->next;
}
};
void print(struct list_t *list){
if(list->head == NULL){
printf("list is empty\n");
return;
}
struct node_t *current = list->head;
while(current != NULL){
printf("%i ", current->value);
current = current->next;
}
printf("\n");
};
void empty_list(struct list_t *list){
struct node_t *current = list->head;
struct node_t *previous = NULL;
while(current != NULL){
if(previous != NULL){
free(previous);
}
previous = current;
current = current->next;
}
if(previous != NULL){
free(previous);
}
list->head = NULL;
};
void free_list(struct list_t *list){
empty_list(list);
free(list);
};
//creazione lista
//list è stato allocato con malloc())
//*head è puntato a NULL (= lista vuota, senza elementi)
[0x55869911b010]
↑ [NULL]
│ ↑
list - *head
//nota: head deve contenere un indirizzo di una struct dello stesso tipo del puntatore *head. Quando c'è NULL non si ha nessun indirizzo per cui il puntatore *head non punta a niente
//creazione elemento e inserimento in testa
//
[0x55869911b010]
↑ [0x55869911b440]
│ ↑
list-*head ┬ .value
└ *next
[0x55869911b440]
↑
node ┬ .value = 100
└ *next = NULL
event ┬ .sdate ┬ .day 10 │ ├ .month 6 │ └ .year 2016 └ .stime ┬ .hour 15 ├ .minute 33 └ .second 59