You are on page 1of 16

Algoritmik Grafet

Grafet

1. Grafet e orientuar dhe te paorientuar

Grafi eshte nje strukture matematikore qe perbehet nga nje bashkesi kulmesh dhe brinjesh
qe lidhin keto kulme. Formalisht brinjet trajtohen si cifte kulmesh, nje brinje (v, w) lidh kulmin
v me kulmin w. Formalisht:
V eshte bashkesia e kulmeve
E eshte nenbashkesi e V x V
Shkruajme G = (V, E) per te treguar qe G eshte nje graf me bashkesi kulmesh bashkesine V dhe
bashkesi brinjesh bashkesine E. Grafi G = (V, E) eshte i paorientuar atehere dhe vetem atehere
kur kur nqs per te gjitha kulmet v, w V, (v, w) E kemi (w, v) E. Nga perkufizimi duket qe
grafet e paorientuara jane raste te vecanta te grafeve te orientuar.
Bashkesia V dhe rrjedhimisht edhe bashkesia E jane te pafundme. Grafe te tilla gjejne
perdorim ne shume fusha, megjithate do te trajtojme vetem bashkesi te fundme V. Mqs E
eshte nenbashkesi e VxV atehere edhe E eshte e fundme.
Figura me poshte paraqet nje graf te orientuar me kulme dhe brinje te percaktuara nga
bashkesite:
V = {0, 1, 2, 3, 4, 5, 6} dhe
E = {(0, 2), (0, 4), (0, 5), (1, 0), (2, 1), (2, 5), (3, 1), (3, 6), (4, 0), (4, 5), (6, 3), (6, 5)}

Fig.1. Graf i orientuar.

Nqs v V eshte nje kulm ne nje graf te orientuar G=(V, E) atehere:


Rendi hyres in(v) i kulmit v eshte numri i brinjeve hyrese tek v, dmth numri i brinjeve
te trajtes (v, u).
Rendi dales out(v) i kulmit v eshte numri i brinjeve dalese nga v, dmth numri i brinjeve
(v, u).
Ne nje graf te paorientuar, rendi i nje kulmi v eshte numri i brinjeve e E per te cilat njeri kulm
eshte v. Dy kulme jane fqinje nese ka nje brinje qe i lidh ato.
Grafet jane modele matematikore qe mund te perdoren ne probleme te ndryshme. Disa nga
perdorimet e grafeve jane:
Hartat e linjave ajrore. Kulmet perfaqesojne aeroporte dhe nga kulmi A tek kulmi B ka nje
brinje nese ka nje fluturim direkt nga nje aeroport i A tek nje aeroport i B.
Qarqet elektrike. Kulmet perfaqesojne dioda, tranzistore, celesa, etj dhe brinjet perfaqesojne
telat qe i lidhin ato.
Rrjetat kompjuterike. Kulmet perfaqesojne kompjutera dhe brinjet perfaqesojne lidhjet e
rrjetit ndermjet tyre.
Worl Wide Web. Kulmet jane faqet e internetit ndersa brinjet jane hyperlinks qe lidhin faqet
me njera tjetren.

2. Strukturat e te dhenave per grafet

Le te jete G=(V, E) nje graf me n kulme. Do ti emertojme kulmet e grafit me numra nga 0, 1,
..., n-1 ne nje menyre te zakonshme.

B.Bimbari -1-
Algoritmik Grafet

2.1 Paraqitja e grafit me matricen e fqinjesise

Matrica e fqinjesise per grafin G eshte nje matrice nxn A = (aij)0i, jn-1, ku aij = 1 nqs ka nje brinje
nga kulmi i tek kulmi j dhe 0 perndryshe.
Psh, matrica e fqinjesise per grafin e paraqitur ne Fig.1 eshte :

Fig.2. Paraqitja e grafit me matrice fqinjesie.

