Sunteți pe pagina 1din 32

TEMA LUCRĂRII:

ALGORITMI DE CĂUTARE A
INFORMAŢIILOR BAZAȚI PE
ARBORI BINARI

LICEUL TEHNOLOGIC METALURGIC, 2020


Cuprins

ARGUMENT ....................................................................................... 3

1. STRUCTURI DINAMICE DE DATE - ARBORI .................... 5

1.1 Noținea de arbore.Proprietăți ................................................... 5

1.2 Arbori parţiali de cost minim ..................................................... 12

1.3 Operaţii pe arbori binari: .......................................................... 14

2. ARBORE BINAR DE CĂUTARE .............................................. 17

2.1 Descrierea generală a arborelui binar de căutare ................... 17

2.2 Implementarea unui nod al arborelui de căutare ...................... 20

2.3 Operaţii într-un arbore de căutare ............................................ 21

3. STUDIU DE CAZ-APLICAȚII ................................................. 28

BIBLIOGRAFIE ............................................................................... 32

2
ARGUMENT

O operație fundamentală intrinsecă pentru un număr mare de


probleme de calcul este căutarea: “recuperarea” unei bucăți de
informații dintr-o mulțime de informații stocate anterior.
De obicei informația este divizată în mai multe înregistrări, fiecare
înregistrare are o cheie care este folosită în procesul de căutare.
Obiectivul căutării este de a găsi toate înregistrările care au chei identice
cu cea care este cheia de căutare. Scopul căutării este de a accesa
informațiile din înregistrări pentru procesare.
Căutarea reprezintă operațiunea care durează cel mai mult în
majoritatea programelor de prelucrare, iar înlocuirea unei metode mai
„proaste” de căutare cu una mai „bună” conduce deseori la o creștere
substanțială în viteza de prelucrare.
O modalitate eficientă de căutare a informațiilor într-o listă o
reprezintă arborii binari de căutare. Fiecare nod al unui astfel de arbore
are asociată, pe lângă informația din nodul respectiv, o cheie de
indexare. Complexitatea algoritmului de căutare cu arbore binar este
foarte mică, de n/2 pentru un arbore cu n noduri. Din această cauză
arborii binari de căutare, cunoscuți și cu denumirea de arbori ABC, sunt
utilizați adesea și de algoritmii de sortare a listelor liniare. Sunt utilizați în
special la sortarea structurilor cu un număr mare de înregistrări cum ar fi
dicționarele lingvistice sau tabelele bazelor de date.
În primul capitol am definit noțiunile de arbore, arbore binar, am
prezentat proprietățile arborilor, modalitățile de reprezentare și
parcurgere.

3
Al doilea capitol este dedicat arborilor binari de căutare. Aici am
descris structura, modul de implementare și operațiile care se pot
efectua asupra nodurilor arborelui.
Ultimul capitol este unul aplicativ, un studiu de caz în care am
realizat un program pentru rezolvarea unei probleme, ce implementează,
prin funcții și proceduri, toate operațiile dintr-un arbore binar de căutare.

4
1. STRUCTURI DINAMICE DE DATE - ARBORI

1.1 Noțiunea de arbore. Proprietăți

Definiție

Un arbore este un graf neorientat, conex și fără cicluri. Arborii


reprezintă grafurile cele mai simple ca structură din clasa grafurilor
conexe, ei fiind cel mai frecvent utilizați în practică. Un arbore Cu n
vârfuri are n-1 muchii.

Definiție

Fie G = (V,E) graf arbore. Subgraful H = (V1,E1) al lui G este un


subarbore al lui G, dacă H este graf arbore.

Un arbore este o mulțime de elemente numite noduri sau vârfuri


pentru care:

1. exista un nod cu destinație specială (rădăcina arborelui);


2. celelalte noduri sunt repartizate în n≥0 seturi disjuncte A1, A2, ...,
An fiecare set constituind la rândul sau un arbore.

5
În structura ierarhica a arborelui, fiecare nod (mai puțin rădăcina) este
subordonat unui alt nod (relație fiu-părinte). Daca un nod nu are fi, el se
numește terminal (sau frunza)

Fie un graf neorientat G=(V,E), unde V e mulțimea vârfurilor, iar E cea


a muchiilor sale. Următoarele afirmații sunt echivalente:

1. G este arbore.
2. G este un graf conex, minimal cu această proprietate (dacă
se elimină o muchie oarecare, se obține un graf neconex).
3. G este un graf fără cicluri, maximal cu această proprietate
(dacă se adaugă o muchie, se obține un graf care are măcar
un ciclu).

 Un arbore cu n ≥ 2 vârfuri conține cel puțin două vârfuri terminale.


 Orice arbore cu n vârfuri are n-1 muchii.
 Fie G un graf neorientat. Un graf parțial H al lui G, cu proprietatea
că H este arbore, se numește arbore parțial al lui G.
 Un graf neorientat G conține un arbore parțial dacă și numai dacă
G este conex.
 Un graf neorientat care nu conține cicluri se numește pădure.

Definiție

Fiind dat un graf neorientat conex, se numește arbore parțial al


grafului un graf parțial cu proprietatea că este arbore. Intuitiv, un arbore
parțial este un arbore obținut prin eliminarea unor muchii din graf.

Un arbore parțial al unui graf neorientat conex poate fi definit ca un


graf parțial conex cu număr minim de muchii, sau un graf parțial aciclic
cu număr maxim de muchii.

6
Corolar: Un arbore cu n varfuri are n - 1 muchii.

De exemplu :

daca alegem 2 ca fiind rădăcina, reprezentarea arborelui pe nivele este:

iar nodul 2 este tatal nodurilor 6, 1, 3, și 7; 5 este fiul lui 6; 4 este fiul lui
3; iar 8 este fiul lui 7. Nodurile 5, 4, 8, și 1 nu au nici un fiu. Nodurile care
nu au fii se mai numesc frunze sau noduri terminale, iar muchiile dintre
noduri, ramuri. Nodurile 6, 1 , 3 și 7 sunt frați. Nodurile 6, 1 , 3 și 7 sunt
urmașii lui 2. De asemenea, nodurile 5, 4 și 8 sunt urmașii lui 2, iar nodul

7
2 este strămoșul tuturor nodurilor (mai puțin el însuși), 2 fiind rădăcina
arborelui. 2 adică rădăcina este singurul nod care nu are tata.
în general, un nod al unui arbore poate avea un număr arbitrar
de fii. Daca orice nod al unui arbore nu are mai mult de n fii atunci
arborele se numește arbore n-ar.

Definiție

Un arbore în care orice nod nu are mai mult de 2 fii se numește


arbore binar.

Definiție

Se numește înălțime a unui arbore lungimea celui mai lung drum


de la rădăcina la un nod terminal din arbore. Pentru arborele de mai sus
înălțimea este 2.Se observă ca intre orice nod și rădăcina exista exact
un singur drum.

Definiție

Un arbore binar este un arbore în care orice nod are cel mult doi
descendenți făcând-se distincție clara intre descendentul drept și
descendentul stâng. Rădăcina unui arbore binar are doi subarbori,
subarborele stâng, cel care are drept rădăcina fiul stâng și subarborele
drept, cel care are ca rădăcina fiul drept. Orice subarbore al unui arbore
binar este el însuși arbore binar. De exemplu, arborele de mai jos este
un arbore binar; rădăcina 10, are drept fiu stâng nodul 4, iar fiu drept
nodul 21, nodul 21 are subarborele stâng format din nodul 15 și
subarborele drept format din nodurile 23 și 28.

8
Nota: Un arbore binar poate fi și vid (adică fără nici un nod).
Un arbore binar pentru care orice nod neterminal are exact doi fii
se numește arbore plin ("full").

Arborele binar este arborele în care un nod are cel mult doi fii. În
aceasta situație se poate vorbi (pentru un arbore nevid) de cei doi
subarbori (stâng și drept) ai unui arbore.

Schematic avem: Arbore binar

Reprezentare

De obicei, nodurile unui arbore, în particular binar, conțin pe lângă


informația corespunzătoare și informații despre cei doi fii stâng și drept.
în calculator, arborii binari se pot reprezenta în doua moduri.
Reprezentarea secvențiala

9
Pentru fiecare nod al arborelui se precizează informația și
descendenții direcți ca elemente a trei vector diferiți, INFO[i], ST[i] și
DR[i], unde i este indicele asociat unui nod. Cei trei vectori au
dimensiunea egala cu numarul de noduri din arbore. De exemplu, pentru
arborele de mai sus, daca numerotam nodurile începând cu nivelul 0, de
la stânga la dreapta, obținem următorii vectori, cu convenția ca rădăcina
este nodul 1: INFO= (10, 4, 21, 1, 9, 15, 23, 28), ST=(1, 4, 6, 0,0, 0, 0,
0), DR = (3, 5, 7, 0, 0, 0, 8, 0).

 Reprezentarea înlănțuita

