Sunteți pe pagina 1din 30

EXPLORAREA

GRAFURILOR
l. Dr. Ing. erban Radu
Departamentul de Calculatoare
Facultatea de Automatic i Calculatoare
Introducere


Explorarea unui graf nseamn

vizitarea
tuturor nodurilor din graf, folosind arcele
existente, astfel nct s

se treac

o
singur

dat

prin fiecare nod


Rezultatul explorrii unui graf este o
colecie de arbori de explorare, numit i
"pdure" de acoperire
Introducere


Rezultatul explorrii unui graf orientat
depinde de nodul de plecare


Pentru graful orientat cu arcele
(1,4),(2,1),(3,2),(3,4),(4,2) numai vizitarea
din nodul 3 poate atinge toate celelalte
noduri
Funcia de explorare a grafului


Primete

ca parametru

un nod de start i
ncearc

s

ating

ct mai multe noduri din
graf


Aceast

funcie poate fi apelat

n mod
repetat, pentru fiecare nod din graf,

considerat
ca nod de start


Astfel,

se asigur

vizitarea tuturor nodurilor
pentru orice graf


Fiecare apel genereaz

un arbore de
acoperire a unei submulimi de noduri
Observaii


Explorarea unui graf poate fi vzut

ca o
metod

de enumerare a tuturor nodurilor
unui graf sau ca o metod

de cutare a
unui drum ctre un nod dat din graf


Transformarea unui graf (structur

bidimensional) ntr-un tablou

(structur

liniar) se poate face n multe feluri,
deoarece fiecare nod are mai muli
succesori i trebuie s

alegem numai unul
singur pentru continuarea explorrii
Algoritmi de explorare


Algoritmii de explorare dintr-un nod dat pot
folosi dou

metode:


1) Explorarea

n adncime (DFS

= Depth
First Search)


2)

Explorarea

n lime

(BFS

= Breadth
First Search)
Explorarea n adncime


Explorarea n adncime folosete, la fiecare
nod, un singur arc (ctre nodul cu numr
minim) i astfel se ptrunde ct mai repede
n adncimea grafului


Dac

rmn noduri nevizitate, se revine
treptat la nodurile deja vizitate,

pentru a lua
n considerare i alte arce, ignorate n prima
faz
Explorarea n adncime


Explorarea DFS din nodul 3 a grafului

produce secvena de noduri 3, 2, 1, 4,

iar
arborele de acoperire este format din
arcele 3-2, 2-1 i 1-4
Explorarea n lime


Explorarea n lime

folosete, la fiecare
nod, toate arcele care pleac

din nodul
respectiv i dup

aceea trece la alte
noduri (la succesorii nodurilor vizitate)


n

felul acesta,

se exploreaz

mai nti
nodurile adiacente din "limea" grafului i
apoi se coboar

mai adnc n graf
Explorarea n lime


Explorarea BFS

din nodul 3 a grafului

conduce la secvena de noduri 3,

2,

4,

1 i
la arborele de acoperire 3-2, 3-4, 2-1,
dac

se folosesc succesorii n ordinea
cresctoare a numerelor lor
Observaii


Este posibil ca pentru grafuri diferite s

rezulte aceeai secven de noduri, dar
lista de arce este unic

pentru fiecare graf,
dac

se aplic

acelai algoritm


Este posibil ca,

pentru anumite

grafuri,

s

rezulte acelai arbore de acoperire,

att la
explorarea DFS,

ct i la explorarea BFS


De exemplu, pentru

grafurile

liniare (1-2,
2-3, 3-4) sau pentru graful 1-2, 1-3, 1-4
Algoritmul de explorare DFS


Se poate

exprima recursiv sau iterativ,
folosind o stiv

de noduri


Ambele variante trebuie s in

evidena
nodurilor vizitate pn

la un moment dat,
pentru a evita vizitarea repetat

a unor
noduri


Cea mai simpl

implementare a mulimii
de noduri vizitate este un tablou

"vzut",
iniializat cu zerouri i actualizat dup

vizitarea fiecrui nod x (vzut[x]

=

1)
Funcia recursiv de explorare
// explorare DFS

dintr-un nod dat v
void dfs (Graf g, int v, int vzut[]) {
int w, n

=

g.n;

// n

= numr

noduri din graful g
vzut[v]

=

1;

// marcare v ca vizitat
printf ("%d ",

v);

// afiare (sau memorare)
for (w = 1; w <= n; w++)
// repet pentru fiecare vecin posibil w
if (arc(g,

v,

w) && vzut[w]

==

0)
// dac

w este un vecin nevizitat al lui v
dfs(g,

w,

vzut);

// continu

explorarea din w
}
Funcia pentru vizitarea nodurilor
// explorare graf n adncime, pornind din primul nod
void df (Graf g) {
int vzut[M]

=

{0};

// mulime noduri vizitate
int v;
for (v

=

1;

v

<=

g.n;

v++)
if (!vazut[v]) {
printf(\n Explorare din nodul %d \n, v);
dfs(g,

v,

vzut);
}
}
Observaii


Un algoritm DFS nerecursiv trebuie s

foloseasc

o stiv,

pentru a memora
succesorii (vecinii) neprelucrai ai fiecrui
nod vizitat, astfel nct