Matrica e fqinjesise varet nga menyra e emertimit te kulmeve te grafit. Matrica e fqinjesise qe
paraqet grafin eshte nje tabele dy dimensionale booleane, ku vlera TRUE (ose 1) tregon qe
ndermjet kulmit paraqitur nga rreshti perkates dhe kulmit paraqitur nga shtylla perkatese ka
nje brinje qe i lidh (pra jane fqinje). Vlera FALSE (ose 0) tregon qe ndermjet kulmeve nuk ka
nje brinje qe i lidh (pra nuk jane fqinje). Mund te ndodhe qe ne vend te vlerave 1 dhe 0 te kete
numra (rastet e grafeve me peshe). Perparesia kryesore e paraqitjes se grafeve me matrice
fqinjesie eshte se per te gjithe kulmet v dhe w mund te kontrollohet ne kohe konstante nese
ato jane fqinje ose jo (pra nese ka nje brinje qe i lidh apo jo).
Cmimi qe paguhet per aksesin e shpejte te shpjeguar me larte eshte kujtesa. Le te jete m numri
i brinjeve te grafit (m mund te jete te shumten n2).Nqs m eshte shume afer vleres n2 atehere
grafi quhet i dendur, ndersa nqs ajo eshte shume me e vogel sesa n2 grafi quhet i rralle. Ruajtja
e grafit do te kerkonte te pakten n+m vende ne kujtese, nderkohe perdorimi i matricave te
fqinjesise perdor n2 vende. Kjo vlere eshte shume me e madhe sesa n+m sidomos per grafet e
rralle (nje pjese e madhe e elementeve te matrices ka vlere 0). Algoritmet qe punojne me
grafet, duhet te inspektojne te gjitha brinjet e grafit te pakten njehere dhe, ne paraqitjen e
grafit me matrice fqinjesie keto algoritme trajtonin cdo element te matrices te pakten njehere
(per tu siguruar qe jane kontrolluar te gjitha brinjet). Algoritmet do te kerkonin O(n2) kohe
per tu ekzektuar.

2.2 Paraqitja e grafit me listen e fqinjesise

Kur grafi paraqitet nepermjet listes se fqinjesise, perdoret nje tabele me n elemente, ku n
eshte numri i kulmeve te grafit. Cdo element i vektorit (qe i korrespondon nje kulmi v) eshte
nje liste e lidhur e cila permban te gjithe kulmet w qe lidhen me kulmin v nepermjet nje brinje.
Elementet e listes do te jene emertimet(numra, emra, etj, ne varesi te menyres se zgjedhur
per emertimin e kulmeve) e kulmeve fqinje. Nuk ka rendesi renditja e kulmeve w ne listen e
lidhur, pra nuk ka rendesi renditja e brinjeve qe ato paraqesin. Kjo gje duhet te kihet parasysh
edhe ne algoritmet qe punojne me grafet e paraqitura me keto struktura.
Grafi i paraqitur ne figuren 1 paraqitet nepermjet listave te fqinjesise si me poshte:

B.Bimbari -2-
Algoritmik Grafet

Fig.3. Paraqitja e grafit me lista fqinjesie.

Per grafe te rralle paraqitja me liste fqinjesie eshte me eficente sesa paraqitja me matrica,
persa i perket hapesires. Per nje graf me n kulme dhe m brinje hapesira qe kerkohet eshte
(m+n), qe mund te jete shume me pak sesa (n2) hapesira e kerkuar kur grafi paraqitet me
matrice fqinjesie. Nga ana tjeter, per te gjetur nese ka nje brinje ndermjet dy kulmeve v dhe
w duhet te bridhet e gjithe lista e fqinjesise, e cila mund te kete te shumten n
elemente. Prandaj, testimi i kushtit te fqinjesise kerkon (n) hapa per paraqitjen me lista
fqinjesie, perkundrejt (1) hapave ne rastin e matrices se fqinjesise.

Per grafin e paraqitur me liste fqinjesie percaktohet struktura si me poshte :

int const MAXK=10; /*konstante qe percakton numrin maksimal te mundshem te


kulmeve te grafit*/

struct brinje{
int w; /* variabel per te ruajtur kulmin fundor te brinjes */
int pesha; /* peshe e brinjes, nese ka */
brinje * pas; /* shenjues tek elementi tjeter i linjes, qe paraqet
brinjen pasardhese ne liste */
};

struct graf{
brinje * brinjet[MAXK]; /* tabela me listen e fqinjesise, MAXK konstante
qe tregon numrin maximal te kulmeve */
int nKulmesh; /* numri kulmeve te grafit */
int nBrinje; /* numri brinjeve te grafit */
bool orientuar; /* indikator, graf i orientuar? */
};

Ne strukturat me lart, nje brinje (v,w) e orientuar paraqitet nepermjet nje brinje w ne listen e
fqinjesise se v. Nje brinje e paorientuar do te shfaqej dy here ne nje graf me kete strukture,
sepse do te ishte njehere ne listen e fqinjesise se v dhe njehere ne listen e fqinjesise se w.

Inicializimi i nje grafi bosh, paraqitur si me lart do te ishte :

graf *inicializo_graf(graf * g, bool eshteIOrientuar)


{
g -> nKulmesh = 0;
g -> nBrinje = 0;
g -> orientuar = eshteIOrientuar;
for (int i=0; i<=MAXK; i++)
g-> brinjet[i] = NULL;

return g;
}
Shtimi i nje brinje ne graf mund te realizohet nepermjet algoritmit shto_brinje me
poshte :

B.Bimbari -3-
Algoritmik Grafet

graf *shto_brinje (graf *g, int v, int w, bool eshteIOrientuar)


