You are on page 1of 51

1.

Noţiuni introductive
Există mai multe moduri echivalente de definire a arborilor. Din
punctul de vedere al teoriei grafurilor numim arbore un graf neorientat
conex şi fără cicluri. Dacă graful este aciclic, dar nu este conex îl vom
numi pădure.
De exemplu,

Fig. 1.
a. este arbore, b. este pădure, nefiind conex, iar c. nu este nici arbore,
nici pădure, deoarece conţine cicluri.

1.1. Proprietăţi ale arborilor

Teorema 1
Fie G = (V, U) un graf neorientat. Următoarele afirmaţii sunt
echivalente:
1) G este arbore.
2) Oricare două vârfuri din G sunt unite printr-un lanţ simplu
unic.
3) G este conex minimal (dacă suprimăm o muchie, graful
obţinut este neconex).
4) G este conex şi are V-1 muchii.
5) G este aciclic şi are V-1 muchii.
6) G este aciclic maximal (dacă adăugăm o muchie, graful
obţinut conţine cicluri).
Demonstraţie:
1 ⇒2
Dacă G este arbore, atunci G este conex, deci oricare ar fi două
vârfuri din graf, acestea sunt unite prin cel puţin un lanţ simplu.
Presupunem prin reducere la absurd că există x şi y două vârfuri unite
prin două lanţuri simple distincte l1 şi l2 .

5
Fig. 2.
Fie z primul vârf de la care cele două lanţuri se despart, iar t
primul vârf în care cele două lanţuri se întâlnesc din nou. Dacă notăm
l'1 porţiunea de pe lanţul l1 între z şi t, iar cu l'2 porţiunea de pe lanţul l2
între z şi t, atunci l'1 şi l'2 nu au vârfuri comune, cu excepţia vârfurilor z
şi t. Concatenând l'1 şi l'2, obţinem un ciclu- contradicţie cu ipoteza că
G este arbore. Deci, oricare două vârfuri din graf sunt unite printr-un
lanţ simplu unic.
2 ⇒3
Dacă oricare două vârfuri x, y∈V sunt unite printr-un lanţ
simplu unic, atunci orice muchie [x, y]∈U reprezintă unicul lanţ dintre
x şi y. Suprimând muchia [x, y], între x şi y nu va mai exista lanţ, deci
graful obţinut nu va mai fi conex.
3 ⇒4
Notăm cu n numărul de vârfuri şi cu m numărul de muchii din
graf.
Pentru a demonstra că orice graf conex minimal are n-1 muchii
vom demonstra prin inducţie completă după n că m ≤ n-1. Cum în
orice graf conex m ≥ n-1, deducem m = n-1.
P(1) Dacă n = 1, atunci m = 0 ⇒ m = n-1.
P(2) Dacă n = 2, atunci m = 1 ⇒ m = n-1.
P(n) Presupunem că într-un graf conex minimal cu cel
mult n vârfuri numărul de muchii este strict mai mic decât numărul de
vârfuri.
P(n+1) Demonstrăm că într-un graf conex minimal cu
n+1 vârfuri, numărul de muchii este cel mult egal cu n.
Fie G conex minimal cu n+1 vârfuri şi m muchii. Eliminând o
muchie oarecare din graf obţinem un graf G' cu m-1 muchii şi două
componente conexe C1 şi C2 cu n1, respectiv n2 vârfuri (n1+n2 = n+1) şi
m1, respectiv m2 muchii (m1+m2 = m-1). Subgrafurile C1 şi C2 sunt
conexe minimale, altfel graful G nu ar fi conex minimal. Din ipoteza
inductivă rezultă că m1 ≤ n1-1, m2 ≤ n2-1; dar m1+m2 = m-1 ≤ n1+n2 =
n-2 ⇒ m ≤ n-1. Deci G conex minimal implică G conex cu n-1 muchii.

4 ⇒5
Fie G un graf conex cu n-1 muchii. Să demonstrăm că G este
6
aciclic.
Presupunem prin reducere la absurd, că graful G conţine un
ciclu C format din vârfurile v1, v2, ..., vk.
Să considerăm subgraful parţial Gk = (Vk, Uk) constând din
ciclul C. Deci Vk = {v1, v2 ,..., vk}, iar Uk = {[v1,v2)], [v2,v3],...,[vk-1,vk],
(vk,v1]} (Vk=Uk= k). Dacă Vk<V, atunci ∃ vi∈Vk şi vk+1∈V-Vk
astfel încât [vi, vk+1]∈U, graful G fiind conex.
Construim Gk+1 = (Vk+1, Uk+1) astfel :Vk+1 = Vk ∪{vk+1};
Uk+1= Uk∪{[vi,vk+1]} şi Uk+1=Vk+1=k+1.
Cât timp k+1 < n, aplicăm acelaşi procedeu până când obţinem
un graf Gn = (V, Un), cu Un= n, Un ⊆ U; deci U ≥ n, contradicţie
cu ipoteza U= n-1.
5 ⇒6
Presupunem că graful G este aciclic cu n-1 muchii, să
demonstrăm că G este aciclic maximal.
Fie C1, C2,..., Cp cele p componentele conexe ale grafului G,
având respectiv n1, n2,..., np vârfuri şi m1, m2,..., mp muchii fiecare.
Evident că n1+n2+...+np = n şi m1+m2+...+mp = n-1.
Cum graful G este aciclic, deducem că fiecare componentă conexă este
un arbore. Deoarece am demonstrat că 1 ⇒ 5, rezultă că m i= ni-1,
∀i∈{1, 2, ..., p}. Înlocuind în relaţia de mai sus, obţinem n-p = n-1 ⇒
p = 1, deci G conex. Dacă G este conex şi aciclic, conform definiţiei G
este arbore. Dar am demonstrat că 1 ⇒ 2, deci oricare două vârfuri din
G sunt unite printr-un lanţ simplu. Astfel, adăugând orice muchie
obţinem un ciclu.
6 ⇒1
Presupunem că graful G este aciclic, dar dacă am mai adăuga o
muchie s-ar obţine un ciclu. Să demonstrăm că G este conex.
Fie u şi v două vârfuri neadiacente din graf, arbitrar alese.
Deoarece adăugând muchia [u, v] se obţine un ciclu, rezultă că u şi v
sunt unite printr-un lanţ ale cărui muchii aparţin grafului G. Cum u,v au
fost alese arbitrar, deducem că graful G este conex.
Q.E.D.
Teorema 2
Numerele întregi 0 < d1 ≤ d2 ≤ ...≤ dn (n ≥ 2) sunt gradele
vârfurilor unui arbore dacă şi numai dacă d1+d2+...+dn = 2n-2.

Demonstraţie:
Necesitatea Condiţia este necesară, deoarece orice arbore cu n vârfuri
are n-1 muchii, iar suma gradelor vârfurilor oricărui graf este de două
ori numărul de muchii. Deci d1+d2+...+dn = 2n-2.

7
Suficienţa Fie 0 < d1 ≤ d2 ≤ ...≤ dn astfel încât d1+d2+...+dn = 2n-2.
Să demonstrăm că există un arbore cu gradele vârfurilor d1, d2,..., dn.
Vom proceda prin inducţie.
P(2) Dacă d1+d2 = 2, atunci d1 = d2 = 1 , arborele fiind cel
din figura de mai jos :

Fig. 3
P(n) Presupunem acum că proprietatea este adevărată pentru
orice secvenţă de n numere naturale 0 < d1 ≤ d2 ≤ ...≤ dn, astfel încât
d1+d2+...+dn = 2n-2.
P(n+1) Să demonstrăm că pentru orice secvenţă 0 < d'1 ≤ d'2
≤ ...≤ d'n ≤ d'n+1 astfel încât d'1+d'2+...+d'n+1 = 2n, există un arbore cu
n+1 vârfuri cu secvenţa gradelor d'1, d'2, ..., d'n+1.
Observăm că există măcar un nod terminal x1 cu gradul d'1= 1,
altfel dacă di ≥ 2,∀i∈{1, 2,..., n+1} ⇒ d'1+d'2+...+d'n+1 ≥ 2(n+1), ceea
ce contrazice ipoteza. În mod analog, observăm că există măcar un nod
neterminal xn+1, cu gradul d'n+1 > 1, altfel dacă d'i = 1,∀i∈{1, 2, ..., n+1}
⇒ d'1+d'2+...+d'n+1 = n+1 < 2n .
Să considerăm următoarea secvenţă de n numere întregi d'2,...,
d'n, d'n+1-1 cu proprietatea că d'2+...+d'n+d'n+1 = 2n-2. Din ipoteza
inductivă există un arbore An cu n vârfuri şi secvenţa gradelor d'2,..., d'n,
d'n+1-1. Adăugăm la arborele An un vârf pe care îl unim printr-o muchie
cu vârful având gradul d'n+1-1. Obţinem un arbore An+1 cu gradele
vârfurilor d'1, d'2,..., d'n+1.
Q.E.D.

Demonstraţia acestei teoreme oferă şi o soluţie constructivă


pentru obţinerea unui arbore cu secvenţa gradelor dată.
Vom reţine gradele vârfurilor într-un vector d de dimensiune n,
ordonat crescător, cu suma componentelor egală cu 2n-2.
Arborele va fi reprezentat prin matricea muchiilor, o matrice a
cu două linii şi n-1 coloane, în care pentru fiecare muchie din arbore
vom reţine extremităţile.
Spre deosebire de ideea din demonstraţie, pentru a conserva
ordinea în vectorul d, la fiecare pas al algoritmului gradul care va fi
decrementat va fi primul grad mai mare ca 1 şi nu ultimul.

Procedure Determinare Arbore;*


*
Programul Construcţie-Arbore-cu-Secvenţa-Gradelor-Dată de la sfârşitul
capitolului curent generează un arbore având secvenţa gradelor dată.

8
//vectorul d, matricea a şi n, numărul de vârfuri, sunt variabile globale
var NrMuchiiSelectate, VfTerminal, VfNeterminal: Integer;
begin
NrMuchiiSelectate := 0;
VfTerminal := 1;
while NrMuchiiSelectate < n-1 do
begin //selectez o muchie în arbore
VfNeterminal := VfTerminal + 1;
//caut un vârf cu grad mai mare decât 1
while d[VfNeterminal] = 1 do inc(VfNeterminal);
inc(NrMuchiiSelectate);
//selectez muchia [VfTerminal,VfNeterminal]
a[1,NrMuchiiSelectate] := VfTerminal;
a[2,NrMuchiiSelectate] := VfNeterminal;
dec(d[VfNeterminal]);
inc(VfTerminal);
end;
end;

De exemplu, pentru n = 11 şi şirul gradelor:


1 2 3 4 5 6 7 8 9 1 11
0
1 1 1 1 1 1 1 2 3 4 4
obţinem arborele din figura 4.

Fig. 4
Acest procedeu sugerează o metodă foarte eficientă de
reprezentare a arborilor. Dacă An este un arbore cu vârfurile x1, x2,.., xn,
suprimăm vârful terminal cu cel mai mic indice şi muchia incidentă cu
acesta şi reţinem a1, vârful adiacent cu vârful terminal suprimat. Am
obţinut astfel un subgraf cu n-2 muchii conex şi aciclic, deci un arbore
An-1. Repetăm procedeul pentru arborele An-1, determinând un al doilea
vârf, a2, adiacent cu vârful terminal de indice minim ce va fi eliminat
din An-1 împreună cu muchia incidentă cu el ş.a.m.d., până când se
obţine un arbore A2 cu două vârfuri adiacente.
9
Am obţinut astfel un sistem {a1, a2,.., an-2} de n-2 numere
1≤ ai≤ n, ∀i∈{1,2,...,n-2} asociat arborelui An numit codul Prüffer al lui
An .
Pentru arborele din figura 4, codul Prüffer este
a={ 8,9,9,10,10,10,11,11,11}.
Propoziţie
Există o corespondenţă biunivocă între mulţimea arborilor A cu
n vârfuri şi mulţimea sistemelor {a1, a2, ..., an-2}, ai∈{1,2,...,n},
∀i∈{1,2,...,n-2} .
Demonstraţie:
Injectivitatea
Fie a={ a1, a2, ..., an-2}, 1 ≤ ai ≤ n, ∀i∈{1,2,...,n-2}, codul Prüffer
al unui arbore A. Completăm şirul cu an-1 = n, deci a = {a1,a2,...,an-2,an-
1}.
Să notăm b = (b1, b2, ..., bn-2, bn-1) indicii vârfurilor în ordinea
în care au fost eliminate. Observăm că :
1. bi ≠ bj, ∀i ≠ j (deoarece un nod nu poate fi eliminat decât o
dată);
2. bi ≠ ai (pentru că există muchia [ai, bi]);
3. bi ≠ aj, ∀j > i (bi fiind eliminat la pasul i, nu mai poate fi
părintele unui alt vârf eliminat ulterior);
4. ∀ k ∈{b1, b2, ..., bi-1, ai, ai+1, ..., an-1}, k este un vârf terminal al
arborelui A-{b1, b2, ..., bi-1}, altfel k ar fi adiacent cu un vârf ce va fi
suprimat ulterior, deci k = aj, cu j > i- contradicţie (un vârf care nu a
fost eliminat şi care nu este părinte pentru un alt vârf, este vârf
terminal).
5. bi, din modul de definire a codului Prüffer va fi :
bi = min{ k k∉{b1, b2, ..., bi-1, ai, ai+1, ..., an-1}} (*)
Deci din codul Prüffer am putut determina în mod unic ordinea
de eliminare a vârfurilor şi implicit, muchiile arborelui
A={[ai, bi], i ∈{1, 2, ..., n-1}}

Surjectivitatea
Demonstrăm că ∀a = {a1, a2, ..., an-2}, 1 ≤ ai ≤ n, ∀i∈{1,2,...,n-
2}, există un arbore A cu n vârfuri astfel încât codul Prüffer al lui A să
fie şirul a.
Completăm a cu an-1 = n şi definim bi conform relaţiei (*),
∀i∈{1, 2, ..., n-1}. Construim A, graful cu muchiile U = {[ai, bi],
∀i∈{1, 2, ..., n-1}}. Vom arăta că A este arbore şi codul Prüffer al lui A
este {a1, a2, ..., an-2}.

10
Notăm Ui = U-{[b1, a1],...,[bi-1, ai-1]}, ∀i∈{1,2,...,n-1},
Vi = {1,2,...,n}-{b1, b2, ..., bi-1}.
Evident A = A1, iar An este format numai din vârful n, deci An este
arbore.
Să demonstrăm că bi este vârf terminal în Ai.
bi = min{ k k∉{b1, b2, ..., bi-1, ai, ai+1, ..., an-1}}
Dar ai∈Ai, pentru că din relaţia (*) ai ≠ bj,∀j < i, iar bi nu poate
fi adiacent în Ai decât cu ai, deoarece, dacă bi ar fi incident cu o altă
muchie [bj, aj], j > i din Ai ar însemna că bi = bj sau aj = bi, cu j > i ceea
ce este în contradicţie cu definiţia lui bi.
Ai-1 se obţine din Ai eliminând vârful terminal bi şi muchia [bi,
ai], incidentă cu aceasta. Procedând inductiv, cum An este arbore,
deducem că Ai, i∈{1,...,n} sunt arbori, în particular A este arbore.
Tot din definirea lui bi rezultă că bi este vârful terminal de indice
minim, deci, conform definiţiei, {a1, a2, ..., ai-2} va fi codul Prüffer al
arborelui Ai. În particular deducem că {a1 ,a2, ..., an-2} este codul Prüffer
al arborelui A.
Q.E.D.
Să considerăm, de exemplu, n = 11 şi a = {1,2,2,2,1,4,4,1,5}.
Pentru a determina muchiile arborelui cu acest cod Prüffer, completăm
codul cu a10= 11. Deci a={ 1,2,2,2,1,4,4,1,5,11} şi determinăm :
b1 = min { kk∉{1,2,2,2,1,4,4,1,5,11}}=3
b2 = min { kk∉{3,2,2,2,1,4,4,1,5,11}}=6
b3 = min { kk∉{3,6,2,2,1,4,4,1,5,11}}=7
b4 = min { kk∉{3,6,7,2,1,4,4,1,5,11}}=8
b5 = min { kk∉{3,6,7,8,1,4,4,1,5,11}}=2
b6 = min { kk∉{3,6,7,8,2,4,4,1,5,11}}=9
b7 = min { kk∉{3,6,7,8,2,9,4,1,5,11}}=10
b8 = min { kk∉{3,6,7,8,2,9,10,1,5,11}}=4
b9 = min { kk∉{3,6,7,8,2,9,10,4,5,11}}=1
b10 = min { kk∉{3,6,7,8,2,9,10,4,1,11}}=5
Muchiile arborelui sunt : [1,3], [2,6], [2,7], [2,8], [1,2], [4,9], [4,10],
[1,4], [5,1], [5,11].

Fig. 5

11
Folosind acest rezultat, deducem că numărul arborilor ce se pot
construi cu n vârfuri date este egal cu nn-2, numărul funcţiilor bijective
definite pe o mulţime cu n-2 elemente, cu valori într-o mulţime cu n
elemente. Această formulă poartă numele de formula lui Cayley.

Aplicaţie*
Generaţi toţi arborii cu n vârfuri.
Problema se reduce la generarea tuturor funcţiilor
a:{1,2,...,n-2} → {1,2,...,n}
şi determinarea arborelui corespunzător fiecărei funcţii.
Vom genera toate codurile Prüffer posibile recursiv, apelând procedura
generare(1).

procedure generare(i:byte);
//poziţiile 1,2,...,i-1 din vectorul global a sunt fixate;
// completăm poziţiile i,...,n-2.
begin
if i = n-1 then // codul este complet
determina_arbore
else
for j := 1 to n do
begin
a[i] := j;
generare(i + 1);
end;
end;

procedure determina_arbore;
// afişează muchiile arborelui;
var k, i: byte;
MB: set of byte;
//mulţimea vârfurilor care au fost deja eliminate din arbore
MA: set of byte;
//mulţimea vârfurilor pentru care trebuie să determinăm nodul
// terminal adiacent
begin
MB := []; MA := [a1, a2, ..., an-1];
for i := 1 to n - 1 do //determin cele n-1 muchii ale arborelui
begin
*
Programul Generare-Arbori-cu-n-Varfuri de la sfârşitul capitolului curent
generează toţi arborii cu n vârfuri date.

12
//calculez k, vârful de indice minim ce ∉ MA∪ MB
k := 1;
while k in MA + MB do inc(k);
MB := MB + [k];
// k este nodul terminal de indice minim căutat
MA := MA - [ai];
write(k, ai,); //afişez muchia [k,ai]
end;
end;

1.2. Arbori cu rădăcină

Pentru problemele în care se impune o ierarhizare a


informaţiilor ce corespund vârfurilor arborelui, astfel încât anumite
vârfuri să fie subordonate altora, este utilă introducerea unei noi
noţiuni- arbore cu rădăcină. Arborii cu rădăcină sunt o prezenţă
cotidiană. Fiecare şi-a reconstituit la un moment dat arborele genealogic
şi, după cum vom vedea, cea mai mare parte a termenilor folosiţi în
limbajul informatic derivă de aici. Un alt exemplu este modul de
organizare a competiţiilor sportive sau organigrama unei întreprinderi.
În multe alte exemple îi veţi întâlni pe parcursul acestei cărţi.
Definiţie
Un arbore cu rădăcină este o mulţime finită de noduri care fie
este vidă fie
- există un nod special numit rădăcina arborelui;
-toate celelalte noduri sunt partiţionate în n ≥ 0 clase A1, A2, ...,
An, fiecare clasă fiind un arbore cu rădăcină. Rădăcina arborelui este
unită prin muchii de rădăcinile arborilorA1, A2, ..., An.

Fig.6.
Definiţia este recursivă, orice nod al unui arbore fiind rădăcina
unui subarbore.
Să observăm că alegând într-un mod arbitrar un vârf drept
rădăcină, orice graf neorientat conex şi fără cicluri este un arbore cu
rădăcină în sensul definiţiei de mai sus. Arborii A1, A2, ..., An se numesc
subarborii rădăcinii, numărul de subarbori nevizi ai unui nod fiind
13
numit gradul nodului respectiv.
De exemplu,

Fig. 7.
Să observăm că definiţia conduce la o ierarhizare a nodurilor
arborelui :
- considerăm că rădăcina r se situează pe nivelul 0.
- dacă notăm cu r1, r2, ..., rn respectiv rădăcinile arborilor A1, A2,
..., An, nodurile r1, r2, ..., rn vor constitui nivelul 1 în arbore, ş.a.m.d.
Nodurile r1, r2, ..., rn, se numesc fiii nodului rădăcină, iar
rădăcina r reprezintă părintele nodurilor r1, r2, ..., rn, rădăcina fiind
singurul nod din arbore care nu are părinte. Fiecărei muchii din arbore
îi putem asocia o orientare de la părinte spre fiu. În plus, fiii nodurilor
de pe nivelul i≥ 0, vor constitui nivelul i+1.
Nivelul maxim din arbore va constitui înălţimea (adâncimea)
arborelui respectiv. Să observăm că orice nod x poate fi atins din
rădăcină pe un drum unic. Orice nod y care se găseşte pe drumul unic
de la r la x se numeşte ascendent (strămoş) al lui x. Dacă y este un
ascendent al lui x, atunci x se numeşte descendent al lui y. Mai exact,
toţi descendenţii unui nod x sunt nodurile din subarborele cu rădăcina x.
Dacă un nod nu are descendenţi el se numeşte nod terminal sau frunză.
Două noduri care au acelaşi părinte se numesc fraţi.
În exemplul de mai sus, 4 este un ascendent al lui 8. Nodurile 5,
6, 3, 8, 9 sunt noduri terminale. Nodurile 8, 9 sunt fraţi, iar descendenţii
nodului 4 sunt nodurile 7, 8, 9.

