You are on page 1of 74

Structura de graf

a g a

b c
b c g h i

h i j k
d j d
k
e f
f e

5
a c a c
Graf orientat Graf ponderat
b 3 4 6

d e d b
2
Implementarea grafurilor
prin matrici de adiacenta
const int numarnoduri=10; typedef struct
typedef int tipcheie; {
typedef char tipinfo[10]; tipcontor contor;
typedef struct { tiptablouelem noduri;
tipcheie cheie; tipmatradj arce;
tipinfo info; } graf;
} tipelement; typedef struct
{
typedef enum {FALSE,TRUE} bool; tipindex linie,coloana;
typedef char tipcontor; } tiparc;
typedef unsigned char tipindex; graf g;
typedef tipelement tipcheie k,k1,k2;
tiptablouelem[numarnoduri]; tipelement e;
typedef bool tipmatradj tipindex indicnod;
[numarnoduri][numarnoduri]; tiparc indicarc;
int i,j;
Insertia unui nod - initial
Contor = 4

1 2 3 4
Noduri = [ a b c d ]

Arce = 1 2 3 4 a b
1 0 0 1 1
2 0 0 1 0
3 1 1 0 1 c d
4 1 0 1 0
Insertia unui nod - dupa
a b
e

Contor = 5 c d

1 2 3 4 5
Noduri = [ a b c d e ]

1 2 3 4 5
1 0 0 1 1 0
2 0 0 1 0 0
Arce = 3 1 1 0 1 0
4 1 0 1 0 0
5 0 0 0 0 0
Functia insernod
void insernod(graf * g,tipelement e)
{
tipindex i,j;
g->contor=g->contor+1;

// incrementeaz contor
g->noduri[g->contor]=e;
// introduce noul element n tabloul g.Noduri pe pozitia urmatoare
for(i=0;i<=g->contor;i++)
{ g->arce[i][g->contor]=FALSE;
g->arce[g->contor][i]=FALSE;
//poziioneaz linia i coloana corespunztoare
// elementuluidin matricea de adiacene cu FALSE
}
}
Suprimarea unui nod - dupa
Contor = 3
1 2 3
noduri = [ a c d ]

1 2 3
a b
1 0 1 1
Arce = 2 1 0 1
3 1 1 0 c d
Functia suprimnod
void suprimnod(graf *g,tipindex indicnod)
{
tipindex i;
indicnod--; // nodurile ncep de la zero !
g->noduri[indicnod]=g->noduri[g->contor];
//nlocuiete elementul din poziia IndicNod cu ultimul element din tablou
for(i=0;i<g->contor;i++)
{
g->arce[i][indicnod]=
g->arce[i][g->contor];
g->arce[indicnod][i]=
g->arce[g->contor][i];
}
// copiaza legaturile ultimului nod peste
nodul suprimat */
g->contor=g->contor-1;
// decrementeaz contor;
}
Insertia si suprimarea de arce
Contor = 4; IndicArc = (2,3)

1 2 3 4
Noduri = [ a b c d ]

