Sunteți pe pagina 1din 14

LABORATOR 4

Enunţ:
Scrieţi programul C care permite crearea şi suprimarea unui nod dintr-un arbore AVL a.î. după
suprimare arborele să rămână tot AVL.

1. Descrierea algoritmului

Considerăm că arborele are structura:

typedef struct nod


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

Vom presupune arborele următor:

1
6 1

1 1
4 7
0 3

1 1
3 9
2 4

Figura 1

Vom presupune că vom şterge pe rând nodurile: 7, 11, 9 , 8, 4.


Suprimarea unui nod dintr-un arbore AVL se face după acelaş pricipiu ca şi în cazul arborilor
binari ordonati. În cazul în care nodul de suprimat are cel mult un fiu suprimarea directă, în caz
contrar nodul se va înlocui cu predecesorul său în inordine.

Suprimarea nodului de cheie 7


Fie p var pointer care conţine adresa rădăcini pointerului din care se face suprimarea.
8

1
p-> 6 1

1 1
4 7
0 3

1 1
3 9
2 4
Figura 2

Nodul cu cheia 7 este nod frunză, factorul de echilibru al acestuia este -1. Nodul de cheie 7
fiind fiul drept al lui 6 cu factorul de echilibru -1 rezultă că în urma suprimării se dezechilibrează
arborele de rădăcină 6, deci trebuie să efectuăm reechilibrarea arborelui de rădăcină 6. Întrucât
dezechilibrarea se produce pe ramura stângă a arborelui rezultă că avem cazul de dezechilibrare I
stânga.

Cazul I stânga de reechilibrare


p->ech = -1;
p1 = p->st; caracteristicile cazului I stânga de reechilibrare
p1->ech <= 0
p->st = p1->dr; reechilibrare
p1->dr = p;
Fie h o variabilă care indică dacă se transmite sau nu modificarea mai sus în arbore a
factorului de echilibru.

If (p1->ech == 0)
{
p->ech = -1;
p1->ech = 1;
h = 0; /* modificarea nu se propagă */
}
else
{
p->ech = 0;
p1->ech = 0;
}
p = p1;

Arborele după suprimarea nodului de cheie 7 şi reechilibrare:


8

1
p-> 4 1

1 1
3 6
0 3

1 1
9
2 4

Figura 3

Suprimarea nodului de cheie 11


Considerăm arborele din care suprimăm nodul ca fiind arborele din figura 3. Nodul cu cheia 11
are 2 fii, după suprimare 11 se va înlocui cu cel mai din dreapta nod al subarborelui său stâng.
Arborele după suprimarea nodului de cheie 11:
8

1
p->ech = 1
4 0

1
3 6 9
3

Figura 4 1 1
2 4
Suprimarea nodului cu cheia 9
Avem cazul de reechilibrare I dreapta.
p1 = p->dr; caracteristicile cazului
p1->ech >= 0
Acest caz se va trata analog cu cazul I stânga prin simetrie înlocuid peste tot st <->dr şi 1<-
>-1.
Arborele după suprimarea nodului cu cheia 9 şi reechilibrare:
8

1
<-p1
4 3

1 <-p
1
3 6
0 4

1
Figura 5
2
Suprimarea nodului cu cheia 8
Considerăm arborele din figura 5. După suprimare ndul cu cheia 8 se va înlocui cu cel mai din
dreapta nod al subarborelui său stâng.
Arborele după suprimarea nodului cu cheia 8 şi reechilibrare:

1
p-> 4 3

1 1
3
0 4

1
2
Figura 6

Suprimarea nodului de cheie 4


Considerăm arborele din figura 6. Nodul de rădăcină 6 se dezechilibrează, rezultă cazul de
reechilibrare II dreapta.
p1 = p->dr;
p1->ech = -1; caracteristicile cazului II dreapta
p2 = p1->st;
p2->ech = 1;
Arborele după suprimarea nodului de cheie 4 şi reechilibrare:
p2-> 1
0

1
6 3 <-p1
p->

1 1
3
2 4
Figura 7

Observaţii:
 Să constatăm că în cazul suprimării unui nod dintr-un arbore AVL intervin 4 situaţii de
rechilibrare: I stânga, II stânga, I dreapta, II dreapta, dar e suficient să tratăm 2 dintre
ele(I, II stânga) celelate 2 cazuri fiind rezolvate prin simetrie.
 Se constată că reechilibrarea se impune doar atunci când scade în înălţime subarborele
nodului de rădăcină al cărui factor de echilibru era 1 sau -1.
 Reechilibrarea când factorul de echilibru al lui p era 1 şi se şterge un nod din ramura
stângă vom avea cazul de reechilibrare dreapta I sau II.Esenţial este că a scăzut în
înălţime ramura stângă. Funcţia care tratează acest caz o vom numi echilibru1.
 Dacă factorul de echilibru era -1 şi şterg un nod din subarborele drept al acestuia se
produce dezechilibrarea pe ramura stângă şi vom avea cazul de reechilibrare stânga I sau
II. Vom numi funcţia care descrie acest caz echilibru2.

