Grafi: rappresentazione e visita
Laboratorio di Algoritmi 02/03
Prof. Ugo de’ Liguoro
AloLab - Grafi
Grafi: definizione
Un grafo diretto (orientato) è una coppia G = V, A dove
• V è un insieme (non vuoto) di vertici
• A  V  V è un insieme, eventulamente vuoto, di archi.
1
2
V = {1,2,3,4}
A = 1,2, 1,3, 3,2, 2,4
3
4
G si dice pesato se esiste una funzione peso:A.
G non è diretto se A è un insieme di coppie non ordinate.
AloLab - Grafi
Grafi: rappresentazione (1)
Matrici di adiacenza: M rappresenta G = V,A se M è una matrice n  n,
dove n = |V|, e (ponendo ogni elemento di V in corrispondenza con un intero
tra 1 e n):
1
se i,j  A
0
altrimenti
Mi,j =
Nel caso di grafi pesati si pone Mi,j = peso(i,j) se i,j  A,  altrimenti.
1
3
2
4
0

0
0

0

1
1
0
0
1
0
0
0
0

1
0

0 
AloLab - Grafi
Grafi: rappresentazione (2)
Liste di adiacenza: G = V,A è rappresentato da un vettore v[1..n] di liste
su V, tale che n = |V|, ad ogni vertice in V sia associato un indice in 1..n, e j
occorra nella lista v[i] se e solo se i,j  A.
Nel caso di grafi pesati le liste hanno elementi in V, e j,r occorre nella
lista v[i] se e solo se i,j  A e peso(i,j) = r.
1
3
2
4
1
2
2
4
3
2
3
4
AloLab - Grafi
Cammini
Dato un qualunque insieme di coppie (relazione binaria) R, la chiusura
transitiva di R, R*, è il piu piccolo insieme di coppie tale che:
i) R  R*,
ii) se x,y, y,z  R*, allora x,z  R*.
Si osservi che la definizione è ricorsiva: un modo alternativo è
• R0 = ,
• Rn+1 = R  {x,z | x,y  Rn, y,z  R},
• R* =  Rn
n
Un cammino in un grafo G = V, A è un elemento della chiusura transitiva
A* di A: quindi un cammino è una sequenza finita di archi,
 = a,b, b,c, … , y,z
