Liste concatenate Una lista concatenata (OLQNHGOLVW) è una sequenza lineare di oggetti connessi attraverso dei puntatori detti link. L’acceso ad una lista concatenata avviene per mezzo di un puntatore al suo primo nodo; ai successivi si accede per mezzo del link all’elemento successivo immagazzinato in ogni nodo. Gli elementi di una lista concatenata sono memorizzati dinamicamente e ciascuno di essi è creato solo quando necessario. Si possono avere liste ramificate i cui elementi puntano ad intere liste. 7XWWLJOLHOHPHQWLGLXQDTXDOXQTXHOLVWDVRQRVWUXWWXUHGHOORVWHVVRWLSRSHUUHQGHUH DJHYROLOHRSHUD]LRQLGLVFRUULPHQWRLOWLSRGHOSXQWDWRUHGLSHQGHLQIDWWLGDOWLSR GHOO¶HOHPHQWRSXQWDWR Code e pile Le FRGH e le SLOH sono anch’esse delle strutture dati lineari; possono essere considerate come OLVWHFRQFDWHQDWH con alcune restrizioni sulle modalità di accesso agli elementi (),)2/,)2). Gli DOEHUL sono strutture dati non lineari. Code (TXHXH) • In una FRGD (queue) gli elementi sono gestiti esclusivamente con una politica ),)2ILUVWLQILUVWRXWovvero si può eliminare un elemento solo dalla testa della coda e si può inserire solo in fondo alla coda. Pile (VWDFN) Una SLODRVWDFN è analoga ad una lista concatenata sulla quale i nuovi elementi possono essere aggiunti e/o rimossi soltanto dalla sua sommità (WRS), ovvero l’ultimo elemento ad entrare è anche il primo ad uscire (ODVWLQILUVWRXW/,)2). Le altre caratteristiche di lista restano inalterate: si punta ad una pila mediante un puntatore all’elemento in cima alla pila ed il membro di link dell’ultimo elemento è impostato a QXOOper indicare la fine della pila. Inserimento di un nuovo elemento L’inserimento di un nuovo elemento nella coda o nella pila prevede sempre i seguenti passi: &UHD]LRQHGLXQQXRYRQRGRDOORFD]LRQHGLQDPLFD $VVHJQD]LRQHGLYDORULDLFDPSLGDWL &ROOHJDPHQWR GHO QXRYR HOHPHQWR DOOD VWUXWWXUD HVLVWHQWH • • DJJLRUQDPHQWRGHOFDPSRSXQWDWRUHGHOQRGR DJJLRUQDPHQWRGHLSXQWDWRULGHOODOLVWD Queste due ultime operazioni caratterizzeranno la tipologia dell’ inserimento in coda o in pila. Creazione di un nuovo nodo La creazione di un nuovo nodo avviene creando una nuova istanza della struttura tramite allocazione dinamica, utilizzando di solito un puntatore d’appoggio (tempp) Es.: rec* tempp = new rec; tempp info next Assegnazione di valori ai campi dati L’assegnazione di valori ai campi dati si ottiene dereferenziando il puntatore al nodo e accedendo ai singoli dati, ovvero utilizzando direttamente l’operatore -> Es.: tempp->info=7; tempp 7 info next Inserimento in testa alla pila (SXVK) Le operazioni di collegamento per O¶LQVHULPHQWR LQ WHVWD SXVK alla pila, utilizzano il riferimento esplicito al top della pila (il puntatore alla pila lis). • ,O FDPSR QH[W GHO QXRYR HOHPHQWR SXQWHUj DOOR VWHVVRYDORUHGLOLV • OLVSXQWHUjDOQXRYRHOHPHQWR tempp->next=lis; lis=tempp; Inserimento in testa alla pila (SXVK) tempp tempp dato lis dato lis 0 0 WHPSS!QH[W OLV tempp tempp dato lis 0 lis dato 0 0 OLV WHPSS tempp lis tempp dato 0 lis dato 0 Eliminazione del nodo di testa della pila (SRS) Bisogna aggiornare il puntatore alla testa OLV che dovrà puntare all’elemento successivo a quello da eliminare. rec* tempp=lis; (salvataggio elemento da eliminare) lis = tempp->next; (aggiornamento lista) delete tempp; (distruzione elemento) Eliminazione di un elemento dalla testa della coda (GHTXHXH) L’eliminazione di un elemento dalla coda prevede: • 6DOYDWDJJLR GHOO¶HOHPHQWR LQ XQD YDULDELOH DXVLOLDULD SHU SDVVR • 6FROOHJDPHQWR GHOO¶HOHPHQWR GDOOD WHVWD GHOOD FRGD DJJLRUQDPHQWRGHLSXQWDWRULGHOODFRGD • 'LVWUX]LRQHGHOO¶HOHPHQWRGHDOORFD]LRQHGHOODPHPRULD In ogni caso, bisogna verificare che la coda non sia già vuota! if (lis != NULL) … Eliminazione dell’elemento di testa della coda (GHTXHXH) Bisogna aggiornare il puntatore alla testa OLV che dovrà puntare all’elemento successivo, ovvero a quello che ora è il secondo. rec* tempp=lis; (salvataggio elemento da eliminare) lis = tempp->next; (aggiornamento coda) delete tempp; (distruzione elemento) Inserimento in pila e in coda void instesta(rec*& lis, int a) { rec* p = new rec; p->info = a; p->next = lis; lis = p; } SXVK void insfondo(rec*& lis, int a) { rec* p = lis; for (rec* q = p; q != NULL; q = q->next) p = q; q = new rec; q->info = a; q->next = NULL; if (p != NULL) p->next = q; else lis = q; } LQTXHXH Pop / Dequeue BOOL esttesta(rec*& lis, int& a) { rec* p = lis; if (lis != NULL) { a = lis->info; lis = lis->next; delete p; return T; } return F; } (VWUD]LRQHGDOODWHVWD Alberi • Un DOEHUR è una struttura dati non lineare i cui nodi contengono due o più membri di link. • I nodi di un DOEHURELQDULR contengono esattamente due link. • Il primo nodo di ogni albero si chiama UDGLFH e per definizione non discende da nessun altro nodo. • Un nodo da cui non discende nessun altro nodo si chiama IRJOLD. Alberi In ogni albero: • tutti i nodi ad eccezione delle foglie sono detti nodi SDGUH; • Tutti i nodi ad eccezione della radice sono detti nodi ILJOLR. Ogni nodo padre può avere 0, 1,2,…n figli Ogni nodo figlio può avere un solo padre. Gli DOEHULQDUL possono avere un numero qualsivoglia di figli per ciascun nodo. Gli DOEHULELQDUL possono avere 0, 1, o al più 2 figli per ciascun nodo Albero binario (GHIULFRUVLYD) Un DOEHURELQDULR è un insieme finito di nodi che: • o è vuoto • o è costituito da un nodo speciale detto radice e da due sottoinsiemi (disgiunti) di nodi che sono a loro volta alberi binari (sottoalbero sinistro e sottoalbero destro) Albero binario Un albero binario in C++ può essere rappresentato associando ad ogni nodo una struttura avente un campo informazione e due campi puntatore. Il tipo di ogni nodo si può definire come: struct nodo { char inf; nodo* sin; nodo* des; }; Albero binario ordinato per contenuto (LQVHULPHQWR) Se l’albero è vuoto, crea il nodo radice e inserisci l’informazione, altrimenti considera l’inserimento nel sottoalbero sinistro o destro a seconda che l’informazione da inserire sia minore o maggiore di quella contenuta nella radice (se l’informazione ha valore uguale a quello della radice, non viene effettuato l’inserimento). Albero binario ordinato per contenuto (LQVHULPHQWR) nodo* inserisci (nodo* r, int d) { if (r==0) { r=new nodo; r->inf=d; r->sin=0; r->des=0; } else if (d<r->inf) r-> sin=inserisci (r>sin,d); else if (d>r->inf) r-> des=inserisci (r>des,d); return r; }; 9LVLWD di un albero Per estrarre il valore di ciascun elemento (nodo) dell’albero binario, si effettua una RSHUD]LRQHGLYLVLWD, ovvero si esaminano tutti i nodi dell’albero in un certo ordine. Le visite più significative sono: YLVLWDLQSUHRUGLQH YLVLWDLQSRVWRUGLQH YLVLWDLQRUGLQHVLPPHWULFR Visita in preordine Se l’albero non è vuoto, visita la radice, visita in preordine il sottoalbero sinistro, visita in preordine il sottoalbero destro. void voa(nodo* r){ if (r!=0){ cout << r->inf; voa(r->sin); voa(r->des); } }; Visita in postordine Se l’albero non è vuoto, visita in postordine il sottoalbero sinistro, visita in postordine il sottoalbero destro, visita la radice. void vod(nodo* r) { if (r!=0){ vod(r->sin); vod (r-> des); cout << r->inf; } }; Visita in ordine simmetrico Se l’albero non è vuoto, visita in ordine simmetrico il sottoalbero sinistro, visita la radice , visita in ordine simmetrico il sottoalbero destro. void vos(nodo* r){ if (r!=0){ vos(r->sin); cout << r->inf; vos(r->des); } };