1.3. Arbori binari

O clasă foarte importantă de arbori cu rădăcină o constituie


arborii binari. Un arbore binar este un arbore cu rădăcină în care gradul
oricărui vârf este cel mult egal cu doi. Putem defini recursiv arborii
binari astfel :
Definiţie
Un arbore binar este un arbore care fie este vid, fie constă

14
dintr-un nod rădăcină şi doi arbori binari disjuncţi numiţi subarborele
stâng, respectiv subarborele.

Fig. 8.
A1 = subarbore stâng; A2 = subarbore drept.
Se face o distincţie clară între subarborele drept şi cel stâng.
Dacă subarborele stâng este nevid, rădăcina lui se numeşte fiul stâng al
rădăcinii. Analog, dacă subarborele drept este nevid, rădăcina lui se
numeşte fiul drept al rădăcinii.
De exemplu,

Fig. 9.
sunt doi arbori binari distincţi.
În continuare, terminologia folosită la arbori cu rădăcină se va
aplica şi la arbori binari. Vom deosebi între arborii binari câteva clase
speciale:
1. Arbori binari stricţi sunt arborii binari în care orice vârf are
gradul zero (este terminal ) sau doi (are exact doi fii).
De exemplu, arborii din figura 9 nu sunt arbori binari stricţi (nodurile 2
şi 6 având un singur fiu), dar

Fig. 10.
este un arbore binar strict.
2. Arbori binari plini sunt arbori binari care au 2k-1 vârfuri

15
dispuse pe nivelurile 0, 1, ... , k-1, astfel încât pe fiecare nivel i se
găsesc 2i vârfuri.
De exemplu, arborele binar plin cu înălţimea 2 este:

Fig. 11.
3. Arborii binari compleţi sunt arbori binari care se obţin
dintr-un arbore binar plin prin eliminarea din dreapta către stânga a
unor noduri de pe ultimul nivel. Mai exact, pentru a construi un arbore
binar complet cu n noduri, determinăm k astfel încât
2k ≤ n < 2k+1 ⇔ k = [log2n].
Construim arborele binar plin cu 2k+1-1 noduri şi eliminăm de pe
ultimul nivel nodurile 2k+1-1, 2k+1-2, ..., n+1.
De exemplu, arborele binar complet cu 5 vârfuri se obţine prin
eliminarea vârfurilor 7 şi 6 din arborele binar plin cu înălţimea 2 :

Fig. 12.
4. Arbori binari degeneraţi- sunt arbori binari cu n vârfuri
dispuse pe n niveluri.
De exemplu,

Fig. 13.
5. Arbori binari echilibraţi - sunt arbori binari în care, pentru
orice nod, numărul nodurilor din subarborele drept şi numărul nodurilor
din subarborele stâng diferă cu cel mult o unitate.
De exemplu,

16
Fig. 14.

1.3.1 Proprietăţi ale arborilor binari

Proprietatea 1.
Numărul maxim de noduri de pe nivelul i al unui arbore binar este 2i.
Demonstraţie:
Vom proceda prin inducţie după numărul nivelului.
P(0) Pe nivelul i = 0 se găseşte un singur nod (rădăcina).
P(k) Presupunem că numărul maxim de noduri de pe nivelul k este
2k .
P(k+1) Vom demonstra că pe nivelul k+1 sunt cel mult 2k+1 noduri.
Pe nivelul k+1 se găsesc fiii nodurilor de pe nivelul k. Din ipoteza
inductivă, pe nivelul k se găsesc cel mult 2k noduri, iar fiecare nod
poate avea cel mult doi fii, deci pe nivelul k+1 se găsesc cel mult 2*2k
= 2k+1 noduri.
Q.E.D.
Proprietatea 2.
Numărul maxim de noduri într-un arbore cu înălţimea h este 2h+1-1.
Demonstraţie:
Numărul maxim de noduri într-un arbore cu înălţimea h se
obţine atunci când fiecare nivel i este plin, deci, conform propoziţiei
anterioare, conţine 2i noduri. Numărul maxim de noduri într-un arbore
cu înălţimea h va fi:
h
i h+1
∑2 = 2 −1
i=0
Q.E.D.
Proprietatea 3.
În orice arbore binar nevid cu n0 noduri terminale există n0-1 noduri de
grad 2.
Demonstraţie:
Notăm cu n0 numărul de noduri terminale, cu n1 numărul de
noduri de grad 1 şi cu n2 numărul de noduri de grad 2. Deci, numărul
total de noduri n= n0+n1+n2.

17
Dacă numărăm muchiile dintr-un arbore binar, observăm că
fiecare nod, cu excepţia rădăcinii, are o singură muchie orientată spre
el. Notând m numărul de muchii obţinem n = m+1. Dar orice muchie
provine de la un nod de grad 1 sau 2, rezultă că m = n1+2n2.
Din n0+n1+n2 = n şi n1+2n2 = n-1 ⇒ n2 = n0-1.
Q.E.D.
Proprietatea 4.
Un arbore cu n vârfuri are înălţimea cel puţin egală cu [log2n].
Demonstraţie:
În cazul cel mai favorabil, nodurile sunt dispuse pe niveluri
astfel încât fiecare nivel să fie plin, cu excepţia, eventuală, a ultimului
nivel. Deci arborele binar cu n noduri de înălţime minimă este arborele
binar complet cu n vârfuri, care, din modul de construcţie, are înălţimea
[log2n].
Q.E.D.
Proprietatea 5.
Definim lungimea drumurilor interne (I) ca fiind suma lungimilor
drumurilor de la rădăcină la noduri neterminale (interne) şi lungimea
drumurilor externe (E) ca fiind suma lungimilor drumurilor de la
rădăcină la noduri terminale (frunză sau externe). Într-un arbore binar
cu n noduri interne, E = I+2n.
Demonstraţie:
Vom proceda prin inducţie după n, numărul nodurilor interne.
P(0) Într-un arbore cu 0 noduri interne (vid sau format numai din
rădăcină) E = I = 0.
P(n-1) Presupunem că într-un arbore binar An-1, cu n-1 noduri interne,
are loc relaţia En-1 = In-1+2(n-1).
P(n) Vom demonstra că într-un arbore binar An, cu n noduri interne,
are loc relaţia En = In+2n.
Fie An un arbore binar cu n noduri interne. Există în An un nod
intern x care are drept fii două noduri terminale. Îndepărtând din An fiii
nodului x, nodul x se transformă în nod terminal, deci obţinem un
arbore An-1 cu n-1 noduri interne. Din propoziţia inductivă rezultă că în
arborele A n-1, En-1 = In-1+2(n-1). Dacă notăm cu d, lungimea drumului
de la rădăcină la nodurile eliminate, obţinem relaţiile :
En = En-1+2d-(d-1) (în An nodurile eliminate sunt terminale, dar nodul x
nu, lungimea drumului de la rădăcină la x fiind d-1).
In = In-1+(d-1) (în An nodul x este intern).
Deci En = In-1+2(n-1)+d+1 = In-d+1+2n-2+d+1 = In+2n.
Q.E.D.

18
1.4. Reprezentarea arborilor

1.4.1. Reprezentarea cu referinţe descendente


Pentru fiecare nod din arbore vom reţine informaţia asociată
nodului şi referinţe către fiii săi. Dacă presupunem că gradul oricărui
nod este cel mult egal cu n, putem reprezenta referinţele spre fii printr-
un vector cu n componente.
Structura unui nod va fi :
Informaţie Fiu1 Fiu2 ...... Fiun

Declararea acestei structuri în secţiunea type în limbajul Pascal


este :
Arbore = ^NodArbore;
NodArbore = record
Inf: TipInformaţie;
Fiu: array[1..NrMaxFii] of Arbore;
end;
Într-o astfel de reprezentare risipa de memorie este foarte mare,
în fiecare nod alocăm memorie pentru numărul maxim de referinţe către
fii. În plus, numărul maxim de fii este, în general, necunoscut. Acest
neajuns ar putea fi eliminat folosind în locul vectorului de referinţe (cu
număr a priori fixat de componente) o listă simplu înlănţuită în care să
reţinem toţi fiii nodului respectiv.
Declararea acestei structuri în secţiunea type în limbajul Pascal va fi :
ListaFii = ^Fiu;
Fiu = record
F: Arbore;
Urm: ListaFii;
end;
Arbore = ^Nod Arbore;
NodArbore = record
Inf: TipInformaţie;
Ref: ListaFii;
end;
De exemplu, arborele din figura de mai jos,

19
Fig. 15.

va fi reprezentat prin :

Fig.16.
Dacă arborele este reprezentat prin referinţe descendente, atunci
este suficient să reţinem rădăcina arborelui pentru a avea acces la toate
nodurile acestuia.

1.4.2. Reprezentarea cu referinţe ascendente


În această reprezentare, pentru fiecare nod din graf reţinem pe lângă
informaţia aferentă, o legătură spre nodul părinte.
Arbore = ^NodArbore;
NodArbore = record
Inf: TipInformaţie;
Tata: Arbore;
end;
Mai simplu, putem utiliza doi vectori în care pentru fiecare nod
reţinem informaţia, respectiv nodul părinte. Această reprezentare este
mai compactă, dar pentru a avea acces la toate nodurile arborelui
trebuie să reţinem toate nodurile terminale.
De exemplu, pentru arborele din figura 15 vom obţine
reprezentarea :
Inf a b c d e f g h i j k l m
Tata a a a b b c d d d e e h

20
O astfel de reprezentare este utilă pentru reprezentarea
mulţimilor disjuncte cu ajutorul arborilor şi o rezolvare eficientă a
problemelor de reuniune a două mulţimi şi de determinare a mulţimii
căreia îi aparţine un element dat.

1.4.3. Reprezentarea Fiu-Frate.


Pentru fiecare nod reţinem fiul cel mai din stânga şi fratele lui
din dreapta cel mai apropiat.
Arbore = ^NodArbore;
NodArbore = record
Inf: TipInformaţie;
FiuSt, FrateDr: Arbore;
end;
Pentru arborele din figura 15 obţinem:

Fig. 17.
Rotind această reprezentare cu 45° în sensul acelor de ceasornic,
obţinem un arbore binar în care pentru fiecare nod, fiul drept este
fratele lui din dreapta cel mai apropiat. Între cele două grafuri există o
corespondenţă biunivocă. Figura de mai jos ilustrează aceasta
transformare.

Fig. 18.

1.5. Reprezentarea arborilor binari

21
1.5.1. Reprezentarea înlănţuită.
În această reprezentare, pentru fiecare nod reţinem, pe lângă
informaţia asociată nodului, rădăcina subarborelui stâng, rădăcina
subarborelui drept şi dacă este necesar, părintele nodului respectiv.
ArboreBinar = ^NodArboreBinar;
NodArboreBinar = record
c: TipInformaţie;
st, dr, părinte: ArboreBinar;
end;
Arborele binar va fi referit prin intermediul rădăcinii.

1.5.2. Reprezentarea secvenţială.


Pentru fiecare nod reţinem într-un vector doar informaţia
asociată nodului, legăturile dintre noduri fiind implicite. Acest tip de
reprezentare este convenabil pentru arbori binari compleţi. Pentru
aceasta, vom numerota nodurile astfel :
- rădăcina este numerotată cu 1.
- cele 2i noduri de pe nivelul i sunt numerotate 2i, 2i+1, ... , 2i+1-1
de la stânga la dreapta(i > 0).
- pe ultimul nivel nodurile sunt numerotate până la n, numărul
de noduri din arbore.
Această numerotare ne permite să deducem legăturile existente
între nodurile arborelui.
Propoziţie
Următoarele relaţiii sunt valabile pentru orice nod x din arbore :
1. fiul stâng al lui x este
{
st( x) = 2x, dacă 2x≤ n
nu există, dacă 2x>n
2. fiul drept al lui x este
{
dr ( x) = 2x+1, dacă 2x+1≤ n
nu există, dacă 2x+1> n
3. părintele lui x este
|R
S
tata( x) = N
L
Mx/2O
P,
Q dacă x>1
|T
nu există, dacă x=1
Demonstraţie:
Vom demonstra relaţiile 1. şi 2. prin inducţie după numărul
nodului x, relaţia 3. fiind o consecinţă imediată a relaţiiilor 1. şi 2.
P(1) Dacă x = 1, st(1) = 2 = 2x, dacă 2 ≤ n
dr(1) = 3 = 2x+1, dacă 3 ≤ n.
P(x) Presupunem că relaţiile 1. şi 2. sunt îndeplinite pentru nodul x.

22
P(x+1) Demonstrăm relaţiile 1. şi 2. pentru x+1, adică
{
st( x + 1) = 2x+2, dacă 2x+2≤ n
nu există, dacă 2x+2>n şi

dr ( x + 1) = {
2x+3,
nu există,
dacă 2x+3≤ n
dacă 2x+3> n
Fiul stâng al nodului x+1 este precedat de fiul drept al nodului
x. Din ipoteza inductivă, dr(x) = 2x+1, deci st(x+1) = 2x+1+1 =
2x+2, evident, dacă 2x+2 ≤ n. Fiul drept al lui x+1 este succesorul lui
st(x+1), deci dr(x+1) = 2x+2+1 = 2x+3, dacă 2x+3 ≤ n.
Q.E.D.
Deci pentru arbori binari compleţi această reprezentare este
ideală, nefiind necesară decât memorarea informaţiilor nodurilor. Se
poate utiliza reprezentarea secvenţială şi pentru arbori binari oarecare,
completând arborele cu noduri fictive până la un arbore binar complet,
dar în acest caz o mare parte din vectorul ce conţine informaţiile
nodurilor rămâne neutilizată. În plus, ca orice reprezentare secvenţială,
este inadecvată pentru inserări şi ştergeri de noduri.

1.6. Operaţii elementare pe arbori binari*

În cele ce urmează, vom utiliza reprezentarea înlănţuită a


arborilor binari.
1.6.1. Crearea unui arbore binar.
Algoritmul de creare depinde în mod esenţial de tipul arborelui
binar pe care dorim să-l construim. Vom prezenta o procedură de creare
a unui arbore binar echilibrat, alţi algoritmi de creare fiind prezentaţi în
capitolele următoare. Pentru a crea un arbore binar echilibrat cu n
vârfuri se stabileşte un vârf rădăcină, se construieşte un arbore binar
echilibrat cu [n/2] vârfuri ca subarbore stâng şi un arbore binar
echilibrat cu n-1-[n/2] vârfuri ca subarbore drept. Dacă n este par
numărul nodurilor din subarborele stâng va fi cu o unitate mai mare
decât numărul nodurilor din subarborele drept, altfel cei doi subarbori
au un număr egal de noduri.
function CreareArboreBinarEchilibrat(n: byte): ArboreBinar;
// funcţia întoarce adresa rădăcinii unui arbore binar echilibrat cu n
//vârfuri
var rad: ArboreBinar;
begin
*
Programul Operaţii-pe-Arbori-Binari implementează operaţiile pe arbori binari
prezentate.

23
if n = 0 then //arborele este vid
CreareArboreBinarEchilibrat := nil
else
begin
new(rad) //aloc zonă de memorie pentru rădăcina arborelui
readln(rad^.Inf);//citesc informaţia rădăcinii arborelui
// creez subarborele stâng, apoi cel drept
rad^. St := CreareArboreBinarEchilibrat(n div 2);
rad^. Dr := CreareArboreBinarEchilibrat(n - n div 2
-1 );
CreareArboreBinarEchilibrat := rad
end
end;

1.6.2. Parcurgerea arborilor binari


Parcurgerile sunt cele mai frecvent utilizate operaţii pe arbori. A
parcurge un arbore înseamnă a vizita fiecare nod al arborelui o singură
dată, în scopul prelucrării informaţiei asociate nodului.
Există mai multe posibilităţi de parcurgere a arborilor- în
adâncime (preordine, inordine, postordine) sau pe niveluri, dar în toate
cazurile atât arborele, cât şi subarborii sunt prelucraţi în acelaşi mod.
a) Parcurgerile în adâncime
În toate cele trei tipuri de parcurgere în adâncime se vizitează mai întâi
subarborele stâng, apoi subarborele drept. Diferenţa constă în poziţia
rădăcinii faţă de cei doi subarbori. Fie scrise recursiv, fie iterativ,
procedurile de parcurgere în adâncime necesită o stivă.
Pentru a parcurge un arbore binar în preordine, se vizitează mai
întâi rădăcina, se parcurge în preordine subarborele stâng, apoi se
parcurge în preordine subarborele drept.
procedure Preordine(rad: ArboreBinar);
begin
if rad ≠ nil then
begin
write(rad^.inf); //vizitez rădăcina
Preordine(rad^.st); //parcurg subarborele stâng
Preordine(rad^.dr); //parcurg subarborele drept
end;
end;
Pentru a parcurge în inordine un arbore binar, se parcurge în
inordine subarborele stâng, se vizitează radăcina, apoi se parcurge în
inordine subarborele drept.

24
procedure Inordine(rad: ArboreBinar);
begin
if rad ≠ nil then
begin
Inordine(rad^.st);
write(rad^.inf);
Inordine(rad^.dr);
end;
end;
Pentru a parcurge în postordine un arbore binar, se parcurge în
postordine subarborele stâng, apoi cel drept, apoi se vizitează rădăcina.
procedure Postordine(rad: ArboreBinar);
begin
if rad ≠ nil then
begin
Postordine(rad^.st);
Postordine(rad^.dr);
write(rad^.inf);
end;
end;
Pentru a înţelege mai bine operaţia de parcurgere, vom prezenta
şi o variantă iterativă de parcurgere în inordine a unui arbore binar.
Pentru a simula recursia vom folosi o stivă S la care vom adăuga sau
şterge elemente în acelaşi mod ca în procedura recursivă.
Stivă = ^NodStivă;
NodStivă = record
Inf: ArboreBinar;
Urm: Stivă;
end;
procedure InordineIterativ (rad: ArboreBinar);
// procedura parcurge iterativ în inordine arborele cu rădăcina rad
var S, p: Stivă;
NodCurent: ArboreBinar;
begin
S := nil;
NodCurent := rad;
repeat
while NodCurent ≠ nil do
begin
//adaugă nodul curent în stiva S
new(p)

25
p^.Inf := NodCurent;
p^.Urm := S;
S := p;
//rădăcina subarborelui stâng devine nod curent
NodCurent := NodCurent^.St
if S ≠ nil then //extrage un element din stivă
begin
p := S;
S := S^.Urm;
write(p^.inf)
NodCurent := p^.Inf^.Dr
dispose(p);
//eliberează zona de memorie a lui p
until (S = nil) and (NodCurent = nil)
end;
Observaţie
Fiecare nod din arbore este plasat şi şters din stivă o singură
dată, deci timpul necesar parcurgerii inordine este de O(n). Spaţiul
suplimentar necesar depinde de înălţimea arborelui, deci în cazul cel
mai defavorabil este de O(n).

b) Parcurgerea pe niveluri
Se vizitează întâi rădăcina, apoi fiul stâng al rădăcinii, apoi cel
drept şi se continuă în acest mod vizitând nodurile de pe fiecare nivel de
la stânga la dreapta.
Pentru a realiza acest mod de parcurgere, vom utiliza o coadă,
pe care o iniţializăm cu rădăcina arborelui şi din care, la fiecare pas,
vom extrage un nod, îl vizităm şi inserăm în coadă fii săi, dacă aceştia
există.
Coadă = ^NodCoadă;
NodCoadă = record
Inf: ArboreBinar;
Urm: Coadă;
end;
procedure ParcurgerePeNiveluri (rad: ArboreBinar)
//procedura parcurge pe niveluri arborele cu rădăcina rad
var C, SfC, p: Coadă;
begin
if rad ≠ nil then //arborele este nevid
begin
new(C) // iniţializez coada cu rădăcina arborelui

26
C^.Inf := rad;
C^.Urm := nil;
SfC := C;
while C ≠ nil do // coada nu este vidă
begin
p := C;
write(p^.Inf);
if p^.Inf^.St ≠ nil then
begin
//adaug fiul stâng în coadă
new(q);
q^.Inf := p^.Inf^.St;
q^.Urm := nil;
SfC^.Urm := q;
SfC := q;
end;
if p^.Inf^.Dr ≠ nil then
begin
//adaug fiul drept în coadă
new(q);
q^.Inf := p^.Inf^.Dr;
q^.Urm := nil;
SfC^.Urm := q;
SfC := q;
end;
C := C^.Urm //extrag din coadă nodul p
dispose(p);
end
end
end;
Observaţie
Mai întâi am inserat în coadă fiii nodului ce urmează a fi vizitat
şi apoi am extras efectiv nodul respectiv din coadă, pentru a evita
inserarea unui nod într–o coadă vidă.

1.6.3. Determinarea înălţimii unui arbore.


Dacă arborele este vid, vom considera că înălţimea sa este –1,
astfel putem calcula înălţimea arborelui ca fiind maximul dintre
înălţimile subarborilor rădăcinii plus nivelul pe care se află rădăcina.
function Înălţime (rad: ArboreBinar): integer;
// funcţia întoarce înălţimea arborelui binar cu rădăcina rad

27
begin
if rad = nil then // arbore vid
Înălţime := –1
else
Înălţime := max(Înălţime(rad^.st),
Înălţime(rad^.dr))+ 1
end;
Am presupus cunoscută funcţia max, care întoarce cel mai mare
dintre cele două argumente ale sale.

1.6.4. Egalitatea a doi arbori binari.


Spunem că doi arbori binari sînt egali dacă au aceeaşi structură
şi conţin aceleaşi informaţii în nodurile corespondente.
function Egali (rad1, rad2: ArboreBinar): boolean;
//funcţia întoarce true dacă arborii cu rădăcinile rad1,
// respectiv rad2 sunt egali, altfel întoarce false
begin
Egali := (rad1 = nil) and (rad2 = nil) //ambii sunt vizi sau
or (rad1 ≠ nil) and (rad2 ≠ nil) // ambii sunt nevizi şi
and (rad1^.c = rad2^.c) //au aceeaşi informaţie în rădăcină
and Egali(rad1^.St, rad2^.St) //subarborii stângi egali
and Egali(rad1^.Dr, rad2^.Dr) // subarborii drepţi egali
end;

Aplicaţie*
Se dau secvenţele obţinute prin parcurgerile în preordine şi în
inordine ale unui arbore binar. Construiţi arborele binar corespunzător.
De exemplu, fie A,B,C,D,E,F,G,H- parcurgerea în preordine şi
C,B,A,E,D,G,F,H- parcurgerea în inordine.
Analizînd parcurgerea în preordine, deducem că nodul A este
rădăcina. De asemeni, analizând parcurgerea în inordine, deducem că
nodurile C, B vor constitui arborele stâng, iar D, E, G, F, H subarborele
drept. Pentru a determina structura subarborelui stâng, respectiv a
subarborelui drept, procedăm analog: din parcurgerea în preordine
deducem că B este rădăcina subarborelui stâng, iar din parcurgerea în
inordine deducem că C este fiul stâng al lui B. În mod similar, pentru
subarborele drept deducem din parcurgerea în preordine că D este
rădăcină, iar din parcurgerea în inordine că subarborele stâng al lui D
este format numai din nodul E, iar subarborele drept al lui D din
*
Programul Construcţie-Arbore-Binar-cu-Secvenţele-Preordine-Inordine-Date
generează un arbore binar pentru care se cunosc parcurgerile în preordine şi inordine.

28
nodurile F, G, H. Procedeul se repetă pînă cînd obţinem întreg arborele.
Succesiunea operaţiilor este ilustrată în figura 19:

Fig. 19.
Propoziţie
Succesiunile de noduri obţinute prin parcurgerile în inordine şi
în preordine ale unui arbore binar definesc în mod unic structura
arborelui.
Demonstraţie:
Vom proceda prin inducţie completă după numărul de noduri.
P(1) Dacă arborele are un singur nod, rădăcina, afirmaţia este
evidentă.
P(n) Presupunem că pentru ∀k∈{1,2,... ,n} afirmaţia este
adevărată, adică pentru orice pereche de secvenţe inordine–preordine de
lungime k, arborele binar corespunzător este unic.
P(n+1) Să demonstrăm că orice pereche de secvenţe preordine-
inordine de lungime n+1 determină în mod unic un arbore binar.
Să considerăm o pereche de secvenţe preordine-inordine de
lungime n+1. Primul nod din parcurgerea în preordine este în mod
necesar rădăcina arborelui, celelalte n noduri fiind distribuite în
subarbori: toate nodurile situate în stânga rădăcinii în parcurgerea în
inordine vor constitui subarborele stâng, nodurile situate în dreapta
rădăcinii în parcurgerea inordine vor constitui subarborele drept.
Obţinem două perechi de secvenţe preordine-inordine de
lungime cel mult n, care din ipoteza inductivă, determină în mod unic

29
subarborele stâng, respectiv cel drept şi în consecinţă, cum rădăcina este
în mod unic determinată, deducem că perechea de secvenţe preordine-
inordine de lungime n+1 determină în mod unic un arbore binar cu n
noduri.
Q.E.D.
Vom descrie o funcţie recursivă ConstrArb, care determină
arborele binar corespunzător unei perechi de secvenţe preordine-
inordine date. Pentru simplificare, vom considera că nodurile arborelui
sunt numerotate în preordine de la 1 la n. Astfel, este suficient să
reţinem într-un vector global i indicii vârfurilor în ordinea în care au
fost atinse în inordine. Iniţial, apelăm ConstrArb(1,1,n).
function ConstrArb (rad, st, dr): ArboreBinar;
//functia întoarce rădăcina arborelui unic determinat de parcurgerile
//inordine-preordine
//rad este indicele rădăcinii arborelui
//st şi dr sunt limitele între care se găseşte parcurgerea inordine a
//arborelui în vectorul i
var r: ArboreBinar;
IPozRad: byte;
begin
new(r); //aloc memorie pentru rădăcina arborelui
r^.c := rad; //reţinem drept informaţie numărul asociat nodului
IPozRad := st;
// determin poziţia rădăcinii arborelui în parcurgerea inordine
while i[IPozRad] ≠ rad do inc(IPozRad);
if IPozRad = st then //subarborele stâng este vid
r.st^ := nil
else
// i[ st.. IPozRad-1] conţine subarborele stâng
r.st^ := ConstrArb(rad+ 1, st, IPozRad-1);
if IPozRad = dr then //subarborele drept este vid
r.dr^:= nil
else
// i[ IPozRad+ 1.. dr] conţine subarborele drept
r.dr^ := ConstrArb(rad+ IPozRad-st+ 1, IPozRad+ 1, dr);
// în subarborele stâng au fost IPozRad-st+ 1 vârfuri
end;

1.7. Numărarea arborilor binari*


*
Programul Numar-Arbori-Binari-Distincţi afişează numărul arborilor binari

30
Se pune problema determinării numărului de arbori binari
distincţi cu n noduri, făcând abstracţie, bineînţeles de numerotarea
nodurilor.
Pentru n= 0 sau n= 1 există un singur arbore binar.
Dacă n= 2, există doi arbori binari distincţi.

Fig. 20.

Pentru n= 3, există 5 astfel de arbori.

Fig. 21.
Notăm cu bn numărul arborilor binari distincţi cu n noduri.
Evident, b0 = 1.
Pentru n > 0 arborii sunt formaţi din rădăcină şi doi subarbori cu i,
respectiv n-i-1 noduri (0 ≤ i < n).
R
||1,
dac\ n=1
bn = S|
||n−1
||i=∑0bibn−i−1, dac\ n>1
T
Pentru a obţine numărul arborilor binari distincţi cu n noduri este
suficient să rezolvăm această relaţie de recurenţă. Să considerăm funcţia
B( x) = ∑ bnxn
n≥ 0
Din relaţia de recurenţă, înmulţind ambii membri cu xn ,obţinem :
n−1
bnxn = x∑ (bx i
i )(bn − i − 1x
n− i −1
)
i =0
Sumând după n ≥ 1, obţinem :
n−1

∑ bnxn = x∑ ∑ (bxi i )(bn − i − 1xn− i −1)


n≥1 n≥1 i = 0

distincţi cu n vârfuri date.

31
Obţinem B(x)-b0 = x*B2(x) ⇔ xB2(x) - B(x)+1 = 0.
Rezolvând această ecuaţie de grad II obţinem :
1
1− 1− 4x 1
B( x) = ⇔ B( x) = (1− (1− 4x)2 )
2x 2x
Dezvoltând binomial (1-4x)1/2 , obţinem:
1 1 1
1 ( −1)...( − n+1)
B( x) = (1− ∑ 2 2
n!
2
(−4x)n ) ⇔
2x n≥ 0

1 1 1
1 ( −1)...( − n+1)
B( x) = ∑
2x n≥1
2 2
n!
2
(−1)n+122n xn ⇔

1 1 1
( −1)...( − n+1)
B( x) = ∑ 2 2
n!
2
(−1)n+122n−1 xn−1)
n≥1
Notând n-1 cu m, obţinem:

1 1 1
( −1)...( − m)
B( x) = ∑ 2 2 2
( m+1)! (−1)m22m+1 xm)
m≥ 0
Cum bn este coeficientul lui xn în B(x) obţinem
1 1 1
( − 1)...( − n)
n 2n+1 2 2 2
bn = (−1) 2 ⇔
(n + 1)!
1 (1− 2)(1− 2⋅ 2)...(1− 2n)
bn = (−1)n 22n+1 ⇔
2n+1 (n + 1)!
(2n − 1)(2(n − 1) − 1)...(2 − 1)
bn = 2n ⇔
(n + 1)!
1 (2n ⋅ n!)(2n − 1)(2(n − 1) − 1)...(2 − 1)
bn = ⇔
n+ 1 n!⋅ n!
(2n)!
bn = n1 1 n
+1⋅ n!⋅n! ⇔ bn = n+1C2n
Numărul arborilor binari distincţi cu n vârfuri va fi aproximativ
F I n
b = OG J
4