{
brinje * b;
b = new brinje;
p->pesha = NULL; /*nqs grafi nuk eshte me peshe, fusha pesha
plotesohet NULL, nese grafi eshte me peshe,
vendoset pesha e brinjes*/
b->w = w;
b->pas = g->brinjet[v];
g-> brinjet[v] = b; /* brinja (v,w) shtohet ne fillim te listes
*/
if (eshteIOrientuar == false)
shto_brinje(g,w,v,true);
else
g->nBrinje ++;

return g;
}

Afishimi i nje grafi mund te realizohet nepermjet algoritmit afisho_graf me poshte:

void afisho_graf(graf *g)


{
for(int i = 0; i < g->nKulmesh; i++)
{
brinje * b;
b = g->brinjet[i];
cout<<"\n"<<"fqinjet e kulmit "<<i<<": ";
while(b != NULL)
{
cout<<b->w<<" ";
b = b->pas;
}
}
cout<<"\n";
}
3. Bredhja e grafeve

Pjesa me e madhe e algoritmeve te bredhjes se grafeve trajtojne cdo kulm dhe brinje sipas nje
rregulli te caktuar. Ne kete menyre algoritmet japin nje bredhje te grafit, dmth nje strategji
per te vizituar kulmet dhe brinjet sipas nje rregulli te pershtatshem.
Dy nga menyrat me te perhapura per bredhjen e grafit jane bredhja ne gjeresi (breadth-first
search) dhe bredhja ne thellesi (depth-first search). Te dyja fillojne nga nje kulm v dhe vizitojne
te gjithe kulmet e arritshme nga v (pra te gjithe fqinjet e tij). Nqs ka kulme qe mbeten te
pavizituara, dmth ka kulme qe nuk jane te arritshme nga v, atehere e vetmja menyre qe ato
te mund te listohen eshte qe kerkimi te zgjedhe nje kulm te ri te pavizituar v dhe te vizitoje
te gjitha kulmet e arritshme prej tij. Ky proces duhet te perseritet deri sa te jene vizituar te
gjitha kulmet.

3.1 Bredhja ne gjeresi (Breadth-First Search - BFS)


Bredhja ne gjeresi qe fillon tek nje kulm v, trajton ne fillim v dhe me pas te gjithe fqinjet e tij
(dmth te gjithe kulmet w te tilla qe nga v tek w ka nje brinje), pastaj te gjithe fqinjet e fqinjeve
qe nuk jane vizituar me pare, pastaj te gjithe fqinjet e fqinjeve te fqinjeve, e keshtu me rradhe.
Psh nje bredhje ne gjeresi e grafit te paraqitur ne figuren 1, duke filluar nga kulmi 0, eshte 0,
2, 5, 4, 1. Ne fillim trajtohet kulmi 0, pastaj fqinjet e tij 2, 5, 5. Me pas trajtohen fqinjet e kulmit
2 qe jane 1 dhe 5. Mqs 5 eshte trajtuar nje here me pare, ne liste shtohet vetem 1. Te gjithe

B.Bimbari -4-
Algoritmik Grafet

fqinjet e 5, 4 dhe 1 jane vizituar, keshtu qe lista permban te gjithe kulmet e arritshem nga 0.
Ka edhe menyra te tjera sesi mund te zgjidhen kulmet qe trajtohen duke u nisur nga kulmi 0.
Nqs kulmet fqinje qe do te vizitohen zgjidhen ne rend numerik, atehere bredhja ne gjeresi
duke filluar nga 0 do te jepte 0, 2, 4, 5, 1. Kulmet 3 dhe 6 nuk jane te arritshme nga kulmi 0,
prandaj per ti vizituar ata duhet te fillohet nje bredhje tjeter ne gjeresi, psh nga kulmi 3.
Bredhja dhe sekuenca qe ajo prodhon varet shume nga kulmi ne te cilin fillohet. Psh
nqs bredhjen e fillojme ne kulmin 6, atehere te gjitha kulmet jane te arritshme dhe trajtohen
ne nje hap te gjitha. Sekuenca qe do merret eshte 6, 5, 3, 1, 0, 2, 4. Renditje tjeter qe mund te
gjenerohet eshte 6, 3, 5, 1, 0, 2, 4 dhe 6, 5, 3, 1, 0, 4, 2 ose 6, 3, 5, 1, 0, 4, 2.
Ne grafet e pa orientuara, numri i rezultateve te ndryshme te bredhjes ne gjeresi eshte
i pavarur nga zgjedhja e kulmit te fillimit.
Gjate bredhjes ne gjeresi te grafit, duhet te ruajme kulmet qe jane vizituar deri ne ate
moment dhe kulmet qe jane trajtuar plotesisht deri ne ate moment (dmth kulmet per te cilet
jane vizituar te gjithe fqinjet e tyre). Tabela booleane vizituar ka aq elemente sa eshte numri
i kulmeve te grafit. Cdo element ka vleren TRUE nqs kulmi te cilit ai i korrespondon eshte
vizituar. Kulmet qe jane vizituar, por qe nuk jane trajtuar plotesisht ruhen ne nje rradhe
Rradhe. Kjo garanton qe kulmet te trajtohen ne rendin e duhur kulmet qe vizitohen me pare
do te trajtohen me pare. Implementimi i algoritmit te bredhjes ne gjeresi jepet me poshte si
pseudokod.