Pentru fiecare nod al arborelui se precizează informația și


descendenții direcți ca elemente ale unei structuri definita astfel:
struct nodarbore
{
T info;
struct nodarbore *stâng;
struct nodarbore *drept;
};
typedef struct nodarbore NODARB;

unde T este presupus definit anterior (eventual printr-o definiție typedef),


stâng este pointer la subarborele stâng al nodului, iar drept este pointer
la subarborele drept al nodului. Pentru identificarea rădăcinii arborelui
vom defini NODARB rad; drept un pointer la rădăcina arborelui. Daca
unul din subarbori este vid, atunci pointerul la acel subarbore este NULL.
Pentru arborele de mai sus, reprezentarea înlănțuita este:

10
Traversare

De multe ori dorim sa accesam ("vizitam") nodurile unei structuri


(lista sau arbore). Pentru arbori aceasta accesare, examinare a unui
nod, sau, mai exact, examinarea tuturor nodurilor unui arbore se
numește traversare și se poate face:
o in preordine: întâi vizitam rădăcina arborelui, apoi subarborele
stâng urmat de subarborele drept
o in inordine (simetrica): întâi vizitam subarborele stâng, , apoi
rădăcina arborelui și apoi subarborele drept
o in postordine: întâi vizitam subarborele stâng și subarborele
drept și ultima data rădăcina arborelui.
Acțiunea explicita de vizitare a unui nod depinde de scopul
traversării (de exemplu, aflarea numărului de elemente ale arborelui,
găsirea unei valori date în arbore). Pentru arborele de mai sus, de
exemplu, traversările sunt:
o preordine: 10, 4, 1, 9, 21, 15, 23, 28
o inordine (simetrica): 1, 4, 9, 10, 15, 21, 23, 28
o postordine: 1, 9, 4, 15, 28, 23, 21.

11
1.2 Arbori parțiali de cost minim

Definiție

Fie G = <X, V> un graf neorientat conex, unde X este mulțimea


vârfurilor și U este mulțimea muchiilor. Un arbore este un asemenea graf
ce nu are cicluri. Fiecare muchie are un cost pozitiv (sau o lungime
pozitiva). Pentru a găsi un arbore se pune problema sa găsim o
submulțime A inclusa în U, astfel încât toate vârfurile din X sa rămână
conectate atunci când sunt folosite doar muchii din A. Numim arbore
parțial de cost minim acel arbore ce are mulțimea vârfurilor X și a
muchiilor A iar suma lungimilor muchiilor din A este minima. Căutam deci
o submulțime A de cost total minim care sa lege printr-un drum oricare
doua noduri din X. Aceasta problema se mai numește și problema
conectării orașelor cu cost minim, având numeroase aplicații.
Graful parțial <X, A> este un arbore și este numit arborele parțial
de cost minim al grafului G (minimal spanning tree). Un graf poate avea
mai mulți arbori parțiali de cost minim.

Observații:

 In orice nod intra cel mult un arc;


 In nodul rădăcina nu intra nici un arc;
 Nodurile pot fi etichetate sau nu.

12
Înălțimea unui arbore este maximum dintre nivelele nodurilor
terminale sau echivalent 1+maximul dintre înălțimile subarborilor săi.

Exemplu: Arborele prezentat în figura de mai sus are înălțimea 5.

Reprezentarea în memorie a arborilor poate fi statica sau dinamica.


În cazul static arborii se pot simula cu ajutorul tablourilor.

Exemplu: În tabloul arbore cu n componente, arbore(i) (i=1...n)


reprezintă tatal nodului i. Astfel, arborele din figura de mai sus se poate
reprezenta sub forma:

Avantajul acestei implementări este următorul: fiecărui nod având


cel mult un tata, îi atașam în tablou o singura informație (Luam
arbore(i)=0 daca nodul i este rădăcina).

Datorita dinamismului structurilor modelate printr-un arbore,


varianta de implementare dinamica este preferabila variantei statice. în
acest caz, daca arborele este binar, o celula va conține trei câmpuri: un
câmp pentru memorarea informației specifice nodului (informația utila) și

13
doua câmpuri care conțin adresa rădăcinii subarborelui stâng, respectiv
drept.

Operațiile fundamentale asupra arborilor includ: parcurgerea


arborelui, ștergerea, căutarea sau adăugarea unui nod.

Doua tipuri de parcurgere a unui arbore sunt folosite frecvent:


parcurgerea în lățime și parcurgerea în înălțime.

In cazul parcurgerii în lățime se vizitează și prelucrează nodurile în