H K
n
3/ 2
n

Observaţii
1. Am demonstrat că fiecărui arbore binar îi corespunde o

32
singură pereche de secvenţe preordine-inordine. Considerând nodurile
numerotate în preordine, rezultă că arborii binari sunt definiţi de
permutările inordine distincte (permutările distincte ce se pot obţine
trecând numerele 1,2,...,n într-o stivă şi ştergându-le în toate modurile
posibile).
Deci numărul permutărilor inordine de n elemente este
1 n
n+1C2n
2. O problemă care are în mod surprinzător legătură cu cele
precedente este calculul produsului a n+1 matrici, M0,M1,...,Mn. Cum
înmulţirea matricilor este asociativă, am dori să ştim în câte moduri
putem calcula produsul M0× M1× ...× Mn.
Pentru n = 1 există o singură posibilitate.
Pentru n = 2 există două posibilităţi: (M0× M1) × M2 sau
M0× (M1× M2).
Pentru n = 3 există cinci posibilităţi :
((M0× M1) × M2) × M3;
(M0× M1) × (M2× M3);
(M0× (M1× M2)) × M3;
M0× ((M1× M2) × M3 );
M0× (M1× (M2× M3)).
Notăm cu P(n) numărul de moduri distincte în care putem calcula
produsul M0× M1× ...× Mn.
Produsul M0× M1× ...× Mn poate fi împărţit într-un produs de două
produse de matrici : (M0× M1× ...× Mk)(Mk+1× ...× Mn ).
Acestei asocieri i se poate pune în corespondenţă un arbore binar:

Fig. 22.

R
| 1, dacă n = 1
P (n) = S
||Tkn∑=−10P (k)⋅P (n−k−1), dacă n>1
Deci numărul de parantezări posibile pentru produsul a n+1
matrici coincide cu numărul arborilor binari distincţi cu n noduri.

1.8. Păduri

33
Definiţie
O pădure este un ansamblu de n ≥ 0 arbori disjuncţi.
De exemplu,

Fig. 23.
Îndepărtând rădăcina din orice arbore obţinem o pădure formată
din subarborii rădăcinii.
Orice pădure poate fi reprezentată ca un arbore binar. Pentru
aceasta, transformăm arborii din care este constituită pădurea în arbori
binari, utilizând reprezentarea fiu-frate. Apoi construim arborele binar
corespunzător pădurii, utilizând câmpul frate al rădăcinii fiecărui
arbore.
De exemplu, pentru pădurea din figura 24 arborele binar asociat este

Fig. 24.

Definiţie
Fie A1, A2, ..., An arborii unei păduri. Atunci arborele binar
corespunzător pădurii, B(A1, A2, ..., An) este:
1.vid, dacă n = 0;
2.are rădăcina egală cu rădăcina lui A1, subarborele stâng este
arborele corespunzător pădurii formată din subarborii lui A1, iar
subarborele drept este arborele binar corespunzător pădurii formată din
arborii A2, ..., An.
Operaţiile de parcurgere a unei păduri se reduc la parcurgerea
arborelui corespunzător.

34
Fig. 25.

1.9. Probleme rezolvate

1.9.1. Arbori binari m-ponderaţi


-Olimpiada de informatică faza judeţeană, Iaşi 1995-
Un arbore binar strict se numeşte m-ponderat dacă fiecare nod i
are asociată o pondere p[i], cu valori între 1 şi m-1, astfel încât pentru
orice nod terminal t suma ponderilor din nodurile aflate pe drumul de la
rădăcină la nodul t este egală cu m.
Definim Pn,m(T) ponderea unui arbore binar strict cu n noduri
terminale m-ponderat ca fiind suma ponderilor ataşate nodurilor din T.
Să se scrie un program care pentru n si m daţi determină un arbore binar
strict m-ponderat cu n noduri terminale T* astfel încât:
Pn,m(T*)= max{Pn,m(T)T arbore binar strict m-ponderat cu n noduri
terminale}
Soluţie:
Pentru ca problema să admită soluţie trebuie ca pentru orice
drum de la rădăcină la un nod terminal să putem asocia nodurilor
ponderi ≥ 1.
Înălţimea minimă a unui arbore cu n vârfuri terminale este
h=[ log2n]. Pentru a asocia ponderi este necesar ca m, suma ponderilor
vârfurilor de pe orice drum de la rădăcină la un vârf terminal, să fie cel
puţin egală cu [log2n]+1.
Deci condiţia necesară pentru ca problema să admită soluţie este
m ≥ [log2n]+1.
Observaţii
1. Fie T un arbore binar strict cu n vârfuri terminale. Construim o m-
ponderare po a arborelui T astfel:
-asociem fiecărui nod interior ponderea 1.
-deoarece suma ponderilor de pe orice drum de la rădăcină la un
vârf terminal trebuie să fie egală cu m, asociem fiecărui nod terminal o
pondere egală cu m-lungimea drumului de la rădăcină la nodul terminal
respectiv.
Demonstrăm că po este o m-ponderare maximală pentru arborele T.

35
Să considerăm p o m-ponderare oarecare pentru arborele T şi x
un vârf interior astfel încât p[x]>1. Dacă există mai multe astfel de
noduri, considerăm un vârf de pe un nivel de rang minim. Fie y şi z cei
doi fii ai lui x. Construim o altă m-ponderare p’ a lui T astfel:
p’[x] = 1; p’[y] = p[y]+p[x]-1; p’[z] = p[z]+p[x]-1.
Atunci P’(T) = P(T)-p[x]-p[y]-p[z]+p’[x]+p’[y]+p’[z] ⇒
P’(T) = P(T) -p[x]-p[y]-p[z]+1+ p[y]+p[x]-1+ p[z]+p[x]-1 ⇒
P’(T) = P(T)+p[x]-1 ⇒ P’(T) > P(T).
Modificând succesiv ponderile nodurilor interioare de sus în jos,
obţinem după un număr finit de paşi m-ponderarea po, în care toate
vârfurile interioare au ponderea 1.
Deci Po(T) ≥ P(T), ∀p o m-ponderare a arborelui T
2. Observaţia 1. oferă o modalitate de m-ponderare optimală a
unui arbore binar strict dat. Rămâne să determinăm, pentru n şi m daţi,
arborele binar strict cu n vârfuri terminale care maximizează Pn,m(T).
Demonstrăm că arborele căutat T* este arborele binar complet. Fie T un
arbore binar strict cu n vârfuri terminale care nu este complet şi fie x şi
y două vârfuri terminale fii ai aceluiaşi nod interior, situate pe nivelul i,
iar z un nod terminal situat pe nivelul j, astfel încât i-j > 1.

Fig. 26.
Mutăm nodurile x şi y de pe nivelul i pe nivelul j+1, ca fii ai
nodului z şi reponderăm nodurile.
P(T’) = P(T)-2(m-i+1)-1-(m-j+1)+2(m-j)+m-i+2+1 ⇒
P(T’) = P(T)+i-j-1 > P(T).
Aplicăm succesiv această transformare până când obţinem un
arbore binar complet.
Deci P(T*) > P(T), ∀T arbore binar strict.
Q.E.D.
Reprezentarea informaţiilor
Arborele căutat fiind complet, pentru implementare alegem
reprezentarea secvenţială.
program arbore_m_ponderat;
uses crt;
const NMaxVfT=20;

36
NMaxVf=2*NMaxVfT-1;
type Vf=0..NMaxVf;
arbore_ponderat=array[Vf] of word;
var n,i,nivel:Vf;
m:word;
p:arbore_ponderat;

procedure afisare;
const pst=13;
pdr=28;
pp=42;
var i:Vf;
begin
writeln('Nodul Fiu stang Fiu drept Pondere');
for i:=1 to n-1 do
begin
write(i);
gotoxy(pst,wherey);write(2*i);
gotoxy(pdr,wherey);write(2*i+1);
gotoxy(pp,wherey);writeln(1);
end;
for i:=n to 2*n-1 do
begin
write(i);
gotoxy(pp,wherey);writeln(p[i]);
end
end;

begin
clrscr;
write('n=');readln(n);
write('m=');readln(m);
if m<trunc(ln(n)/ln(2))+1
then writeln('Nu exista solutie!')
else
begin
for i:=1 to n-1 do p[i]:=1;
{nodurile interioare au ponderea 1}
for i:=n to 2*n-1 do
begin
nivel:=trunc(ln(i)/ln(2));
p[i]:=m-nivel;
{nodurile terminale au ponderea egala cu m-numarul
nivelului pe care sunt situate}
end;
afisare
end;
readln
end.

1.9.2. Interclasarea optimală a n şiruri ordonate


Fie n secvenţe S1,S2,...,Sn de lungimi respectiv L1,L2,...,Ln,
ordonate nedescrescător. Să se interclaseze cele n secvenţe.
37
Soluţie:
1. Notăm cu m L1+L2+...+Ln.
O prima soluţie ar fi să selectăm la fiecare pas articolul cu cheia
cea mai mică şi să-l plasăm în şirul rezultat. Pentru selectarea
minimului ar fi necesare n-1 comparaţii, deci algoritmul ar fi de
O(n•m).
2. Vom utiliza un arbore de selecţie.
Definiţie
Numim arbore de selecţie un arbore binar complet în care
fiecare nod este cel mai mic dintre fiii săi.
Observaţie
Fiecare nod din arbore are asociată ca valoare minimul valorilor
nodurilor din subarborele corepunzător.
Vom construi arborele de selecţie în mod bottom-up, apoi la
fiecare pas selectăm minimul, care este rădăcina arborelui şi
restructurăm arborele.
Construcţia arborelui de selecţie este de O(n), restructurarea
arborelui, care se repetă de m ori, de O(log n). Deci algoritmul va fi de
O(m log n).
Reprezentarea informaţiilor
Arborele de selecţie fiind complet, vom utiliza reprezentarea
secvenţială.

program interclasare_optimala;
const NMaxSecv=20;
LgMaxSecv=50;
type Ind=1..LgMaxSecv;
Secv=1..NMaxSecv;
Nod=1..2*NMaxSecv;
Arbore=array[Nod] of integer;
var l:array[Secv] of Ind;{lungimile secventelor}
n:Secv; {numarul de secvente}
m,k:word;{m=numarul total de elemente}
o:array[1..LgMaxSecv*NMaxSecv] of integer;
{rezultatul interclasarii}
s:array[Secv,Ind] of integer;{secventele}
A:Arbore;{arborele de selectie}
j:array[Secv] of Ind;{indicii curenti in secvente}

procedure citire;
var f:text;
i:Secv;
j:Ind;
begin
assign(f,'int.in'); reset(f);
readln(f,n);
for i:=1 to n do read(f,l[i]);

38
readln(f);
for i:=1 to n do
begin
m:=m+l[i];
s[i,l[i]+1]:=MaxInt;
for j:=1 to l[i] do read(f,s[i,j]);
readln(f);
end;
close(f);
end;

procedure ConstrArbSel;
var i:Nod;
begin
{constructia arborelui de selectie}
for i:=n to 2*n-1 do A[i]:=s[i-n+1,1];
{initializarea nodurilor terminale}
for i:=n-1 downto 1 do
if A[2*i]<A[2*i+1] then
A[i]:=A[2*i]
else
A[i]:=A[2*i+1];
{initializez valorile indicilor in secvente}
for i:=1 to n do j[i]:=1;
end;

procedure restructurare;
var i,tata,frate:Nod;
begin
{determin secventa corespunzatoare nodului eliminat}
i:=1;
while i<=n-1 do
if A[i]=A[2*i] then
i:=2*i
else
i:=2*i+1;
{i este nodul terminal corespunzator secventei din care am luat
un element}
inc(j[i-n+1]);
A[i]:=s[i-n+1,j[i-n+1]];
{restauram valorile nodurilor de pe drumul de la nodul i la
radacina}
while i>1 do
begin
tata:=i div 2;
if i=2*tata then frate:=2*tata+1
else frate:=2*tata;
if A[i]>A[frate] then A[tata]:=A[frate]
else A[tata]:=A[i];
i:=tata;
end;
end;

