Sunteți pe pagina 1din 15

LABORATOR 3

Enunţ:
Scrieti programul C care permite crearea şi vizualizarea unui arbore AVL.

Descrierea algoritmului
Problema constă în inserarea unu nou nod într-un arbore AVL a.î. şi după inserare arborele să
rămână tot AVL.

S D
hs – înălţimea subarborelui stâng
hd – înălţimea subarborelui drept
Pentru a stabili când se impune reechilibrarea şi în ce caz de reechilibrare suntem vom
introduce noţiunea de factor de echilibru a unui arbore AVL înţelegând prin aceasta diferenţa dintre
înălţimea subarborelui său drept şi înălţimea subarborelui său stâng.
Structura arborelui va fii următoarea:

typedef struct nod


{
int cheie;
int contor;
int ech; /*factorul de echilibru*/
struct nod *st, *dr;
}Tnod;
typedef Tnod* ref;
ref radacina;

Cele 3 situaţii de inserae într-un arbore AVL referitoare la diferenţa de înălţime dintre
subarborele stâng şi drept se traduc prin intermediul factorului de echilibru al nodului radacina.

Înainte de inserare După inserare


hs < hd p->ech = 1 hs = hd p->ech = 1
hs = hd p->ech = 0 hs > hd p->ech = -1
hs > hd p->ech = -1 hs > hd p->ech = -2

Factorul de echilibru al unui nod într-un arbore AVL devine important în realizarea algoritmului
de inserare a unui nod într-un arbore AVL. Acest algoritm se va desfăşura în 3 paşi:
1. se caută în arbore nodul cu cheia de inserat
2. dacă nodul există în arbore se incrementează contorul asociat nodului şi algoritmul se
opreşte, altfel se inserează în locul determinat la pasul 1
3. se merge înapoi pe drumul de căutare între locul de inserat şi nodul radacina restabilind în
mod corespunzător factorul de echilibru pentru toate nodurile de pe acest drum.

Exemplu:
Se consideră arborele:
8

1
4 0

2 6

Cazul I a)

Inserarea nodului de cheie 1


După inserare

1
4 0

2 6

Se dezechilibrează arborele de radacină 8 => se impune reechilibrarea.


p->ech = -1
p1->ech = -1

caracteristicile cazului I a)
După reechilibrare

8
2

1
1 6
0

După reechilibrare factorii de echilibru nu s-au modificat.


Reechilibrare:
p1->st = p1->dr;
p1->dr = p;
După reechilibrare modificăm factorii de echilibru ai nodurilor care intervin în reechilibrare
(adică *p, *p1).
Restabilirea factorilor de echilibru:
p->ech = 0;
p1->ech = 0;
p = p1;

Cazul I b)

Inserarea nodului de cheie 3


La inserarea nodului de cheie 3 se constată că se efectuează aceleaşi operaţii şi deci le putem
comasa în cazul I stânga.

Descrierea cazului I stânga

Caracteristicile Restabilirea factorilor de


Reechilibrarea
cazului I stânga echilibru
p1 = p->st; p->st = p1->dr; p->ech = 0;
p->ech = -1; p1->dr = p; p1->ech = 0;
p1->ech = -1; p = p1;

Cazul II a)

Inserăm în arborele iniţial nodul de cheie egală cu 5

Arborele dupa inserare

p -> 8

1
p1 -> 4 0

2 6 <- p2

Caracteristicile cazului II a)
p1 = p->st;
p2 = p1->dr;
p->ech = -1;
p1->ech = 1;
Arborele se dezechilibrează şi deci se impune reechilibrarea.
Arborele după reechilibrare

8
4

1
2 5
0

Reechilibrarea constă în:


p1->dr = p2->st;
p->st = p2->dr;
p2->st = p1;
p2->dr = p;
p2->ech = -1;
După reechilibrare nu sunt stabiliţi factorii de echilibru. Restabilirea factorilor de echilibru
constă în:
p->ech = 1;
p1->ech = 0;

Cazul II b)

Inserăm în arborele iniţial nodul de cheie egală cu 7

Arborele după reechilibrare

p -> 8

1
p1 -> 4 0

2 6 <- p2

7
0

După inserare factorii de echilibru ai nodurilor nu au fost modificaţi şi mergem înapoi pe