che si dice un cammino da a a z, la cui lunghezza è pari al numero degli
archi che lo compongono (lunghezza() = min{n |   An}).
AloLab - Grafi
Visita di un grafo
Una visita di un grafo G = V, A è un insieme di cammini in G con origine in
uno stesso stesso vertice.
Una visita è dunque un albero, i cui vertici sono contenuti in V ed i cui archi
sono contenuti in A (è un sottografo di G), la cui radice è l’origine dei
cammini.
1
2
3
3
1
1
2
4
3
2
4
4
AloLab - Grafi
Partizioni per una visita (1)
Un vertice j è adiacente ad i se i,j  A.
Per implementare un algoritmo di visita si considerano due partizioni
dei vertici del grafo: una partizione in visitati e non visitati; ed una
partizione nei tre sottoinsiemi:
• frontiera (GRIGIO): insieme dei vertici visitati che possono avere
altri vertici adiacenti non ancora visitati;
• interno (NERO): insieme dei vertici visitati i vertici adiacenti sono
stati visitati;
• esterno (BIANCO): insieme dei vertici non ancora visitati.
AloLab - Grafi
Partizioni per una visita (2)
v
G
Interno
Frontiera
Esterno
AloLab - Grafi
Pseudocodifica degli algoritmi di visita:
schema generale
Function visita_grafo (grafo G = V, A, vertice v): insieme;
var albero, interno, esterno, frontiera, D, visitato: insieme;
begin
esterno := V / {v}; frontiera := {v}; interno := ; albero := ;
visitato := {v};
while frontiera   do begin
{Inv. interno, frontiera, esterno soddisfano le rispettive definizioni e,
se interno ha almeno due vertici allora albero è una copertura di interno }
sia w  frontiera;
D : {u | w,u  A and u  esterno}; visitato := visitato  D;
if D =  then begin
frontiera := frontiera / {w}; interno:= interno  {w};
end
else foareach u  D do begin
esterno:= esterno / {u};
frontiera:= frontiera  {u};
albero := albero {w,u}
endforeach
endif
endwhile
return albero
AloLab - Grafi
endfunction;
Visita in ampiezza (BFS)
La visita procede aggiungendo alla frontiera tutti i vertici
esterni adiecenti ad un vertice nella frontiera; fatto questo il
vertice considerato viene rimosso dalla frontiera ed
aggiunto ai vertici interni. La scelta di D è:
D := {u w,u  A and u  esterno}
per qualche w in frontiera.
La frontiera è costituita da una sequenza di vertici la cui
distanza da v è non decrescente: il primo elemento è il più
vicino a v.
Quale struttura dati può implementare la frontiera?
AloLab - Grafi
Algoritmo BFS
BFS (grafo G = V, A, vertice v)
var interno, esterno, albero : insieme;
frontiera: coda;
interno := ; albero := ; esterno:= V/{v}
Accoda(v,frontiera);
while frontiera   do
u := EstraiDallaCoda(frontiera);
foreach w s.t. u,w  A and w  esterno do
esterno = esterno / {w};
albero := albero  {u,w}
Accoda(w,frontiera);
interno := interno  {u}
return albero
AloLab - Grafi
Visita in ampiezza esempio.
Frontiera =
1
2
3
4
5
6
1
Albero =
1
AloLab - Grafi
Visita in ampiezza esempio.
Frontiera =
1
2
3
4
5
6
2 4
1
Albero =
2
4
AloLab - Grafi
Visita in ampiezza esempio.
Frontiera =
1
2
3
4
5
6
5
1
Albero =
2
4
5
AloLab - Grafi
Visita in ampiezza esempio.
Frontiera =
1
2
3
4
5
6
3 6
1
Albero =
2
4
5
3
6
AloLab - Grafi
Visita in ampiezza esempio.
1
2
3
4
5
6
Frontiera = 
1
Albero =
2
4
5
3
6
AloLab - Grafi
Visita in profondità (DFS)
La scelta di D è:
D := {u}, per qualche u tale che
esiste w  frontiera , w è l’ultimo vertice inserito e
w,u  A.
La frontiera è un cammino che comincia da v; l’ultimo
vertice aggiunto alla frontiera è il primo ad essere
considerato: sia per aggiungere altri vertici, sia per
rimuoverlo dalla frontiera.
Con quale struttura conviene implementare la frontiera?
AloLab - Grafi
Algoritmo DFS-Visit
DFS-Visit (grafo G = V, A, vertice v)
var interno, esterno, albero : insieme;
frontiera: pila;
interno := ; albero := ; esterno:= V/{v}
Push(v,frontiera);
while frontiera   do
u := Top(frontiera);
D := {w | u,w  A and w  esterno}
if D   then with w  D do
esterno = esterno / {w};
albero := albero  {u,w}
Push(w,frontiera);
else interno := interno  {u};
Pop(frontiera);
return albero
AloLab - Grafi
Visita in profondità esempio.
Frontiera =
1
1
2
3
4
5
6
Albero =
1
AloLab - Grafi
Visita in profondità esempio.
Frontiera =
2 1
1
2
3
4
5
6
Albero =
1
2
AloLab - Grafi
Visita in profondità esempio.
Frontiera =
1
2
3
4
5
6
5 2 1
Albero =
1
2
5
AloLab - Grafi
Visita in profondità esempio.
Frontiera =
3
1
2
3
4
5
6
5 2 1
Albero =
1
2
5
3
AloLab - Grafi
Visita in profondità esempio.
Frontiera =
1
2
3
4
5
6
5 2 1
Albero =
1
2
5
3
AloLab - Grafi
Visita in profondità esempio.
Frontiera =
1
2
3
4
5
6
6 5 2 1
Albero =
1
2
5
3
AloLab - Grafi
6
Visita in profondità esempio.
Frontiera =
1
2
3
4
5
6
5 2 1
Albero =
1
2
5
3
AloLab - Grafi
6
Visita in profondità esempio.
Frontiera =
2 1
1
2
3
4
5
6
Albero =
1
2
5
3
AloLab - Grafi
6
Visita in profondità esempio.
Frontiera =
1
1
2
3
4
5
6
Albero =
1
2
5
3
AloLab - Grafi
6
Visita in profondità esempio.
Frontiera =
4 1
1
2
3
4
5
6
1
Albero =
4
2
5
3
AloLab - Grafi
6
Visita in profondità esempio.
Frontiera =
1
1
2
3
4
5
6
1
Albero =
4
2
5
3
AloLab - Grafi
6
Visita in profondità esempio.
Frontiera =

1
2
3
4
5
6
1
Albero =
4
2
5
3
AloLab - Grafi
6
Fine
AloLab - Grafi