Rappresentazione dei grafi
In questa pagina 5
Sia con vertici ed archi (i vertici si indicano spesso con gli interi o ). Tutte le rappresentazioni partono da due strutture di base:
- lista dei vertici : ogni nodo contiene le informazioni di un vertice distinto; con vertici interi può essere un array (Array e stringhe in CArray di dimensione fissa in memoria contigua, inizializzazione, nessun controllo sugli indici, passaggio a funzioni con la lunghezza, matrici; stringhe come array di char terminati da '\0' e funzioni di string.h.Array e stringhe in C →);
- lista degli archi : ogni nodo contiene le informazioni di un arco , compresi i puntatori a e a .
Ogni vertice o arco può avere campi aggiuntivi (ID, peso, etichette, parent) richiesti dall'algoritmo. Le liste sono quelle di Liste, pile e codeRipasso degli ADT elementari: lista index-based (array) e position-based (lista doppiamente concatenata con sentinelle), pila LIFO, coda FIFO, deque, iteratori; interfacce, implementazioni e costi; array estendibile e coda circolare.Liste, pile e code → (Liste concatenate in CLista singolarmente concatenata in C con nodo struct e testa passata per riferimento (Nodo **); addHead, addTail ricorsiva e iterativa, pop, inversione in loco, liberazione; coda con puntatori a testa e coda; ricorsione sulle liste; costi.Liste concatenate in C → per l'implementazione) e i riferimenti tra nodi sono puntatori (Puntatori in CUn puntatore contiene un indirizzo di memoria; operatori & e *, NULL, puntatori come parametri per modificare variabili del chiamante, aritmetica dei puntatori, legame tra array e puntatori, const, puntatori a puntatori.Puntatori in C →).
Liste di adiacenza
Definizione (liste di adiacenza). Per ogni vertice una lista di puntatori agli archi di incidenti su (in alternativa, ai vicini; al posto delle liste si possono usare mappe, ad esempio Tabelle hashTabella hash per implementare una mappa: funzione hash = hash code + compression function, bucket array, separate chaining; hash code per numeri e stringhe (polynomial, cyclic shift), division e MAD; load factor, complessità al caso pessimo Theta(n) e medio O(1+lambda), rehashing; esempio svolto con inserimenti e collisioni.Tabelle hash →: con una mappa
areAdjacentcosterebbe in media). È la rappresentazione più usata, e quella assunta se non detto altrimenti, perché:
- occupa spazio lineare nella taglia del grafo, (in un grafo non diretto ogni arco compare nelle liste dei suoi due estremi);
- permette di scorrere i vicini di in tempo lineare nel grado di .
Esempio. Con archi e il vertice isolato: , e .
Matrice di adiacenza
Definizione (matrice di adiacenza). Matrice di dimensione , con righe e colonne in corrispondenza 1-1 con i vertici (che devono essere rappresentati da interi):
Dà accesso a un arco in tempo costante, ma occupa , che può essere superlineare nella taglia del grafo: conviene per grafi densi ().
Esempio. Con la matrice ha celle; punta all'arco se esiste, altrimenti vale null.
Confronto
Proprietà (spazio e tempi delle rappresentazioni di un grafo)
Operazione / risorsa Solo Liste di adiacenza Matrice di adiacenza spazio incidentEdges(v)opposite(v, e)areAdjacent(u, v)scansione di tutti i vicini di tutti i vertici
Esempio. Con vertici e archi le liste di adiacenza usano celle (più precisamente riferimenti, perché ogni arco è in due liste), la matrice .
Come si legge la tabella. incidentEdges(v) con sola costringe a guardare tutti gli archi per trovare quelli incidenti su ; con le liste basta percorrere , lunga ; con la matrice si legge tutta la riga ( celle, quasi tutte vuote in un grafo sparso). areAdjacent(u,v) con le liste si fa scorrendo in parallelo e e fermandosi appena una finisce, quindi in ; con la matrice si legge la cella , un solo accesso diretto ( come l'indicizzazione di un array nel modello RAM, Problemi computazionali e algoritmiProblema computazionale come insieme di coppie (istanza, soluzione); algoritmo e modello di calcolo RAM; pseudocodice; taglia di un'istanza; ADT e struttura dati concreta; esempio svolto con ricerca lineare e binaria in un array ordinato.Problemi computazionali e algoritmi →). Il grafico confronta lo spazio per un grafo sparso con (ogni vertice ha in media grado ):
Grafico interattivo: Memoria per un grafo con m = 3n archi: liste di adiacenza n + 2m = 7n riferimenti, matrice di adiacenza n² celle; a n = 100 sono 700 contro 10000, e il rapporto cresce con n
Rappresentare gli archi solo con rende lenti gli algoritmi che esplorano i vicini; per questo le visite (vedi Visite di grafi - BFS e DFSVisite in ampiezza (BFS) e in profondità (DFS) come design pattern; etichette discovery, cross e back edge; BFS tree e distanze; complessità Theta(n+m) con liste di adiacenza; applicazioni (connettività, componenti, spanning tree, cammini minimi non pesati, cicli, vertici a distanza al più d); esempio svolto su un grafo di 7 vertici.Visite di grafi - BFS e DFS →) usano le liste di adiacenza, e le loro complessità dipendono da questa scelta (con la matrice sarebbero ).
Esempio
Grafo con vertici e archi , , , (il vertice è isolato).
- , .
- Liste di adiacenza: , , , , . La somma delle lunghezze è (somma dei gradi, vedi Grafi - definizioni e proprietàGrafo G=(V,E) diretto e non diretto, grafo semplice e pesato; incidenza, adiacenza, grado; cammini, cicli, sottografi, grafi connessi e componenti connesse; alberi liberi, foreste, spanning tree e spanning forest; proprietà con dimostrazioni (somma dei gradi = 2m, m <= n(n-1)/2, alberi m = n-1, connessi m >= n-1, foreste m <= n-1).Grafi - definizioni e proprietà →).
- Matrice di adiacenza (1 = arco presente; per un grafo non diretto è simmetrica, , perché l'arco è lo stesso di : Operazioni tra matriciLe matrici m×n formano uno spazio vettoriale (somma e prodotto per scalare elemento per elemento); il prodotto righe per colonne corrisponde alla composizione di funzioni lineari, è associativo ma non commutativo; la trasposta scambia righe e colonne e (AB)^T = B^T A^T.Operazioni tra matrici →; la somma della riga è il grado di , quella di tutte le righe ):
| 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|
| 1 | 0 | 1 | 1 | 0 | 0 |
| 2 | 1 | 0 | 1 | 0 | 0 |
| 3 | 1 | 1 | 0 | 1 | 0 |
| 4 | 0 | 0 | 1 | 0 | 0 |
| 5 | 0 | 0 | 0 | 0 | 0 |
Numero di vertici isolati (richiesto in un esame): si scorrono i vertici e si contano quelli con lista di adiacenza vuota: con le liste (non serve guardare gli archi); con la matrice occorrerebbe .
Errori comuni
- Usare la matrice di adiacenza per un grafo sparso: spreca spazio ( contro ) e rende le visite quadratiche.
- Dimenticare che in un grafo non diretto ogni arco compare due volte nelle liste di adiacenza (e due volte nella matrice, simmetrica).
- Esprimere il costo dello scorrimento dei vicini come invece di .
Versione ripasso
- Strutture di base: lista dei vertici (array se i vertici sono interi) e lista degli archi , in cui ogni arco ha puntatori ai due estremi; si aggiungono campi come ID, peso,
parent(vedi Liste concatenate in CLista singolarmente concatenata in C con nodo struct e testa passata per riferimento (Nodo **); addHead, addTail ricorsiva e iterativa, pop, inversione in loco, liberazione; coda con puntatori a testa e coda; ricorsione sulle liste; costi.Liste concatenate in C →). - Liste di adiacenza (rappresentazione di default): per ogni la lista dei puntatori agli archi incidenti. Spazio , perché ogni arco compare nelle liste dei due estremi ( riferimenti); scorrere i vicini costa . Esempio: archi con isolato danno , , .
- Matrice di adiacenza: matrice con = puntatore all'arco , oppure
null. Accesso a un arco in , spazio : conviene solo per grafi densi. Per un grafo non diretto è simmetrica. - Confronto: spazio con liste contro con matrice;
incidentEdges(v): con sola , con liste, con matrice;areAdjacent(u,v): , , ; scansione di tutti i vicini: con liste, con matrice. - Numeri: con e le liste usano circa riferimenti, la matrice celle.
- Esempio: la somma delle lunghezze delle liste dell'esempio è (vedi Grafi - definizioni e proprietàGrafo G=(V,E) diretto e non diretto, grafo semplice e pesato; incidenza, adiacenza, grado; cammini, cicli, sottografi, grafi connessi e componenti connesse; alberi liberi, foreste, spanning tree e spanning forest; proprietà con dimostrazioni (somma dei gradi = 2m, m <= n(n-1)/2, alberi m = n-1, connessi m >= n-1, foreste m <= n-1).Grafi - definizioni e proprietà →); i vertici isolati sono quelli con lista vuota, contati in .
- Visite: solo con liste (vedi Visite di grafi - BFS e DFSVisite in ampiezza (BFS) e in profondità (DFS) come design pattern; etichette discovery, cross e back edge; BFS tree e distanze; complessità Theta(n+m) con liste di adiacenza; applicazioni (connettività, componenti, spanning tree, cammini minimi non pesati, cicli, vertici a distanza al più d); esempio svolto su un grafo di 7 vertici.Visite di grafi - BFS e DFS →); con la matrice sarebbero .
- Errori tipici: matrice per grafi sparsi; archi contati una sola volta nelle liste di un grafo non diretto; costo dei vicini scritto come invece di .