Enunţ:
Scrieţi programul C care permite crearea şi vizualizarea unui arbore binar ordonat cu
vizualizare naturală. Programul va permite suprimarea şi căutarea unui nod de cheie dată.
1. Descrierea algoritmului.
Fie x o cheie dată. Problema constă în suprimarea din structura de arbore a nodului care are
cheia egală cu a nodului cu cheia precizată de x. Suprimarea trebuie facută a.î. şi după suprimare
arborele să rămână binar şi ordonat.
În prealabil se va căuta în arbore pentru a vedea dacă există un nod cu această cheie. Dacă
nu există suprimarea se termină şi se va afişa un mesaj de eroare, iar dacă nodul există va fi
suprimat.
Există 2 situaţii:
1) nodul de suprimat este un nod terminal sau are cel mult un fiu;
2) nodul are 2 fii.
<-p
Figura 1
Pentru a putea descrie acest proces mai avem nevoie de o var auxiliară: ref q.
Secvenţa C care descrie acest proces este:
q = p;
if(q->dr==NULL)
p = q->st; /*nodul nu are fiu drept*/
else if(q->st==NULL)
p = q->dr; /*nodul nu are fiu stâng*/
else /*nodul are 2 fii*/
{
/*cazul 2*/
}
Cazul 2. Nodul de suprimat are 2 fii(fig. 2).
Figura 2
Notăm cu p – var. pointer din nodul părinte a lui x care conţine adresa nodului x.
Suprimarea se va realiza astfel: se caută predecesorul sau succesorul nodului x în inordine, fie
acesta nodul y, se înlocuieşte nodul x cu nodul y(în sensul că toate câmpurile nodului y se vor asigna
nodului x, cu excepţia câmpului stâng şi drept).
În acest moment nodul y intervine de 2 ori în structura de arbore. Vom suprima nodul y din
poziţia iniţială conform cazului 1), întrucât nodul y va avea cel mult un fiu fiind
predecesorul(succesorul) său în inordine.
Rezolvare:
Scrieţi programul C care permite crearea şi vizualizarea unui arbore binar ordonat cu
vizualizare naturală. Programul va permite suprimarea şi căutarea unui nod de cheie dată.
#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 suprimare(int, ref *);
void suprimafd(ref *);
ref Loc(int, ref);/*cauta un nod in arbore*/
ref radacina, r, q;
int x,
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(" S. Suprimarea unui nod din 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 'S':
printf("Introduceti nodul de suprimat: ");
while(scanf("%d", &x)==0)
{
printf("Introduceti un intreg!\n");
fflush(stdin);
printf("Introduceti cheia nodului de cautat: ");
}
suprimare(x, &radacina);
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 'F':
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, "Parcurgere in INORDINE" );
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 !\n");
break;
}
}
while(op!='E');
}/*main*/
void creare(void)
{
int x;
radacina=NULL;
printf("Introduceti noul nod (0-pt a termina): ");
while(scanf("%d", &x)!=1)
{
printf("Introduceti un numar!\n");
fflush(stdin);
}
while(x!=0)
{
inarbore(x, &radacina);
printf("Introduceti noul nod (0-pt a termina): ");
while(scanf("%d", &x)!=1)
{
printf("Introduceti un numar!\n");
fflush(stdin);
}
}
}/*creare*/
void initializare_mod_grafic(void)
{
int gdriver=DETECT, gmode, err;
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)
{
tip(rad, nivel, x1, x2, c1, c2, s);
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);
}
}/*preordine*/
void postordine(ref rad, int nivel, int x1, int x2, int c1, int c2)
{
static char s[10];
if(rad!=NULL)
{
postordine(rad->st, nivel+1, x1, (x1+x2)/2, (x1+x2)/2,
nivel*spatiu+raza);
postordine(rad->dr, nivel+1, (x1+x2)/2, x2, (x1+x2)/2,
nivel*spatiu+raza);
tip(rad, nivel, x1, x2, c1, c2, s);
}
}/*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;
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*/
Observaţii:
Dacă vom folosi pe postul lui y succesorul lui x în inordine el va fi cel mai din stânga
nod al subarborelui său drept.
Predecesorul în inordine va fi cel mai din dreapta nod al subarborelui său stâng.
Referitor la găsirea nodului y putem preciza următorele: se construieşte o secvenţă de noduri
începând cu fiul stâng al nodului x şi pentru fiecare nod din secvenţă se va lua drept succesor fiul
drept. Primul nod care nu va avea fiu drept va fi nodul y.
Functiile care descriu suprimarea unui nod în acest caz şi care sunt valabile în cazul general
sunt:
void suprimafd(ref *r)
{
if((*r)->dr!=NULL)
suprimafd(&((*r)->dr));
else
{
q->cheie = (*r)->cheie;
q = *r;
*r = q->st;
}
}/*suprimafd*/
void suprimare(int x, ref *p)
{
if((*p)==NULL)
printf("Nodul nu exista, nu am ce sterge!\n");
else
if(x < (*p)->cheie)
suprimare(x, &((*p)->st));
else
if(x > (*p)->cheie)
suprimare(x, &((*p)->dr));
else /*sterge *p*/
{
q=*p;
if(q->dr==NULL)
*p = q->st;
else
if(q->st==NULL)
*p=q->dr;
else suprimafd(&(q->st));
free(q);
}
}/*suprima*/