


















Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
grafi ed alberi
Tipologia: Appunti
1 / 26
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!



















In questo capitolo richiameremo i principali concetti di due ADT che ricorreranno puntualmente nel corso della nostra trattazione: i grafi e gli alberi. Naturale applicazione dell’ADT Grafo è data dalla rappresentazione delle relazioni che intercorrono tra più oggetti. Un esempio classico di applicazione di un grafo è la rappresentazione delle strade che pongono in comunicazione tra loro un insieme di siti. Relativamente al corso di Laboratorio Algoritmi e Strutture Dati, ricorreremo all’uso di tale ADT durante lo studio del problema del Minimo Albero Ricoprente (MST) e del problema del Cammino di Costo Minimo (SP). Gli alberi sono una specializzazione dell’ADT Grafo. Mediante gli alberi rappresentiamo comunque relazioni che intercorrono tra più oggetti, ma più specificatamente rappresentiamo relazioni di tipo gerarchico. L’albero genealogico è un esempio classico di tale ADT. Ricorreremo durante la nostra trattazione all’ADT Albero nello studio del problema della ricerca, del problema dell’Union Find e del problema del Minimo Albero Ricoprente (MST).
Si definisce prodotto cartesiano A x B di due insiemi A e B non vuoti, l’insieme costituito da tutte le coppie ordinate (a, b) dove a é un elemento di A e b é un elemento di B. Formalmente: A x B = { (a, b) | a ∈ A, b ∈ B}
Quando A e B coincidono una coppia ordinata é determinata anche dalla loro posizione.
Esempio 1.1. Siano A e B due insiemi così definiti A={ a 1 , a 2 ,, a 3 , a 4 } e B = { b 1 , b 2 ,, b 3 }. La coppia (a 1 , b 2 ) dove a 1 ∈ A e b 2 ∈ B appartiene al prodotto cartesiano AxB. La coppia (b 1 , a 2 ) invece non appartiene al prodotto cartesiano AxB.
Esempio 1.1. Siano A e B due insiemi così definiti A = B = {1, 2, 3, 4}. La coppia ordinata (2, 3), dove 2 ∈ A e 3 ∈ B, é diversa dalla coppia ordinata (3, 2), dove 3 ∈ A e 2 ∈ B.
Una coppia non ordinata di elementi di due insiemi A e B é una coppia [a, b] , dove a ∈ A e b ∈ B , in cui l’ordine dei due elementi all’interno della coppia non risulta essere rilevante. Insomma dati due elementi a e b, dove a ∈ A e b ∈ B , si ha che [a, b] = [b, a].
Esempio 1.2. Siano A e B due insiemi così definiti A={ a 1 , a 2 ,, a 3 , a 4 } e B = { b 1 , b 2 ,, b 3 }. La coppia non ordinata (a 1 , b 2 ) dove a 1 ∈ A e b 2 ∈ B è uguale alla coppia non ordinata (b 2 , a 1 ).
Esempio 1.2. Siano A e B due insiemi così definiti A = {1, 2, 3, 4} e B = {5, 6, 7} La coppia non ordinata (2, 5), dove 2 ∈ A e 5 ∈ B, é uguale alla coppia non ordinata (5, 2).
Esempio 2.1. Sia G il grafo raffigurato nell’esempio 2.1.1. Abbiamo che:
Cammino Lunghezza Semplice Chiuso Ciclo 1,3,4 2 Si No No 1,2,2,4,1,2 5 No No No 1,2,2,4,1 4 No Si No 1,2,4,1 3 Si Si Si 1,3,4,1 3 Si Si Si
Definizione : sia G un grafo orientato si definisce cammino non diretto la sequenza di
Esempio 2.1. Sia G il grafo raffigurato nell’esempio 2.1.1. si ha che (4, 3, 1 ) e (2, 1, 3) sono ambedue cammini non diretti
Definizione: un grafo orientato si dice connesso se per ogni coppia di vertivi v e w, esiste almeno un cammino non diretto che collega v e w.
Esempio 2.1. Il grafo raffigurato nell’esempio 2.1.1 è connesso. Il grafo riportato in basso è non connesso.
Chiudiamo con le seguenti:
Definizione: sia G=(V, E) un grafo orientato si definisce grado entrante di un vertice
Definizione: sia G=(V, E) un grafo orientato si definisce grado uscente di un vertice
indica con Degree( v ) la somma tra il grado entrante e quello uscente, cioè: Degree( v ) = Indegree( v ) + Outdegree( v )
Definizione: sia G=(V, E) un grafo orientato si definisce grado di un grafo e lo si indica con Degree( G ) il massimo dei gradi dei suoi vertici, cioè:
Esempio 2.2. Il grafo non orientato riportato nell’esempio 2.2.1 è connesso, mentre il seguente grafo non orientato è non connesso.
Descriviamo il grafo mediante i formalismi dell’ADT riportando il set minimo di operatori applicabili.
Tipo di dato: Grafo Insieme V di vertici ed insieme E di archi Operazioni: AggiungiVertice( vertice v) Dato un vertice v, inserisce un nuovo vertice al grafo RimuoviVertice( vertice v) Dato un vertice v, rimuove il vertice dal grafo AggiungiArco( vertice v, vertice z ) Dati due vertici, aggiunge l’arco (v,z) CancellaArco(vertice v, vertice z ) Dati due vertici, rimuove l’arco (v,z) EsisteArco( vertice v, vertice z )ÆBooleano Dati due vertici, ritorna true se esiste l’arco (v,z) false altrimenti
Esamineremo n questo paragrafo le strutture dati, ovvero le tipologie di organizzazione delle informazioni, utili per la rappresentazione di un grafo. Nello specifico studieremo la Matrice di Adiacenza e la Lista di Adiacenza.
1 3 4
2
Sia G=(V, E) un grafo, una matrice di adiacenza è una matrice quadrata, A , di ordine n dove n =|V| tale che:
Esempio 2.4. Sia G=(V, E), V={1, 2, 3, 4} e E={ (1,2); (1,3); (2,4); (3,2); (3,4)} il grafo orientato in figura
la matrice di adiacenza di G è:
Esempio 2.4. Sia G=(V, E), V={1, 2, 3, 4} e E={ (1,2); (1,3); (2,3); (3,4)} il grafo non orientato in figura
la matrice di adiacenza di G è:
Nota La matrice di adiacenza di un grafo non orientato è simmetrica rispetto alla diagonale.
1
3 4
2
1
3 4
2
Come già detto in precedenza, i concetti di struttura dati ed implementazione di un operatore sono strettamente connessi tra loro. L’utilizzo di una struttura dati ha influenza sull’implementazione di un operatore. La rappresentazione tramite matrice di adiacenza ha il pregio di essere particolarmente semplice da implementare. Ma, aspetto più importante, e dato dal fatto che essa consente un accesso diretto alle informazioni. Gli operatori elencati nella definizione dell’ADT, sono implementabili in modo tale che essi richiedano un tempo di esecuzione costante: il numero di passi da eseguire è indipendente dal numero di vertici ed archi che costituiscono il grafo. Di contro, il difetto principale di tale rappresentazione è dato dall’eccessivo utilizzo di memoria. La rappresentazione di un grafo con |V| vertici richiede la definizione di una matrice di dimensione |V| 2. Tale dispendio di risorsa diventa ancor più rilevante quando il grafo contiene un numero ridotto di archi. Viceversa, la lista di adiacenza non consente un accesso diretto alle informazioni rappresentate. In tal caso gli operatori elencate nella definizione dell’ADT richiederanno, nel caso pessimo, un tempo proporzionale al numero di vertici. A favore, la rappresentazione mediante liste di adiacenza richiede un’occupazione di memoria minore rappresentato dalla somma tra il numero di vertici del grafo ed il numero di archi del grafo.
La visita di un grafo è una metodologia di analisi sistematica dei vertici. Un grafo è visitabile mediante la visita in profondità o la visita in ampiezza. Estendiamo quindi il numero di operatori applicabili ad un grafo e definiamo gli operatori visita in profondità e visita in ampiezza. VisitaAmpiezza()Æpath Ritorna una stringa formata dalla sequenza di vertici incontranti durante la visita. La sequenza di vertici sarà compatibile con le regole dettate dalla visita in ampiezza VisitaProfondità()Æpath Ritorna una stringa formata dalla sequenza di vertici incontranti durante la visita. La sequenza di vertici sarà compatibile con le regole dettate dalla visita in profondità
Nota Poiché un grafo può contenere cicli, al fine di evitare che gli algoritmi di visita cadano in un loop, le visite di un grafo prevedono il marcamento del vertice visitato.
esso collegato richiamiamo la visita in profondità. Generiamo in tal modo un movimento sul grafo che scende in profondità. Possiamo implementare l’algoritmo di visita utilizzando sia l’approccio ricorsivo che quello iterativo.
Algoritmo Ricorsivo L’algoritmo ricorsivo richiede l’esecuzione di tre passi. Il primo rappresenta il punto di terminazione della ricorsione
Algoritmo ricorsivo di visita in profondità _ VisitaProfonditàRicorsiva( v ) { se v è già marcato ritorna analizza v è marcalo come già visitato ∀ vj ∈ V tale che (v, vj ) ∈ E, VisitaProfonditàRicorsiva ( vj ) }
Algoritmo iterativo di visita in profondità _ VisitaProfonditàIterativa( vertice v) { Pila P Vertice r, s P.Push( v ) marca v come già visitato while (! P.Empty()) { r = P.Pop() analizza r ∀ s ∈ V tale che (r, s ) ∈ E, s non marcato { marca s P.Push( s ) } } }
livello generando un movimento sul grafo che richiama il movimento generato da un pendolo. L’algoritmo è solo di tipo iterativo ed utilizza una coda:
Algoritmo iterativo di visita in ampiezza _ VisitaAmpiezza( vertice v ) { Coda Q Vertici r, s Q.Inserisci( v) marca v come già visitato while (! Q.Empty()) { r = Q.Estrai() analizza r ∀ s ∈ V tale che (r, s ) ∈ E, s non marcato { marca s Q.Inserisci( s ) } } }
Esempio 2.5. Sia considerato il seguente grafo in figura
una possibile sequenza di vertici determinata da una visita in ampiezza è: (1, 3, 2, 4, 5 )
1
3 4
2 5
Sia T un grafo orientato allora T è un albero orientato se:
E’ pratica comune, rappresentare mediante alberi orientati le organizzazioni gerarchiche. Un albero orientato inoltre è un valido strumento per la rappresentazione di procedimenti enumerativi o decisionali.
v
u
radice
nodo interno
foglia
foglia
padre di u
figlio di v
Definizione: si definisce altezza di un nodo, n , la lunghezza del cammino (ovvero il numero di archi che attraversiamo) che collega la radice al nodo n.
Definizione: si definisce altezza di un albero il massimo delle altezze dei suoi nodi:
L’albero rappresenta la collezione di oggetti che maggiormente si presta all’utilizzo della ricorsione. Primo esempio di applicazione di tale approccio è la seguente definizione alternativa di altezza di un nodo:
altezza 2
altezza 0
altezza 1
altezza 3
Descriviamo ora mediante gli opportuni formalismi l’ADT Albero. Nella specifica, elencheremo l’insieme di operazioni minime applicabili ad un albero.
Tipo di dato: Albero Insieme N di nodi ed insieme E di archi Operazioni: RitornaPadre( nodo n )Ænodo Dato un nodo n ritorna il padre di n RitornaFigli( nodo n )Æ( nodo 1 , …., nodon ) Dato un nodo n, ritorna una tupla rappresentante i figli di n Outgree( nodo n )Ægrado Dato un nodo n, ritorna il numero di figli del nodo n RitornaRadice()Ænodo Ritorna il nodo rappresentante la radice dell’albero AggiungiFiglio( nodo n, nodo m ) Inserisce il nodo m come figlio del nodo n.
Studieremo in questo paragrafo le strutture dati utili per la rappresentazione di un albero. Per semplicità di esposizione considereremo solo alberi binari. Possiamo organizzare le informazioni contenute in un albero mediante la rappresentazione indicizzata, utilizzo di array, o mediante la rappresentazione collegata, utilizzo dei puntatori. Al fine di evitare l’appesantimento della nostra disamina, non studieremo la rappresentazione indicizzata. Diremo solo che essa è di facile realizzazione ma rende particolarmente laboriose le operazioni di inserimento e cancellazione. Inoltre che, essa rappresenta l’unica soluzione applicabile quando si utilizzano linguaggi di programmazione privi di puntatori. Vediamo quindi la rappresentazione collegata. Essa si basa essenzialmente sulla definizione di un record, il record di rappresentazione , mediante il quale rappresentiamo un nodo dell’albero. Nel caso di alberi binari strutturiamo il record di rappresentazione come di seguito illustrato:
Il campo etichetta contiene il valore associato al nodo, il campo figlio sinistro contiene il riferimento al figlio sinistro del nodo ed infine il campo figlio destro contiene il riferimento al figlio destro del nodo. I campi figlio destro e figlio sinistro sono non avvalorati se il nodo non possiede rispettivamente figlio destro o figlio sinistro. Rappresentiamo l’intero albero definendo per ogni nodo dell’albero un record di rappresentazione ed operando gli opportuni collegamenti. Ad esempio la raffigurazione della rappresentazione collegata dell’albero binario in figura 3.1 è:
Nota Possiamo arrichire, tramite la definizione di ulteriori campi, le informazioni contenute all’interno di un record di rappresentazione. Ad esempio, se volessimo agevolare la navigazione tra i nodi dell’albero dal basso verso l’alto potremmo introdurre all’interno del record di rappresentazione un campo che memorizzi il puntatore al nodo padre.
puntatore figlio sinistro
etichetta del nodo
puntatore figlio destro