drumul de căutare pentru a restabili factorii de echilibru.
p->ech = -1;
p1->ech = 1;
Observăm că sunt aceleaşi caracteristici ca în cazul II a).
Arborele se dezechilibrează şi deci se impune reechilibrarea.
Arborele dupa reechilibrare

6
p2 ->

8
p1 -> 4 <- p

1
2 7 0

Modificarea factorilor de echilibru:


p->ech = 0;
p1->ech = -1;
p = p2;
p->ech = 0;
Comparând cazul II a) cu cazul II b) rezultă că se fac aceleaşi operaţii pentru reechilibrare
exceptând doar factorii de echilibru ai nodurilor *p,*p1,*p2 care se restabilesc în funcţie de factorul
de echilibru al lui *p2.

Cazul II c)

Insearea nodului de cheie 6

După inserare 2 După6reechilibrare


5 6
p -> 8 p2 ->

8
4 <- p1 p1 -> 4 <- p

6 <- p2

p->ech = 0;
p1->ech = 0;
p = p2;
p->ech = 0;
Cele 3 cazuri II a), b), c) le putem uni într-un singur caz: cazul II stânga(S.D.)
Considerăm că p este nodul rădăcină.

Descrierea cazului II Stânga(S.D.)

p1 = p->st;
p2 = p1->dr;
p->ech = -1;
p1->ech = 1;
p1->dr = p2->st;
p->st = p2->dr;
p2->st = p1;
p2->dr = p;
if(p2->ech==-1)
p->ech = 1;
else p->ech = 0;
if(p2->ech==1)
p->ech = 1;
else p1->ech = 0;
p = p2;
p->ech = 0;

Cazurile I dreapta şi II dreapta de reechilibrare(D.D. şi D.S.) se tratează în mod analog prin


simetrie înlocuind st cu dr şi -1 cu 1.
La fiecare pas al algoritmului de inserare trebuie să transmitem informaţia dacă a crescut sau
nu în înălţime subarborele în care s-a făcut inserarea. În acest sens vom folosi o variabilă de tip
boolean h a cărei valoare de adevăr va indica dacă a crescut în înălţime subarborele în care s-a făcut
inserarea.
Funcţia care realizează inserarea cu reechilibrare într+un arbore AVL
este:

void insertechil(int x, ref *p, int *h)


{
ref p1,p2;
if((*p)==NULL)
{
/* h=0 */
/* nodul nu exista,se insereaza */
(*p)=malloc(sizeof(Tnod));
(*p)->cheie=x;
(*p)->contor=1;
(*h)=1;
(*p)->ech=0; /* este nod frunza */
(*p)->st=NULL;
(*p)->dr=NULL;
}
else
if(x<(*p)->cheie)
{
/* continuam pe ramura stanga */
insertechil(x,&((*p)->st),h);
if(*h==1)
switch((*p)->ech)
{
case 1: (*p)->ech=0;
*h=0;
break;
case 0: (*p)->ech=-1;
break;
case -1: /* reechilibrarea */
p1=(*p)->st;
if(p1->ech==-1)
{
/* cazul 1 stanga */
(*p)->st=p1->dr;
p1->dr=(*p);
(*p)->ech=0;
(*p)=p1;
}
else
{
/* cazul 2 stanga,p1->ech=1 */
p2=p1->dr;
p1->dr=p2->st;
(*p)->st=p2->dr;
p2->st=p1;
p2->dr=(*p);
if(p2->ech==-1)
(*p)->ech=1;
else (*p)->ech=0;
if(p2->ech==1)
p1->ech=-1;
else p1->ech=0;
*p=p2;
}/* cazul 2*/
(*p)->ech=0;
*h=0;
break; /* reechilibrarea */
}/*switch */
}/* ramura stanga */
else if(x>(*p)->cheie)
{
/* se cauta pe ramura dr */
insertechil(x,&((*p)->dr),h);
if(*h==1)
switch((*p)->ech)
{
case -1: (*p)->ech=0;
*h=0;
break;
case 0: (*p)->ech=1;
break;
case 1: /* reechilibrarea */
p1=(*p)->dr;
if(p1->ech==1)
{
/* cazul 1 stanga */
(*p)->dr=p1->st;
p1->st=(*p);
(*p)->ech=0;
(*p)=p1;
}
else
{
/*cazul 2 dreapta,p1->ech=-1*/
p2=p1->st;
p1->st=p2->dr;
(*p)->dr=p2->st;
p2->dr=p1;
p2->st=(*p);
if(p2->ech==1)
(*p)->ech=-1;
else (*p)->ech=0;
if(p2->ech==-1)
p1->ech=1;
else p1->ech=0;
*p=p2;
}/* cazul 2*/
(*p)->ech=0;
*h=0;
break; /* reechilibrarea */
}/*switch */
}/* ramura dreapta */
else
{
/*nodul exista in arbore,increm contorul*/
(*p)->contor++;
*h=0;
}
} /* insertechil */