Algoritem bredhje_ne_gjeresi(G)
1. Inicializo tabelen booleane vizituar me te gjitha vlerat FALSE
2. Inicializo Rradhen Q
3. per te gjitha v V bej
4. nqs vizituar[v] = FALSE atehere
5. bredhje_ne_gjeresi_nga_kulmi(G, v)

Algoritem bredhje_ne_gjeresi_nga_kulmi (G, v)


1. vizituar[v] = TRUE
2. Q.futNeRradhe(v)
3. per sa kohe Q.eshteBosh() bej
4. v Q.hiqNgaRradha()
5. per te gjithe w fqinje me v me
6. nqs vizituar[w] = FALSE atehere
7. vizituar[w] = TRUE
8. Q.futNeRradhe(w)

Algoritmi kryesor bredhje_ne_gjeresi inicializon tabelen vizituar dhe rradhen dhe me pas
bredh te gjitha kulmet. Per secilin kulm qe nuk eshte shenjuar si i vizituar, ai inicion nje
bredhje_ne_gjeresi_nga_kulmi. Algoritmi bredhje_ne_gjeresi_nga_kulmi viziton te gjitha
kulmet e arritshme nga kulmi fillestar sic u pershkrua me lart. Cikli ne rreshtat 5-8 mund te
implementohet duke perdorur bredhur listen e fqinjesise te kulmit v.
Ne implementimin e algoritmit te mesiperm te bredhjes ne gjeresi perdoren dy tabela
booleane per te ruajtur informacion per cdo kulm te grafit. Kulmi quhet i vizituar heren kur ai
vizitohet per here te pare nga algoritmi. Kulmi konsiderohet i procesuar (trajtuar plotesisht)
nqs eshte kaluar neper te gjitha brinjet qe dalin prej tij. Pra, gjate kerkimit, cdo kulm kalon nga
gjendja i pavizituar ne i vizituar dhe ne fund i procesuar.

bool procesuar[MAXK+1]; /* kulmet qe jane procesuar*/


bool vizituar[MAXK+1]; /* kulmet qe jane zbuluar/vizituar*/
int prindi[MAXK+1]; /* kulmi tjeter i brinjes */

B.Bimbari -5-
Algoritmik Grafet

//Rradha implementohet me lista te lidhura nje drejtimore. Elementet


shtohen ne fund te listes, per te realizuar parimin e rradhes,
elementi qe futet i pari ne liste, eshte ai qe trajtohet i pari.

struct Rradhe{
int vl;
Rradhe * pas;
};

Rradhe * shto_ne_rradhe(Rradhe * r, int vl)


{
Rradhe * element;
Rradhe * tmp;
element = new Rradhe;
element->vl = vl;
element->pas = NULL;

if(r == NULL)
r = element;
else
{
tmp = r;

while(tmp->pas != NULL)
tmp = tmp->pas;

tmp->pas = element;
}

return r;
}
void inicializo_bredhje(graf *g)
{
for (int i=0; i<g->nKulmesh; i++)
{
procesuar[i] = vizituar[i] = false;
prindi[i] = -1;
}
}

void bredhje_ne_gjeresi(graf *g, int kulmFillimi)


{
Rradhe * q; /* rradha me kulmet qe do te vizitohen */
q = NULL;
int v; /* kulmi korent */
int y; /* kulmi pasardhes */
brinje *p; /* shenjues i perkohshem */

q = shto_ne_rradhe(q,kulmFillimi);
vizituar[kulmFillimi] = true;

while (q != NULL)
{
Rradhe * fillim = q;
v = fillim->vl;
p = g->brinjet[v];

while (p != NULL)
{
y = p->w;
if (vizituar[y] == false)

B.Bimbari -6-
Algoritmik Grafet

{
q = shto_ne_rradhe(q,y);
vizituar[y] = true;
prindi[y] = v;
}
p = p->pas;
}
procesuar[v] = true;
fillim = fillim->pas;
q = fillim;
}
}
Bredhja ne gjeresi prodhon pemen(t) e bredhjes ne gjeresi. Kjo peme ka si rrenje kulmin s prej
nga nis bredhja ne thellesi dhe permban te gjitha kulmet e arritshme prej tij. Fillimisht
algoritmi shton ne kete peme vetem kulmin prej nga nis bredhja (s). Sa here qe algoritmi gjen
kulme te pazbuluar (psh ndonje kulm v, te arritshem nga ndonje kulm u ne listen e fqinjesise
se kulmit fillester), ai shton ne peme kulmin v dhe brinjen (u,v).