s se

poat

reveni
ulterior la acetia
Pseudocod DFS nerecursiv
pune nodul de start

n stiv
repet

ct timp stiva nu e goal
scoate din stiv

nodul

x
afiare i marcare nodul

x
pune n stiv

orice succesor nevizitat y al lui x
Funcia DFS nerecursiv
void dfs (Graf g,

int v, int vzut[]) {
int x,

y;
Stack s;

// s este o stiv

de numere naturale
initSt(s); // iniializare stiv
push(s,

v);

// pune nodul v pe

stiv
while (

!

emptySt(s)) {
x

=

pop(s); // scoate din stiv

nodul

x
vzut[x]

=

1;

// marcheaz

x ca vizitat
printf("%d ",

x);

// afieaz

nodul x
for (y

=

g.n; y >=

1; y--)
// caut

un vecin al lui

x, care este

nevizitat
if (arc(g,

x,

y) && !

vzut[y]) {
vzut[y]

=

1;
push(s,

y); // pune

nodul

y pe stiv

} }

}
Observaii


Pentru ca funcia DFS nerecursiv

s

produc

aceleai rezultate ca i funcia
DFS recursiv, succesorii unui nod sunt
pui n stiv

n ordinea descresctoare a
numerelor lor, iar extragerea lor din stiv i
afiarea lor se va face n ordine invers
Exemplu


Se consider graful

cu arcele:


(1,2), (1,4),

(2,3),

(2,4),

(3,4)


Evoluia stivei i a nodurilor x i y este:
Stiva s x y Afiare
1
- 1 1
- 1 4
4 1 2
2, 4 1
4 2 2
4 2 4
Stiva s x y Afiare
4, 4 2 3
3, 4, 4 2
4, 4 3 3
4, 4 3 4
4, 4, 4 3
4, 4 4 4
4 4
- 4
Algoritmul de explorare n lime


Se afieaz i

se

memoreaz

pe rnd
succesorii fiecrui nod


Ordinea de prelucrare a nodurilor memorate
este aceeai cu ordinea de introducere n

coad


Algoritmul BFS este asemntor
algoritmului DFS nerecursiv


Diferena apare numai la tipul listei folosite
pentru memorarea temporar

a succesorilor
fiecrui nod: stiv

la DFS i coad

la BFS
Funcia

de explorare n lime
// explorare n lime dintr-un nod dat v
void bfs ( Graf g, int v, int vzut[]) {
int x,

y;
Queue q;

//

q este

o coad

de numere naturale
initQ(q);
vzut[v]

=

1; // marcare v ca vizitat
enqueue(q,

v); // pune pe v n coad
Funcia

de explorare n lime
while ( ! emptyQ(q)) {
x

=

dequeue(q); // scoate

pe x

din coad
for (y

=

1;

y <=

g.n; y++)
// repet

pentru

fiecare potenial vecin cu x
if (arc(g,

x,

y) && vzut[y]

==

0) {
// dac

y este vecin cu x i nevizitat
printf("%d -

%d \n",

x,

y); // scrie muchia x-y
vzut[y]

=

1;

// y vizitat
enqueue(q,

y);

// pune

pe

y n coad
}
}
}
Exemplu


Se consider graful

cu arcele:


(1,2), (1,4),

(2,3),

(2,4),

(3,4)


Evoluia cozii i a nodurilor x i y este:
Coada q x y Afiare
1
- 1
- 1 2 1 -

2
2 1 4 1 -

4
2, 4 1
4 2
4 2 3 2 -

3
3, 4 2
4 3
- 4
Drum minim


Un drum minim

ntre dou

vrfuri este drumul
care folosete cel mai mic numr de muchii


Drumurile minime de la un vrf v la toate
celelalte noduri pot fi gsite prin explorare n
lime

din

nodul v, cu actualizarea

distanei

fa

de v, la fiecare coborre cu un nivel n graf


Se

folosete

un tablou

d, unde

d[y]

=

distana
vrfului y fa

de "rdcina" v, precum

i un
tablou

p, cu p[y]

=

numr vrf predecesor pe
calea de la v la y
Calculul distanei minime
//distana minim

de la v la toate celelalte noduri din graf
void bfs (Graf

g, int v,

int vzut[],

int d[], int p[]) {
int x,

y;
Queue q;
initQ(q);
vzut[v]

=

1;
d[v]

=

0;
p[v]

=

0;
enqueue(q,

v); // pune

pe

v n coad
Calculul distanei minime
while ( ! emptyQ(q)) {
x

=

dequeue(q); // scoate

pe x

din coad
for (y

=

1;y <=

g.n;

y++)
if (arc(g,

x,

y) && vzut[y]

==

0) {
// dac exist

arc ntre x i y

i y nu a fost vizitat
vzut[y]

=

1;
d[y]

=

d[x]

+

1;

// y este un nivel mai jos dect

x
p[y]

=

x;

// x este predecesorul lui y

pe drumul minim
enqueue(q,

y);
}
}
}
Observaii


Pentru afiarea vrfurilor de pe un drum
minim de la v la x,

trebuie parcurs n sens
invers tabloul

p (de la ultimul element la
primul):


x

p[x] p[p[x]] v