Arce = 1 2 3 4
1 0 0 1 1
2 0 0 0 0
3 1 0 0 1
4 1 0 1 0
Functiile suprimarc si insertarc
void suprimarc(graf * g,tiparc indicarc)
{
indicarc.linie--; // tabloul ncepe de la 0 !
indicarc.coloana--;
g->arce[indicarc.linie][indicarc.coloana] =FALSE;
g->arce[indicarc.coloana][indicarc.linie] =FALSE;
// pune pe False elementul g.Arce[IndicArc.linie,IndicArc.coloana]
//respectiv g.Arce[IndicArc.coloana,IndicArc.linie]din matricea de adiacene;
}
void insertarc(graf * g,tiparc indicarc)
{
indicarc.linie--;
indicarc.coloana--;
g->arce[indicarc.linie][indicarc.coloana]=TRUE;
g->arce[indicarc.coloana][indicarc.linie]=TRUE;
//pune pe TRUE elementul g.Arce[IndicArc.linie,IndicArc.coloana]
//respectiv g.Arce[IndicArc.coloana,IndicArc.linie] din matricea de adiacene;
}
O varianta de implementare a
grafurilor utilizind matrici de adiacenta
#include <stdlib.h> typedef tipelement
#include <stdio.h> tiptablouelem[numarnoduri];
typedef boolean
#include <string.h>
tipmatradj[numarnoduri]
#include <conio.h> [numarnoduri];
const char numarnoduri=10;
typedef char tipcheie[10]; typedef struct {
typedef char tipinfo[10]; tipcontor contor;
typedef struct { tiptablouelem noduri;
tipcheie cheie; tipmatradj arce;
//info:tipinfo; } graf;

typedef struct {
} tipelement;
tipindex linie,coloana;
typedef enum {FALSE,TRUE}
} tiparc;
boolean;
typedef unsigned char
tipcontor;
typedef int tipindex;
Functia cautbin
graf g; int cautbin(tipcheie kt)
tipcheie k,k1,k2; {
int i,j,k;
tipelement e;
div_t dt;
tipindex indicnod;
i=0;j=g.contor-1;
tiparc indicarc; do
int nrnod,nrarc,i,j; {
dt=div(i+j,2);
void grafvid() k=dt.quot;
{ if (strcmp(kt,g.noduri[k].cheie)>0)
i=k+1; else j=k-1;
g.contor=0;
}
for(i=0;i<numarnoduri;i++)
while
for(j=0;j<numarnoduri;j++) ((strcmp(g.noduri[k].cheie,kt)!=0)&&
g.arce[i][j]=FALSE; (i<=j));
} if (strcmp(g.noduri[k].cheie,kt)==0)
return(k); else return(-1);
}
Functia insernod
void insernod(graf *g,tipelement e) for(j=g->contor-2;j>=s;j--)
{ {
tipindex i,j,k,s,d,m; for(k=0;k<g->contor-1;k++)
div_t dt;
g->contor=g->contor+1;
{
if (g->contor==1) g->arce[k][j+1]=g-
{ >arce[k][j];
g->noduri[g->contor-1]=e; g->arce[j+1][k]=g-
for(i=0;i<g->contor;i++) >arce[j][k];
g->arce[i][g->contor-1]=FALSE; }
for(j=0;j<g->contor;j++) g->noduri[j+1]=g->noduri[j];
g->arce[g->contor-1][j]=FALSE; }
} g->noduri[s]=e;
else
for(i=0;i<g->contor;i++) g-
{ >arce[i][s]=FALSE;
s=0;d=g->contor-2;
while (s<=d)
for(i=0;i<g->contor;i++) g-
>arce[s][j]=FALSE;
{
dt=div((s+d),2); }
m=dt.quot; }
if (strcmp(e.cheie,
g->noduri[m].cheie)<0)
d=m-1; else s=m+1;
}
Functia suprimnod si insertarc
void suprimnod(graf *g,tipcheie k)
{ tipindex i,j,indicnod;
indicnod=cautbin(k);
for(j=indicnod+1;j<=g->contor-1;j++)
{
g->noduri[j-1]=g->noduri[j];
for(i=0;i<=g->contor-1;i++)
g->arce[j-1][i]=g->arce[j][i];
for(i=0;i<=g->contor-1;i++)
g->arce[i][j-1]=g->arce[i][j];
}
g->contor=g->contor-1;
}

void insertarc(graf *g,tipcheie k1,tipcheie k2)


{
indicarc.linie=cautbin(k1);
indicarc.coloana=cautbin(k2);
g->arce[indicarc.linie][indicarc.coloana]=TRUE;
g->arce[indicarc.coloana][indicarc.linie]=TRUE;
}
Functia suprimarc si tiparire
void suprimarc(graf *g,tipcheie k1,tipcheie k2)
{
indicarc.linie=cautbin(k1); indicarc.coloana=cautbin(k2);
g->arce[indicarc.linie][indicarc.coloana]=FALSE;
g->arce[indicarc.coloana][indicarc.linie]= FALSE;
}

void tiparire()
{
printf(" ");
for(i=0;i<nrnod;i++) printf("%s ",g.noduri[i].cheie,' ');
printf("\n");
for(i=0;i<nrnod;i++)
{
printf("%s ",g.noduri[i].cheie," ");
for(j=0;j<nrnod;j++)
if (g.arce[i][j]) printf("1 ");
else printf("0 ");
printf("\n");
}
}
Programul principal
void main() tiparire();
{
printf("numarul de noduri si de printf("Introduceti nodul
arce\n"); de suprimat ");
printf("noduri=");scanf("%d",&nrnod); scanf("%s",&k);
printf("arce=");scanf("%d",&nrarc);
grafvid(); nrnod=nrnod-1;
for(i=0;i<nrnod;i++) suprimnod(&g,k);
{
printf("cheie pt. nodul %d =",i);
tiparire();
scanf("%s",&e.cheie); printf("Introduceti arcul
insernod(&g,e); de suprimat");
}
printf("legaturi intre noduri\n"); scanf("%s",&k1);
for(j=0;j<nrarc;j++) scanf("%s",&k2);
{
printf("nodstart=");scanf("%s",&k1);
suprimarc(&g,k1,k2);
printf("nodend=");scanf("%s",&k2); tiparire();
insertarc(&g,k1,k2); }
}
Implementarea grafurilor
prin structuride adiacenta
g
a null

b null

c
null

d null

a b
e null null
e

c d
Structurile de date
typedef struct _celulalistnod {
char data;
struct _celulalistnod *urm;
struct _celulalistarc *incep;
int marc; //boolean
}CELULALISTNOD;
typedef struct _celulalistarc {
struct _celulalistnod *nod;
struct _celulalistarc *urm;
int marcarb; //boolean
}CELULALISTARC;
typedef struct _arc{
struct _celulalistnod *nod1,*nod2;
}ARC;
typedef CELULALISTNOD * graf;
char ch1, ch2,ch;
graf gr;
CELULALISTNOD *p,*fanion; CELULALISTARC *q;
ARC arcul; int er; // boolean
Functiile creaza si adiacent
void creaza(graf *g)
{ fanion=(CELULALISTNOD *) malloc(sizeof(CELULALISTNOD));
fanion->urm=NULL; (*g)=fanion;
} //creaza graful vid
int adiacent(CELULALISTNOD *p, CELULALISTNOD *q)
{ int gata; CELULALISTARC *curent; curent=p->incep;
gata=false;
while (gata==false)
{
if (curent==NULL)
{ gata=true; return false; }
else
if (curent->nod==q)
{ gata=true; return true; }
else curent=curent->urm;
}
}
Functiile modifica, furnizeaza
si suprimacel
void modifica(char a, CELULALISTNOD **p)
{ (*p)->data=a; }
char furnizeaza(CELULALISTNOD *p)
{ return p->data; }
void suprimacel(CELULALISTNOD *n, CELULALISTARC **inceput)
{
CELULALISTARC *temp;
if ((*inceput)!=NULL)
if ((*inceput)->nod==n)
{
temp=(*inceput);
(*inceput)=(*inceput)->urm;
free(temp);
}
else suprimacel(n,&((*inceput)->urm));
}
Functiile stergelist si suprimnod
void stergelist(CELULALISTARC **inceput)
{ if ((*inceput)!=NULL) stergelist(&((*inceput)->urm));
free(*inceput); }
void suprimnod(CELULALISTNOD *p, graf *g)
{ CELULALISTNOD *nodcurent, *r;
nodcurent=(*g);
while (nodcurent!=fanion)
{
if (p!=nodcurent)
suprimacel(p,&(nodcurent->incep));
nodcurent=nodcurent->urm;
}
stergelist(&(p->incep));
r=p->urm; *p=*r;
if (r==fanion) fanion=p; // cazul n care nodul suprimat este ultimul nod
free(r);
}
Functiile insernod si inserarc
void insernod(CELULALISTNOD **p, graf *g)
{ (*p)=(CELULALISTNOD *) malloc(sizeof(CELULALISTNOD));
(*p)->urm=(*g);
(*p)->incep=NULL; (*g)=(*p);
}
void inserarc(ARC e, graf *g)
{ CELULALISTARC *temp;
if (!adiacent(e.nod1,e.nod2))
{
temp=e.nod1->incep;
e.nod1->incep=(CELULALISTARC *) malloc(sizeof(CELULALISTARC));
e.nod1->incep->nod=e.nod2; e.nod1->incep->urm=temp;
temp=e.nod2->incep;
e.nod2->incep=(CELULALISTARC *) malloc(sizeof(CELULALISTARC));
e.nod2->incep->nod=e.nod1; e.nod2->incep->urm=temp;
}
}
Functiile suprimarc si poz
void suprimarc(ARC e, graf *g)
{
if (adiacent(e.nod1,e.nod2))
{
suprimacel(e.nod2,&(e.nod1->incep));
suprimacel(e.nod1,&(e.nod2->incep));
}
}
CELULALISTNOD *poz(char ch, graf g)
{CELULALISTNOD *p;
int gasit;
p=g;
gasit=false;
while ((p!=fanion) && (!gasit))
if (p->data==ch) gasit=true; else p=p->urm;
return p;
}
Functia tiparire
void tiparire(graf g)
{
p=g;
while (p!=fanion)
{
printf("%c ",p->data);
q=p->incep;
while (q!=NULL)
{
printf("%c ",q->nod->data);
q=q->urm;
}
p=p->urm;
printf("\n");
}
}
Programul principal (1)
void main() // programul principal
{
creaza(&gr);
printf("nodurile :");
fflush(stdin); scanf("%c",&ch);
do
{
insernod(&p,&gr);
modifica(ch,&p);
fflush(stdin); scanf("%c",&ch);
}while (ch!='0');
printf("legaturile :");
fflush(stdin); scanf("%c",&ch1);
fflush(stdin); scanf("%c",&ch2);
Programul principal (2)
do
{ arcul.nod1=poz(ch1,gr); arcul.nod2=poz(ch2,gr);
inserarc(arcul,&gr);
fflush(stdin); scanf("%c",&ch1);
fflush(stdin); scanf("%c",&ch2);
} while (ch1!='0');
tiparire(gr);
printf("dati arcul de suprimat");
fflush(stdin); scanf("%c",&ch1); fflush(stdin); scanf("%c",&ch2);
arcul.nod1=poz(ch1,gr); arcul.nod2=poz(ch2,gr);
suprimarc(arcul, &gr);
tiparire(gr);
printf("dati nodul de suprimat");
fflush(stdin); scanf("%c",&ch);
p=poz(ch,gr);
suprimnod(p,&gr);
tiparire(gr);
}
Traversarea grafurilor
prin cautare in adancime CA
PROCEDURE CautaInAdincime (x:Nod);
VAR y:Nod;
BEGIN
marc[x] := vizitat;
FOR fiecare nod y adiacent lui x DO
IF marc[y]= nevizitat THEN CautaInAdincime(y);
END;
typedef struct _celulalistnod
{ char data;
struct _celulalistnod *urm;
struct _celulalistarc *incep;
int marc; // cmp suplimentar pt. cutare
}CELULALISTNOD;
typedef struct _celulalistarc
{ struct _celulalistnod *nod;
struct _celulalistarc *urm;
int marcarb; // cmp suplimentar pt. cutare
}CELULALISTARC;
Cautarea in adincime (1)
void constructieCA g
(CELULALISTNOD *p) a null
{
CELULALISTARC *arccurent; b null
CELULALISTNOD *q;
printf("%c\n",p->data); c
null
p->marc=true; arccurent=p->incep;
while (arccurent!=NULL) d null
{
q=arccurent->nod; e null null
if (!q->marc)
{
arccurent->marcarb=true;
printf("Arc intre %c si %c\n,p->data,q->data);
constructieCA(q);
}
arccurent=arccurent->urm;
}
}
Cautarea in adincime (2)
void arboredeacoperireCA(graf g) p=g;
{ s=1; // numerotare componente conexe
CELULALISTNOD *p; while (p!=NULL)
CELULALISTARC *e; {
int s; p=g; if (!p->marc)
while (p!=NULL) {
// iniializarea cu false a cmpurilor printf("Componenta conexa
//marc i marcarb %d\n",s);
{ constructieCA(p);
p->marc=false; s++;
e=p->incep; printf("\n");
while (e!=NULL) getch();
{ }
e->marcarb=false; p=p->urm;
e=e->urm; }
} }
p=p->urm;
}
Traversarea grafurilor
prin cautare prin cuprindere CC
void initializare(COADA *c) void adauga(CELULALISTNOD *x,
{ (*c).fatza=(NODC *) COADA *c)
malloc(sizeof(NODC)); {
(*c).fatza->urm=NULL; (*c).spate->urm=
(*c).spate=(*c).fatza; (NODC *)malloc(sizeof(NODC));
} (*c).spate=(*c).spate->urm;
int vid(COADA c) (*c).spate->element=x;
{ if ((c.fatza)==(c.spate)) (*c).spate->urm=NULL;
return true; else return false; }
} void scoate(COADA *c)
CELULALISTNOD *fatza(COADA c) {
{ if (vid(*c))
if (vid(c)) {
{ er=true; er=true;printf("Coada este
printf("Coada este vida\n"); vida\n");
} }
else else (*c).fatza=(*c).fatza->urm;
return (c.fatza->urm->element); }
}
Traversarea prin cuprindere (1)
void arboredeacoperireCC(graf g)
{ COADA c; //de pozitii
CELULALISTNOD *m,*n; CELULALISTARC *e,*arccurent; int s;
n=g;
while (n!=NULL)
{n->marc=false;
e=n->incep;
while (e!=NULL)
{
e->marcarb=false;
e=e->urm;
}
n=n->urm;
}
n=g;
s=0;
Traversarea prin cuprindere (2)
while (n!=fanion)
{
initializare(&c);
adauga(n,&c);
if (!n->marc)
{
n->marc=true;
s++;
printf("COMPONENTA CONEXA
%d\n", s);
// marcare componente conexe
}
Traversarea prin cuprindere (3)
g
while (!vid(c))
a null
{ n=fatza(c); scoate(&c);
arccurent=n->incep;
b null
if (n->incep==NULL)
printf("%c\n",n->data);
while (arccurent!=NULL) c
null
{
m=arccurent->nod; d null

if (!m->marc)
{ e null null
adauga(m,&c);
arccurent->marcarb=true;
m->marc=true;
printf("arc intre %c si %c\n",n->data,arccurent->nod->data);
}
arccurent=arccurent->urm;
}
} n=n->urm;
} // arboredeacoperireCC
Grafuri ponderate
Arborele de acoperire minim

6 1 5 1
2 5 1 5 4 2 5 1 4
3 3
2
3 6 4 2 3 4
5 6 5 6
6
Determinarea arborelui de acoperire
minim utilizind algoritmul lui Prim
FUNCTION PRIM (g:graf; VAR t:multime_de_arce);
VAR U:multime_de_noduri; u,v:nod;
BEGIN
t:=multimea_vida; U:=primul_nod;
WHILE U<>N DO
BEGIN
fie (u,v) arcul cu costul cel mai mic
care satisface conditia u U si v (N-U);
t:=t + (u,v);
U:= U + v;
V:= V - v;
END
END;
Conventii utilizate
daca arcul (i,j) nu exista, cost[i,j] are o valoare mare, specifica, mai mare
decit orice cost posibil, dar mai mic dect valoarea infinit utilizat n
cadrul algoritmului
apropiat - tablou continind pe pozitia i nodul din U cel mai apropiat in
momentul curent de nodul i din N-U
costmin - tablou continind costul arcului ( i, apropiat[i] )
ori de cite ori se gaseste un nod k pentru a fi introdus in arborele de
acoperire (multimea U), se face costmin[k] egal cu infinit
(o valoare foarte mare, mai mare decit cea de la initializarea arcelor
inexistente), astfel incit acel nod sa nu mai poata fi selectat in continuare
si inclus in U. Deci, valoarea infinit este mai mare decit costul oricarui arc
al grafului, sau decit costul asociat lipsei arcului.
Algoritmul lui Prim (1)
typedef int tipmatrcost[numarnoduri][numarnoduri];
typedef struct _graf
{ tipcontor contor;
tiptablouelem noduri;
tipmatradj arce;
//se poate renuna eventual, utilizndus-a matricea cost
tipmatrcost cost; // se adaug costul arcelor
} graf;

void prim(graf * g)
{
int costmin[numarnoduri];
tipindex apropiat[numarnoduri];
int min;
for(i=1;i<=g->contor;i++)
{ costmin[i]=g->cost[0][i];
apropiat[i]=0;
}
Algoritmul lui Prim (2)
for (i=1;i<=g->contor;i++)
{
k=1;min=costmin[1];
for(int j=2;j<=g->contor;j++)
if (costmin[j]<min)
{ min=costmin[j];
k=j;
}
printf(" arc %d si %d de cost %d\n",apropiat[k]+1,k+1,
g->cost[apropiat[k]][k]);
costmin[k]=infinit;
for(j=1;j<=g->contor;j++)
if ((g->cost[k][j]<costmin[j]) && (costmin[j]<infinit))
{
costmin[j]=g->cost[k][j];
apropiat[j]=k;
}
}
} //prim
Determinarea
arborelui de acoperire minim utiliznd
cutarea bazat pe prioritate (1)
se bazeaza pe utilizarea unei cozi cu prioritate
utilizeaz proceduri specifice : init_coadap, extrage_coadap
respectiv adauga_coadap
coada este implementat cu ajutorul unei liste simplu nlnuite, cu dou
noduri fictive (primul i ultimul - fanion)
funcia adauga_coadap verific dac nodul precizat apare n coada
bazat pe prioritate, cu o prioritate cel puin egal cu cea precizat ca
parametru. Dac nodul nu apare n coad, el este inserat n poziia
corespunztoare prioritii sale; dac nodul apare n coad, ns are un
cost mai mare dect cel precizat (prioritate mai mica) => introducerea
nodului cu noua prioritate
dac se produce vreo modificare n cadrul cozii (inserie sau modificare
prioritate), adauga_coadap returneaz valoarea true; n caz contrar
returneaza false => tablourile marc i parinte.
Determinarea
arborelui de acoperire minim utiliznd
cutarea bazat pe prioritate (2)
typedef struct _nodc
{ char element;
int prioritate;
struct _nodc *urm;
}NODC;

typedef struct {
NODC *fatza,*spate;
}COADA;

void init_coadap(COADA *c)


{ (*c).fatza=(NODC *)malloc(sizeof(NODC)); //noduri fictive
(*c).spate=(NODC *)malloc(sizeof(NODC));
(*c).fatza->urm=(*c).spate;
(*c).spate->urm=NULL;
}
Implementarea
cozii cu prioritate (1)
int vid_coadap(COADA c)
{
if (c.fatza->urm==c.spate) return true; else return false;
}
char fatza_coadap(COADA c)
{
if (vid_coadap(c))
{ er=true; printf("Coada este vida"); }
else return c.fatza->urm->element;
}
void afis_coadap(COADA c)
{
NODC *p; p=c.fatza->urm; printf("Coadap: \n");
while (p!=c.spate)
{
printf("%c(%d) ",p->element,p->prioritate); p=p->urm;
}
printf("\n");
}
Implementarea
cozii cu prioritate (2)
int adauga_coadap(COADA *c, CELULALISTNOD *nod,int p)
{ NODC *q, *q1, *q2;
int gasit; gasit=false; q=(*c).fatza->urm;
(*c).spate->element=nod->data; (*c).spate->prioritate=p;
while (q->element!=nod->data) q=q->urm;
if (q!=(*c).spate) //nodul este gasit
if (q->prioritate>p) //se verifica prioritatea
{
q1=q->urm;
(*q)=(*q1);
if (q1==(*c).spate) (*c).spate=q;
free(q1); //stergere nod din coada
}
else
{
gasit=true;
return false;
}
Implementarea
cozii cu prioritate (3)
if (!gasit)
{ //prioritate maxima cost minim
q=(*c).fatza->urm;
while (q->prioritate<p) q=q->urm;
q1=(NODC *)malloc(sizeof(NODC));
(*q1)=(*q); //insertie inaintea lui q
if (q==(*c).spate) (*c).spate=q1;
q->urm=q1; q->element=nod->data; q->prioritate=p;
return true;
}
}
CELULALISTNOD *extrage_coadap(COADA *c)
{
CELULALISTNOD *pozitie;
if (vid_coadap(*c)) printf("Coada este vida");
else
{ pozitie=poz((*c).fatza->urm->element,gr); (*c).fatza=(*c).fatza->urm; }
return pozitie;
}
Algoritmul cautarii
bazate pe prioritate - structuri de
adiacenta (1)
utilizeaz o coad bazat pe prioritate n cadrul creia sunt introduse, pe
rnd, toate nodurile adiacente nodului curent, funcie de prioritatea
acestora (cost mic, prioritate mare)
rnd pe rnd, aceste noduri sunt extrase din coada cu prioritate, (avnd n
vedere c nodul cu prioritate maxim, deci cost minim, va fi ntotdeauna
primul), actualizndu-se n consecin tablourile marc i parinte =>
pentru fiecare nod k care a fost deja vizitat, urmtorul nod selectat pe
baza cozii cu prioritate, reprezint printele nodului curent, i se va
memora n parinte[k], iar costul arcului care care l leag pe k de
nodul selectat din coad se memoreaz n marc[k]
nodurile care au fost deja vizitate sunt marcate cu valori negative n
tabloul marc, iar nodurile nc nevizitate sunt marcate cu o valoare
specific, -nevazut, i nu cu zero.
Algoritmul cautarii
bazate pe prioritate - structuri de
adiacenta (2)
void arbore_minim(void) //determinarea arborelui de acoperire minim
{
int id=0;
CELULALISTNOD *k;
init_coadap(&c);
p=gr;
while (p!=fanion)
{
p->marc=-nevazut;
p=p->urm;
}
p=gr;
while (p!=fanion)
{
if (p->marc==-nevazut) caut_prioritar(p,&id);
p=p->urm;
}
}
Algoritmul cautarii
bazate pe prioritate - structuri de
adiacenta (3)
void caut_prioritar(CELULALISTNOD *k,int *id)
{
CELULALISTARC *t;
if (adauga_coadap(&c,k,nevazut)) k->parinte='0';
do
{id++; k=extrage_coadap(&c); k->marc=-k->marc;
if (k->marc==nevazut) k->marc=0;
t=k->incep;
while (t!=NULL)
{ if (t->nod->marc<0)
if (adauga_coadap(&c,t->nod,t->cost))
{ t->nod->marc=-t->cost; t->nod->parinte=k->data; }
t=t->urm;
}
afis_coadap(c);getch();
}
while (!vid_coadap(c));
}
Algoritmul cautarii bazate pe prioritate -
structuri de adiacenta (4)
void tip_arbore_minim()
//tiparirea arborelui de acoperire minim in reprezentarea indicator spre parinte
{
p=gr;
printf("Arborele de acoperire minim este:\n");
while (p!=fanion)
{
printf("%c---%c cost %d \n",p->data, p->parinte,abs(p->marc));
p=p->urm;
}
}
nod parinte cost Continutul cozii cu prioritate:
6 0 0
5 2 3 4 (2) 3 (4) 5 (6)
3 (4) 1 (5) 5 (6)
4 6 2 1 (1) 2 (5) 5 (6)
3 6 4 2 (5) 5 (6)
2 3 5 5 (3)
1 3 1
Algoritmul cautarii bazate pe
prioritate matrici de adiacenta (1)
pentru implementarea cozii bazate pe prioritate se poate utiliza un tablou
neordonat marc, iar operaiile definite special pentru structura de coad
pot fi implementate, n acest caz, direct n cadrul algoritmului. Ca i n cazul
anterior, semnul unui element aparinnd tabloului precizeaz dac acesta a
fost deja selectat n arborele de acoperire minim (vizitat = semnul +) sau
este nc n coada bazat pe prioritate (vecintate = semnul -).
iniial, toate nodurile aparin categoriei nevizitate i n consecin ele sunt
plasate cu valoarea -nevazut n tabloul marc. Pentru a modifica prioritatea
unui nod, se introduce pur i simplu noua prioritate n tabloul marc. Pentru
a extrage nodul cu cea mai mare prioritate, se baleeaz tabloul marc i se
caut poziia care memoreaz cea mai mic valoare negativ. Nodul n cauz
se extrage din coada bazat pe prioritate (schimbarea semnului) i se
introduce n arborele de acoperire minim, prin completarea
corespunztoare a tabloului parinte (parinte[t]:=k).
Algoritmul cautarii bazate pe
prioritate matrici de adiacenta (2)
void caut_prioritar(graf *g) do
{ {
int parinte[numarnoduri+1]; k=min;marc[k]=-marc[k];min=0;
int k,min,t; if (marc[k]==nevazut)marc[k]=0;
int prioritate; for (t=1;t<=g->contor;t++)
for (k=1;k<=g->contor;k++) if (marc[t]<0)
{ {
marc[k]=-nevazut; parinte[k]=0; prioritate=g->cost[k][t];
} if ((g->cost[k][t]!=0)
marc[0]=-(nevazut+1); min=1; && marc[t]<-prioritate))
________________________________ {
marc[t]=-prioritate;
/* afisare tablou parinte */ parinte[t]=k;
for (k=1;k<=g->contor;k++) }
printf("%d %d %d\n",k, if (marc[t]>marc[min])
parinte[k], min=t;
g->cost[k][parinte[k]]); }
} /* cautprioritar */ }while (min!=0);
Grafuri orientate
sunt grafuri n care arcurile care conecteaz nodurile au un singur sens.
sunt simple restricii ale grafurilor neorientate; este ns posibil ca ntre
dou noduri s existe dou arce avnd sensuri opuse.
n cazul reprezentrii prin matrici de adiacen, arcul de la nodul x la nodul
y se va marca o singur dat, prin valoarea true a elementului matricii din
linia x coloana y, dar nu i a elementului din linia y coloana x, matricea
fiind n acest caz ne-simetric
n reprezentarea bazat pe liste de adiacen, arcul de la x la y este
reprezentat prin inseria nodului y n lista de adiacene a nodului x
grafurile orientate pot fi la rndul lor i ponderate, n cazul n care fiecrui
arc i se asociaz un cost.
Grafuri orientate si ponderate

10 1 100
30 5
2
50 10 60
3 4
20
O problem des abordat n contextul grafurilor orientate i ponderate o
reprezint determinarea drumurilor minime cu origine unic: adic de a
determina costurile celui mai scurt drum de la un anumit nod de origine la
toate celelalte noduri ale grafului. Un caz particular al problemei
anterioare o reprezint determinarea drumului cel mai scurt ntre dou
noduri precizate dintr-un graf.
Algoritmul lui Dijkstra - concepte
algoritmul se bazeaz pe o structur de date de mulime M, n care se
pstreaz nodurile pentru care cea mai scurt distan la nodul origine
este deja cunoscut. Iniial, M conine numai nodul origine; la fiecare pas
se adaug nc un nod, care nu aparine lui M i a crui distan de la
origine este ct mai scurt posibil
dac se consider c toate arcele au ponderi pozitive, exist ntotdeauna
un drum minim, numit drum special, care leag originea de nodul x, i
care trece numai prin nodurile coninute de mulimea M
pentru nregistrarea lungimii drumurilor speciale corespunztoare tuturor
nodurilor grafului se utilizeaz tabloul d, care este actualizat la fiecare pas
in final, costurile tuturor drumurilor speciale, ctre toate nodurile grafului,
vor fi coninute n tabloul auxiliar costmin
Algoritmul lui Dijkstra - principiu
procedure Dijkstra;
begin
M:=[1];
for i:=2 to numar_noduri do {iniializare d}
begin
d[i]:=cost[1,i]; costmin[i]:=cost[1,i];
end;
for i:=1 to numar_noduri-1 do
begin
alege un nod x aparinnd mulimii N-M astfel nct d[x] minim;
adaug pe x lui M;
for fiecare nod y al lui N-M do
begin
d[y]:=min(d[y],d[x]+cost[x,y]); parinte[y]:=x;
actualizeaz tabloul costmin;
end
end;
end;
Algoritmul lui Dijkstra - rezultate
arborele de acoperire minim rezultat n urma algoritmului va fi memorat
n tabloul parinte, n reprezentarea indicator spre printe
acesta se iniializeaz la nceput cu parinte[i]=1 pentru toate valorile lui
i<>1; pentru a gsi drumul minim de la nodul origine la un alt nod al
grafului, se poate merge n sens invers mergnd pe nlnuirile indicate de
tabloul parinte
costul drumului minim de la origine la nodul i va fi coninut n tabloul
costmin, respectiv costmin[i].
observatie: trebuie precizat c n tabloul cost, care conine costurile
arcurilor grafului, n cazul n care arcul (i,j) nu exist, se va iniializa
cost[i,j]=infinit (o valoare foarte mare, mai mare dect orice cost)
Algoritmul lui Dijkstra (1)
void dijkstra(graf *g) for(i=0;i<=g->contor;i++)
{ {
int d[numarnoduri]; x=1;minim=d[1];
int costmin[numarnoduri]; for(j=2;j<=g->contor;j++)
int m[numarnoduri]; if ((d[j]<minim) && (m[j]==false))
int parinte[numarnoduri]; { minim=d[j]; x=j; }
int i,x,minim; m[x]=true;
for(i=0;i<=g->contor;i++) for(j=0;j<=g->contor;j++)
m[i]=false; if (m[j]==false)
m[0]=true; if (d[x]+g->cost[x][j]<d[j])
for(i=1;i<=g->contor;i++) {
{ d[j]=d[x]+g->cost[x][j];
d[i]=g->cost[0][i]; parinte[j]=x;
costmin[i]=g->cost[0][i]; costmin[j]=d[j];
} }
for(i=1;i<=g->contor;i++) d[x]=maxv;
parinte[i]=0;parinte[0]=-1;
Algoritmul lui Dijkstra (2)
printf("Matricea M: ");
for(j=0;j<=g->contor;j++)
if (m[j]==true) printf(" %d",j);
printf("\n");
printf("Tabloul d: ");
for(j=1;j<=g->contor;j++)
printf(" %d",d[j]);
printf("\n");
printf("Tabloul parinte: ");
for(j=0;j<=g->contor;j++)
printf(" %d",parinte[j]);
printf("\n");
printf("Tabloul costmin: ");
for(j=0;j<=g->contor;j++)
printf(" %d",costmin[j]); printf("\n");
}
}
Evolutia algoritmului
1 2 3 4 5
d: - 10 infinit 30 100
m={1,2} d: - maxv 60 30 100
m={1,2,4} d: - maxv 50 maxv 90
m={1,2,3,4} d: - maxv maxv maxv 60
m={1,2,3,4,5} d: - maxv maxv maxv maxv

1 2 3 4 5
Parinte: 0 1 4 1 3

Costmin: 0 10 50 30 60

Arborele de acoperire minim: (1,2), (1,4), (4,3), (3,5)


Algoritmul lui Floyd concepte (1)
utilizeaz o matrice a de dimensiuni NumarnodurixNumarnoduri, unde
memoreaz lungimile drumurilor minime
iniial, a[i,j]:=cost[i,j], pentru i<>j; dac nu exist arc de la i la j,
cost[i,j]:=infinit; elementele diagonalei principale n matricea a se
iniializeaz la zero.
algoritmul execut numarnoduri iteraii asupra matricii a, rezultind pe rind
matricile a1, a2, ..., anumarnoduri. Dup cea de-a k-a iteraie, a[i,j] va conine
lungimea minim a oricrui drum de la i la j, care nu trece prin nici un nod
cu numr mai mare dect k, notat cu ak[i,j]
Algoritmul lui Floyd concepte (2)
astfel, pentru calcului lui ak[i,j] se compar ak-1[i,j], adic costul drumului
de la i la j fr a trece prin nodul k, i nici printr-un alt nod cu numr mai
mare dect k, cu ak-1[i,k]+ ak-1[k,j], adic costul drumului de la i la k nsumat
cu costul drumului de la k la j, fr a trece prin nici un nod cu numr mai
mare dect k; dac acesta din urm se dovedete a fi mai scurt, atunci
costul acestuia se atribuie lui ak[i,j], altfel, acesta rmne neschimbat

k
ak-1[i,k] ak-1[k,j]

i j
ak[i,j]
Identificarea traseului
pe lng determinarea costurilor drumurilor minime prin intermediul
functiei traseu se determin i traseul acestora, utiliznd n acest scop o
alt matrice, numit drum, n cadrul creia drum[i,j] memoreaz acel nod
k care conduce la cea mai mic valoare a[i,j];
dac drum[i,j]=0 nseamn c exist un drum direct ntre nodul i i j, care
este i cel mai scurt
void traseu(int i,int j) //afiseaza traseul de la nodul i la nodul j
{ int k;
k=drum[i][j];
if (k!=0)
{
traseu(i,k);
printf("%d ",k);
traseu(k,j);
}
}
Algoritmul lui Floyd (1)
void floyd(graf *g) for (k=0;k<=g->contor;k++)
{ {
for (i=0;i<=g->contor;i++) for (i=0;i<=g->contor;i++)
for (j=0;j<=g->contor;j++) for (j=0;j<=g->contor;j++)
{ a[i][j]=g->cost[i][j]; if (a[i][k]+a[k][j]<a[i][j])
drum[i][j]=0; } { a[i][j]=a[i][k]+a[k][j];
for (i=0;i<=g->contor;i++) drum[i][j]=k; }
a[i][i]=0; printf("matricea a%d:",k);
printf("matricea a0:"); for (i=0;i<=g->contor;i++)
for (i=0;i<=g->contor;i++) {
{ for (j=0;j<=g->contor;j++)
for (j=0;j<=g->contor;j++) if (a[i][j]!=maxint-1)
if (a[i][j]!=maxint-1) printf("\t%d ",a[i][j])
printf("\t%d ",a[i][j]); else printf("\t**");
else printf("\t**"); printf("\n");
printf("\n"); }
} getch();
getch(); }
Algoritmul lui Floyd (2)
printf("Traseu de la nodul 0 prin nodurile:");
traseu(0,g->contor);
printf("catre nodul 4");
printf("matricea drum:");
for (i=0;i<=g->contor;i++)
{
for (j=0;j<=g->contor;j++)
printf("%d ",drum[i][j]);
printf("\n");
}
}
Rezultatul algoritmului
matricea ai (1)
a0: 0 10 xx 30 100
xx 0 50 xx xx
xx xx 0 xx 10
xx xx 20 0 60 10 1 100
xx xx xx xx 0
30 5
2
a1: 0 10 xx 30 100
xx 0 50 xx xx
50 10 60
xx xx 0 xx 10
xx xx 20 0 60 3 4
xx xx xx xx 0 20
a2: 0 10 60 30 100
xx 0 50 xx xx
xx xx 0 xx 10
xx xx 20 0 60
xx xx xx xx 0
Rezultatul algoritmului
matricea ai (2)
a3: 0 10 60 30 70
xx 0 50 xx 60
xx xx 0 xx 10
xx xx 20 0 30 10 1 100
xx xx xx xx 0
30 5
2
a4: 0 10 50 30 60
xx 0 50 xx 60
50 10 60
xx xx 0 xx 10
xx xx 20 0 30 3 4
xx xx xx xx 0 20
a5: 0 10 50 30 60
xx 0 50 xx 60
xx xx 0 xx 10
xx xx 20 0 30
xx xx xx xx 0
Rezultatul algoritmului
matricea drum
drum: 0 0 4 0 4
0 0 0 0 3
0 0 0 0 0
0 0 0 0 3
0 0 0 0 0

10 1 100
30 5
2
50 10 60
3 4
20
Inchiderea tranzitiv
Algoritmul lui Warshall concepte (1)
o problem care se pune n cazul grafurilor orientate este aceea de a
determina dac exist un drum ntre dou noduri date
o modalitate de a rezolva aceast problem o reprezint determinarea
nchiderii tranzitive a grafului orientat iniial, un graf la care se ajunge din
graful iniial, prin adugarea de arce suplimentare dup urmtorul
principiu: dac n graful orientat iniial se poate ajunge, ntr-un mod
oarecare, nu neprat direct, de la nodul x la nodul y, atunci se adaug
grafului arcul (x,y)
graful obinut prin adugarea de arce de aceast natur, se numeste
nchiderea tranzitiv a grafului iniial
deoarece, prin metoda de mai sus, este de ateptat s fie adugate un
numr mare de arce, deci graful de nchidere tranzitiv obinut s fie un
graf dens, cea mai potrivit metod de reprezentare n acest caz este cea
bazat pe matrice de adiacen
Inchiderea tranzitiv
Algoritmul lui Warshall - concepte
din algoritmul lui Floyd se poate obine un algoritm care s determine
nchiderea tranzitiv a unui graf => dac exist o modalitate de a ajunge
de la nodul i la nodul k, precum i o modalitate de a ajunge de la nodul k la
nodul j, atunci, n mod sigur exist un drum care conecteaz nodul i cu
nodul j
construirea matricii T astfel nct calculul s se realizeze ct mai puine
treceri prin matricea de adiacene iniial: dac exist o posibilitate de a
ajunge de la nodul i la nodul k, utiliznd numai noduri cu indici mai mici
dect k, precum i o posibilitate de a ajunge de la nodul k la nodul j, atunci
exist un drum de la nodul i la nodul j care trece numai prin noduri cu
indici mai mici dect k. In cadrul algoritmului, bucla exterioar (contor k),
realizeaz nrnod parcurgeri ale matricii T iniiale, de fiecare dat
actualiznd, pe baza celor menionate mai sus, valorile T[i,j].
Algoritmul lui Warshall (1)
#define FALSE 0
#define TRUE 0
void Warshall(graf *g)
{
int i,j,k;
int t[numarnoduri][numarnoduri]; matricea n care se memoreaz nchiderea tranzitiv
for (i=0;i<=g->contor;i++)
for (j=0;j<=g->contor;j++)
if (g->arce[i][j]==FALSE) t[i][j]=0; else t[i][j]=1;
for (k=0;k<=g->contor;k++)
for (i=0;i<=g->contor;i++)
for (j=0;j<=g->contor;j++)
if (t[i][j]==0) t[i][j]=(t[i][k] && t[k][j]);
for (i=0;i<=g->contor;i++)
for (j=0;j<=g->contor;j++)
if (t[i][j]==0) g->arce[i][j]=FALSE; else g->arce[i][j]=TRUE;
}
Algoritmul lui Warshall (2)
void inchidere_tranzitiva(graf *g)
{
for (i=0;i<=g->contor;i++)
{
for (j=0;j<=g->contor;j++)
printf("%d ",g->arce[i][j]);
printf("\n\n");
} // matricea iniial
Warshall(g);
for (i=0;i<=g->contor;i++)
{
for (j=0;j<=g->contor;j++)
printf("%d ",g->arce[i][j]);
printf("\n");
} // matricea final
}
Rezultatul algoritmului
A B C D E F G
_____________________________________________________________________________________________________________________________________________________________________

A T T T T F F F
B T T T T F F F
C T T T T F F F
D T T T T F F F
E T T T T F F F
F T T T T T F F
G T T T T T T F

a c e
g

b d f
Traversarea grafurilor orientate -
concepte
tehnicile de traversare a grafurilor, prezentate n capitolele anterioare, au
un caracter universal i pot fi aplicate n cazul oricrui tip de graf, ns
innd cont de particularitile specifice fiecruia => graf orientat => acest
lucru de reflect n structura arborilor de acoperire rezultai, a
componentelor conexe rezultate, etc.

procedure CautInAdincime(x:Nod);
var k:Nod;
begin
marc[x]:=vizitat;
for fiecare nod k adiacent lui x do
if marc[k]=nevizitat then CautInAdincime(k);
end;
Traversarea grafurilor orientate (1)
void cauta_in_adincime(int i)
{
int j;
marc[i]=vazut;
printf("Nodul %d",i);
for (j=0;j<=g.contor;j++)
if ((g.arce[i][j]==TRUE) && (marc[j]==nevazut))
{
printf("arc de la %d la %d\n",i,j);
/* marcarea arcelor arborelui de acoperire} */
cauta_in_adincime(j);
}
printf("arc de revenire de la %d\n",i);
}
Traversarea grafurilor orientate (2)
void traversare()
{
int conex=1;
/* determinarea numarului componentelor conexe */
for (i=0;i<=g.contor;i++) marc[i]=nevazut;
for (i=0;i<=g.contor;i++)
{
if (marc[i]==nevazut)
{
printf("\nComponenta conexa
%d\n",conex);
conex++;
cauta_in_adincime(i);
}
}
}
Rezultatul algoritmului (1)
numrul de componente conexe obinute depinde de nodul de pornire
ales: dac se realizeaz corespondena: A=1, B=2, C=3, D=4, E=5, F=6, G=7
atunci va rezulta c graful este compus din 2 componente conexe (A, B, C,
D) i respectiv (E, F, G). Arborele de acoperire corespunztor cuprinde
arcele (A-B), (B,C), si (B,D) pentru prima component conex i respectiv
din arcele (E,F) si (E,G) pentru cea de-a doua component conex. D

a c e
g

b d f
Rezultatul algoritmului (2)
daca ns se alege nodul G pe post de nod de pornire, atunci tot graful
conine o singur component conex
diferena se reflect i n topologia arborilor de acoperire care rezult n
urma unor astfel de parcurgeri

a c e
g

b d f

You might also like