3.2 Bredhja ne thellesi (Depth-First Search - DFS)

Bredhja ne thellesi qe fillon nga nje kulm v, viziton ne fillim v, pastaj ndonje fqinj w te v, pastaj
ndonje fqinje x te w qe nuk eshte vizituar me pare, e keshtu me rradhe. Kur algoritmi ngec
dmth i ka trajtuar te gjithe kulmet fqinje si me siper, kthehet dhe gjen kulmin e pare te vizituar
qe ka nje fqinje te vizituar. Ai vazhdon me bredhjen deri sa ti duhet te kthehet perseri
mbrapa. Ne kete menyre, algoritmi do te mbuloje te gjitha kulmet e arritshme nga v. Me pas
fillon nje bredhje tjeter ne thellesi. Kjo bredhje fillon nga ndonje kulm qe nuk eshte i arritshem
nga v dhe perseritet derisa te gjitha kulmet te jene vizituar.
Per grafin me poshte, nje bredhje ne thellesi qe fillon nga kulmi 0 do te jepte sekuencen

Fig. 4. Graf i orientuar.

0, 2, 1, 5, 4. Pasi jane vizituar kulmet 0, 2 dhe 1, algoritmi kthehet tek kulmi 0 dhe viziton 4.
Bredhja ne thellesi qe fillon tek 0 mund ti vizitoje kulmet edhe ne rendin 0, 4, 5, 2, 1 ose 0, 5,
4, 2, 1 ose 0, 2, 5, 1, 4. Ashtu si dhe tek bredhja ne gjeresi, sekuenca e kulmeve qe jep algoritmi
varet nga radha ne te cilen trajtohen kulmet.
Bredhja ne thellesi mund te implementohet ne menyre te ngjashme me bredhjen ne
thellesi, duke perdorur nje stive ne vend te rradhes. Duke perdorur stive per te ruajtur kulmet
qe jane vizituar, por nuk jane procesuar, sigurohemi qe eksplorojme kulmet duke ecur perpara
ne shteg. Pra vizitojme nje fqinj te ri, nese ekziston nje fqinj dhe kthehemi kur i kemi vizituar
te gjithe fqinjet.
Algoritmi me poshte eshte nje implementim rekursiv i bredhjes ne thellesi. Prania e
rekursivitetit eleminon nevojen e perdorimit ne menyre eksplicite te stives.

Algoritem bredhje_ne_thellesi(graph G, u)
gjendje[u] = vizituar
for each v fqinjet[u] do
proceso_brinjen (u, v) //sipas nevojes
if gjendje[v] = pazbuluar then
paraardhesi [v] = u

B.Bimbari -7-
Algoritmik Grafet

bredhje_ne_thellesi(G, v)
gjendje[u] = procesuar

Implementimi i algoritmit me lart eshte:

bool procesuar[MAXK+1]; /* kulmet qe jane procesuar*/


bool vizituar[MAXK+1]; /* kulmet qe jane zbuluar/vizituar*/
int prindi[MAXK+1]; /* kulmi tjeter i brinjes */

void bredhje_ne_thellesi(graf * g, int kulmFillimi)


{
brinje *p; /*shenjues i perkohshem*/
int y; /*kulmi fqinj*/
int v = kulmFillimi;
vizituar[v]= true;
p = g->brinjet[v];
while (p!= NULL)
{
y = p->w;
if(vizituar[y] == false)
{
prindi[y] = v;
bredhje_ne_thellesi(g,y);
}
p = p->pas;
}

procesuar[v] = true;

}
4. Aplikime te bredhjeve te grafeve
4.1 Perdorime te bredhjes ne gjeresi

Pjesa me e madhe e algoritmeve ne grafe bredhin nje ose dy here grafin. Kur keto algoritme
perdorin listat e fqinjesise koha e ekzekutimit te tyre eshte lineare, mqs algoritmi i bredhjes
ne gjeresi ka kompleksitet O(m+n) (m- numri i brinjeve, n- numri i kulmeve).

4.1.1 Gjetja e shtigjeve ne graf