procedure afisare;

39
var i:word;
begin
writeln('Rezultatul interclasarii: ');
for i:=1 to m do
write(o[i],' ');
writeln;
readln
end;

begin {program principal}


citire;
ConstrArbSel;
for k:=1 to m do
begin
o[k]:=A[1];{elementul minim}
restructurare;
end;
afisare;
end.

1.9.3. O reprezentare a arborilor binare stricţi


-problemă propusă de Horia Georgescu, G.I. nr.10/1993-
Fie următorul arbore binar strict

Fig. 27.
Codificăm drumurile de la rădăcină la nodurile terminale
marcând cu 0 fiecare deplasare la stânga şi cu 1 fiecare deplasare la
dreapta. Concatenând codificările în preordine, obţinem o reprezentare
a arborilor binari stricţi.
Pentru exemplul din figura 27 codificarea este 00010001010111.

Problemă
Data fiind s, reprezentarea unui arbore binar strict obţinută prin
concatenarea în preordine a codificărilor drumurilor de la rădăcină la
nodurile terminale, generaţi arborele corespunzător.
Soluţie:
Fie x, y două noduri terminale, situate pe nivelul maxim in
arbore, fii ai aceluiaşi nod t. Dacă notăm p secvenţa ce codifică drumul

40
de la rădăcină la t, atunci şirul s are forma αp0p1β. Determinăm p astfel
încât s = αp0p1β, p fiind cea mai lungă secvenţă cu această proprietate.
De exemplu, pentru codificarea de mai sus p = 010.
Putem construi astfel un drum de la rădăcina arborelui la două
noduri terminale fraţi.

Fig. 28.
Eliminăm din s secvenţa 0p1, ceea ce corespunde eliminării din
arbore a două noduri terminale fii ai aceluiaşi nod. Obţinem, de
exemplu, s = 000100111.
Am redus problema la generarea unui arbore cu un nod terminal
mai puţin, pe care îl vom suprapune peste drumul generat anterior.

program Generare_Arbore_Binar_Strict;
uses crt;
type Arbore=^NodArbore;
NodArbore= record
st,dr:Arbore
end;
var s:string;
f:text;
n, poz, NrNod, lg, NrTest: byte;
A, T: Arbore;

procedure procesare(var poz, lg: byte);


{determina cea mai lunga subsecventa p a lui s astfel incat
s=αp0p1β; poz -pozitia de inceput a lui p; lg -lungimea lui p}
var i,j: byte;
begin
lg:=0; poz:=1;
i:=1;
while i<=n-2*lg-1 do
begin
{caut o secventa p care sa inceapa pe pozitia i de
lungime mai mare ca lg}
j:=lg+1;
while i+2*j<n do
begin
while (i+2*j<n) and (s[i+j]<>'0') do inc(j);
if i+2*j<n then
if (copy(s,i,j)=copy(s,i+j+1,j)) and (s[i+2*j+1]='1')

41
then begin
lg:=j;
poz:=i
end;
inc(j);
end;
inc(i)
end;
end;

procedure ConstrDrum;
var q, x: Arbore;
gata: boolean;
i: byte;
begin
q:=A; i:=poz;
{construiesc drumul de la radacina arborelui la nodul tata al
nodurilor terminale ce urmeaza sa le agat in arbore,
suprapunand eventual peste arborele deja construit}
gata:=false;{gata devine true cand am terminat de parcurs
portiunea de drum deja construita in arbore}
while not gata and (i<poz+lg) do
if s[i]='0' then
if q^.st<>nil then
begin
q:=q^.st;
inc(i)
end
else gata:=true
else
if q^.dr<>nil then
begin
q:=q^.dr;
inc(i)
end
else gata:=true;
while i<poz+lg do
begin
new(x);
x^.st:=nil; x^.dr:=nil;
if s[i]='0' then
q^.st:=x
else
q^.dr:=x;
q:=x;
inc(i)
end;
{agat doua noduri terminale, fii ai nodului q}
new(x);
x^.st:=nil; x^.dr:=nil;
if q^.st=nil then q^.st:=x;
new(x);
x^.st:=nil; x^.dr:=nil;
if q^.dr=nil then q^.dr:=x;

42
end;

procedure scrie(x: Arbore; niv, st, dr: byte);


var poz: byte;
begin
if x<>nil then
begin
poz:=(st+dr)div 2;
gotoxy(poz,niv);
write(NrNod);inc(NrNod);
scrie(x^.st, niv+2, st, poz-1);
scrie(x^.dr, niv+2, poz+1, dr);
end;
end;

procedure afisare;
begin
clrscr;
inc(NrTest);
NrNod:=1;
writeln('Testul nr. ', NrTest,':');
scrie(A,2,1,80);
readln;
end;

begin {program principal}


assign(f,'a.in');
{fisierul de intrare contine mai multe seturi de date de test}
reset(f);
while not seekeof(f) do
begin
readln(f,s);
new(A);{generam arborele corespunzator secventei s vide}
A^.st:=nil; A^.dr:=nil;
repeat
n:=length(s);
procesare(poz,lg);
ConstrDrum;
delete(s,poz+lg,lg+2);
until n=0;
afisare;
end;
readln
end.

1.10. Exerciţii
1. Demonstraţi că în orice graf G = (V, U) conex, U≥ V-1.
2. Demonstraţi că în orice arbore există cel puţin două vârfuri
terminale.
3. Calculaţi numărul arborilor cu n vârfuri şi secvenţa gradelor
vârfurilor d1,d2,...,dn (di ≥ 1, ∀i∈{1, 2, ..., n}, d1+d2+...+dn = 2n-2).
Scrieţi un program de generare a tuturor arborilor cu secvenţa gradelor
43
dată.
4. Calculaţi numărul arborilor cu n vârfuri, dintre care p terminale.
5. Secvenţele obţinute prin parcurgerile în postordine şi în inordine ale
unui arbore binar definesc în mod unic arborele? Dacă da, scrieţi un
algoritm de generare a arborelui binar corespunzător.
Aceeaşi problemă pentru parcurgerile în preordine şi în postordine,
respectiv parcurgerea în inordine şi parcurgerea pe niveluri.
6. Generaţi toţi arborii binari distincţi cu n vârfuri.
7. Scrieţi o funcţie de duplicare a unui arbore binar.
8. Scrieţi o funcţie de căutare a unei valori de tipul informaţiei asociate
nodurilor într-un arbore binar. Analizaţi complexitatea funcţiei.
9. Scrieţi o procedură iterativă de parcurgere în preordine a unui arbore
binar.
10. Scrieţi o procedură iterativă de parcurgere în postordine a unui
arbore binar.
11. Scrieţi o funcţie de ştergere a unui arbore binar.
12.Scrieţi un program care să parcurgă un arbore oarecare în
reprezentarea fiu-frate pe niveluri.
13. Definim gradul unui arbore cu rădăcină ca fiind gradul maxim al
nodurilor sale. Fie un arbore cu gradul k şi înălţimea h. Care este
numărul maxim de noduri din acest arbore ?
Reprezentăm fiecare nod al arborelui printr-un articol ce conţine
informaţia asociată nodului şi k pointeri spre rădăcinile subarborilor :
Arbore = ^NodArbore;
NodArbore = record
c: TipInf;
leg: array[1..k] of Arbore;
end;
a). Scrieţi o funcţie de creare a unui arbore echilibrat de grad k.
b). Descrieţi algoritmul de parcurgere pe niveluri şi în adâncime a unui
arbore de grad k.
c). Scrieţi o funcţie care să determine înălţimea unui arbore de grad k.
d). Scrieţi o funcţie care să testeze egalitatea a doi arbori de grad k.
14. Scrieţi o funcţie care să determine numărul de noduri terminale ale
unui arbore binar.
15. Scrieţi un algoritm care, dat fiind un arbore binar, schimbă fiul
stâng cu fiul drept, pentru orice nod din arbore. De exemplu :

44
Fig. 29.
16. Demonstraţi că orice arbore binar este 2-colorabil.
17. Fie P un poligon convex. O diagonală este un segment ce uneşte
două vârfuri neadiacente. Numim triangularizare a poligonului convex
P o mulţime de diagonale care împart poligonul în triunghiuri disjuncte.
Calculaţi numărul triangularizărilor posibile pentru un poligon convex
cu n vârfuri.
18. Scrieţi o funcţie care să verifice dacă un arbore binar este strict.
19. Calculaţi numărul arborilor binari de înălţime h.
20. Scrieţi un program care să construiască arborele binar corespunzător
pădurii formate din arborii A1, A2, ..., An şi parcurgeţi arborele în
preordine, inordine, postordine.
21. Fie P o pădure, arborii componenţi fiind reprezentaţi prin referinţe
ascendente. Scrieţi un algoritm care să determine pentru oricare două
vârfuri din pădure cel mai apropiat ascendent comun, dacă acesta există.
Analizaţi complexitatea algoritmului.
22. "Problema" telefonistelor
O reţea telefonică formată din n centrale numerotate de la 1 la n,
are forma unui arbore oarecare. Telefonista de la centrala k, 1 ≤ k
≤ n, care a intrat în posesia unei informaţii importante, arde de
nerăbdare s-o împărtăşescă tuturor colegelor ei. Ştiind că fiecare
telefonistă poate vorbi la un moment dat doar cu una dintre vecinele ei,
că o convorbire durează un minut şi că fiecare telefonistă, după ce a
intrat în posesia informaţiei se grăbeşte să o comunice celorlalte vecine
ale ei care n-au aflat-o încă, să se determine succesiunea propagării în
timp a informaţiei şi timpul minim necesar ca toate telefonistele să
cunoască vestea pornită de la centrala k.

45
Anexă

program Constructie_arbore_cu_secventa_gradelor_data;
const NMaxVf = 20;
type Vf = 1..NMaxVf;
var a, d: array[Vf] of Vf;
n, i, VfT, VfNt: Vf;
s: byte;
fout: text;

procedure citire;
var i: Vf;
fin: text;
begin
assign(fin, 'grade.in'); reset(fin);
readln(fin, n);
for i := 1 to n do read(fin, d[i]);
readln(fin);
close(fin);
end;

procedure afisare;
var i: Vf;
begin
writeln(fout, 'Muchiile arborelui sunt: ');
for i := 1 to n-1 do write (fout, '(', i, ',', a[i], ') ');
writeln(fout);
end;