ordinea: rădăcina, nodurile de la stânga spre dreapta de pe primul nivel,
de pe al doilea nivel etc. Astfel, rezultatul parcurgerii în lățime a arborelui
din figura este lista de noduri 1, 2, 5, 6, 3, 4, 7, 8, 9, 10.

Putem realiza parcurgerea în lățime a unui arbore binar printr-un


algoritm care utilizează o coada drept element ajutător:

1.3 Operații pe arbori binari:

Operațiile pe arbori se grupează în următoarele categorii:


 Operații de creare a arborilor binari.

Crearea arborilor binari presupune construirea în memorie a unui


arbore binar folosind informații din mediul extern, sursele cele mai
frecvente fiind introducerea de la tastatura de către utilizator sau
fișierele. Algoritmii de creare ai unui arbore binar presupun a cunoaște
relațiile în care se află un nod cu celelalte noduri din arbore. O metodă
simplă de a specifica aceste relații este ca după crearea unui nod să se
specifice fiul stâng și fiul drept, dacă ei există.

14
 Operații cu elemente (noduri), categorie din care cele mai
importante sunt operațiile de inserare și ștergere de noduri în și
din arbore.

Deoarece operația de inserare a unui nod necesită specificarea


relației în care se află nodul respectiv cu celelalte noduri din arbore, iar
ștergerea unui nod implică formarea unor noi relații între noduri, aceste
operații sunt ușor de definit în cazul în care peste mulțimea informațiilor
din noduri există o relație de ordine.

 Traversări de arbori atât pentru prelucrarea informației utile cât și


pentru căutare de informație în arbore.

Cele mai frecvente moduri de traversare utilizate în cazul arborilor


binari sunt:
- preordine: traversarea se face prin rădăcina arborelui, apoi se
traversează subarborele stâng, iar apoi subarborele drept;
- inordine: traversarea se face începând cu subarborele stâng, apoi
prin rădăcină, iar apoi se traversează subarborele drept;
- postordine: traversarea se face începând cu subarborele stâng,
apoi se traversează subarborele drept, iar apoi rădăcina.

Algoritmul pentru operația de căutare într-un arbore binar de căutare


este următorul:
1. Se compară cheia căutate cu cheia din rădăcină;
2. Dacă sunt egale algoritmul se încheie;
3. Dacă valoarea cheii căutate este mai mică decât valoarea din
rădăcină atunci se va relua algoritmul pentru subarborele stâng.

15
Dacă nu există subarbore stâng, înseamnă că informația
căutată nu se găsește în arbore;
4. Altfel, dacă valoarea cheii căutate este mai mare decât valoarea
cheii din rădăcină, se va relua algoritmul pentru subarborele
drept. Dacă nu există subarbore drept, înseamnă că informația
căutată nu se găsește în arbore;

 Conversii și stocare în fișier.

Conversiile și stocarea în fișiere presupune traversarea arborilor și


salvarea informațiilor în alte structuri de date aflate în memorie sau în
fișiere pe medii de stocare.

16
2. ARBORE BINAR DE CĂUTARE

2.1 Descrierea generală a arborelui binar de căutare

Definiție

Se numește arborescență un arbore caracterizat astfel:


-are un vârf special numit rădăcină;
-celelalte noduri pot fi grupate în p>=0 mulțimi disjuncte,
astfel
încât fiecare dintre aceste mulțimi să conțină un nod
adiacent cu rădăcina iar subgrafurile generate de acestea să
fie la rândul lor arborescențe.

OBSERVAŢII!
1. Dacă o arborescență este formată dintr-un singur nod
spunem că este formată doar din nodul rădăcină.
2. Dacă ordinea relativă a arborescențelor, are importantă,
arborescența se numește se numește arbore ordonat.
Informația din fiecare nod este mai mare decât informația din nodul
fiului stâng și mai mică sau egală cu cea din nodul fiului drept. Un astfel
de arbore se poate reprezenta printr-o structură de date înlănțuită, în
care fiecare nod este un obiect. Pe lângă un câmp cheie și date
adiționale, fiecare obiect nod conține câmpurile stânga, dreapta și p care
punctează spre nodurile corespunzătoare fiului stâng, fiului drept și
respectiv părintelui nodului.

17
Într-un arbore binar de căutare, cheile sunt întotdeauna astfel
memorate încât ele satisfac proprietatea arborelui binar de căutare:

Fie x un nod dintr-un arbore binar de căutare. Dacă y este un nod