Rezolvare:
Scrieţi programul C care permite crearea şi suprimarea unui nod dintr-un arbore AVL a.î. după
suprimare arborele să rămână tot AVL.

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

#define CALE "c:\\Borlandc\\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 *);
void echilibru1(ref *, int *);
void echilibru2(ref *, int *);
void suprimaechil(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 AVL si sa se afiseze
grafic\n");
printf(" C. Creare\n");
printf(" I. Insereaza un nod in arbore!\n");
printf(" S. Sterge un nod din arbore!\n");
printf(" F. Cauta un nod in arbore\n");
printf(" A. Afisare in mod grafic in inordine\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 'I':
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 'S':
if(radacina==NULL)
{
printf("Arbore vid! Nu avem ce suprima!\n");
printf("Apasati o tasta pentru a
continua!\n");getch();
break;
}
printf("Introduceti cheia nodului de suprimat: ");
while(scanf("%d", &x)!=1)
{
printf("Introduceti un numar!\n");
fflush(stdin);
printf("Introduceti cheia nodului de suprimat: ");
}
h = 0;
suprimaechil(x, &radacina, &h);
printf("Nodul cu cheia %d a fost sters din
arbore!\n",x);
printf("Apasati o tasta pentru a continua!\n");
getch();
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");
printf("Apasati o
tasta pentru a continua!\n");getch();
}
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 'A':
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 '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 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;
r = NULL;
}
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);
}/*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*/

void echilibru2(ref *p, int *h)


{
ref p1, p2;

switch((*p)->ech)
{
case 1:(*p)->ech = 0;
break;
case 0:(*p)->ech = -1;
*h = 0;
break;
case -1: /* reechilibrare */
p1 = (*p)->st;
if(p1->ech<=0) /* cazul I stanga */
{
(*p)->st = p1->dr;
p1->dr = *p;
if(p1->ech==0)
{
(*p)->ech = -1;
p1->ech = 1;
*h = 0;
}
else
{
(*p)->ech = 0;
p1->ech = 0;
}
*p = p1;
}
else /* cazul II stanga */
{
p2 = p1->dr;
p1->dr = p2->st;
(*p)->st = p2->dr;
p2->dr = (*p);
p2->st = p1;
if(p2->ech==-1)
{
(*p)->ech = 1;
p1->ech = 0;
}
else if(p2->ech==0)
{
(*p)->ech = 0;
(p1)->ech = 0;
}
else /* p2->ech = 1 */
{
(*p)->ech = 0;
p1->ech = -1;
}
p2->ech = 0;
(*p) = p2;
}
break;
}/* switch */
} /* echilibru2 */

void echilibru1(ref *p, int *h)


{
ref p1, p2;

switch((*p)->ech)
{
case -1:(*p)->ech = 0;
break;
case 0:(*p)->ech = 1;
*h = 0;
break;
case 1: /* reechilibrare */
p1 = (*p)->dr;
if(p1->ech>=0) /* cazul I stanga */
{
(*p)->dr = p1->st;
p1->st = *p;
if(p1->ech==0)
{
(*p)->ech = 1;
p1->ech = -1;
*h = 0;
}
else
{
(*p)->ech = 0;
p1->ech = 0;
}
*p = p1;
}
else /* cazul II stanga */
{
p2 = p1->st;
p1->st = p2->dr;
(*p)->dr = p2->st;
p2->st = (*p);
p2->dr = p1;
if(p2->ech==1)
{
(*p)->ech = -1;
p1->ech = 0;
}
else if(p2->ech==0)
{
(*p)->ech = 0;
(p1)->ech = 0;
}
else /* p2->ech = -1 */
{
(*p)->ech = 0;
p1->ech = 1;
}
p2->ech = 0;
(*p) = p2;
}
break;
}/* switch */
} /* echilibru1 */

void suprfd(ref *r, int *h, ref *q)


{
if((*r)->dr!=NULL)
{
suprfd(&(*r)->dr, h, q);
if(*h) echilibru2(r, h);
}
else
{
(*q)->cheie = (*r)->cheie;
(*q)->contor = (*r)->contor;
(*q) = (*r);
(*r) = (*q)->st;
*h = 1;
}
}/*suprfd*/

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


{
ref q;

if((*p)==NULL)
{
printf("Nodul nu exista in arbore!\n");
*h = 0;
}
else if(x<(*p)->cheie)
{/* caut in subarborele stang */
suprimaechil(x, &(*p)->st, h);
if(*h) echilibru1(p, h);
}
else if(x>(*p)->cheie)
{ /* caut in ramura dreapta */
suprimaechil(x, &(*p)->dr, h);
if(*h) echilibru2(p, h);
}
else /* am gasit, deci sterg *p */
{
q = (*p);
if(q->dr==NULL)
{
(*p) = q->st;
(*h) = 1;
}
else if(q->st==NULL)
{
(*p) = q->dr;
(*h) = 1;
}
else /* are 2 fii */
{
suprfd(&(q->st), h, &q);
if(*h) echilibru1(p, h);
}
}
}/*suprimaechil*/

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