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
1
6 1
1 1
4 7
0 3
1 1
3 9
2 4
Figura 1
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.
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;
1
p-> 4 1
1 1
3 6
0 3
1 1
9
2 4
Figura 3
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
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>
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 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*/
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 */
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 */
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*/