din subarborele stâng al lui x, atunci cheie[y]  cheie[x]. Dacă y este un
nod din subarborele drept al lui x, atunci cheie[x]  cheie[y].

Proprietatea arborelui binar de căutare ne permite să afişăm toate


cheile în ordine crescătoare, parcurgând nodurile arborelui în inordine.

Exemple:

(a) (b)

Într-o structură de date de tip arbore de căutare, informațiile, sunt


structurate pe nivele, pe primul nivel, numit nivel 0, există un singur
element numit rădăcină, de care sunt legate mai multe elemente numite
fii care formează nivelul 1; de acestea sunt legate elementele de pe
nivelul 2, ş.a.m.d. (vezi figura următoare).

18
Un arbore este compus din elementele numite noduri sau vârfuri
și legăturile dintre acestea. După cum am văzut, cea mai des utilizată
formă de organizare a unui arbore binar este următoarea:

Cheia nodului fiu stânga < Cheia nodului fiu stânga < Cheia
nodului fiu stânga

Utilizând formula de mai sus se obțin arbori binari speciali, utilizați


pentru organizarea și căutarea datelor, numiți arbori binari de căutare
ABC.
Un nod situat pe un anumit nivel este nod tată pentru nodurile
legate de el, situate pe nivelul următor, acestea reprezentând fii săi.
Arborii, ca structuri de date dinamice, au foarte multe aplicații în
informatică. Structurile arborescente sunt foarte des utilizate pentru
memorarea și regăsirea rapidă a unor informații. Informațiile sunt
organizate după un câmp numit cheie, ales de programator, care
servește la identificarea lor datelor stocate în structura arborescentă. De
exemplu, dacă datele sunt datele relative la studenții unei facultăți, atunci
cheia poate fi aleasă ca fiind numele și prenumele studentului. Cheile
trebuie alese în așa fel încât să nu apară chei duble. În exemplul nostru
relativ la studenții unei facultăți poate că ar fi mai bine să evităm
posibilitatea existenței unor chei duble, același nume și prenume, prin
introducerea inițialei tatălui, evitând astfel cheile duble.
Un arbore binar de căutare este un arbore ale cărui noduri cuprind
o singură cheie de identificare, nodurile cu chei mai mici decât o valoare
X a cheii asociate unui anumit nod se găsesc în subarborele stâng al
acestui nod, iar nodurile ale căror chei au valori mai mari decât X se
găsesc în subarborele său drept.

19
Căutarea unei informații identificate printr-o valoare X a cheii
începe de la rădăcină și se termină în cel mai rău caz la unul din nodurile
terminale, căutarea presupunând testarea a cel mult atâtea noduri câte
nivele are arborele binar de căutare. Dispunerea nodurilor arborelui pe
nivele face ca numărul operațiilor de testare la căutare să fie mult mai
mic decât în cazul listelor ordonate.
Metoda căutării binare prezentate în capitolul anterior poate fi
explicată cu ușurință cu ajutorul arborilor de căutare. Figura următoare
arată o reprezentare cu ajutorul arborilor binari al algoritmului care
corespunde cu algoritmul de căutare binară prezentat în capitolul
anterior, pentru N=10.

Fig. 2.1 - Exemplu de arbore binar de căutare

2.2 Implementarea unui nod al arborelui de căutare

Un nod al unui arbore ABC are următoarea structură:

20
Fiu_st Cheia Alte_info Fiu_dr
Structura nodului ABC.
unde:
Fiu_st : reprezintă adresa fiului stânga;
Cheia: reprezintă câmpul ales după care este ordonat ABC și care
verifică relația ;
Alte_info : alte informații adiacente;
Fiu_dr : reprezintă adresa fiului dreapta;

Structura nodului, în implementarea Pascal este următoarea :


Type
Adresa = ^Nod
Nod = RECORD
Fiu_st : Adresa;
Cheia : tipcheia;
Alte_info : tipinfo;
Fiu_dr : Adresa;
end

2.3 Operații într-un arbore de căutare

Operațiile în cazul arborilor binari de căutare sunt:

a. creare-inițializare;

b. inserare;

c. căutare;

d. ștergere;

e. traversare:

21
Deoarece operația de traversare a fost analizată și descrisă în
capitolul anterior la arbori binari, ne vom ocupa de celelalte operații
specifice arborilor binari de căutare.
a. Operația de creare-inițializare. Specificarea problemei de creare-
inițializare, având ca date de intrare ABC specificat prin adresa ROOT
a nodului rădăcină, este următoarea:

DATE root;
REZULTATE root;

Descrierea algoritmului în Pseudocod este:


ALGORITMUL CREARE_INIŢIALIZARE ESTE: { Se creează un ABC
vid }
ROOT := NIL;
SFALGORITM

b. Operația de inserare. Specificarea problemei de inserare, având


ca date de intrare ABC cu adresa nodului rădăcină ROOT și datele de
inserat cheia_nou, info_nou, este următoarea:
DATE ROOT, cheia_nou, info_nou;
REZULTATE ROOT;
Vom folosi subalgoritmul numit Creare_nod care va aloca dinamic
spațiul de memorie necesar noului nod de inserat și va completa
câmpurile nodului ABC.
OBS. : Vom folosi în cele ce urmează o referință de tip Pascal pentru
algoritmul în Pseudocod, și anume:
adresa^.câmp

22
unde adresa reprezintă variabila de tip adresă a nodului, iar câmp
reprezintă numele câmpului nodului. Descrierea algoritmului în
Pseudocod este:
SUBALGORITMUL Creare_nod (ch, inf) ESTE:
@Alocare_spaţiu (NOU); { cererea de alocare spaţiu pentru un nod }
NOU^.fiu_st := NIL; { sistemul returnează adresa noului nod în variabila
adresă NOU }
NOU^.fiu_dr := NIL;
NOU^.cheia := ch;
NOU^.info := inf;
SF-Creare_nod

ALGORITMUL INSERARE ESTE: { Se inserează un nod nou ca nod


terminal, prima dată se caută nodul
tată }
CITEŞTE cheia_nou, info_nou;
DACĂ ROOT = NIL ATUNCI { primul nod inserat }
CHEAMĂ Creare_nod (cheia_nou, info_nou); { se alocă spaţiu pentru
noul nod de }
ROOT = NOU; { inserat la adresa NOU și se completează
câmpurile }
EXIT;
SFDACĂ
tmp := ROOT;
CÂTTIMP tmp <> NIL EXECUTĂ
Tata := tmp;
DACĂ cheia_nou < tmp^.cheia
ATUNCI tmp := tmp^.fiu_st;
ALTFEL DACĂ cheia_nou > tmp^.cheia
ATUNCI tmp := tmp^.fiu_dr;
ALTFEL
TIPĂREŞTE (‘EROARE – CHEIE DUBLĂ);
EXIT;
SFDACĂ
SFDACĂ
SFCÂT
CHEAMĂ Creare_nod (cheia_nou, info_nou);
DACĂ cheia_nou < tata^.cheia
ATUNCI
tata^.fiu_st := NOU;
ALTFEL
tata^.fiu_dr := NOU;

23
SFDACĂ
SFALGORITM

c. Operația de căutare. Specificarea problemei de căutare, având ca


date de intrare ABC cu adresa nodului rădăcină ROOT și cheia
nodului căutat cheia_caut, este următoarea:
DATE root, cheia_caut;
REZULTATE adresa;
Obs. : adresa returnată de algoritmul de căutare este adresa nodului cu
cheia cheia_caut, dacă acesta există.
ALGORITMUL CAUTĂ ESTE:
CITEŞTE cheia_caut;
tmp := ROOT;
CÂTTIMP (tmp <> NIL) EXECUTĂ
DACĂ cheia_caut < tmp^.cheia
ATUNCI tmp := tmp^.fiu_st;
ALTFEL
DACĂ cheia_caut > tmp^.cheia
ATUNCI tmp := tmp^.fiu_dr;
ALTFEL @returnează adresa tmp;
SFDACĂ
SFDACĂ
SFCÂT
@returnează adresa NIL;
SFALGORITM

d. Operația de ștergere. Specificarea generală a problemei de


ștergere este:

DATE root, cheia_de_sters;

24
REZULTATE root;

Există mai multe situații posibile, în funcție de numărul de fii ai nodului


de șters :

Cazul 1: nodul de șters este un nod terminal, deci fără fii. Operația de
ștergere necesită eliminarea legăturii nod_tată și nod_de_şters și
eliberarea spațiului ocupat de nodul de șters.
Exemplu: nodurile cu cheia 1, 4, 7, 10 din ABC figura 2.1.

Cazul 2: nodul de șters este un singur fiu. Operația de ștergere


necesită realizarea legăturii nod_tată și nod_de_fiu (stânga sau dreapta)
și eliberarea spațiului ocupat de nodul de șters.
Exemplu: nodurile cu cheia 3, 6, 9 din ABC figura 2.1.