Rezolvare:
Realizaţi programul C care permite crearea şi vizualizarea unui arbore AVL.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
#include <graphics.h>
#include <dos.h>

#define CALE "e:\\Bc\\BGI"

#define raza 10
#define timp 500
#define spatiu 40

typedef struct nod


{
int cheie;
int contor;
int ech;
struct nod *st, *dr;
} Tnod;
typedef Tnod *ref;

void creare(void);
void inarbore(int, ref *);
void initializare_mod_grafic(void);
void tip(ref, int, int, int, int, int, char *);
void inordine(ref, int, int, int, int, int);
void preordine(ref, int, int, int, int, int);
void postordine(ref, int, int, int, int, int);
void tipt(ref anod, int nivel);
void inordinest(ref rad, int nivel);
void insertechil(int , ref *, int *);
ref Loc(int, ref);/*cauta un nod in arbore*/

ref radacina, r, q;
int x, h,
culoare_fundal=15,/*culoarea de fundal a nodurilor arborelui*/
culoare_scris=1, /*culoarea cu care sunt scrise nodurile arborelui*/
afisare=0;/*pt. cautare*/

void main(void)
{
char op;

radacina = NULL;
do
{
clrscr();
printf("Sa se creeze un arbore binar ordonat si sa se afiseze
grafic\n");
printf(" C. Creare\n");
printf(" N. Insereaza un nod in arbore!\n");
printf(" F. Cauta un nod in arbore\n");
printf(" I. Afisare in mod grafic in inordine\n");
printf(" P. Afisare in mod grafic in preordine\n");
printf(" O. Afisare in mod grafic in postordine\n");
printf(" E. Iesire\n");
printf("Introduceti optiunea: ");
fflush(stdin); op=toupper(getc(stdin));
switch (op)
{
case 'C':
creare();
initializare_mod_grafic();
delay(2000);
settextjustify(1,1);
outtextxy(getmaxx()/2, 10, "Parcurgere in INORDINE" );
setviewport(0,30,getmaxx(), getmaxy(), 1);
inordine(radacina, 0, 0, getmaxx(), getmaxx()/2, raza);
setcolor(WHITE);
outtextxy(getmaxx()/2, getmaxy()-40, "Apasati o tasta pt. a
termina");
fflush(stdin);getch();
closegraph();
break;

case 'N':
printf("Introduceti nodul de inserat: ");
while(scanf("%d", &x)!=1)
{
printf("Introduceti un numar!\n");
fflush(stdin);
printf("Introduceti nodul de inserat: ");
}
h = 0;
insertechil(x, &radacina, &h);
initializare_mod_grafic();
delay(2000);
settextjustify(1,1);
outtextxy(getmaxx()/2, 10, "Inserarea unui nod in arbore");
setviewport(0,30,getmaxx(), getmaxy(), 1);
inordine(radacina, 0, 0, getmaxx(), getmaxx()/2, raza);
setcolor(WHITE);
outtextxy(getmaxx()/2, getmaxy()-40, "Apasati o tasta pt. a
termina");
fflush(stdin);getch();
closegraph();
break;

case 'F':
if(radacina==NULL)
{
printf("Arbore vid!\n");
printf("Apasati o tasta pt. a continua!\n"); getch();
break;
}
afisare = 0;
printf("Introduceti cheia nodului de cautat: ");
while(scanf("%d", &x)==0)
{
printf("Introduceti un intreg!\n");
fflush(stdin);
printf("Introduceti cheia nodului de cautat: ");
}
r = Loc(x, radacina);
if(r == NULL)
printf("Nodul nu exista in arbore!\n");
else
{
afisare = 1;
initializare_mod_grafic();
delay(2000);
settextjustify(1,1);
outtextxy(getmaxx()/2, 10, "Cautarea unui nod in
arbore");
setviewport(0,30,getmaxx(), getmaxy(), 1);
inordine(radacina, 0, 0, getmaxx(), getmaxx()/2, raza);
setcolor(WHITE);
outtextxy(getmaxx()/2, getmaxy()-40,
"Nodul a fost gasit in arbore");
fflush(stdin);getch();
closegraph();
}
break;

case 'I':
if(radacina==NULL)
{
printf("Arborele este vid\n");
printf("Apasati o tasta pt. a continua\n");getch();
}
else
{
initializare_mod_grafic();
delay(2000);
settextjustify(1,1);
outtextxy(getmaxx()/2, 10, "Parcurgere in INORDINE" );
setviewport(0,30,getmaxx(), getmaxy(), 1);
inordine(radacina, 0, 0, getmaxx(), getmaxx()/2, raza);
setcolor(WHITE);
outtextxy(getmaxx()/2, getmaxy()-40, "Apasati o tasta pt.
a termina");
fflush(stdin);getch();
closegraph();
}
break;

case 'P':
if(radacina==NULL)
{
printf("Arborele este vid\n");
printf("Apasati o tasta pt. a continua\n");getch();
}
else
{
initializare_mod_grafic();
delay(2000);
settextjustify(1,1);
outtextxy(getmaxx()/2, 10, "Parcurgere in PREORDINE" );
setviewport(0,30,getmaxx(), getmaxy(), 1);
preordine(radacina, 0, 0, getmaxx(), getmaxx()/2, raza);
setcolor(WHITE);
outtextxy(getmaxx()/2, getmaxy()-40, "Apasati o tasta pt.
a termina.");
fflush(stdin);getch();
closegraph();
}
break;

case 'O':
if(radacina==NULL)
{
printf("Arborele este vid\n");
printf("Apasati o tasta pt. a continua\n");getch();
}
else
{
initializare_mod_grafic();
delay(2000);
settextjustify(1,1);
outtextxy(getmaxx()/2, 10, "Parcurgere in POSTORDINE" );
setviewport(0,30,getmaxx(), getmaxy(), 1);
postordine(radacina, 0, 0, getmaxx(), getmaxx()/2, raza);
setcolor(WHITE);
outtextxy(getmaxx()/2, getmaxy()-40, "Apasati o tasta pt.
a termina.");
fflush(stdin);getch();
closegraph();
}
break;

case 'E':
break;

default:
printf("\nOptiune invalida !\nApasati o tasta!\n");
getch();
break;
}
}
while(op!='E');
}/*main*/

void creare(void)
{
radacina = NULL;
printf("Introduceti nodurile(0 pt. a termina): ");
while(scanf("%d", &x)!=1)
{
printf("Introduceti un numar!");
fflush(stdin);
}
while(x!=0)
{
h = 0;
insertechil(x, &radacina, &h);
printf("Introduceti nodurile(0 pt. a termina): ");
while(scanf("%d", &x)!=1)
{
printf("Introduceti un numar!\n");
fflush(stdin);
printf("Introduceti nodurile(0 pt. a termina): ");
}
}
}/*creare*/

void insertechil(int x, ref *p, int *h)


{
ref p1,p2;
if((*p)==NULL)
{
/* h=0 */
/* nodul nu exista,se insereaza */
(*p)=malloc(sizeof(Tnod));
(*p)->cheie=x;
(*p)->contor=1;
(*h)=1;
(*p)->ech=0; /* este nod frunza */
(*p)->st=NULL;
(*p)->dr=NULL;
}
else
if(x<(*p)->cheie)
{
/* continuam pe ramura stanga */
insertechil(x,&((*p)->st),h);
if(*h==1)
switch((*p)->ech)
{
case 1: (*p)->ech=0;
*h=0;
break;
case 0: (*p)->ech=-1;
break;
case -1: /* reechilibrarea */
p1=(*p)->st;
if(p1->ech==-1)
{
/* cazul 1 stanga */
(*p)->st=p1->dr;
p1->dr=(*p);
(*p)->ech=0;
(*p)=p1;
}
else
{
/* cazul 2 stanga,p1->ech=1 */
p2=p1->dr;
p1->dr=p2->st;
(*p)->st=p2->dr;
p2->st=p1;
p2->dr=(*p);
if(p2->ech==-1)
(*p)->ech=1;
else (*p)->ech=0;
if(p2->ech==1)
p1->ech=-1;
else p1->ech=0;
*p=p2;
}/* cazul 2*/
(*p)->ech=0;
*h=0;
break; /* reechilibrarea */
}/*switch */
}/* ramura stanga */
else if(x>(*p)->cheie)
{
/* se cauta pe ramura dr */
insertechil(x,&((*p)->dr),h);
if(*h==1)
switch((*p)->ech)
{
case -1: (*p)->ech=0;
*h=0;
break;
case 0: (*p)->ech=1;
break;
case 1: /* reechilibrarea */
p1=(*p)->dr;
if(p1->ech==1)
{
/* cazul 1 stanga */
(*p)->dr=p1->st;
p1->st=(*p);
(*p)->ech=0;
(*p)=p1;
}
else
{
/*cazul 2 dreapta,p1->ech=-1*/
p2=p1->st;
p1->st=p2->dr;
(*p)->dr=p2->st;
p2->dr=p1;
p2->st=(*p);
if(p2->ech==1)
(*p)->ech=-1;
else (*p)->ech=0;
if(p2->ech==-1)
p1->ech=1;
else p1->ech=0;
*p=p2;
}/* cazul 2*/
(*p)->ech=0;
*h=0;
break; /* reechilibrarea */
}/*switch */
}/* ramura dreapta */
else
{
/*nodul exista in arbore,increm contorul*/
(*p)->contor++;
*h=0;
}
} /* insertechil */
void initializare_mod_grafic(void)
{
int gdriver=DETECT, gmode, err;

initgraph(&gdriver, &gmode, CALE);


err=graphresult();
if(err!=grOk)
{
printf("Eroare la initializarea modului grafic: %s\n",
grapherrormsg(err));
printf("Apasati o tasta pentru a termina ...\n");
getch();
exit(1);
}
}/*initializare mod grafic*/

void inordine(ref rad, int nivel, int x1, int x2, int c1, int c2)
{
static char s[10];
if(rad!=NULL)
{
inordine(rad->st, nivel+1, x1, (x1+x2)/2, (x1+x2)/2,
nivel*spatiu+raza);
tip(rad, nivel, x1, x2, c1, c2, s);
inordine(rad->dr, nivel+1, (x1+x2)/2, x2, (x1+x2)/2,
nivel*spatiu+raza);
}
}/*inordine*/

void preordine(ref rad, int nivel, int x1, int x2, int c1, int c2)
{
static char s[10];
if(rad!=NULL)
{
preordine(rad->st, nivel+1, x1, (x1+x2)/2, (x1+x2)/2,
nivel*spatiu+raza);
preordine(rad->dr, nivel+1, (x1+x2)/2, x2, (x1+x2)/2,
nivel*spatiu+raza);
tip(rad, nivel, x1, x2, c1, c2, s);
}
}/*preordine*/

void postordine(ref rad, int nivel, int x1, int x2, int c1, int c2)
{
static char s[10];
if(rad!=NULL)
{
postordine(rad->dr, nivel+1, (x1+x2)/2, x2, (x1+x2)/2,
nivel*spatiu+raza);
tip(rad, nivel, x1, x2, c1, c2, s);
postordine(rad->st, nivel+1, x1, (x1+x2)/2, (x1+x2)/2,
nivel*spatiu+raza);
}
}/*postordine*/

void tip(ref anod, int nivel, int x1, int x2, int c1, int c2, char *s)
{
if(afisare==1 && anod==r)
{
culoare_scris=BLUE;
culoare_fundal=RED;
}
else
{
culoare_scris=1;/*albastru*/
culoare_fundal=15;/*alb*/
}
setcolor(15);
line((x1+x2)/2, nivel*spatiu+raza, c1,c2+textheight("1")/2);
setfillstyle(SOLID_FILL, culoare_fundal);
fillellipse((x1+x2)/2, nivel*spatiu+raza, raza, raza);
setcolor(culoare_scris);/*albastru*/
sprintf(s, "%d", anod->cheie);
outtextxy((x1+x2)/2, nivel*spatiu+raza, s);
delay(timp);
r = NULL;
}/*tiparire grafica*/

ref Loc(int x, ref t)


{
int gasit = 0;
while((gasit==0)&&(t!=NULL))
if(t->cheie == x)
gasit=1;
else
if(x < t->cheie)
t = t->st;
else t= t->dr;
return t;
}/*Loc*/

S-ar putea să vă placă și