begin
citire;
assign(fout,'grade.out'); rewrite(fout);
s := 0;
for i := 1 to n do s := s+d[i];
if s <> 2*(n-1)then
writeln(fout,'Secventa eronata! Suma gradelor trebuie sa
fie 2(n-1)!')
else
for VfT := 1 to n-1 do
begin
VfNt := VfT+1;
while (VfNt < n) and (d[VfNT] = 1) do inc(VfNt);
a[VfT] := VfNt;
dec(d[VfNT]);
end;
afisare;
close(fout);
end.

De exemplu, pentru fişierul de intrare:


7
1112223
fişierul de ieşire va conţine:

46
Muchiile arborelui sunt:
(1,4) (2,5) (3,6) (4,7) (5,7) (6,7)
program Generare_Arbori_cu_n_Varfuri;
const NrMaxVf=10;
type Vf = 1..NrMaxVf;
Arbore = array[Vf] of Vf;
var n: Vf;
fout: text;
a: Arbore;
NrArb: longint;

procedure determina_arbore;
var MB, MA: set of Vf;
i, k: Vf;
begin
inc(NrArb);
write(fout, 'Arborele nr. ',NrArb,' :');
MB := []; MA := [];
for i := 1 to n-1 do MA := MA+[a[i]];
for i := 1 to n-1 do
begin
k := 1;
while k in MA+MB do inc(k);
MB := MB+[k];
MA := MA-[a[i]];
write(fout, '(', k, ',', a[i], ') ');
end;
writeln(fout);
end;

procedure generare(i: Vf);


var j: Vf;
begin
if i = n-1 then
determina_arbore
else
for j := 1 to n do
begin
a[i] := j;
generare(i+1);
end;
end;

begin {program principal}


write('Introduceti numarul de varfuri '); readln(n);
a[n-1] := n;
NrArb := 0;
assign(fout,'arbnvf.out');
rewrite(fout);
generare(1);
close(fout);
end.

47
De exemplu, pentru n=4, conţinutul fişierului de ieşire va fi:
Arborele nr. 1 :(2,1) (1,1) (3,4)
Arborele nr. 2 :(3,1) (1,2) (2,4)
Arborele nr. 3 :(2,1) (1,3) (3,4)
Arborele nr. 4 :(2,1) (1,4) (3,4)
Arborele nr. 5 :(3,2) (2,1) (1,4)
Arborele nr. 6 :(1,2) (2,2) (3,4)
Arborele nr. 7 :(1,2) (2,3) (3,4)
Arborele nr. 8 :(1,2) (2,4) (3,4)
Arborele nr. 9 :(2,3) (3,1) (1,4)
Arborele nr. 10 :(1,3) (3,2) (2,4)
Arborele nr. 11 :(1,3) (2,3) (3,4)
Arborele nr. 12 :(1,3) (2,4) (3,4)
Arborele nr. 13 :(2,4) (3,1) (1,4)
Arborele nr. 14 :(1,4) (3,2) (2,4)
Arborele nr. 15 :(1,4) (2,3) (3,4)
Arborele nr. 16 :(1,4) (2,4) (3,4)

program Operatii_pe_arbori_binari;
const NrMaxVf = 20;
type Vf = 0..NrMaxVf;
ArboreBinar = ^NodArboreBinar;
NodArboreBinar = record
inf: char;
st, dr: ArboreBinar;
end;
var n: Vf;
fin, fout: text;
A: ArboreBinar;
function CreareArbore(x: Vf): ArboreBinar;
{creeaza un arbore binar echilibrat cu n varfuri}
var rad: ArboreBinar;{radacina arborelui care se creaza}
begin
if x = 0 then {arbore vid}
CreareArbore := nil
else
begin
new(rad);{aloc memorie pentru radacina arborelui}
read(fin, rad^.inf);
{citesc informatia asociata radacinii}
rad^.st := CreareArbore(x div 2);
{creez subarborele stang}
rad^.dr := CreareArbore(x-x div 2 -1);
{creez subarborele drept}
CreareArbore:=rad;
end;
end;

procedure preordine(rad: ArboreBinar);


{parcurge recursiv in preordine arborele binar cu radacina rad}

48
begin
if rad <> nil then
begin
write(fout, rad^.inf);
preordine(rad^.st);
preordine(rad^.dr);
end
end;

procedure postordine(rad: ArboreBinar);


{parcurge recursiv in postordine arborele cu radacina rad}
begin
if rad <> nil then
begin
postordine(rad^.st);
postordine(rad^.dr);
write(fout, rad^.inf);
end
end;

procedure inordine_iterativ(rad: ArboreBinar);


{parcurge iterativ in inordine arborele binar cu radacina rad}
type Stiva = ^NodStiva;
NodStiva = record
inf: ArboreBinar;
urm: Stiva
end;
var S, p: Stiva;
NodCurent: ArboreBinar;
begin
write(fout, 'Parcurgerea inordine: ');
S := nil;
NodCurent := rad;
repeat
while NodCurent <> nil do
begin {introduc in stiva nodul curent}
new(p); p^.inf := NodCurent; p^.urm := S; S := p;
NodCurent := NodCurent^.st;
end;
{extrag, daca este posibil, un element din stiva si
vizitez nodul din arbore corespunzator}
if S <> nil then
begin
p := S; S := S^.urm;
write(fout, p^.inf^.inf);
NodCurent := p^.inf^.dr;
dispose(p);
end;
until (S = nil) and (NodCurent = nil);
writeln(fout);
end;

procedure parcurgere_pe_niveluri(rad: ArboreBinar);


{parcurge pe niveluri arborele binar cu radacina rad}

49
type Coada = ^NodCoada;
NodCoada = record
inf: ArboreBinar;
urm: Coada
end;
var IncC, SfC, p, q: Coada;
begin
write(fout, 'Parcurgerea pe niveluri: ');
if rad <> nil then
begin
{initializez coada cu radacina arborelui}
new(IncC); IncC^.inf := rad; IncC^.urm := nil; SfC := IncC;
while IncC <> nil do
begin
p := IncC;
write(fout, p^.inf^.inf);
{vizitez nodul din arbore corespunzator lui p}
if p^.inf^.st <> nil then
{inserez in coada fiul stang al nodului vizitat}
begin
new(q); q^.inf := p^.inf^.st; q^.urm := nil;
SfC^.urm := q; SfC := q
end;
if p^.inf^.dr <> nil then
{inserez in coada fiul drept al nodului vizitat}
begin
new(q); q^.inf := p^.inf^.dr; q^.urm := nil;
SfC^.urm := q; SfC := q
end;
{extrag efectiv din coada nodul p}
IncC := IncC^.urm;
dispose(p)
end;
end;
writeln(fout)
end;

function max(a, b: integer): integer;


begin
if a > b then max := a
else max := b
end;

function inaltime(rad: ArboreBinar): integer;


{intoarce inaltimea arborelui binar cu radacina rad}
begin
if rad = nil then {arborele este vid}
inaltime := -1
else
inaltime := max(inaltime(rad^.st), inaltime(rad^.dr))+1;
end;

begin {program principal}


assign(fin,'opbin.in'); reset(fin);

50
assign(fout,'opbin.out'); rewrite(fout);
readln(fin,n);
A:=CreareArbore(n);
close(fin);
write(fout,'Parcurgerea preordine: '); preordine(A);
writeln(fout);
write(fout,'Parcurgerea postordine: '); postordine(A);
writeln(fout);
inordine_iterativ(A);
parcurgere_pe_niveluri(A);
writeln(fout, 'Inaltimea arborelui este: ', inaltime(A));
close(fout);
end.

program Constructie_Arbore_Binar;
const NrMaxVf = 20;
type Vf = 0..NrMaxVf;
ArboreBinar = ^NodArboreBinar;
NodArboreBinar = record
inf: Vf;
st, dr: ArboreBinar;
end;
Parcurgere = array[Vf] of Vf;
var A: ArboreBinar;
i: Parcurgere;{parcurgerea inordine}
n: Vf;{numarul de varfuri din arbore}
fout: text;
function ConstrArb(rad, st, dr: Vf): ArboreBinar;
{functia intoarce un adresa radacinii arborelui binar cu
radacina rad; st,dr reprezinta limitele intre care se gaseste
parcurgerea inordine a arborelui in vectorul i}
var r: ArboreBinar;
IPozRad: Vf;
begin
new(r); r^.inf := rad;
{determin pozitia radacinii in parcurgerea inordine}
IPozRad := st;
while i[IPozRad] <> rad do inc(IPozRad);
if IPozRad = st then {subarborele stang este vid}
r^.st := nil
else
{i[st..IPozRad-1] constituie parcurgerea inordine a
subarborelui stang, cu radacina rad+1}
r^.st := ConstrArb(rad+1,st,IPozRad-1);
if IPozRad = dr then {subarborele drept este vid}
r^.dr := nil
else
{i[IPozRad+1..dr] constituie parcurgerea inordine a
subarborelui drept, cu radacina rad+IPozRad-st+1,
deoarece in subarborele stang sunt IPozRad-st+1 varfuri}
r^.dr := ConstrArb(rad+IPozRad-st+1,IPozRad+1,dr);

51
ConstrArb := r;
end;

procedure Citire;
var k: Vf;
fin: text;
begin
assign(fin,'pi.in'); reset(fin);
readln(fin,n);
for k := 1 to n do read(fin, i[k]);
readln(fin);
close(fin);
end;

procedure preordine(rad: ArboreBinar);


{parcurge recursiv in preordine arborele binar cu radacina rad}
begin
write(fout, rad^.inf, '(');
if rad^.st <> nil then preordine(rad^.st);
write(fout, ',');
if rad^.dr <> nil then
preordine(rad^.dr);
write(fout, ')');
end;

procedure AfisareArb;
begin
assign(fout,'pi.out'); rewrite(fout);
if A = nil then
write(fout, 'Arbore vid')
else
preordine(A);
{afiseaza reprezentarea cu paranteze a arborelui}
writeln(fout);
close(fout);
end;
begin {program principal}
Citire;
if n > 0 then
A := ConstrArb(1, 1, n)
else
A := nil;
AfisareArb;
end.

De exemplu, pentru fişierul de intrare:


10
3 4 5 2 6 1 8 7 10 9
fişierul de ieşire va fi:
1(2(3(,4(,5(,))),6(,)),7(8(,),9(10(,),)))

{$N+ }

52
program Numar_Arbori_Binari_Distincti;
var NrVf, i: byte;
NrArb: extended;
begin
write('Introduceti numarul de varfuri '); readln(NrVf);
NrArb := 1;
for i := 2 to NrVf do
NrArb := NrArb*(NrVf+i)/i;
writeln('Nr. de arbori binari distincti cu ',NrVf,'varfuri: ');
writeln(NrArb:50:0);
readln
end.

53
54
55