Cazul 3: nodul de șters este doi fii. În această situație nodul de șters
trebuie înlocuit și abia după aceea poate fi eliminat. Nodul înlocuitor
poate fi nodul cu cheia cea mai mare din punct de vedere lexicografic din
subarborele stâng al nodului de șters sau nodul cu cheia cea mai mică
din subarborele drept al nodului de șters.
Exemplu: nodurile cu cheia 2, 5, 8 din ABC figura 2.1. Nodul înlocuitor
al nodului cu cheia 2 este nodul cu cheia 1 din subarborele stâng sau
nodul cu cheia 3 din subarborele său drept. Nodul înlocuitor al nodului cu
cheia 5 este nodul cu cheia 4 din subarborele stâng sau nodul cu cheia 6
din subarborele său drept. Nodul înlocuitor al nodului cu cheia 8 este
nodul cu cheia 7 din subarborele stâng sau nodul cu cheia 9 din
subarborele său drept.

Obs.: Pentru a găsi nodul înlocuitor al unui nod de șters în Cazul 3,


acesta poate fi găsit astfel: Dacă nodul înlocuitor este nodul cu cheia cea
mai mare din punct de vedere lexicografic din subarborele stâng al

25
nodului de șters atunci se navighează de la nodul de șters un pas la
stânga și oricâți pași la dreapta, până ajungem la o legătură nulă.

Descrierea generală a algoritmului de ștergere, în Pseudocod este:

ALGORITMUL ŞTERGERE ESTE:


CITEŞTE cheia_de_sters;
DACĂ ROOT = NIL ATUNCI
TIPĂREŞTE (‘EROARE – ARBORE VID’);
EXIT;
SFDACĂ
tmp := ROOT; { Se caută nodul de șters }

CÂTTIMP (tmp <> NIL) și (cheia_de_sters <> tmp^.cheia) EXECUTĂ


Tata := tmp;
DACĂ cheia_nou < tmp^.cheia
ATUNCI tmp := tmp^.fiu_st;
ALTFEL tmp := tmp^.fiu_dr;
SFDACĂ
SFCÂT
DACA tmp = NIL ATUNCI
TIPĂREŞTE (‘EROARE – NODUL NU EXISTĂ ÎN ABC’);
EXIT;
SFDACĂ
DACĂ tmp^.fiu_st = NIL și tmp^.fiu_dr = NIL ATUNCI
CHEAMĂ Cazul_1 (ROOT, tata, tmp); { Cazul 1 }
EXIT;
SFDACĂ
DACĂ tmp^.fiu_st = NIL xor tmp^.fiu_dr = NIL ATUNCI
CHEAMĂ Cazul_2 (ROOT, tata, tmp); { Cazul 2 }
EXIT;
SFDACĂ
CHEAMĂ Cazul_3 (ROOT, tata, tmp); { Cazul 3 }
SFALGORITM

SUBALGORITMUL Cazul_1 (rad, t, adr) ESTE:


DACĂ t^.fiu_st = adr ATUNCI
t^.fiu_st := NIL;
ALTFEL
t^.fiu_dr := NIL;
@Eliberare spaţiu (adr); { Eliberarea spațiului de la adresa adr
}

26
SF-Cazul_1

SUBALGORITMUL Cazul_2 (rad, t, adr) ESTE:


DACĂ t^.fiu_st = adr ATUNCI { Nodul de șters este fiul stânga al nodului
tata }
DACĂ adr^.fiu_st = NIL ATUNCI
t^.fiu_st := adr^.fiu_dr;
ALTFEL
t^.fiu_st := adr^.fiu_st;
ALTFEL { Nodul de șters este fiul dreapta al nodului
tata }
DACĂ adr^.fiu_dr = NIL ATUNCI
t^.fiu_dr := adr^.fiu_st;
ALTFEL
t^.fiu_dr := adr^.fiu_dr;
@Eliberare spaţiu (adr); { Eliberarea spațiului de la adresa adr
}
SF-Cazul_2

SUBALGORITMUL Cazul_3 (rad, t, adr) ESTE:


tmp := adr^.fiu_st; { Se caută nodul înlocuitor – un pas la
stînga}
tata := tmp;
CÂTTIMP tmp^.fiu_dr <> NIL EXECUTĂ { Oricâţi pași la dreapta}

