Ministerul Educaţiei al Republicii Moldova
Universitatea Tehnică a Moldovei
RAPORT
Lucrare de laborator nr.2
la Matematica Discreta
Tema: Păstrarea grafurilor în memoria calculatorului.
Algoritmul de cautare in [Link] de cautare in latime
A elaborat:
st. gr. CR-182 Maradri I.
A verificat:
lector superior Andrievschi-Bagrin V.
Chisinau 2019
Structuri de date - arbori
Se va defini o mulţime de structuri fiecare din care va consta dintr-un obiect de bază numit vârf sau
rădăcina arborelui dat şi o listă de elemente din mulţimea definită, care (elementele) se vor numi
subarbori ai arborelui dat. Arborele pentru care lista subarborilor este vidă se va numi arbore trivial, iar
rădăcina lui - frunză.
Rădăcina arborelui se va numi tatăl vârfurilor care servesc drept rădăcini pentru subarbori; aceste vârfuri
se vor mai numi copiii rădăcinii arborelui: rădăcina primului subarbore se va numi fiul cel mai mare, iar
rădăcina fiecărui subarbore următor în listă se va numi frate.
Operaţiile de bază pentru arbori vor fi:
• Formarea unui arbore trivial;
• Alegerea sau înlocuirea rădăcinii arborelui;
• Alegerea sau înlocuirea listei rădăcinilor subarborilor;
• Operaţiile de bază care sunt valabile pentru liste.
Algoritmul de căutare în lărgime
Parcurgerea grafului în lărgime, ca şi parcurgerea în adâncime, va garanta vizitarea fiecărui vârf al
grafului exact o singură dată, însă principiul va fi altul. După vizitarea vârfului iniţial, de la care va începe
căutarea în lărgime, vor fi vizitate toate vârfurile adiacente cu vârful dat, apoi toate vârfurile adiacente cu
aceste ultime vârfuri ş.a.m.d. până vor fi vizitate toate vârfurile grafului. Evident, este necesar ca graful să
fie conex. Această modalitate de parcurgere a grafului (în lărgime sau postordine), care mai este adesea
numită parcurgere în ordine orizontală, realizează parcurgerea vârfurilor de la stânga la dreapta, nivel
după nivel.
Algoritmul de mai jos realizează parcurgerea în lărgime cu ajutorul a două fire de aşteptare O1 şi O2.
Se vor forma două fire de aşteptare vide O1 şi O2;
Introduce rădăcina în FA O1;
WHILE cel puţin unul din firele de aşteptare O1 sau O2 nu va fi vid DO
IF O1 nu este vid THEN
BEGIN
fie p vârful din topul FA O1;
vizitează vârful p eliminându-l din O1;
vizitează pe toţi fiii lui p în FA O2, începând cu cel mai mare;
END
ELSE
în calitate de O1 se va lua FA O2, care nu este vid,
iar în calitate de O2 se va lua FA vid O1;
Vom nota că procedura parcurgerii grafului în lărgime permite să realizăm arborele de căutare şi în acelaşi
timp să construim acest arbore. Cu alte cuvinte, se va rezolva problema determinării unei rezolvări sub
forma vectorului (a1, a2,...) de lungime necunoscută, dacă este cunoscut că există o rezolvare finită a
problemei.
Algoritmul pentru cazul general este analogic cu cel pentru un graf în formă de arbore cu o mică
modificare care constă în aceea că fiecare vârf vizitat va fi marcat pentru a exclude ciclarea algoritmului.
Căutare în adâncime
La căutarea în adâncime (parcurgerea unui graf în sens direct, în preordine) vârfurile grafului vor
fi vizitate în conformitate cu următoarea procedură recursivă:
mai întâi va fi vizitată rădăcina arborelui q, apoi, dacă rădăcina arborelui nu este frunză - pentru fiecare
fiu p al rădăcinii q ne vom adresa recursiv procedurii de parcurgere în adâncime pentru a vizita vârfurile
tuturor subarborilor cu rădăcina p ordonate ca fii ai lui q.
În cazul utilizării unei stive pentru păstrarea drumului curent pe arbore, drum care începe din rădăcina
arborelui şi se termină cu vârful vizitat în momentul dat, poate fi realizat un algoritm nerecursiv de forma:
Vizitează rădăcina arborelui şi introdu-o în stiva vidă S;
WHILE stiva S nu este vidă DO
BEGIN
fie p - vârful din topul stivei S;
IF fiii vârfului p încă nu au fost vizitaţi
THEN vizitează fiul mai mare al lui p şi introduce-l în S
ELSE BEGIN
elimină vârful p din stiva S
IF p are fraţi THEN vizitează pe fratele lui p şi introduce-l în stiva S
END
END
Acest algoritm poate fi modificat pentru a putea fi utilizat la parcurgerea tuturor vârfurilor unui
graf arbitrar. În algoritmul de mai jos se va presupune că este stabilită o relaţie de ordine pe
mulţimea tuturor vârfurilor grafului, iar mulţimea vârfurilor adiacente cu un vârf arbitrar al
grafului este de asemenea ordonată:
WHILE va exista cel puţin un vârf care nu a fost vizitat DO
BEGIN
fie p - primul din vârfurile nevizitate;
vizitează vârful p şi introduce-l în stiva vidă S;
WHILE stiva S nu este vidă DO
BEGIN
fie p - vârful din topul stivei S;
IF m vârfuri ale lui p sunt vârfuri adiacente nevizitate
THEN BEGIN
fie z primul vârf nevizitat din vârfurile adiacente cu p;
parcurge muchia (p,z), vizitează vârful z şi introduce-l în stiva S;
END
ELSE elimină vârful p din stiva S
END
END
În cazul în care se va lucra cu un graf conex arbitrar cu relaţia de ordine lipsă, nu va mai avea importanţă
ordinea de parcurgere a vârfurilor. Propunem un algoritm care utilizează mai larg posibilităţile stivei, cea
ce face programul mai efectiv în sensul diminuării timpului de calcul necesar. De exemplu, acest algoritm
în varianta recursivă este pe larg utilizat în programele de selectare globală în subdirectori (cazul
programelor antivirus).
Introdu în stivă vârful iniţial şi marchează-l;
WHILE stiva nu este vidă DO
BEGIN
extrage un vârf din stivă;
IF există vârfuri nemarcate adiacente cu vârful extras
THEN marchează-le şi introduce-le în stivă;
END
1. SARCINA DE BAZĂ
1. Elaboraţi procedura căutării în adâncime într-un graf arbitrar (vezi anexaA si B);
2. Elaboraţi procedura care va realiza algoritmul de parcurgere a grafului în lărgime;
3. Elaboraţi un program cu următoarele posibilităţi:
• introducerea grafului în calculator,
• parcurgerea grafului în adâncime,
• parcurgerea grafului în lărgime;
• vizualizarea rezultatelor la display şi imprimantă.
Codul programului in C:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include<string.h>
#include<windows.h>
void setcolor(unsigned short color){
HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hcon,color);
}
int optiune,pl,i,k,n,m,y=0,x,j,p,a[50][50],v[50][50],virf[50][50],b,u,z,q,t,c[50],viz[50];
void nod(){
printf(" Numarul de virfuri: ");
scanf(" %d",&n);
}
void citirelista(){
for(x=0;x<=n;x++){
printf(" %d: ",x);
for(y=0;y<=n+1;y++){
scanf("%d",&y);
if(y==0){break;}
if(x==y){
a[x][y]=2;}
else{a[x][y]=1;}
}
}
}
void citirema(){
for (x=0;x<=n;x++){
for (y=0;y<=n;y++){
printf(" %d->%d = ",x,y);
scanf("%d",&a[x][y]);
}
}
}
void mat_ad(){
setcolor(12);
printf(" Matricea de adiacenta\n\n");
for (i=0;i<n+1;i++){
setcolor(12);
printf("\t[X%d]",i);
}
for (i=0;i<n+1;i++)
{ printf("\t");
}
printf("\n");
for(i=0;i<=n;i++){
setcolor(12);
printf("[X%d]\t",i);
for(j=0;j<=n;j++){
setcolor(14);
printf(" %d\t",a[i][j]);
}
printf("\n");
}
printf("\n");
}
void mat_in(){
printf(" Matricea de incidenta\n\n");
for (i=0;i<n+1;i++){
setcolor(12);
printf("\t[X%d]",i);
}
for (i=0;i<n+1;i++){
printf("\t");
}
y=0;
memset(v, 0, sizeof(int)*50*50);
for (i=0; i<=n; i++){
for (j=0; j<=n; j++){
if (a[i][j]==1)
{
//memset(v[y], 0, 50);
v[y][i]=-1;
v[y][j]=1;
y++;
}
else if (a[i][j]==2)
{
v[y][i]=2;
y++;
}
}
}
printf("\n");
for(i=0;i<y;i++){
setcolor(12);
printf("[U%d]\t",i+1);
for(j=0;j<=n;j++){
setcolor(14);
printf(" %d\t",v[i][j]);
}
printf("\n");
}
printf("\n");
}
void lista_in(){
setcolor(12);
printf(" Lista de incidenta:\n\n");
for (i=0; i<=n; i++){
for (i=0; i<=n; i++)
{ setcolor(12);
printf(" %d: ", i);
setcolor(14);
for (j=0; j<=n+1; j++)
{
if (a[i][j]==1)
{ setcolor(14);
printf(" %d,", j);
}
if (a[i][j]==2)
{ setcolor(14);
printf(" %d,", j);
}
}
printf(" -1\n\n");
}
}
return;
}
void addvirf(){
k=1;
puts(" Varful a fost adaugat cu succes!\n");
n++;
for (i=1;i<n-1;i++){
for (j=1;j<n-1;j++){
virf[i][j]=a[i][j];
}
}
for (i=1;i<n-1;i++){
for (j=1;j<n-1;j++){
a[i][j]=virf[i][j];
}
}
}
void addarc(){
printf(" Introduceti virful initial: ");
scanf("%d",&x);
printf(" Introduceti virful final : ");
scanf("%d",&y);
if(x<=n&&y<=n){
a[x][y]=1;
}
if(x==y){
a[x][y]=2;
v[y][i]=2;
y++;
}
}
void delarc(){
a[x][y] = 0;
return;
for (i=0;i<m;i++) {
for (i=0;i<m;i++){
a[x][y]=a[x+1][y+1];
v[y][i]=v[y+1][i+1];
v[y][j]=v[y+1][j+1];
}
x=x-1;
y=y-1;
i=i-1;
j=j-1;
}
}
void delvirf(){
for (i=0;i<n;i++) {
for (j=0;j<n;j++){
a[j][p]=0;
a[i][p]=0;
a[p][j]=0;
}
}
}
void latime(){
int i,p,v,ii=1,jj=1;
c[1]=pl;
viz[pl]=1;
p=u=1;
while(p<=u){
v=c[p];
p++;
jj=1;
for(i=1;i<=n;i++){
if(a[v][i]==1 && viz[i]==0)
{u++;
c[u]=i;
viz[i]=1;}
}
}
}
void afisare_latime(){
setcolor(12);
printf(" Graful parcurs in latime: ");
for(i=1;i<=u;i++){
setcolor(14);
printf("%d ",c[i]);
}
printf("\n");
}
void adincime2(int pl){
if (viz[pl]){
return;
}
printf("%d ",pl);
viz[pl]=1;
int j;
for(j=1;j<=n;j++){
if((a[pl][j]==1)){
adincime2(j);
}
}
}
void adincime(int p){
memset(viz, 0, sizeof(viz));
adincime2(p);
}
int main(){
optiune=0;
int c=0;
setcolor(15);
printf("\
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n\
º º\n\
º Ministerul Educatiei al Republicii Moldova º\n\
º º\n\
º Universitatea Tehnica a Moldovei º\n\
º º\n\
º Catedra FCIM º\n\
º º\n\
º º\n\
º º\n\
º º\n\
º Lucrare de la borator Nr.2 º\n\
º º\n\
º la Matematica discreta º\n\
º º\n\
º º\n\
º TEMA: º\n\
º º\n\
º Pastrarea grafurilor im memoria calculatorului. º\n\
º Algoritmii de cautare in adincime si latime a unui graf. º\n\
º º\n\
º º\n\
º º\n\
º º\n\
º º\n\
º A efectuat : [Link]. CR-182 º\n\
º Tenu Maxim º\n\
º º\n\
º A verificat: lector superior º\n\
º Bagrin Veronica º\n\
º º\n\
º º\n\
º º\n\
º º\n\
º Chisinau 2016 º\n\
º º\n\
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n",185);
setcolor(3);
printf(" Doriti sa afisati MENU programului?\n Daca 'Da' tastati '1', daca 'Nu' tastati orice
tasta: ");
scanf("%d",&c);
if(c==1){
do{
system("CLS");
setcolor(9);
printf("\
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n\
º MENU PROGRAMULUI º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º INTRODUCEREA GRAFULUI º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º 1. Numarul de virfuri. º\n\
º 2. Prin lista de adiacenta. º\n\
º 3. Prin matricea de adiacenta. º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º AFISAREA GRAFULUI º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º 4. Matricea de adiacenta. º\n\
º 5. Matricea de incidenta. º\n\
º 6. Lista de incidenta. º\n\
º 7. Toate. º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º MODIFICAREA GRAFULUI º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º 8. Adaugarea unui virf. º\n\
º 9. Adaugarea unui arc. º\n\
º 10. Stergerea unui arc. º\n\
º 11. Sergerea unui virf. º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º PARCURGEREA GRAFULUI º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º 12. Parcurgerea in latime. º\n\
º 13. Parcurgerea in adincime. º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º IESIRE DIN PROGRAM º\n\
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͺ\n\
º 0. Iesire. º\n\
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ\n",185);
setcolor(3);
printf("\n Alegeti optiunea: ");
scanf("%d",&optiune);
switch (optiune){
case 1: {nod();
setcolor(15);
system("PAUSE");
break;
}
case 2: {citirelista();
setcolor(15);
system("PAUSE");
break;
}
case 3: {citirema();
setcolor(15);
system("PAUSE");
break;
}
case 4: {mat_ad();
setcolor(15);
system("PAUSE");
break;
}
case 5: {mat_in();
setcolor(15);
system("PAUSE");
break;
}
case 6: {lista_in();
setcolor(15);
system("PAUSE");
break;
}
case 7: {
mat_ad();
mat_in();
lista_in();
setcolor(15);
system("PAUSE");
break;
}
case 8: {addvirf();
setcolor(15);
system("PAUSE");
break;
}
case 9: {addarc();
setcolor(15);
system("PAUSE");
break;
}
case 10: {
printf(" Introduceti arcul de sters\n");
printf(" Originea: ");
scanf("%d",&x);
printf(" Extremitatea: ");
scanf("%d",&y);
delarc();
puts(" Arcul a fost sters!");
setcolor(15);
system("PAUSE");
break;
}
case 11: {
printf(" Introduceti virful de sters\n");
printf(" Virful: ");
int x=n;
scanf("%d",&p);
delvirf();
n=x;
puts(" Virful a fost sters!");
setcolor(15);
system("PAUSE");
break;
}
case 12: {
for(i=1;i<=n;i++)viz[i]=0;
printf(" Dati nodul de plecare: ");
scanf("%d",&pl);
latime();
afisare_latime();
setcolor(15);
system("PAUSE");
break;
}
case 13: {
for(i=1;i<=n;i++)viz[i]=0;
printf(" Dati nodul de plecare: ");
scanf("%d",&pl);
setcolor(12);
printf(" Graful parcurs in adincime: ");
setcolor(14);
adincime(pl);
printf("\n");
setcolor(15);
system("PAUSE");
break;
}
case 0:{
printf(" Daca doriti sa iesiti tastati ENTER\n");
return 0;
}
default:{
printf(" Optiunea nu exista!\n");
setcolor(15);
system("PAUSE");
break;
}
}
}
while(optiune!=0);
getch();
return 0;
}
else{return 0;}
}
Fig.1 Meniu
Fig.2 Introducerea numarului de virfuri
Fig3 Introducerea grafului prin lista de adiacenta
Fig.4 Afisarea grafului
Fig.5 Parcurgerea grafului in latime
Fig.6 Parcurgerea grafului in adincime
Fig. 7
Fig.7,8 Adaugarea unui virf
Fig.9
Fig.9,10 Adaugarea unui arc
Fig.11
Fig.10,11 Stergerea unui arc
Fig.12
Fig.12,13 Stergerea unui virf
Concluzii
In urma efectuarii lucrarii date unde am studiat metodele de definire a unui graf: in matrice
adiacenta,matrice de incedinta si lista,am elaborat un procedeu de introducere, afisare si
extragere a unei din metodele mentionate mai sus prin programul [Link] observat cu usurinta
editarea grafului. Prin orice metoda de definire a grafului putem usor sa obitnem metoda grafica
a grafului. Efecuand aceasta lucrare de laborator,am obtinut practica de lucru metodele de reprezentare
ale grafului
Pe parcursul lucrarii, am ajuns la concluzia ca cea mai simpla metoda de introducere a grafului de la
tastatura este lista adiacenta, care permite utilizatorului sa aleaga cu usurinta virfurile necesare,de
asemenea aceasta metoda utilizeaza si cel mai putin din memoria calculatorului.
Bibliografie
• Conspectul la matematica discreta
• “Matematica discreta in inginerie” indrumar de laborator Chisinau 1999