Tabela prindi ne algoritmin e bredhjes ne gjeresi sherben per te gjetur shtigje ne graf. Kulmi
qe sherbeu si nisje kur u zbulua kulmi i percaktohet si prind[i]. Te gjitha kulmet zbulohen
gjate bredhjeve te grafit, keshtu qe te gjithe kulmet pervec rrenjes kane nje prind. Relacioni
prind percakton nje peme te bredhjes se grafit ku rrenja eshte kulmi fillestar ku fillon bredhja.
Gjate procesit te zbulimeve te kulmeve duke u nisur nga rrenja, distanca e tyre nga
rrenja rritet. Shtegu unik nga rrenja tek cdo kulm x permban numrin me te vogel te mundshem
te brinjeve qe lidhin brinjen me cdo kulm. Kjo eshte nje veti shume e rendesishme e pemes
qe krijohet sipas menyres se pershkruar me lart.
Shtegu mund te ndertohet duke ndjekur zinxhir paraardhesit e x per te arritur deri tek
rrenja. Duhet punuar duke ecur mbrapsht ne shteg sepse ai nuk mund te gjendet duke u nisur
nga rrenja. Prandaj mqs shtegu gjenerohet ne rend te kundert, duhet qe ose nepermjet
rekursivitetit ose nepermjet stivave te shnderrohet ne rendin korrekt.

B.Bimbari -8-
Algoritmik Grafet

gjej_shteg(int kFillim, int kFund, int prindi[])


{
if ((kFillim == kFund) || (kFund == -1))
printf("\n%d",kFillim);
else {
gjej_shteg (kFillim, prindi [kFund], prindi);
printf(" %d", kFund);
}
}

Per grafin me poshte (dhe pemen perkatese te formuar per bredhjen ne gjeresi) algoritmi i
bredhjes ne gjeresi jep lidhjen kulm-prind sic eshte paraqitur ne tabele.

Kulmi 1 2 3 4 5 6
Prindi -1 1 2 5 1 1

Fig.5. Grafi G, pema e bredhjes se tij ne gjeresi dhe tabela e relacionit kulm-prind.

Algoritmi gjej_shteg per kulmet 1 dhe 4 gjen si shtegun me te shkurter mes ketyre dy
kulmeve shtegun {1, 5, 4}.

Kur perdoret algoritmi i bredhjes ne gjeresi per te gjetur shtegun me te shkurter ndermjet
kulmeve x dhe y duhet mbajtur parasysh qe:
- pema e shtegut me te shkurter hyn ne pune vetem kur bredhja ne gjeresi eshte
realizuar duke filluar nga kulmi x.
- algoritmi jep shtegun me te shkurter vetem nese grafi nuk eshte me peshe.

4.1.2 Komponentet e lidhur

Nje graf eshte i lidhur nqs ekziston nje shteg ndermjet cdo dy kulmesh. Nje komponente e
lidhur ne nje graf te paorientuar eshte bashkesia maksimale e kulmeve e tille qe ndermjet cdo
dy kulmeve ekziston nje shteg. Studimi i komponenteve te lidhura eshte me rendesi sepse nje
numer i madh problemesh reduktohen ne gjetjen e komponenteve te lidhura te grafit.
Komponentet e lidhura mund te gjenden duke perdorur bredhjen ne gjeresi, mqs nuk
ka rendesi renditja e kulmeve. Fillohet nga kulmi i pare. Cdo kulm qe zbulohet gjate ketij
kerkimi duhet te jete pjese e te njejtit komponent te lidhur. Per te zbuluar komponente te
tjera, kerkimi perseritet duke nisur nga ndonje kulm i pazbuluar (nese ekziston nje kulm i tille).
Kjo perseritet derisa te gjenden te gjitha komponentet. Algoritmi paraqitet me poshte:

komponente_te_lidhura(graf *g)
{
int c; /* numri i komponenteve */
int i;

inicializo_kerkimin(g);
c = 0;
for (i=1; i<=g->nKulmesh; i++)
if (vizituar[i] == FALSE) {

B.Bimbari -9-
Algoritmik Grafet

c = c+1;
printf("Komponenti %d:",c);
bredhje_ne_gjeresi(g,i);
printf("\n");
}
}

Numri c inkrementohet sa here qe nis nje bredhje ne gjeresi nga nje kulm i pavizituar me pare.
Fakti qe gjenden kulme te pavizituar me pare do te thote qe nuk ka pasur nje shteg nga kulmi
i nisjes deri tek ky kulm, pra ai ndodhet ne nje komponente tjeter.

4.2 Perdorime te bredhjes ne thellesi

Bredhja ne thellesi eshte nje menyre e rendesishme e bredhjes se grafeve. Ndryshimi me