tata := tmp;
tmp := tmp^.fiu_dr; { Adresa tatălui nodului înlocuitor este în variabila
tata}
SFCÂT { Adresa nodului înlocuitor este în variabila tmp}
adr^.cheia := tmp^.cheia; { Înlocuim nodul de șters cu nodul înlocuitor}
adr^.info := tmp^.info; { Înlocuim nodul de șters cu nodul înlocuitor}
tata^.fiu_dr := tmp^.fiu_st; { Eliminăm legătura tata - nodul înlocuitor}
@Eliberare spaţiu (tmp); { Eliberarea spațiului nod înlocuitor de la adresa
tmp }
SF-Cazul_3

27
3. STUDIU DE CAZ-APLICAȚII

Problema arborilor asociați expresiilor aritmetice.

Fiind date n expresii aritmetice sintactic corecte care cuprind paranteze,


operanzi notați cu literele mici din alfabet și operatori binari sau unari din
mulțimea {+, -, *, / }, să se construiască și să se afișeze în postordine
arborele binar asociat fiecărei expresii.

Arborele binar asociat expresiei aritmetice - (a + b)*c - d este prezentat


în figura următoare:

Se observă că rădăcina cuprinde simbolul ultimei operații,


subarborele stâng, iar nodul din dreapta corespunde operandului drept;
aceeași regulă se aplică subarborilor. Operatorul "-" unar din expresie s-
a transformat în arborele binar în "&" pentru a-l distinge de cel binar;
nodul asociat operatorului are numai subarbore drept ( operația este
unară ).

28
Existenta operatorilor "+" sau "-" unari modifică numai diagrama de
sintaxă a expresiei aritmetice ( vezi figura ), celelalte rămânând
neschimbate.

Program arbori_asociati_expresiilor_aritmetice ;
type
reper =^nod ;
nod = record
v : char ;
stg, dr : reper ;
end ;
var
rad : reper ;
x : pointer ;
i, n : byte ;
car : char ;

procedure citire ;
begin
if not eoln then read(car)
end ;

procedure postordine ( p : reper );


begin
if p < > NIL then
begin
postordine (p ^.stg) ;
postordine (p ^.dr) ;
write(p ^.v);
end ;
end ;

29
procedure expresie (var p : reper ) ; forward ;
procedure termen (var p : reper ) ; forward ;
procedure factor (var p : reper ) ;
{ creeaza nodul terminal p^ sau subarborele de rădăcina p^ }
{ asociat unei expresii aritmetice cuprinsa între () }
begin
if car = '(' then
begin
citire ;
expresie (p) ; { aici car =) }
end ;
else
begin
new(p) ;
p ^.v := car ;
p ^.stg := NIL ;
p ^.dr := NIL ;
end ;
citire ;
end ;

procedure termen ;
var q : reper ;
begin
factor ( p ) ;
while car în [ '*', '/' ] do
begin
new ( q ) ;
q ^.v := car ;
q ^.stg := p ;
citire ; { operandul 2 începe după car }
factor (q ^. dr) ; { creează și leagă în dr. nodului q ^ }
p := q ; { subarb. asociat operandului 2 al lui car }
end ;
end ;

procedure expresie ;
var q : reper ;
begin
if car în [ '+', '-' ] then { expresia începe cu + sau - }
if car = '-' then
begin { car = - unar }
new ( p ) ;

30
p ^.v := '$' ; { $= - unar }
p ^.stg := NIL ;
citire ;
termen(p ^.dr) ;
end
else
begin { car =+ unar }
citire ;
termen ( p );
end
else termen ( p ) ;
while car în [ '+', '-' ] do
begin
new ( q ) ;
q ^.v := car ;
q ^.stg := p ;
citire ;
termen ( q ^.dr) ;
p := q;
end
;
BEGIN { programul principal }
mark (x) ; {retine vârful zonei HEAP }
write (' n=') ; readln (n);
for i:= 1 to n do
begin
read ( car ) ;
expresie ( rad ) ;
postordine (rad );
writeln ;
readln ;
release (x) ; { eliberează memoria ocupata dinamic }
end ;
END.
Pentru n=2 vom obține rezultatul :

(a+b)*(c-d)
abc+cd-*
-a+b
a$b+

31
BIBLIOGRAFIE

1. V.Huţanu, T.Sorin – Manual de informatică, Ed.L&S Soft,


Bucureşti, 2006
2. E. Cerchez, M. Şerban – Programarea în limbajul C/C++ pentru
liceu, Ed. Polirom, Bucureşti 2007
3. ***www.cs.utcluj.ro,13.06.2009
4. ***www.labs.cs.utt.ro,15.06.2009
5. ***www.facultate.regielive.ro,14-15.06.2009
6. ***www.didactic.ro,12.06.2009
7. ***www.infoscience.3x.ro,14.06.2009

32

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