bredhjen ne gjeresi eshte rradha sipas se ciles vizitohen dhe trajtohen kulmet e grafit. Ne
bredhjen ne thellesi kulmet qe vizitohen ruhen ne nje stive (strukture ku elementi qe futet i
pari ne stive hiqet/trajtohet i pari prej saj). Ne kete menyre vizitohet nje kulm, fqinji i tij, fqinji
i fqinjit, deri sa te jene vizituar te gjithe kulmet e arritshme. Ne kete moment bredhja kthehet
tek kulme te patrajtuar. Bredhja ne thellesi gjeneron pemen e bredhjes ne thellesi te grafit,
ne menyre te ngjashme me bredhjen ne gjeresi.

Bredhja ne thellesi i ndan brinjet e nje grafi te paorientuar ne dy klasa:


- brinje te pemes te cilat jane brinje qe zbulojne kulme te reja ne graf dhe jane ato qe
ruhen ne relacionin prind.
- brinje te kthimit pas qe jane brinje qe njerin kulm e kane paraardhes te kulmit i cili po
trajtohet (pra kulmi i ri qe u zbulua nga bredhja).
Te gjitha brinjet e grafit jane ose brinje te pemes ose brinje te kthimit pas. Nuk mund te kete
brinje qe kthehen tek ndonje kulm qe eshte vella. Pse?

Fig.6. Graf i paorientuar dhe pema e bredhjes ne thellesi e tij.


Ne figuren me lart, brinjet e paraqitura me vija te nderprera jane brinje te kthimit pas ne graf
ndersa te tjerat brinje te pemes.

4.2.1 Gjetja e cikleve ne graf


Nje nga aplikimet e bredhjes ne thellesi eshte gjetja e cikleve ne graf. Prania e brinjeve qe
lidhin nje kulm me nje nga paraardhesit e tij (ne bredhjen ne thellesi) tregon pranine e nje cikli
ne graf. Algoritmi qe realizon gjetjen e nje cikli qe krijohet sepse ndermjet kulmit x dhe kulmit
paraardhes te tij y ekziston nje brinje eshte:

B.Bimbari - 10 -
Algoritmik Grafet

gjej_cikel(int x, int y)
{
if (prindi[x] == y) { /* u gjet brinje e kthimit pas! */
printf("Cikel nga %d to %d:",y,x);
gjej_shteg(y,x,prindi);
printf("\n\n");
}
}

B.Bimbari - 11 -
Algoritmik Grafet

Programi C++ i implementimit t grafeve me lista fqinjsie


#include <iostream>
#include <conio.h>

using namespace std;

int const MAXK=10; /*konstante qe percakton numrin maksimal te


mundshem te kulmeve te grafit*/

struct brinje{
int w; /* variabel per te ruajtur kulmin fundor te brinjes */
int pesha; /* peshe e brinjes, nese ka */
brinje * pas; /* shenjues tek elementi tjeter i linjes, qe paraqet
brinjen pasardhese ne liste */
};

struct graf{
brinje * brinjet[MAXK]; /* tabela me listen e fqinjesise, MAXK
konstante qe tregon numrin maximal te kulmeve */
int nKulmesh; /* numri kulmeve te grafit */
int nBrinje; /* numri brinjeve te grafit */
bool orientuar; /* indikator, graf i orientuar? */
};

struct Rradhe{
int vl;
Rradhe * pas;
};

Rradhe * shto_ne_rradhe(Rradhe * r, int vl)


{
Rradhe * element;
Rradhe * tmp;
element = new Rradhe;
element->vl = vl;
element->pas = NULL;

if(r == NULL)
r = element;
else
{
tmp = r;

while(tmp->pas != NULL)
tmp = tmp->pas;

tmp->pas = element;
}

return r;
}

bool procesuar[MAXK+1]; /* kulmet qe jane procesuar*/


bool vizituar[MAXK+1]; /* kulmet qe jane zbuluar/vizituar*/
int prindi[MAXK+1]; /* kulmi tjeter i brinjes */

/*funksion qe inicializon nje graf bosh, me 0 kulme dhe 0 brinje*/


graf *inicializo_graf(graf * g, bool eshteIOrientuar)

B.Bimbari - 12 -
Algoritmik Grafet

{
g -> nKulmesh = 0;
g -> nBrinje = 0;
g -> orientuar = eshteIOrientuar;
for (int i=0; i<=MAXK; i++)
g-> brinjet[i] = NULL;

return g;
}

//funksion qe shton brinjen e re (v,w) ne grafin g, i cili merret si


parameter i funksionit
graf *shto_brinje (graf *g, int v, int w, bool eshteIOrientuar)
{
brinje * b;
b = new brinje;
//p->pesha = NULL; //nqs grafi nuk eshte me peshe, fusha pesha
plotesohet NULL, nese grafi eshte me peshe, vendoset pesha e brinjes
b->w = w;
b->pas = g->brinjet[v];
g-> brinjet[v] = b; /* brinja (v,w) shtohet ne fillim te listes
*/
if (eshteIOrientuar == false)
shto_brinje(g,w,v,true);
else
g->nBrinje ++;

return g;
}

/*funksion qe afishon grafin g*/


void afisho_graf(graf *g)
{
for(int i = 0; i < g->nKulmesh; i++)
{
brinje * b;
b = g->brinjet[i];
cout<<"\n"<<"fqinjet e kulmit "<<i<<": ";
while(b != NULL)
{
cout<<b->w<<" ";
b = b->pas;
}
}
cout<<"\n";
}

/*funksion qe inicializon tabelat qe perdoren nga


bredhjet e grafit. Ne fillim te bredhjeve te gjthe kulmet jane
te pavizituar dhe te paprocesuar.*/
void inicializo_bredhje(graf *g)
{
for (int i=0; i<g->nKulmesh; i++)
{
procesuar[i] = vizituar[i] = false;
prindi[i] = -1;
}
}

void bredhje_ne_gjeresi(graf *g, int kulmFillimi)


{

B.Bimbari - 13 -
Algoritmik Grafet

Rradhe * q; /* rradha me kulmet qe do te vizitohen */


q = NULL;
int v; /* kulmi korent */
int y; /* kulmi pasardhes */
brinje *p; /* shenjues i perkohshem */

q = shto_ne_rradhe(q,kulmFillimi);
vizituar[kulmFillimi] = true;

while (q != NULL)
{
Rradhe * fillim = q;
v = fillim->vl;
p = g->brinjet[v];

while (p != NULL)
{
y = p->w;
if (vizituar[y] == false)
{
q = shto_ne_rradhe(q,y);
vizituar[y] = true;
prindi[y] = v;
}
p = p->pas;
}
procesuar[v] = true;
fillim = fillim->pas;
q = fillim;
}
}

void gjej_shteg(int kFillim, int kFund, int prindi[])


{
if ((kFillim == kFund) || (kFund == -1))
cout<<kFillim<<"-";
else {
gjej_shteg (kFillim, prindi [kFund], prindi);
cout<<kFund<<"-";
}
}

void bredhje_ne_thellesi(graf * g, int kulmFillimi)


{
brinje *p; /*shenjues i perkohshem*/
int y; /*kulmi fqinj*/
int v = kulmFillimi;
vizituar[v]= true;
p = g->brinjet[v];
while (p!= NULL)
{
y = p->w;
if(vizituar[y] == false)
{
prindi[y] = v;
bredhje_ne_thellesi(g,y);
}
p = p->pas;
}

B.Bimbari - 14 -
Algoritmik Grafet

procesuar[v] = true;

int main()
{

graf g;
graf * pg;
pg = &g;

/*inicializohet grafi bosh*/


pg = inicializo_graf(pg, true);

int nKulme; int nBrinje;

/*lexohet nga tastiera numri i kulmeve dhe numri i brinjeve te


grafit*/
printf("Jepni numrin e kulmeve:", "\n");
cin>>nKulme;

printf("Jepni numrin e brinjeve:", "\n");


cin>>nBrinje;

pg->nKulmesh = nKulme;
pg->nBrinje = nBrinje;

cout<<"Jepni brinjet e grafit duke dhene kulmin e pare dhe


kulmin e dyte te grafit"<<"\n";
int v; int w;
for(int i =0; i < nBrinje; i++)
{
cin>>v;
cin>>w;
cout<<"\n";
if(v<nKulme && w<nBrinje)
pg = shto_brinje(pg, v, w, pg->orientuar);
else
{
cout<<"Brinja e dhene eshte e gabuar, rijepeni
ate"<<"\n";
i--;
}
}

afisho_graf(pg);

inicializo_bredhje(pg);
for (int i = 0; i < pg->nKulmesh; i++)
{
if(vizituar[i] == false)
bredhje_ne_gjeresi(pg, i);
}

cout<<"Tabela prindi pas bredhjes ne gjeresi eshte:"<<"\n";


for(int i = 0; i < pg->nKulmesh; i++)
cout <<prindi[i]<<", ";

cout<<"Jepni kulmet per te gjetur shtegun:"<<"\n";


int kFillim, kFund;
cin>>kFillim;

B.Bimbari - 15 -
Algoritmik Grafet

cin>>kFund;
gjej_shteg(kFillim, kFund, prindi);

inicializo_bredhje(pg);
for(int i = 0; i < pg->nKulmesh; i++)
{
if(vizituar[i] == false)
bredhje_ne_thellesi(pg,i);
}
cout<<"\n"<<"Tabela prindi pas bredhjes ne thellesi
eshte:"<<"\n";
for(int i = 0; i < pg->nKulmesh; i++)
cout <<prindi[i]<<", ";

getch();
return 0;
}

B.Bimbari - 16 -

You might also like