Sunteți pe pagina 1din 130

Structuri de date i algoritmi

_______________________________________________________________________________

V. TEHNICI DE CAUTARE
V.1. Introducere n tehnicile de cutare

O operaie fundamental intrinsec pentru un numr mare de probleme de calcul este


cutarea: recuperarea unei buci de informaii dintr-o mulime de informaii stocate anterior.
De obicei informaia este divizat in mai multe nregistrri, fiecare nregistrare are o cheie
care este folosit n procesul de cutare. Obiectivul cutrii este de a gsi toate nregistrrile care au
chei identice cu cea care este cheia de cutare. Scopul cutrii este de a accesa informaiile din
nregistrri pentru procesare.
In cazul procesului de cutare avem diferite programe care sunt cunoscute pretutindeni i
utilizate frecvent, deci merit s studiem o serie de metode mai detaliat. Vom ncepe cu studierea
unor metode elementare care sunt utilizate cu succes pentru tabele de dimensiuni mici i n alte
situaii speciale i ilustreaz fundamental tehnicile exploatate de ctre metode mult mai avansate.
Vom studia metodele care stocheaz nregistrri n liste, care sunt cutate ori prin compararea
cheilor sau prin indexare valorii cheii i vom studia metode fundamentale care construiesc structuri
definite de valoarea cheii.
Cutarea reprezint operaiunea care dureaz cel mai mult n majoritatea programelor de
prelucrare, iar nlocuirea unei metode mai proaste de cutare cu una mai bun conduce deseori
la o cretere substanial n viteza de prelucrare.
Deci scopul acestui capitol este s prezinte ntr-o manier accesibil pentru programatori
cteva tehnici de cutare cum ar fi: cutarea secvenial, cutarea binar, arbori binari de cutare
si tabele de dispersie (hash) precum o serie de tehnici de rezolvare a coliziunilor [Kor, 1988].
n locul descrierii la nivel conceptual a soluiilor unor probleme de programare, folosind
exclusiv instrumente "artificiale" gen Pseudocod, care s fie adaptate mai mult sau mai puin
claselor de algoritmi discutai, prezentarea celor mai performante soluii teoretice este completat
de descrierea metodelor i mecanismul de implementare a lor, folosind limbajul de programare
Pascal.

V.1.1.CUTARE SECVENTIAL

V.1.1.1. Descrierea general a metodei

Cea mai simpl metod de cutare este cutarea secvenial. O metod simpl de stocare a
informaiei este stocarea nregistrrilor ntr-o tabel. Cnd o nou nregistrare este inserat, acesta se
adaug n poziia dorit, cnd trebuie efectuat o cutare, tabela este parcurs secvenial.
Cutarea secvenial este cea mai simpl metod de cutare a unei nregistrri ntr-o tabel

________________________________________________________________________________

170
Structuri de date i algoritmi
_______________________________________________________________________________

neordonat, ntr-un mod secvenial, pn cnd nregistrarea dorit este gsit.


n multe aplicaii este nevoie ca s extindem programul pentru ca s putem lucra cu
nregistrri si chei mai complicate, dar acesta nu va afecta fundamental algoritmul de cutare.
Alte operaii posibile ntr-o tabel, n afar de operaia de cutare, sunt operaiile de
inserare i tergere. Datele pot fi inserate sau terse la nceputul tabelei, la sfritul tabelei i n
interiorul tabelei.
Un algoritm de inserare la sfritul tabelei, implementat n Pascal, este prezentat mai jos:

PROCEDURE INSERARE;
BEGIN
WRITE('Introducei elementul pe care dorii s-l inserai:');
READLN(g);
T[nr+1]:=g; { nr numrul de elemente din tablou }
END;

In cazul operaiei de tergere la nceput primul element din tabel este ters, iar celelalte
elemente se vor translata fiecare cu o poziie n sus n tabel. Un algoritm general pentru cutare
secvenial este prezentat mai jos.
Avem un vector neordonat T avnd MAX (MAX >= 1) elemente. Acest algoritm caut n
vectorul T elementul particular avnd valoarea X. Funcia returneaz indexul elementului vector
dac cutarea este cu succes altfel returneaz 0.
Secvena de instruciuni n Pseudocod este:

k := 1;
CTTIMP k <= MAX EXECUT
DAC T[k] = X
ATUNCI
@ returneaz k; {cutare cu succes}
EXIT;
ALTFEL
k := k + 1;
SFDAC
SFCT
@ returneaz 0; {cutare cu insucces}

Primul pas al algoritmului iniializeaz valoarea variabilei k, cu ajutorul creia parcurgem


tabela. n pasul al doilea se face o cutare secvenial. Dac variabila k depete capacitatea
maxim MAX atunci avem cutare fr succes (nu s-a gsit un element al tabelei cu valoarea X),
altfel avem cutare cu succes i variabila k va conine indexul nregistrrii cutate.
Implementarea n PASCAL a algoritmului de cutare secvenial este:

________________________________________________________________________________

171
Structuri de date i algoritmi
_______________________________________________________________________________

Exemplul 4.1.
Function CAUTARE _SECVENTIALA ( T , j , X ) : integer ;
Begin
k := 1 ; { k - elementul cu care parcurgem tabela }
OK := false
while ( not OK ) and ( k <= j ) do { j - numrul de elemente din tabela T }
begin
if T [ k ] = X then { X cheia cutat }
begin
OK := true ;
CAUTARE_SECVENTIALA := k ;
end ;
exit
else
k := k + 1 ;
end;
CAUTARE_SECVENTIALA := 0 ;
end ;

Performana unei metode de cutare se msoar prin numrarea comparaiilor cheii pn ce


este gsit o nregistrare particular. Sunt dou cazuri importante i anume [Aho, 1987]:
Cazul general (Average Length of Search - ALOS)
Cazul cel mai nefavorabil (Worst Length of Search - WLOS) .
Cutarea secvenial (implementare cu ajutorul unui vector de dimensiune n), necesit n
cazul cel mai nefavorabil (cutare fr succes) n+1 operaii de comparaie, iar n cazul general,
avem (n+1)/2 operaii de comparaie pentru o cutare cu succes. Formula de calcul a performanelor
metodei de cutare n cazul general ALOS , este exprimat prin formula ([Tre, 1984]):
n
ALOS p i nri (5.1)
i 1

unde pi reprezint probabilitatea ca informaia a-i-a s fie cutat, iar nri reprezint numrul de
operaii necesar accesrii informaiei a-i-a. Probabilitatea ca o dat s fie cutat poate fi exprimat
prin raportul:
nr _ de _ cautari _ al _ datei _ i
pi (5.2)
nr _ total _ de _ cautari
Pentru o cutare cu succes, dac presupunem c probabilitatea de cutare a unei nregistrri
particulare este aceeai cu probabilitatea de cutare a altor nregistrri, atunci numrul general de
comparaii este:

________________________________________________________________________________

172
Structuri de date i algoritmi
_______________________________________________________________________________

n n 1
1 1 2 n
n
n 1
2
(5.3)
ALOS i
i 1 n n n 2
n cazul n care probabilitatea de accesare a datelor din tabel nu este echiprobabil, atunci
cea mai eficient metod de organizare a datelor este cea n ordine descresctoare a probabilitilor
de cutare, datele cele mai probabile a fi cutate fiind dispuse la nceputul tabelei. S dovedim
aceast afirmaie:
- fie datele organizate ntr-o tabel n ordinea descresctoare a probabilitilor de cutare, i
anume:

Data1 Data2 .. Datai .. Datan

astfel nct:
p1 p 2 p i p n (5.4)

Pentru aceast organizare a datelor n tabel avem performana:


n n
ALOS1 p i nri p i i 1 p1 2 p 2 i p i j p j n p n
i 1 i 1

unde i j . S presupunem c exist o alt organizare a datelor, unde acestea nu sunt organizate n
tabel n ordinea descresctoare a probabilitilor de cutare (5.3), i s msurm performana
ALOS a algoritmului de cutare. Este suficient s presupunem c exist o simpl permutare a
datelor, i anume c avem permutate Datai cu Dataj n tabel. n aceast situaie performana
algoritmului de cutare este:
n n
ALOS 2 pi nri p i i 1 p1 2 p 2 i p j j p i n p n
i 1 i 1

S comparm cele dou performane:


ALOS1 ALOS 2 i p i j p j i p j j p i p i i j p j j i p i p j i j 0 deoarece
p i p j i i j .

Concluzia este evident, organizarea datelor ntr-o tabel pentru a avea cea mai bun
performan media a operaiei de cutare este conform cu (5.4), adic datele trebuie organizate n
ordine descresctoare a probabilitii de cutare.

V.1.1.2. Probleme rezolvate pentru cutare secvenial

Exemplul 4.2. Problema cutrii unei nregistrri particulare ntr-o tabel


Fiind dat un tablou cu o capacitate de maxim MAX nregistrri posibile (nregistrri de tip
numr ntreg ), se cere implementarea n limbajul Pascal a unui algoritm algoritmi care s realizeze
________________________________________________________________________________

173
Structuri de date i algoritmi
_______________________________________________________________________________

urmtoarele operaii: inserare, cutare (secvenial) i tergere n tablou.

Program cautare_in_tabel ;
const
MAX=100;
type
tablou = array [1..MAX] of integer;
var
T : tablou ;
d , nr , k , g , i , j : integer ;
a : char ;

Procedure TESTARE ;
begin
if nr > MAX then begin
{ nr numrul elementelor din tabel }
{ MAX numrul maxim de elemente }
write ( ' Depire capacitate ' ) ;
delay ( 4000 ) ;
halt ;
end ;
end ;

Procedure INSERARE ;
begin
write ( ' Introducei elementul de inserat: ' ) ;
readln ( g ) ; { g elementul care se nsereaz }
for k := nr downto 1 do
T[ k+1 ] := T [ k ] ;
T[ 1 ] := g ;
writeln ( ' Tabloul este: ' ) ;
for i := 1 to (nr + 1) do
writeln ( ' T[ ' , i , ' ]= ' , T[ i ] ) ;
readln ;
end ;

Procedure STERGERE ;
begin
write ( 'Introducei poziia elementului de sters: ' ) ;
readln ( d ) ; { d reprezint poziia elementului care va fi ters }
for k := d+1 to nr do
T [ k-1 ] := T [ k ] ;
writeln ( ' Tabloul este : ' ) ;
for i := 1 to ( nr-1 ) do
writeln ( ' T [ ' , i , ' ]= ' , T [ i ] ) ;
________________________________________________________________________________

174
Structuri de date i algoritmi
_______________________________________________________________________________

readln ;
end ;

Procedure CAUTARE ;
var
ok : boolean ;
h : integer ;
begin
write ( ' Introducei elementul cutat : ' ) ;
readln ( h ) ; { h elementul cutat }
ok := false ;
for i := 1 to nr do
begin
if T[ i ] = h then
begin
ok := true;
writeln ( ' Elementul cutat se afl pe poziia : ' , i ) ;
end ;
end ;
if not ok then
writeln ( ' Elementul cutat nu exist n tablou ! ' ) ;
readkey ;
end ;

BEGIN
clrscr ;
write ( ' Introducei nr. de elemente dorite : ' ) ;
readln ( nr ) ;
TESTARE ;
for i := 1 to nr do
begin
write ( ' T[ ' , i , ' ] = ' ) ;
readln ( T[ i ] ) ;
end ;
repeat
clrscr ;
writeln ( ' Apsai tasta dorit : ' ) ;
writeln ( ' 0 : Pentru nserare n tablou ' ) ;
writeln ( ' 1 : tergere n tablou ' ) ;
writeln ( ' 2 : Cutare n tablou ' ) ;
writeln ( Pentru ieire din program apsai tasta Esc ) ;
a := readkey ;
case a of
' 0 ' : INSERARE ;
' 1 ' : STERGERE;
' 2 ' : CAUTARE ;
________________________________________________________________________________

175
Structuri de date i algoritmi
_______________________________________________________________________________

end ;
until a = # 27 ;
END.

Exemplul 4.2. Problema elementelor pozitive, negative si nenule

Numrai elementele pozitive, negative i nenule ale unei liste ntr-o funcie care dup
apelare, returneaz un pointer la un vector cu trei componente, ce stocheaz rezultatele parcurgerii
listei.

Program numara ;
type
plista = ^ lista ;
lista =record
b : integer ;
paue : plista ;
end ;
vec = array [ 1..3 ] of byte ;
pv = vec ;
var
cp1 : plista ;
i, n : integer ;
vect : vec ;
pvec : pv ;

Function creare ( n:integer ) : plista ;


var
prad : plista ;
begin
if n = 0 then
creare := NIL
else
begin
n := n-1;
write ( ' Dati elementul : ') ;
new (prad) ;
readln (prad ^.b) ;
prad ^.paue := creare (n) ;
creare := prad ;
end ;
end ;

Function numr (p1 : plista) : pv ;


var
plucru : pv ;
________________________________________________________________________________

176
Structuri de date i algoritmi
_______________________________________________________________________________

begin
plucru := vect ;
for i := 1 to 3 do
plucru ^[ i ] := 0 ;
while p1 < > NIL do
begin
if p1 ^. b > 0 then
plucru ^ [ 1 ] := plucru ^[ 1 ] + 1
else
if p1 ^.b < 0 then
plucru ^ [ 2 ] := plucru ^[ 2 ] + 1
else
plucru ^ [ 3 ] := plucru ^[ 3 ] + 1 ;
p1 := p1 ^.paue ;
end ;
numr := plucru ;
end ;
BEGIN
write (' Introduceti numrul de elemente ale listei : ') ;
readln (n) ;
cp1 := creare (n) ;
pvec := numr (cp1) ;
writeln ;
END.

V.1.1.3. Probleme propuse

1. Dac toate cheile de cutare sunt echiprobabile, care este deviaia standard a numrului de
comparaii efectuate ntr-o cutare secvenial cu succes ntr-un tabel cu N nregistrri ?

2. Presupunem c dorii s cutai ntr-un fiier voluminos ,nu dup criteriul egalitii, ci pentru a
gsi 1000 de nregistrri cele mai apropiate unei chei date, n sensul c aceste 1000 de
nregistrri au cea mai mic valoare a lui d (Ki,K) pentru o funcie d de distan dat. Care
structur de date este cea mai adecvat pentru o asemenea cutare secvenial ?

3. Fiind date dou succesiuni < X1 , X2 , , Xn> i < Y1 , Y2 , , Yn> de numere reale, care
permutare a1*a2**an a indiciilor va determina valoarea maxim al lui (Xi * Yai)? Dar
valoarea minim ?

4. Un programator dorete s testeze dac n condiii date snt sau nu simultan ndeplinite. (De
exemplu, el poate dori s testeze dac simultan este adevrat ca x > 0 si y < z*z, dar nu este
evident care dintre condiii trebuie testat prima). S presupunem c sunt necesare T i uniti de
________________________________________________________________________________

177
Structuri de date i algoritmi
_______________________________________________________________________________

timp pentru testarea condiiei i i c aceast condiie se adeverete cu probabilitatea P i,


independent de rezultatul celorlalte teste de condiii. n care ordine trebuie s se execute testarea
condiiilor ?

5. Fiind dat un text cu maxim 80 de caractere ce se termin cu caracterul $, s se scrie un program


care s afieze textul n ordine invers.

6. Dac X este un vector cu n componente reale, scriei secvene de instruciuni pentru a obine
urmtoarele transformri ( fr a folosi un vector suplimentar ) :

a ) ( X1 , X2 , , Xn ) ( Xn , X1 , X2 , , Xn-1 )
b ) ( X1 , X2 , , Xn ) ( Xn , Xn-1 , Xn-2 , , X2 ,X1 )
c ) ( X1 , X2 , , Xn ) ( X i1 ,Xi2 , , Xin )
astfel nct X i1 < X i2 < < X in iar 1 < = ik < = n ; 1 < = k < = n .
d ) Pe primele poziii s apar elementele negative in aceeai ordine ca n irul iniial .

7. Se consider un text ce conine litere mari, litere mici, semnele de punctuaie: , ; . ; : ; ! ;


? ; - ; _ ; i se termin cu caracterul $. S se afieze numrul de apariii ale fiecrui
caracter, precum i numrul de caractere diferite ntlnite n text. Se presupune c $ nu este un
caracter al textului.

8. Fie E un numr natural cu n cifre memorate ntr-un vector cu n din domeniul 0..9. S se verifice
dac E este un numr divizibil cu :
a) 2 ; b) 5 ; c) 4 ; d) 3 ; e) 9 ; f) 7 ; g)11 ; h) 8 ; i) 25 ; j) 125 ;
k) 13 ; l) 27 ; m) 37 ; n) 6 ; o) 15.

9. S se afieze toate numerele de n cifre care adunate cu rsturnatul lor dau un ptrat perfect .

10. S se implementeze un algoritm care rearanjeaz toate elementele dintr-un tablou


unidimensional, astfel nct toate valorile negative vor precede pe cele pozitive . S se utilizeze
un numr minim de interschimbri .

11. S se implementeze un algoritm care pentru dou numere ntregi cu n cifre memorate vectorial
s determine suma, produsul, ctul i restul mpririi primului numr la al doilea numr.
Rezultatele se vor obine sub forma vectorial .

V.1.2. CUTARE BINAR

V.1.2.1.Descrierea general a metodei

________________________________________________________________________________

178
Structuri de date i algoritmi
_______________________________________________________________________________

O alt metod relativ simpl de accesare a unei tabele este metoda cutrii binare.
Organizarea datelor n aceast tabel se bazeaz pe ordonarea linear a cheilor (de exemplu, n
ordine alfabetic sau ordine numeric cresctoare). O metod potrivit pentru ordonarea datelor este
sortarea, despre care vom vorbi ntr-un alt capitol.
O cutare pentru o nregistrare cu o anumit valoare a cheii este asemntoare cu cutarea
unui nume ntr-o agend de telefoane. Este localizat cu aproximaie nregistrarea din mijlocul
tabelei, este comparat cheia nregistrrii din mijloc cu cheia nregistrrii cutate. Dac cheia
cutat este mai mare dect valoarea cheii din mijloc atunci procedura se repet n jumtatea de
interes a tabelei, pn cnd nregistrarea dorit este gsit sau intervalul de cutare este gol, ceea ce
semnific lipsa cheii cutate.

n Figura 4.1 avem un exemplu de cutare binar a cheii m aflat ntr-o tabel construit
prin inserarea cheilor a s e a r c h i n g e x a m p l e (Tre, [1984]). Intervalul de chei este
njumtit la fiecare pas, deci numai patru comparaii snt necesare n acest caz.

Figura 1. Exemplu de cutare binar.

Operaia de inserare (metoda inseriei binare ) realizeaz n fiecare din cei N-1 pai ai si
nserarea celei de a i a nregistrri din tabloul iniial n irul deja sortat al precedentelor i -1
nregistrri .
Determinarea poziiei de nserare se face prin cutare binar, folosindu-se faptul c

nregistrrile precedente sunt deja sortate i reducndu-se astfel numrul mediu de comparaii
necesare de la i/2 la log 2 i .
Operaia de tergere este identic cu cea din cutarea secvenial, adic elementele din
tablou, aflate naintea elementului care va fi ters, vor rmne pe loc, poziiile lor nu se schimb
Elementele care se afl dup elementul care va fi ters, vor fi translatate cu o poziie.

V.1.2.2. Descrierea algoritmului de cutare n Pseudocod

Un algoritm pentru o astfel de procedur de cutare este prezentat n rndurile urmtoare.


Avem un vector K cu N elemente ordonate cresctor, acest algoritm face o cutare pentru
un element cu valoarea X. Variabilele LOW, MIDDLE i HIGH noteaz limita inferioar,

________________________________________________________________________________

179
Structuri de date i algoritmi
_______________________________________________________________________________

mijlocul i limita superioar a intervalului de cutare. Funcia de cutare returneaz indexul


elementului cutat, dac avem o cutare cu succes, altfel returneaz valoarea 0.

LOW := 1
HIGH := N
CTTIMP LOW <= HIGH EXECUT
MIDDLE := [(LOW +HIGH ) / 2 ]
DAC X < K [MIDDLE]
ATUNCI HIGH := MIDDLE-1
ALTFEL DAC X > K [MIDDLE]
ATUNCI LOW := MIDDLE + 1
ALTFEL {Cutare cu succes }
@returneaz MIDDLE.
SFDAC
SFDAC
SFCT
@returneaz 0. {Cutare fr succes }

Pasul 1 iniializeaz variabilele LOW i HIGH, pasul 3 calculeaz valoarea variabilei


MIDDLE, care este mijlocul tabelei. Pasul 4 face comparaiile ntre cheia de cutat i valorile limit
i returneaz cheia cutat dac este gsit. Pasul 5 returneaz valoarea 0, adic cutare fr succes.
Cutarea binar poate fi fcut i n mod recursiv. La un astfel de algoritm este important
timpul de execuie (timpul de cutare ) i spaiul folosit. Descrierea algoritmului de cutare binar
(n mod recursiv ) n Pseudocod este prezentat n continuare .
Avem un subinterval a crei limite snt P si Q, i un vector K. Acest algoritm recursiv caut
un element dat al crei valoare este stocat n variabila X , MIDDLE i LOC snt variabile de tip
ntreg.

FUNCTIA CAUTARE_BINARA _R (P , Q , K , X ) ESTE:


DAC P > Q
ATUNCI
LOC := 0;
ALTFEL
MIDDLE := [( P + Q )/ 2 ];
DAC X < K [MIDDLE ]
ATUNCI
LOC := CAUTARE_BINARA _R (P,MIDDLE-1,K,X );
ALTFEL
DAC X > K [MIDDLE ]
ATUNCI
LOC:=CAUTARE_BINARA _R (MIDDLE+1,Q,K,X );
ALTFEL
LOC := MIDDLE;
SFDAC
SFDAC

________________________________________________________________________________

180
Structuri de date i algoritmi
_______________________________________________________________________________

SFDAC
SF-CAUTARE_BINARA;

Exemplul 4.3. Implementarea algoritmului de cutare binar n Pascal.

Function CAUTARE _BINARA ( K , LOW,HIGH ,MIDDLE, X ) : integer ;


Begin
LOW := 1 ;
HIGH := N;
repeat
MIDDLE := (LOW + HIGH) / 2 ;
if X < K[MIDDLE] then
begin
HIGH := MIDDLE-1
else if X > K[MIDDLE] then do
LOW := MIDDLE + 1
else begin
writeln ( Cutare cu succes ! ) ;
writeln ( Poziia : , MIDDLE );
exit ;
end ;
end ;
until LOW <= HIGH;
writeln ( Cutare fr succes ! ) ;
end ;

V.1.2.3. Performana algoritmului de cutare

Timpul de cutare (execuie), T(n) depinde de numrul de comparaii efectuate, care depind
la rndul lor de poziia informaiei cutate X. n cel mai bun caz, informaia cutat este poziionat
n 1
n locaia (am notat cu [ ] funcia parte ntreag). n aceast situaie este necesar doar o
2

________________________________________________________________________________

181
Structuri de date i algoritmi
_______________________________________________________________________________

singur operaie de comparaie, deci T(n) = O(1). Cutarea binar nu folosete nici odat mai mult
de lg N +1 comparaii pentru cutarea cu succes, ct i pentru cutarea fr succes ([Aho, 1987]).
In procesul de cutare binar recursiv cheia cutat este gsit n maximum logN comparaii
care este un ctig deosebit faa de cele N/2 comparaii ale cutrii secveniale .
Pentru a determina timpul de cutare n cazul operaiei de cutare binar, vom considera c
toate datele sunt echiprobabile. Pentru a simplifica analiza vom presupune c dimensionalitatea
datelor este de forma n 2 k 1 . Atunci k log 2 n 1 .
Aceast ipotez nu distruge generalitatea argumentaiei, cci putem oricnd completa o
structur de date cu elemente care nu sunt cutabile, ca s o aducem la forma 2k 1. Oricum, timpul
de execuie al structurii de date originale va fi mai mic sau egal dect a structurii de date aduse la
forma n 2 k 1 .
S notm cu Si, numrul de elemente pentru care algoritmul de cutare binar efectueaz un
numr de i operaii (comparaii). Avem:

S 1 1 2 0 ; S 2 2 21 ; S 3 4 2 2 ; , S i 2 i 1 , i k

Aplicnd formula (5.1) vom avea:

1 k
i i 2 i 1 i 2 i 2 i 1 i 2 i i 1 2 i
k 1
k k
Si 1 k 1 k
T n pi d i
i 1 i 1 n n i 1 n i 1 n i 1 i 0
1 1

i 2 i 2 2 i k 2 k 2 k 1 k 1 2 k 1 k k 1
k k 1 k 1
i i 1 k
n i 1 i 1 i 0 n n n
log 2 n 1 1
log 2 n 1 1 1 log 2 n 1 1 log 2 n
n n
Putem considera c avem: T n O log 2 n , att pentru cazul general ct i pentru cel mai
nefarorabil caz.

In caracterizarea acestui algoritm pe lng timpul de execuie este important i spaiul


necesar pentru memorarea datelor. Pentru algoritmul de cutare binar analiza spaiului este mai
interesant dac presupunem c vectorul este transmis ca i parametru prin valoare [Sed, 1988].
Acesta nseamn c pentru fiecare accesare a funciei Cutare_Binar_R are loc o stocare local
diferit pentru vector (vectorul are mai multe copii). Deci spaiul pentru un apel al rutinei este
prorional cu O(n). Dup cum am vzut mai sus, n cazul general sau cel mai nefavorabil avem
nevoie de O(log2n) operaii de cutare , adic n final avem nevoie de un spaiu de memorie
proporional cu O(n log2n).
Observaia 4.1:
Tehnica de cutare binar are i unele proprieti nedorite. Inserarea unei noi nregistrri
impune ca o serie de nregistrri existente n tabel s fie mutate fizic pentru a pstra ordinea
cresctoare. O situaie similar este prezent i n cazul procesului de tergere .
La aceast metod timpul necesar operaiei de tergere ocup o proporie mare din timpul de
cutare. Cutarea binar este potrivit pentru aplicaii n care sunt efectuate puine operaii de
inserare sau tergere.

________________________________________________________________________________

182
Structuri de date i algoritmi
_______________________________________________________________________________

V.1.2.4. Probleme rezolvate pentru cutarea binar

Exemplul 4.3. Problema cutrii elementelor comune a dou iruri de numere [Tud, 1993].

Aceast problem construiete vectorul elementelor comune a doi vectori (a, b). Se va
parcurge secvenial vectorul a, i fiecare element care este gsit i n vectorul b va fi memorat ntr-
un vector nou c construit de ctre subprogram .
Acest program funcioneaz att pentru vectori ordonai cresctor, ct i pentru vectori
ordonai descresctor.

Program elemente_comune ;
const
max_elem = 10 ;
type
cazuri = ( constant , cresc , desc ,neord ) ;
val_indice = 1 .. max_elem ;
vector = array [val_indice ] of integer ;
var
a , b , c : vector ;
na , nb , ic , indice : val_indice ;
tip : cazuri ;

Procedure citete vector ( var x : vector ; var numr : val_indice ; car : char ) ;
var
i : integer ;
begin
i := 0 ;
repeat
i := i + 1 ;
write ( , car , [ , I :2 , ] = ) ; read (x [ i ]) ;
if ( i mod 5 ) = 0
then writeln ;
until ( x[ i ] < 0 ) or ( i > = max_elem ) ;
if x [ i ] < 0
then numr : = i 1
else
numr : = i ;
writeln ;
end
end ;

Procedure afieaz ( x : vector ; numr : val_indice ) ;


var
i : val_indice ;

________________________________________________________________________________

183
Structuri de date i algoritmi
_______________________________________________________________________________

begin
for i : = 1 to numr do
begin
write ( x [ , I : 2 , ] = , x [ I ] ) ;
If ( i mod 5 ) = 0
then writeln ;
end
end ;

function gasit ( x : vector ; numr : val_indice ; elem : integer ) : boolean ;


var
i : integer ;
begin
i := 1 ;
while ( x [ i ] <> elem ) and ( i < numr ) do
i := i + 1 ;
gasit := x [ i ] = elem
end ;

function tip_ord ( x : vector ; numr : val_indice ) : cazuri ;


var
ord_cresc , odr_desc : boolean ;
i : integer ;
begin
ord_cresc := true ;
ord_desc := true ;
i := 0 ;
while (ord_cresc or ord_desc ) and ( I < numr 1 ) do
begin
i := i+ 1 ;
if x [ i ] > x [ i + 1 ]
then ord_cresc := false ;
if x [ i ] < x [ i + 1 ]
then ord_desc := false ;
End ;
if ord_cresc and ord_desc
then tip_ord := constant { ir constant }
else
if ord cresc
then tip_ord :=cresc { ir cresctor }
else
if ord_desc
then tip_ord := desc {ir descresctor }
else tip_ord := neord ( ir neordonat }
end;

________________________________________________________________________________

184
Structuri de date i algoritmi
_______________________________________________________________________________

Function cautare_bin ( x : vector ; numr : val_indice ; valoare : integer ) : boolean ;


var
inferior , superior , mijloc : integer ;
begin
inferior := 1 ;
superior := numr ;
mijloc := ( inferior + superior) div 2 ;
while ( valoare <> x [ mijloc ] ) and ( ( superior inferior ) > 1 ) do
begin
if ( tip = cresc ) and ( valoare < x [ mijloc ] ) or
( tip = desc ) and ( valoare > x [ mijloc ] )
then superior := mijloc
else inferior := mijloc ;
mijloc := ( inferior + superior ) div 2 ;
end ;
if x [ mijloc ] <> valoare
then
begin
if x [ superior ] = valoare
then mijloc := superior ;
if x [ inferior ] = valoare
then mijloc := inferior
end;
cutare_bin := x [ mijloc ] = valoare
end ;

Procedure construieste (x ,y : vector ; nx , ny : val_indice ; var numr : val_indice ) ;


Procedure memoreaz ;
begin
if ( not gasit (c , numr , x [ indice ])) or ( numr = 0 )
then
begin
Numr := numr + 1 ;
c [ numr ] := x [ indice ]
end
end;

begin
numr := 0 ;
for indice := 1 to nx do
case tip of
constant : if x [ indice ] = y [ 1 ]
then memoreaz ;
desc , cresc : if cutare _bin ( y , ny , x [ indice ] )
then memoreaz ;
________________________________________________________________________________

185
Structuri de date i algoritmi
_______________________________________________________________________________

neord : if gsit ( y, ny , x [ indice ] )


then memoreaz
end;
end;

{ program principal }

BEGIN
citete vector ( a , na , a );
citete vector ( b , nb , b );
tip := tip_ord ( a , na ) ;
if tip = neord ;
then
begin
tip := tip_ord ( b , nb );
construiete ( a , b , na , nb , ic )
end
else
construiete ( b , a , nb , na , ic );
writeln ;
if ic <> 0
then
begin
writeln ( Elementele comune sunt : ) ;
writeln ;
afieaza ( c , ic );
end
else
writeln ( Nu exist elemente comune );
END.

Exemplul 4.4. Cutare binar ntr-un ir dat.

Se citete un ir cu un numr dat de componente numere reale i se introduce apoi de la


tastatur o valoare real. S se stabileasc dac valoarea dat se gsete sau nu n ir.

Program cutare_binar ;
var
a : array [ 1.. 1000 ] of real ;
x : real ;
i , n , margs , margd , jum : integer ;
este : boolean ;
BEGIN
write ( ' Nr . elemente = ') ;
readln ( n) ;
write ( ' Introducei elementele cu spaii sau enter : ') ;
________________________________________________________________________________

186
Structuri de date i algoritmi
_______________________________________________________________________________

for i := 1 to n do read ( a [ i ] ) ; readln ;


write ( ' Numrul cutat = ' ) ;readln ( x ) ;
if ( x = a [1] ) or ( x = a [n] then writeln ( ' este ' ) ;
else
begin
margs := 1 ; margd := n ;
{ marginile stnga / dreapta ale intervalului }
este := false ;
while ( margd - margs > 1 ) and not este do
begin
jum := trunc ( (margs + margd ) / 2 ) ;
{ mijlocul intervalului }
if a [jum] = x then este := true
else if x > a [jum] then margs := jum
else margd := jum
end ;
if este = true then writeln ( ' este ' )
else writeln ( ' nu este ' )
end ;
readln ;
END.

V.1.2.5.Probleme propuse

1. Dac o operaie de cutare ce folosete algoritmul de cutare secvenial necesit exact 638 de
operaii, ct va dura operaia de cutare dac folosete algoritmul de cutare binar?

2. Pentru ce valori al lui N algoritmul de cutare binar este n medie mai lent dect algoritmul de
cutare secvenial, presupunnd o cutare cu succes?

3. Problema 2 sugereaz c ar fi mai bine s dispunem de o metod hibrid, adic s trecem de la


cutare binar la cutare secvenial n momentul n care intervalul rmas are o lungime mai mic
dect o anumit valoare judicios aleas. Scriei un algoritm eficient pentru o asemenea cutare i
determinai valoarea optim de comutare.

4. ListaOrdonata este un tablou de tip ntreg cu 10 poziii. Cum ar arta tabloul ListaOrdinara n
cazul n care ar conine urmtoare valori, citite dintr-un fiier: 14, 27, 95, 12, 26, 5, 33, 15, 9, 99 i
elementele ar fi sortate n ordine cresctoare?

________________________________________________________________________________

187
Structuri de date i algoritmi
_______________________________________________________________________________

V.2. Arbori de cutare

V.2.1. Arbore binar de cutare

V.2.1.1. Descrierea general a arborelui binar de cutare

Intr-o structur de date de tip arbore de cutare, informaiile, sunt structurate pe nivele, pe
primul nivel, numit nivel 0, exist un singur element numit rdcin, 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 V.1).
Un arbore este compus din elementele numite noduri sau vrfuri i legturile dintre acestea.
Dup cum am vzut, cea mai des utilizat form de organizare a unui arbore binar este urmtoarea:

Cheia nodului fiu stnga < Cheia nodului fiu stnga < Cheia nodului fiu stnga (5.1)

Utiliznd formula de mai sus se obin arbori binari speciali, utilizai pentru organizarea i
cutarea datelor, numii arbori binari de cutare ABC.
Un nod situat pe un anumit nivel este nod tat pentru nodurile legate de el, situate pe nivelul
urmtor, acestea reprezentnd fii si. Arborii, ca structuri de date dinamice, au foarte multe aplicaii
n informatic. Structurile arborescente sunt foarte des utilizate pentru memorarea i regsirea
rapid a unor informaii. Informaiile sunt organizate dup un cmp numit cheie, ales de
programator, care servete la identificarea lor datelor stocate n structura arborescent. De exemplu,
dac datele sunt datele relative la studenii unei faculti, atunci cheia poate fi aleas ca fiind
numele i prenumele studentului. Cheile trebuie alese n aa fel nct s nu apar chei duble. n
exemplul nostru relativ la studenii unei faculti poate c ar fi mai bine s evitm posibilitatea
existenei unor chei duble, acelai nume i prenume, prin introducerea iniialei tatlui, evitnd astfel
cheile duble.
Un arbore binar de cutare este un arbore ale crui noduri cuprind o singur cheie de
identificare, nodurile cu chei mai mici dect o valoare X a cheii asociate unui anumit nod se gsesc
n subarborele stng al acestui nod, iar nodurile ale cror chei au valori mai mari dect X se gsesc
n subarborele su drept.
Cutarea unei informaii identificate printr-o valoare X a cheii ncepe de la rdcin i se
termin n cel mai ru caz la unul din nodurile terminale, cutarea presupunnd testarea a cel mult
attea noduri cte nivele are arborele binar de cutare. Dispunerea nodurilor arborelui pe nivele face
ca numrul operaiilor de testare la cutare s fie mult mai mic dect n cazul listelor ordonate.

________________________________________________________________________________

188
Structuri de date i algoritmi
_______________________________________________________________________________

Metoda cutrii binare prezentate n capitolul anterior poate fi explicat cu uurin cu


ajutorul arborilor de cutare. Figura urmtoare arat o reprezentare cu ajutorul arborilor binari al
algoritmului care corespunde cu algoritmul de cutare binar prezentat n capitolul anterior, pentru
N=10.

Figura V.1. Exemplu de arbore binar de cutare

V.2.1.2. Implementarea unui nod al arborelui ABC

Un nod al unui arbore ABC are urmtoarea structur:

Fiu_st Cheia Alte_info Fiu_dr

Figura V.2. Structura nodului ABC.


unde:
Fiu_st : reprezint adresa fiului stnga;
Cheia: reprezint cmpul ales dup care este ordonat ABC i care verific relaia (5.1);
Alte_info : alte informaii adiacente;
Fiu_dr : reprezint adresa fiului dreapta;

Structura nodului, n implementarea Pascal este urmtoarea :

________________________________________________________________________________

189
Structuri de date i algoritmi
_______________________________________________________________________________

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

V.2.1.3. Operaii ntr-un ABC

Operaiile n cazul arborilor binari de cutare sunt:


a. creare-iniializare;
b. inserare;
c. cutare;
d. tergere;
e. traversare:
Deoarece operaia de traversare a fost analizat i descris n capitolul anterior la arbori
binari (seciunea 4.5.2), ne vom ocupa de celelalte operaii specifice arborilor binari de cutare.

a. Operaia de creare-inializare. Specificarea problemei de creare-iniializare, avnd ca date de


intrare ABC specificat prin adresa ROOT a nodului rdcin, este urmtoarea:

DATE root;
REZULTATE root;

Descrierea algoritmului n Pseudocod este:

ALGORITMUL CREARE_INIIALIZARE ESTE: { Se creeaz un ABC vid }


ROOT := NIL;
SFALGORITM

b. Operaia de inserare. Specificarea problemei de inserare, avnd ca date de intrare ABC cu


adresa nodului rdcin ROOT i datele de inserat cheia_nou, info_nou, este urmtoarea:

DATE ROOT, cheia_nou, info_nou;


REZULTATE ROOT;

________________________________________________________________________________

190
Structuri de date i algoritmi
_______________________________________________________________________________

Vom folosi subalgoritmul numit Creare_nod care va aloca dinamic spaiul de memorie
necesar noului nod de inserat i va completa cmpurile nodului ABC.

OBS. 5.x: Vom folosi n cele ce urmeaz o referin de tip Pascal pentru algoritmul n Pseudocod, i
anume:
adresa^.cmp
unde adresa reprezint variabila de tip adres a nodului, iar cmp reprezint numele cmpului
nodului. Descrierea algoritmului n Pseudocod este:

SUBALGORITMUL Creare_nod (ch, inf) ESTE:


@Alocare_spaiu (NOU); { cererea de alocare spaiu 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 }
CITETE cheia_nou, info_nou;
DAC ROOT = NIL ATUNCI { primul nod inserat }
CHEAM Creare_nod (cheia_nou, info_nou); { se aloc spaiu pentru noul nod de }
ROOT = NOU; { inserat la adresa NOU i se completeaz cmpurile }
EXIT;
SFDAC
tmp := ROOT;
CTTIMP 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
TIPRETE (EROARE CHEIE DUBL);
EXIT;
SFDAC
SFDAC
SFCT
CHEAM Creare_nod (cheia_nou, info_nou);

________________________________________________________________________________

191
Structuri de date i algoritmi
_______________________________________________________________________________

DAC cheia_nou < tata^.cheia


ATUNCI
tata^.fiu_st := NOU;
ALTFEL
tata^.fiu_dr := NOU;
SFDAC
SFALGORITM

c. Operaia de cutare. Specificarea problemei de cutare, avnd ca date de intrare ABC cu


adresa nodului rdcin ROOT i cheia nodului cutat cheia_caut, este urmtoarea:
DATE root, cheia_caut;
REZULTATE adresa;
Obs. 5.x.: adresa returnat de algoritmul de cutare este adresa nodului cu cheia cheia_caut, dac
acesta exist. Dac nodul cu cheia cheia_caut nu exist n ABC atunci valoarea returnat va fi o
adres nul.

ALGORITMUL CAUT ESTE:


CITETE cheia_caut;
tmp := ROOT;
CTTIMP (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
SFCT
@returneaz adresa NIL;
SFALGORITM

d. Operaia de tergere. Specificarea general a problemei de tergere este:

DATE root, cheia_de_sters;


REZULTATE root;

Exist mai multe situaii posibile, n funcie de numrul de fii ai nodului de ters [Tre, 1984]:

________________________________________________________________________________

192
Structuri de date i algoritmi
_______________________________________________________________________________

Cazul 1: nodul de ters este un nod terminal, deci fr fii. Operaia de tergere necesit
eliminarea legturii nod_tat i nod_de_ters i eliberarea spaiului ocupat de nodul de ters.
Exemplu: nodurile cu cheia 1, 4, 7, 10 din ABC figura 5.1.

Cazul 2: nodul de ters este un singur fiu. Operaia de tergere necesit realizarea legturii
nod_tat i nod_de_fiu (stnga sau dreapta) i eliberarea spaiului ocupat de nodul de ters.
Exemplu: nodurile cu cheia 3, 6, 9 din ABC figura 5.1.

Cazul 3: nodul de ters este doi fii. n aceast situaie 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 stng 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 5.1. Nodul nlocuitor al nodului cu cheia 2 este
nodul cu cheia 1 din subarborele stng sau nodul cu cheia 3 din subarborele su drept. Nodul
nlocuitor al nodului cu cheia 5 este nodul cu cheia 4 din subarborele stng sau nodul cu cheia 6 din
subarborele su drept. Nodul nlocuitor al nodului cu cheia 8 este nodul cu cheia 7 din subarborele
stng sau nodul cu cheia 9 din subarborele su drept.

Obs. 5.x: Pentru a gsi nodul nlocuitor al unui nod de ters n Cazul 3, acesta poate fi gsit astfel:
Dac nodul nlocuitor este nodul cu cheia cea mai mare din punct de vedere lexicografic din
subarborele stng al nodului de ters atunci se navigheaz de la nodul de ters un pas la stnga i
orici pai la dreapta, pn ajungem la o legtur nul. Dac nodul nlocuitor este nodul cu cheia
cea mai mic din punct de vedere lexicografic din subarborele drept al nodului de ters atunci se
navigheaz de la nodul de ters un pas la dreapta i orici pai la stnga, pn ajungem la o legtur
nul.
Descrierea general a algoritmului de tergere, n Pseudocod este:

ALGORITMUL TERGERE ESTE:


CITETE cheia_de_sters;
DAC ROOT = NIL ATUNCI
TIPRETE (EROARE ARBORE VID);
EXIT;
SFDAC
tmp := ROOT; { Se caut nodul de ters }
CTTIMP (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
SFCT
DACA tmp = NIL ATUNCI
TIPRETE (EROARE NODUL NU EXIST N ABC);

________________________________________________________________________________

193
Structuri de date i algoritmi
_______________________________________________________________________________

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 spaiu (adr); { Eliberarea spaiului de la adresa adr }
SF-Cazul_1

SUBALGORITMUL Cazul_2 (rad, t, adr) ESTE:


DAC t^.fiu_st = adr ATUNCI { Nodul de ters este fiul stnga 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 spaiu (adr); { Eliberarea spaiului 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 stnga}
________________________________________________________________________________

194
Structuri de date i algoritmi
_______________________________________________________________________________

tata := tmp;
CTTIMP tmp^.fiu_dr <> NIL EXECUT { Orici pai la dreapta}

tata := tmp;
tmp := tmp^.fiu_dr; { Adresa tatlui nodului nlocuitor este n variabila tata}
SFCT { 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; { Eliminm legtura tata - nodul nlocuitor}
@Eliberare spaiu (tmp); { Eliberarea spaiului nod nlocuitor de la adresa tmp }
SF-Cazul_3
V.2.1.4. Probleme rezolvate

Exemplul 5.x: Problema arborilor asociai expresiilor aritmetice. Fiind date n expresii aritmetice
sintactic corecte care cuprind paranteze, operanzi notai cu literele mici din alfabet i operatori
binari sau unari din mulimea {+, -, *, / }, s se construiasc i s se afieze n postordine arborele
binar asociat fiecrei expresii [Dal, 1988].

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

Se observ c rdcina cuprinde simbolul ultimei operaii, subarborele stng, iar nodul din
dreapta corespunde operandului drept; aceeai 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 ( operaia este unar ).
Existena operatorilor "+" sau "-" unari modific numai diagrama de sintax a expresiei
aritmetice ( vezi figura ), celelalte rmnnd neschimbate.

________________________________________________________________________________

195
Structuri de date i algoritmi
_______________________________________________________________________________

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 ;

procedure expresie (var p : reper ) ; forward ;


procedure termen (var p : reper ) ; forward ;
procedure factor (var p : reper ) ;
{ creeaza nodul terminal p^ sau subarborele de radacina p^ }
{ asociat unei expresii aritmetice cuprinsa ntre () }
begin
if car = '(' then

________________________________________________________________________________

196
Structuri de date i algoritmi
_______________________________________________________________________________

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 in [ '*', '/' ] do
begin
new ( q ) ;
q ^.v := car ;
q ^.stg := p ;
citire ; { operandul 2 ncepe dup car }
factor (q ^. dr) ; { creeaz si leag n dr. nodului q ^ }
p := q ; { subarb. asociat operandului 2 al lui car }
end ;
end ;

procedure expresie ;
var q : reper ;
begin
if car in [ '+', '-' ] then { expresia ncepe cu + sau - }
if car = '-' then
begin { car = - unar }
new ( p ) ;
p ^.v := '$' ; { $= - unar }
p ^.stg := NIL ;
citire ;
termen(p ^.dr) ;
end
else
begin { car =+ unar }
citire ;
termen ( p );
end
________________________________________________________________________________

197
Structuri de date i algoritmi
_______________________________________________________________________________

else termen ( p ) ;
while car in [ '+', '-' ] do
begin
new ( q ) ;
q ^.v := car ;
q ^.stg := p ;
citire ;
termen ( q ^.dr) ;
p := q;
end
end ;

BEGIN { programul principal }


mark (x) ; {retine vrful 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 obine rezultatul :

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

V.2.2. Arbore binar de cutare balansat n nlime

V.2.1.1. Descrierea general a arborelui balansat n nlime

Primul tip de arbore balansat este Arborele Binar de Cutare Balansat n nlime -
ABCBI. Intr-un astfel de arbore ncercm meninerea tuturor nodurilor frunz la aceeai distant
fa de rdcin .

________________________________________________________________________________

198
Structuri de date i algoritmi
_______________________________________________________________________________

In Figura V.2. este prezentat un arbore binar de cutare balansat n nlime, iar n Figura
V.3. este prezentat un arbore binar debalansat [Tre, 1984].

Figura III.2. Figura III.3.

Pentru a prevenii debalansarea arborelui, asociem un indicator de balansare pentru toate


nodurile arborelui. Indicatorul de balansare poate s conin trei valori notate astfel :
nod greu stnga (L)
nod greu dreapta (R)
nod balansat (B)
Definiia V.1. Nod greu stnga (L) : Un nod al unui ABCBI se numete nod greu stnga, dac
nlimea subarborelui su stng este mai mare cu 1 dect nlimea subarborelui su drept.

Definiia V.2. Nod greu dreapta (R) : Un nod al unui ABCBI se numete nod greu dreapta, dac
nlimea subarborelui su drept este mai mare cu 1 dect nlimea subarborelui su stng.
Definiia V.3. Nod balansat (B) : Un nod al unui ABCBI se numete nod balansat, dac nlimea
subarborelui su stng este egal cu nlimea subarborelui su drept.
Definiia V.4. Nod critic (C) : Un nod al unui ABCBI se numete nod critic, dac nu este nod greu
dreapta, nod greu stnga sau nod balansat.

ntr-un ABCBI fiecare nod trebuie se afle in una din aceste trei stri, adic s fie nod greu
dreapta, nod greu stnga sau nod balansat.

Definiia V.5. Un arbore binar de cutare se numete arbore binar de cutare balansat n nlime
ABCBI, dac are doar noduri greu stnga, noduri greu dreapta sau noduri balansate.
________________________________________________________________________________

199
Structuri de date i algoritmi
_______________________________________________________________________________

Dac exist un nod care nu satisface nici una din aceste trei stri, atunci arborele se numete
arbore binar debalansat.
Definiia V.6. Un arbore binar de cutare se numete arbore binar de cutare debalansat dac
conine cel puin un nod critic.

V.2.2.2. Implementarea unui nod a arborelui ABCBI

Un nod al unui arbore ABCBI are urmtoarea structur:

Fiu_st Cheia Alte_info IB Fiu_dr

Figura V.4. Structura nodului ABCBI.


unde:
Fiu_st : reprezint adresa fiului stnga;
Cheia: reprezint cmpul ales dup care este ordonat ABCBI;
Alte_info : alte informaii;
IB : indicatorul de balansare;
Fiu_dr : reprezint adresa fiului dreapta;
Structura nodului, n implementarea Pascal este urmtoarea :
Type
Adresa = ^Nod
Nod = RECORD
Fiu_st : Adresa;
Cheia : tipcheia;
Alte_info : tipinfo;
IB : char;
Fiu_dr : Adresa;
end

V.2.2.3. Operaii ntr-un ABCBI

Operaiile n cazul arborilor binari de cutare balansai n nlime sunt aceleai ca i la


arborii binari de cutare, i anume:
a. creare-iniializare;
b. inserare-balansare;
c. cutare;
d. tergere;
________________________________________________________________________________

200
Structuri de date i algoritmi
_______________________________________________________________________________

e. traversarea:

Operaiile creare-iniializare, cutare i traversare sunt identice cu operaiile de la arborii


binari de cutare. Doar operaiile de inserare-balansare i tergere sunt specifice i vor fi detaliate n
cele ce urmeaz.

a. Operaia de inserare. In cazul operaiei de inserare al unui nod, presupunem c inserarea se face
la nivelul unui nod terminal, dup regula general de inserare de la arborii binari de cutare. Numai
la acele noduri se schimb indicatorul de balansare n cazul unui astfel de nserri, care se afl pe un
drum cuprins ntre rdcin arborelui i noul nod terminal inserat, numit drum de inserare.
Posibilele schimbri pentru un nod, aflat pe drumul de inserare sunt urmtoarele [Tre, 1984]:
Cazul 1: Nodul era nod greu dreapta sau nod greu stnga i a devenit balansat.
Cazul 2: Nodul era balansat i a devenit nod greu dreapta sau nod greu stnga.
Cazul 3: Nodul era un nod greu, iar noul nod este nserat n subarborele su greu, crend un
subarbore debalansat. Un astfel de nod se numete nod critic.

n cazul 1, n urma operaiei de inserare, indicatorul de balansare (IB) a nodurilor strmo


ale nodului de inserat, aflate pe drumul de inserare, rmn neschimbate, cu excepia noului tat.
Acest exemplu este prezentat n Figura V.5. n acest exemplu nodul inserat este nodul cu cheia 3.
n cazul 2, dup cum se vede i n Figura V.6, indicatorii de balansare (IB) a nodurilor
strmo, situate pe drumul de inserare se pot modifica. n acest exemplu nodul de inserat este nodul
cu cheia 4.
n Cazul 3, n urma unei operaii de inserare, arborele devine debalansat i se creeaz noduri
critice. n Figura V.7 este prezentat un astfel de exemplu, aprut n urma inserrii nodului cu cheia
4: nodul cu cheia 5 se transform n nod critic iar arborele binar devine debalansat.

________________________________________________________________________________

201
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.5.Cazul 1. Figura V.6. Cazul 2.


Figura V.7. Cazul 3.

Operaia de inserare poate duce la crearea unor noduri critice, deci la debalansarea arborelui.
Pentru a putea pstra caracteristica de ABCBI, este necesar efectuarea unei operaii specifice,
numit rebalansare a arborelui, care s duc la eliminarea nodurilor critice i la transformarea lor n
noduri greu dreapta, greu stnga sau balansat.
Sunt dou cazuri de rebalansare, care se divid fiecare n dou subcazuri, corespunztoare
direciei grele stnga sau dreapta care a dus la apariia nodului critic [Tre, 1884].

Cazul 1: Rebalansare prin rotaie simpl. Acest caz apare cnd operaia de inserare s-a fcut pe
direcia grea a nodului care a devenit critic. Cele dou sub cazuri sunt:

Cazul 1.a.: Rebalansare prin rotaie simpl la dreapta. Acest caz apare cnd operaia de inserare s-

a fcut pe direcia grea stng a nodului care a devenit critic.

Cazul 1.b.: Rebalansare prin rotaie simpl la stnga. Acest caz apare cnd operaia de inserare
s-a fcut pe direcia grea dreapta a nodului care a devenit critic.

O reprezentare a cazului 1.a, este n Figura V.8., unde T1, T2 i T3 reprezint subarbori, iar
NEW reprezint noul nod de inserat. Expresia din partea de jos a dreptunghiurilor reprezint
nlimea subarborilor, nainte i dup inserare.
De exemplu, n Figura V.8. (a.1) presupunem c n urma unei operaii de inserare nodul X,
din nod greu stnga, a devenit critic. Atunci arborele binar devine debalansat. Problema se rezolv
dac rotim la dreapta arborele n jurul nodului nodul Y, Figura V.8. (a.2).

________________________________________________________________________________

202
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.8. Exemplu de soluionare a debalansrii arborelui binar, prin rotaie simpl la
dreapta n jurul nodului Y.

Figura V.9. Exemplu de soluionare a debalansrii arborelui binar, prin rotaie simpl la
stnga n jurul nodului Y.

De exemplu, n Figura V.8. (b.2) presupunem c n urma unei operaii de inserare nodul X,
din nod greu dreapta, a devenit critic. Atunci arborele binar devine debalansat. Problema se
rezolv dac rotim la stnga arborele n jurul nodului nodul Y, Figura V.8. (b.1).
Cazul 2: Rebalansare prin rotaie dubl. Acest caz apare cnd operaia de inserare s-a fcut pe
direcia opus direciei grele a nodului care a devenit critic. Cele dou subcazuri sunt:
Cazul 2.a.: Rebalansare prin rotaie dubl la dreapta. Acest caz apare cnd operaia de inserare s-
a fcut pe direcia opus direciei grele stng a nodului care a devenit critic.
Cazul 2.b.: Rebalansare prin rotaie dubl la stnga. Acest caz apare cnd operaia de inserare s-a
fcut pe direcia opus direciei grele dreapta a nodului care a devenit critic.
Cazul doi, care este reprezentat n Figura V.9 i Figura V.10., este asemntor cu primul
caz, cu excepia c nodul Y devine nod greu n direcia opus n care nodul X era nod greu. Este
clar c nodul Z trebuie balansat prioritar fa de inserare .

________________________________________________________________________________

203
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.10. Exemplu de soluionare a debalansrii arborelui binar, prin rotaie dubl la
stnga n jurul nodului Z.

________________________________________________________________________________

204
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.11. Exemplu de soluionare a debalansrii arborelui binar, prin rotaie dubl la
dreapta n jurul nodului Z.
Specificarea problemei de inserare, avnd ca date de intrare ROOT, cheia_nou, info_nou,
este urmtoarea:

DATE root, cheia_nou, info_nou;


REZULTATE root;

Descrierea algoritmului n Pseudocod este:

ALGORITMUL INSERARE ESTE: { Se insereaz un nod nou i dac este cazul se


rebalanseaz arborele }
CITETE cheia_nou, info_nou;
DAC @este primul nod inserat ATUNCI
CHEAM Creare_nod (cheia_nou, info_nou);
EXIT;
SFDAC
DAC @nu este cheie dubl ATUNCI
@ataeaz noul nod n arbore;
ALTFEL
TIPRETE Eroare - Cheie dubla;
EXIT;
SFDAC
@caut un nod debalansat.
@calculeaz IB (indicatorii de balansare).
@caut un nod debalansat.
DAC @nu exist nod critic ATUNCI
EXIT;
SFDAC
DAC @nodul era balansat i a devenit greu sau nodul era greu i a devenit balansat
ATUNCI @calculeaz IB (indicatorii de balansare);
EXIT;
SFDAC
@rebalanseaz arborele;
SFALGORITM

b. Operaia de tergere. Specificarea general a problemei de tergere este:

DATE root, cheia_de_sters;


REZULTATE root;

________________________________________________________________________________

205
Structuri de date i algoritmi
_______________________________________________________________________________

Descrierea general a algoritmului de tergere, n Pseudocod este:

@Caut nodul marcat pentru tergere cu cheia cheia_de_sters


DAC @nodul cu cheia cheia_de_sters are doi fii
ATUNCI @caut succesorul (inordine) nodului cu cheia cheia_de_sters
@terge succesorul (inordine ) nodului cu cheia cheia_de_sters
@schimb nodul marcat pentru tergere cu succesorul (inordine )
ALTFEL @terge nodul marcat i schimb cu fiul (dac exist )
SFDAC
@Rebalanseaz arborele pe drumul de cutare.

V.2.2.4. Probleme rezolvate

Exemplul V.1: Implementarea PASCAL a operaiilor efectuate ntr-un ABCBI: creare-iniializare,


inserare, cutare, tergere, traversare.

Program operaii ABCBI;


type
adresa = ^nod ;
nod = record
lptr , rptr : adresa ; {lptr, rptr: pointeri ctre subarborele stng respectiv drept}
key : integer ;
end ;
var
root , tata , nou , temp , nodp : adresa ;
c , bi1 : char ;
s : integer ;

Procedure creare ( var cap : adresa ) ;


begin
cap := nil ;
end ;

Procedure inserare ( var cap : adresa ; cheia : integer ) ;


var curent : adresa ; { procedura care insereaz un nod nou }
begin
curent := cap ;
tata := cap ;
while curent <> nil do
if curent^.key < cheia then begin
tata := curent ;
curent := curent^.rptr ;
end

________________________________________________________________________________

206
Structuri de date i algoritmi
_______________________________________________________________________________

else
if curent^.key > cheia then begin
tata := curent ;
curent := curent^.lptr ;
end
else begin
writeln ( ' Cheie dubl !' ) ;
readln ;
exit ;
end ;
new ( nou ) ;
nou^.key := cheia ;
nou^.lptr := nil ;
nou^.rptr := nil ;
if cap = nil then begin
cap := nou ;
exit ;
end;
if cheia < tata^.key then tata^.lptr := nou
else tata^.rptr := nou ;
balansinalt ;

end;

Procedure caut (root : adresa ; ch : integer ) ;


Begin
{ procedura care caut un anumit nod }
temp := root ; tata := root ;
while (ch <> temp^.key ) and ( temp <> nil ) do
begin
tata := temp ;
if temp^.key < ch then temp := temp^.rptr
else temp := temp^.lptr ;
end ;
end ;

Procedure sterg ; { procedura de tergere a unui nod }


var fiu , predec , tatap : adresa ;
begin
if ( temp^.lptr = nil ) and ( temp^.rptr = nil ) then {nodul de ters nu
are nici un fiu}
if temp^.key < tata^.key then
begin
tata^.lptr := nil ;
dispose ( temp ) ;
end
________________________________________________________________________________

207
Structuri de date i algoritmi
_______________________________________________________________________________

else begin
tata^.rptr := nil ;
dispose ( temp ) ;
end
else if ( temp^.lptr = nil ) xor ( temp^.rptr = nil ) then
{ nodul de ters are un singur fiu }
begin
if temp^.lptr = nil then fiu := temp^.rptr
else fiu := temp^.lptr ;
if temp^.key < tata^.key then tata^.lptr := fiu
else tata^.rptr := fiu ;
dispose ( temp ) ;
end
else begin
predec := temp^.lptr ; tatap := predec ;
while predec^.rptr <> nil do
begin
tatap := predec ; predec := predec^.rptr ;
end ;
temp^.key := predec^.key ;
if predec^.lptr <> nil then begin
tatap^.rptr := predec^.lptr ;
dispose ( predec ) ;
end ;
if predec = tatap then begin
temp^.lptr := nil ;
dispose ( predec ) ;
end ;
end ;
end ;

Procedure terge ( rdcina : adresa ; cheias : integer ) ;


begin
cauta ( rdcina , cheias ) ;
if temp <> nil then begin
write ( ' Sterg elementul cu cheia ' , cheias , ' ... ' ) ;
sterg ;
writeln ( ' OK! ' ) ;
end
else begin
writeln ( ' Cheie inexistenta ! ' ) ; exit ;
end ;
end ;

Procedure inordine ( def : adresa ) ; { traversare inordine }


begin
________________________________________________________________________________

208
Structuri de date i algoritmi
_______________________________________________________________________________

if def <> nil then


begin
inordine ( def^.lptr ) ;
write ( def^.key : 3 ) ;
inordine ( def^.rptr ) ;
end ;
end ;

Procedure preordine ( def : adresa ) ; { traversare preordine }


begin
if def <> nil then
begin
write ( def^.key : 3 ) ;
preordine ( def^.lptr ) ;
preordine ( def^.rptr ) ;
end ;
end ;

Procedure postordine ( def : adresa ) ; { traversare postordine }


begin
if def <> nil then
begin
postordine ( def^.lptr ) ;
postordine(def^.rptr);
write ( def^.key : 3 ) ;
end ;
end ;

Procedure meniu ;
begin
repeat
clrscr ;
writeln ( ' Optiuni : C-Creare ');
writeln ( ' I-Inserare ');
writeln ( ' S-tergere ');
writeln ( ' T-Traversare-N-Inordine ' ) ;
writeln ( ' T-Traversare-P-Preordine ' ) ;
writeln ( ' T-Traversare-O-Postordine ' ) ;
writeln ( ' ESC-Ieire ');
c := readkey ;
case upcase ( c ) of
' C ' : begin
writeln ; writeln ( '* CREARE *' : 15 ) ; writeln ;
write ( 'Creez rdcina...' ) ;
creare ( root ) ; writeln ( ' OK! ' ) ;
readkey ;
________________________________________________________________________________

209
Structuri de date i algoritmi
_______________________________________________________________________________

end ;
' I ' : begin
writeln ; writeln( ' * INSERARE * ' : 15 ) ; writeln ; writeln ;
write ( ' Cheia : ' ) ; readln( s ) ; writeln ;
insere ( root , s ) ;
end ;
' S ' : begin
writeln ; writeln (' *TERGERE * ' : 15 ) ; writeln ;
write ( ' Cheia elementului pt. sters: ' ) ;
readln ( s ) ; sterge ( root , s ) ;
end ;
' T ' : begin
writeln ; writeln ( ' * TRAVERSARE * ' : 15 ) ; writeln ;
write ( ' Optiunea: ' ) ; readln(c) ;
if root^.key = 0 then
begin
writeln ; writeln ( ' Arbore vid ! ' : 15 ) ;
c := ' ' ;
end ; writeln ;
case upcase ( c ) of
' N ' : begin
write ( ' Inordine: ' ) ;
inordine ( root ) ;
readkey ;
end ;
' P ' : begin
write ( ' Preordine: ' ) ;
preordine ( root ) ;
readkey ;
end ;
' O ' : begin
write ( ' Postordine: ' ) ;
postordine ( root ) ;
readkey ;
end ;
else writeln ( ' Ai apsat o tast gresit ! ' ) ;
end ;
end ;
end ;
until c = # 27 ;
end ;
BEGIN
meniu ;
END.

________________________________________________________________________________

210
Structuri de date i algoritmi
_______________________________________________________________________________

V.2.2.5. Performanele algoritmilor n ABCBI

Performana algoritmului ce corespunde operaiei de inserare n arborele binar balansat n


nlime cu n noduri este de ordinul O(1.5* log2 (n+1)) [Knu, 1976].
Performana algoritmului ce corespunde operaiei de cutare este identic cu performana
algoritmului de cutare a arborilor binari de cutare, adic este de ordinul O(log2n).
n referina [Tre, 1984], se arat c performana algoritmului ce corespunde operaiei de
tergere este de ordinul O(log2n).

V.2.3. Arbore binar de cutare balansat n greutate

V.2.3.1. Descrierea general a arborelui balansat n greutate

Am vzut n V.1.1.1, (5.4) faptul c organizarea datelor influeneaz semnificativ


performanele algoritmilor de cutare. Concluzia modului de organizare a datelor conform cu (5.4)
este evident: dac datele nu sunt echiprobabil cutate, atunci datele cele mai cutate, sau cu
probabilitatea de cutare cea mai mare trebuie s se gseasc la nceputul drumului de cutare. La
un arbore binar de cutare procesul de cutare ncepe ntotdeauna de la nodul rdcin. Avem atunci
stabilit urmtorul el: dac datele organizate sub forma unei structuri de tip arbore binar de cutare
sunt echiprobabile, au aceeai probabilitate de cutare, atunci arborii binari de cutare balansai n
nlime sunt structura cea mai potrivit. Dac ns, datele organizate sub forma unui arbore binar
de cutare nu sunt echiprobabile, avem nevoie de o alt structur arborescent binar de cutare
care s dispun n arbore datele cele mai cutate ct mai aproape de nceputul drumului de cutare
adic de rdcin.
Introducem astfel o nou structur de date arborescent, i anume, arborele binar de
cutare balansat n greutate ABCBG, a crei regul de organizare poate fi formulat astfel: cele
mai des cutate noduri se afl ct mai aproape de rdcin .
Dac probabilitatea de cutare a unei date particulare este necunoscut, putem s folosim
formula (5.2), ca un raport dintre numrul de accesri a unei asemenea date i numrul total de
accesri al structurii de date arborescente. Aceast probabilitate de cutare poate fi meninut
dinamic, dac avem grij s incrementm la fiecare acces al unei date variabila corespunztoare
numrului de accesri al acelei date precum i numrul total de accesri a structurii de date
arborescente.
Rezult firesc c fiecare nod al unui astfel de ABCBG are nevoie de un cmp suplimentar
de informaie, i anume numrul de cte ori a fost accesat acea informaie i pe care o vom numi
greutatea nodului respectiv.

________________________________________________________________________________

211
Structuri de date i algoritmi
_______________________________________________________________________________

Obs.: In orice arbore (subarbore) nodul rdcin este cel mai greu nod.

Arborele prezentat n figura de mai jos, este o structur de date de tip ABCBG. Se observ
c n primul rnd avem un ABC deoarece, lexicografic avem respectat regula de organizare a
arborilor binari de cutare. De asemenea, se observ c nodurile cele mai grele se gsesc la
nceputul drumului de cutare, adic ct mai aproape de nodul rdcin [Tre, 1884]..

Figura V.12. Exemplu de arbore binar de cutare T1 balansat n greutate ABCBG.

Regula de plasare al unui nod n arborele binar de cutare balansat n greutate poate fi
exprimat n mod recursiv dup urmtoarea regul [Aho, 1987] :

1. Nodul rdcin al oricrui arbore (subarbore) este nodul cu cea mai mare greutate din
mulimea de noduri care constituie arborele (subarborele);
2. Subarborele stng al oricrui arbore (subarborelui) este compus din noduri a cror
valoare lexical este mai mic dect nodul rdcin;
3. Subarborele drept al oricrui arbore (subarborelui este compus din noduri a cror valoare
lexical este mai mare dect nodul rdcin.

n cazul arborelui binar de cutare balansat n greutate, la fiecare operaie de inserare sau la
o orice operaie de accesare a unui anumit nod, greutatea nodului este incrementat cu 1. Dac se
insereaz un nod nou n arbore, acesta va fi poziionat conform cu regulile generale de inserare de la
arborii binari de cutare, ca i nod terminal, greutatea nodului fiind iniializat cu 1.
S considerm n continuare acelai arbore binar de cutare, dar care s nu mai fie balansat
n greutate.
________________________________________________________________________________

212
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.13. Exemplu de arbore binar T2 de cutare debalansat n greutate.

S comparm performanele algoritmilor de cutare n cei doi arbori de cutare T1 (balansat


n greutate) i T2 (debalansat n greutate):
6 5 3 4 2 1 4
ALOST1 1 2 2 3 3 3 4 2.36
25 25 25 25 25 25 25
2 4 3 4 5 6 1
ALOST2 1 2 2 3 3 3 3 2.56
25 25 25 25 25 25 25
Se observ clar c arborele binar de cutare balansat n greutate are performane de cutare
mai bune dect un arbore binar de cutare. Cu ct structura de date arborescent este mai mare ca
dimensiuni, diferenele de performan se accentueaz n favoarea ABCBG.

V.2.3.2. Implementarea unui nod al arborelui ABCBG

Un nod al unui ABCBG are urmtoarea structur:

Fiu_st Cheia Alte_info Greutate Fiu_dr

Figura V.14. Structura nodului ABCBG.

unde:
Fiu_st : reprezint adresa fiului stnga;
Cheia: reprezint cmpul ales dup care este ordonat ABCBG;

________________________________________________________________________________

213
Structuri de date i algoritmi
_______________________________________________________________________________

Alte_info: alte informaii;


Greutate: greutatea nodului, reprezentat prin numrul de accesri ale nodului;
Fiu_dr: reprezint adresa fiului dreapta;

Structura nodului n implementarea Pascal este urmtoarea :


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

V.2.3.3. Operaii ntr-un ABCBG

Operaiile n cazul arborilor binari de cutare balansai n greutate sunt aceleai ca i la


arborii binari de cutare, i anume:
a. creare-iniializare;
b. inserare-balansare;
c. cutare;
d. tergere;
e. traversarea:

Operaiile creare-iniializare, inserare i traversare sunt identice cu operaiile de la arborii


binari de cutare. Doar operaiile de cutare i tergere sunt specifice i vor fi detaliate n cele ce
urmeaz. Operaia de cutare poate modifica greutatea unui nod i debalansa arborele.

c. Operaia de cutare.

Balansarea unui ABCBG este ilustrat n Figura V.15 [Tre, 1884]..

________________________________________________________________________________

214
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.15. Operaia de balansare a unui ABCBG. n figura V.15.a, presupunem c n


urma unei accesri a nodului COPIL, greutatea acestuia devine mai mare dect
greutatea nodului PARINTE, deci arborele devine debalansat n greutate. n figura
V.15.b, se prezint strategia de balansare.

Obs.V.2: Vom presupunem existenta unei stive care este folosit pentru a memora drumul de
cutare, de la nodul rdcin pn la nodul cutat. Aceast stiv va fi necesar pentru operaia de
tergere.

________________________________________________________________________________

215
Structuri de date i algoritmi
_______________________________________________________________________________

Specificarea problemei de inserare, avnd ca date de intrare cheia_caut, info_nou, este


urmtoarea:

DATE root, cheia_caut, info_nou;


REZULTATE root;

Descrierea algoritmului n Pseudocod este:

ALGORITMUL INSERARE ESTE: { Se insereaz un nod nou i dac este cazul se


rebalanseaz arborele }
CITETE cheia_caut, info_nou;
@Caut nodul cu cheia cheia_caut i memoreaz drumul de cutare n stiv;
DAC @nodul cutat este gsit
ATUNCI @incrementeaz greutatea cu 1
@balanseaz arborele (dac este nevoie )
ALTFEL TIPRETE cutare fr succes
SFDAC
SFALGORITM

Implementarea algoritmului de cutare n Pascal este:

Function cutare (rad : adresa ; cheia_caut : char ) : adresa ;


begin
temp := rad ;
tata := rad ;
reset (st , ind ) ; { reset (st,ind) iniializeaz stiva }
while ( temp <> nil ) and ( temp^.key <> cheia_caut) do
begin
if cheia_caut < temp^.key then
begin
tata := temp;
push (st , ind , tata ); {procedura push introduce n stiva }
temp := temp^.lptr ; {strmoii nodului cutat }
end
else
begin
tata := temp ;
push ( st , ind , tata ) ;
temp := temp^.rptr ;
end ;
end ;
if temp^.key = cheia_caut then
________________________________________________________________________________

216
Structuri de date i algoritmi
_______________________________________________________________________________

begin
inc ( temp^.weight ) ;
writeln ( ' Cutare cu succes Informaia exist ' ) ;
cautare := temp ;
rebalansare ( temp , tata ) ; { rebalanseaz arborele dac este necesar }
exit ;
end
else
begin
cautare := nil ;
writeln ( ' Cutare cu insucces Informaia nu exist ' ) ;
end ;
end ;

d. Operaia de tergere.

n cazul operaiei de tergere al unui nod, avem 4 cazuri care trebuie examinate [Tre, 1884]..

Cazul 1. Nodul de ters este un nod frunz. In acest caz, tergerea este simpl, tergem legtura care
leag nodul frunz de nodul printe.
Cazul 2. Nodul este un nod neterminal, care nu are subarbore drept, i nodul de ters este un nod fiu
stnga. n acest caz fiul stng al nodului printe va deveni egal cu fiul stng al nodului marcat
pentru tergere. Aceeai rezolvare pentru cazul simetric.
Cazul 3. Nodul este un nod neterminal, care nu are subarbore stng, i nodul de ters este un nod
fiu stnga. n acest caz fiul stng al nodului printe va deveni egal cu fiul drept al nodului marcat
pentru tergere. Aceeai rezolvare pentru cazul simetric.
Cazul 4. Nodul este nod neterminal, cu ambii subarbori nenuli. In acest caz tergerea direct a
nodului ar duce la debalansarea arborelui. Pentru a nu debalansa arborele, se va nlocui nodul de
ters cu un nod urma, i anume cu acela care are cea mai mare greutate. n urma aplicrii acestei
nlocuiri, ne vom regsi ntr-una din regulile exprimate prin Cazurile 1,2,3 sau 4. Repetm regula
1,2, 3 sau 4, pn cnd se poate terge nodul dorit

Specificarea general a problemei de tergere este:

DATE root, cheia_de_sters;


REZULTATE root;
Descrierea general a algoritmului recursiv de tergere, n Pseudocod este:

________________________________________________________________________________

217
Structuri de date i algoritmi
_______________________________________________________________________________

SUBALGORITMUL sterge (radacina, cheia_s) ESTE:


DAC @nodul de sters cu cheia_s este nod terminal sau are un subarbore vid

ATUNCI @terge nodul { Cazurile 1, 2, 3 }


ALTFEL @interschimb nodul de ters cu nodul urma cel mai greu
{ Cazul 4 }
SFDAC
CHEAM sterge (radacina, cheia_s);
SF-sterge

V.2.3.4. Probleme rezolvate

Exemplul V.2: Implementarea PASCAL a operaiilor efectuate ntr-un ABCBG: creare-iniializare,


inserare, cutare, tergere, traversare.

program ABCBG;
const max=100;
type adresa = ^nod;
nod = record
lptr : adresa ;
key : char ;
info : string[30] ;
rptr : adresa ;
weight : word ;
end ;
str = string[30] ;
stiva = array[0..max] of adresa ;
top = 0..max ;
var
tata , temp , copil , root , rad : adresa ;
ch : char ;
student : nod ;
i , n : integer ;
st : stiva ;
ind : top ;

Procedure reset (st:stiva ; var indic:top ) ; {iniializeaz stiva }


begin
indic := 0 ;
end ;

Function fullstack(indic:top) : boolean ; { stiv plin ?}


begin
if indic = max then fullstack := true

________________________________________________________________________________

218
Structuri de date i algoritmi
_______________________________________________________________________________

else fullstack := false ;


end ;

Function emptystack ( indic:top ) : boolean ; { stiv goal ?}


begin
if indic=0 then emptystack: = true
else emptystack := false ;
end ;

Procedure push (var st:stiva ; var indic:top ; elem:adresa ) ;


{ depune elemente n stiv }
begin
if not fullstack (indic) then
begin
st[indic] := elem ;
indic := indic+1 ;
end
else
begin writeln ('stack overflow') ;
exit ;
end;
end;

Function pop (st:stiva;var indic:top) : adresa ;


{ scoate elementele din stiv }
begin
if not emptystack (indic) then
begin
indic := indic-1 ;
pop := st [indic] ;
end
else
begin writeln ('stack underflow') ;
exit ;
end ;
end ;
Procedure creare (rad : adresa) ; { creare rdcin vid}
begin
rad:=nil;
end;

Procedure inserare (var rad : adresa ; cheia : char ) ; { inserarea elementelor }


var
curent , nou : adresa ;
begin
if rad = nil then begin { inserare n cazul cnd arborele este vid }
________________________________________________________________________________

219
Structuri de date i algoritmi
_______________________________________________________________________________

new(nou) ;
nou^.key := cheia ;
nou^.weight := 0 ;
nou^.lptr := nil ;
nou^.rptr := nil ;
rad := nou ;
end
else begin { inserare n cazul cnd arborele nu este vid }
curent := rad ; tata := curent ;
while curent <> nil do
if cheia < curent^.key then { inserarea fiului stng al nodului curent }
begin
tata := curent ;
curent := curent^.lptr ;
end
else if cheia > curent^.key then { inserarea fiului drept al nodului curent }
begin
tata := curent ;
curent := curent^.rptr ;
end
else begin
writeln ( 'cheie dubl:eroare') ;
exit ;
end ;
new (nou) ; {inserarea propriuzis i actualizarea cmpurilor }
nou^.key := cheia ;
nou^.weight := 0 ;
nou^.lptr := nil ;
nou^.rptr := nil ;
if tata^.key > cheia then tata^.lptr := nou
else tata^.rptr := nou ;
end ;
end ;

Procedure rebalansare (temp : adresa ; var tata : adresa) ; {rebalansarea arborelui}


var
bunic, t : adresa ;
begin
if temp^.weight <= tata^.weight then exit
else if (tata = root) then { interschimbarea nodului rdcin }
if temp^.key < tata^.key then
begin
tata^.lptr := temp^.rptr ;
temp^.rptr := tata ;
root := temp ;
exit ;
________________________________________________________________________________

220
Structuri de date i algoritmi
_______________________________________________________________________________

end
else
begin
tata^.rptr := temp^.lptr ;
temp^.lptr := tata ;
root := temp ;
exit ;
end
else
t := pop (st,ind) ;
bunic := pop (st,ind) ;
if tata^.key < bunic^.key then
if temp^.key<tata^.key then
begin
bunic^.lptr := temp ;
tata^.lptr := temp^.rptr ;
temp^.rptr := tata ;
end
else
begin
bunic^.lptr:=temp;
tata^.rptr:=temp^.lptr;
temp^.lptr:=tata;
end
else
if temp^.key<tata^.key then
begin
bunic^.rptr:=temp;
tata^.lptr:=temp^.rptr;
temp^.rptr:=tata;
end
else
begin
bunic^.rptr:=temp;
tata^.rptr:=temp^.lptr;
temp^.lptr:=tata;
end;
push (st,ind,bunic) ;
tata:=bunic ;
rebalansare (temp,tata) ;
end ;

Function cautare ( rad : adresa ; cheiac : char ) : adresa ;


begin
temp := rad ; tata := rad ; reset (st,ind) ;
while (temp <> nil) and (temp^.key <> cheiac) do
________________________________________________________________________________

221
Structuri de date i algoritmi
_______________________________________________________________________________

begin
if cheiac<temp^.key then begin { se caut n subarborele stng }
tata:=temp;
push(st,ind,tata);
temp:=temp^.lptr;
end
else begin { se caut in subarborele drept }
tata:=temp;
push(st,ind,tata);
temp:=temp^.rptr;
end;
end;
if temp^.key=cheiac then begin inc(temp^.weight); { cheia este gsit }
writeln('Exista');
cautare:=temp;
rebalansare(temp,tata);
exit;
end
else
begin
cautare:=nil;
writeln('Nu exist');
end;
end;

Procedure sterg;
var fiu , predec , tatap : adresa ;
begin
if (temp^.lptr=nil) and (temp^.rptr=nil) then {tergerea unui nod terminalCazul1}
if temp^.key<tata^.key then begin
tata^.lptr:=nil;
dispose(temp);
end
else begin
tata^.rptr:=nil;
dispose(temp);
end
else
if (temp^.lptr = nil) XOR (temp^.rptr = nil) then { tergerea unui nod cu un } begin
{ singur fiu Cazul 2, 3 }
if temp^.lptr<>nil then fiu:=temp^.lptr
else fiu:=temp^.rptr;
if temp^.key<tata^.key then begin
tata^.lptr:=fiu;
dispose(temp);
end
________________________________________________________________________________

222
Structuri de date i algoritmi
_______________________________________________________________________________

else begin
tata^.rptr:=fiu;
dispose(temp);
end;
end
else begin {tergerea unui nod cu doi fii Cazul 4}
predec:=temp;
tatap:=predec;
predec:=temp^.lptr;
while predec^.rptr<>nil do begin
tatap:=predec;
predec:=predec^.rptr;
end;
temp^.key:=predec^.key;
temp^.info:=predec^.info;
if predec^.lptr<>nil then tatap^.lptr:=predec^.lptr
else tatap^.lptr:=nil;
dispose(predec);
end;
end;

Procedure stergere ( var rad : adresa ; cheias : char );


begin
temp:=cautare(root,cheias);
if temp<>nil then sterg
else begin
writeln('eroare-element inexistent');
exit;
end;
end;

Procedure preordine (var rad : adresa) ; { traversarea n preordine a arborelui}


begin
if rad<>nil then
begin
writeln (rad^.key , ' : ' , rad^.weight) ;
preordine (rad^.lptr) ;
preordine (rad^.rptr) ;
end ;
end ;
Procedure menu ;
begin
write ('1-Inserare 2-Cutare 3-Afiare 4-tergere ');
write('5-Ieire');
end;

________________________________________________________________________________

223
Structuri de date i algoritmi
_______________________________________________________________________________

begin
menu;
creare(root);
repeat
ch := readkey;
case ch of
'1':begin
writeln;
write('introducei cheia:');
readln(student.key);
inserare(root,student.key);
end;
'2':begin
writeln;
write('introducei cheia cutat:');
readln(student.key);
cautare(root,student.key);
end;
'3':begin
writeln('traversare preordine:');
preordine(root);
end;
'4':begin
writeln;
write('introducei cheia de sters:');
readln(student.key);
stergere(root,student.key);
end;
end;
until ch='5';
end.

V.2.4. Arbori de cutare 2-3.

V.2.4.1. Descrierea general a arborelui de cutare 2-3

Un alt tip de arbore de cutare este arborele de cutare 2-3 AC2-3. Un arbore 2-3 este
________________________________________________________________________________

224
Structuri de date i algoritmi
_______________________________________________________________________________

definit ca un arbore de cutare n care nodurile non-frunz (neterminale) au 2 sau 3 fii, i toate
nodurile frunz (terminale) au aceeai distan fa de nodul rdcin.
Observaie: Un arbore care are un singur nod (nod frunz) este considerat a fi tot AC2-3. Evident,
arborii de cutare 2-3 nu sunt arbori binari, dei algoritmul de cutare este pe undeva asemntor
algoritmului de cutare binar.
Figura V.xx. ne prezint un exemplu de arbore 2-3 avnd inserate 5 date, cu cheile de
cutare 1, 3, 6, 7, 11. Celelalte noduri non-frunz sunt noduri pentru cutare.

Figura V.xx. Exemplu de arbore de cutare 2-3.

ntr-un AC2-3 numai nodurile frunz conin date propriu-zise, celelalte noduri (nodurile
non-frunz) sunt noduri auxiliare de cutare.
Un nod non-frunz va fi denumit nod auxiliar de cutare. Un astfel de nod auxiliar de
cutare va conine dou valori, corespunztoare limitei inferioare respectiv limitei superioare a
drumului de cutare [Aho, 1987].
Limita inferioar a unui nod auxiliar de cutare reprezint cea mai mare cheie de cutare din
subarborele stng. Limita superioar a unui nod auxiliar de cutare reprezint cea mai mare cheie de
cutare din subarborele mijlociu.
Observaie: Cnd un nod non-frunz (neterminal) are doar doi fii, atunci se consider c fiul lips
este fiul din dreapta.
n cazul operaiilor de cutare, cheia de cutare este comparat cu cele dou valori limit ale
nodurilor auxiliare de cutare:
Dac cheia de cutare este mai mic sau egal cu limita inferioar de cutare, atunci
cutarea se face pe legtura fiu_stnga.
Dac cheia de cutare este strict mai mare dect limita inferioar de cutare, dar mai mic
sau egal dect limita superioar de cutare, atunci cutarea se face pe legtura fiu_mijloc.
Altfel, dac cheia de cutare este mai mare dect limita superioar de cutare i dac exist
legtura fiu_dreapta atunci cutarea se face pe legtura fiu_dreapta, altfel cutarea se face
pe legtura fiu_mijloc .
________________________________________________________________________________

225
Structuri de date i algoritmi
_______________________________________________________________________________

V.2.4.2. Implementarea nodurilor AC2-3

Dup cum am vzut, un AC2-3 conine dou tipuri de noduri:

a. Nod auxiliar de cutare (non-frunz) :

fiu_s a b tip fiu_mi fiu_s


t j t

Unde:
fiu_st : reprezint adresa fiului stnga;
a: limita inferioar a drumului de cutare;
b: limita superioar a drumului de cutare;
tip: tipul nodului, nod auxiliar de cutare (non-frunz) tip = 1, nod de date (frunz) tip = 1;
fiu_mij : reprezint adresa fiului din mijloc;
fiu_dr : reprezint adresa fiului dreapta;

b. Nod de date (frunz) :

tip cheia Alte_info

Unde:
tip: tipul nodului, nod auxiliar de cutare (non-frunz) tip = 1, nod de date (frunz) tip = 1;
cheia: reprezint cmpul de date ales dup care este ordonat AC2-3;
Alte_info: alte informaii;

Structura nodului implementat n Pascal este:


Type
Tip_nod =(frunza, non-frunza);
adresa = ^.Nod
Nod = record
case tag :Tip_nod of
frunza: (cheia : integer;
Alte_info : tip_info);

________________________________________________________________________________

226
Structuri de date i algoritmi
_______________________________________________________________________________

non-frunza: ( Fiu_stg : adresa;


a : integer;
b : integer;
fiu_mij : adresa;
fiu_dr : adresa;

end

V.2.4.3. Operaii ntr-un AC2-3

Operaiile n cazul arborilor de cutare 2-3 sunt urmtoarele:

a. creare-iniializare;
b. inserare;
c. cutare;
d. tergere;
e. traversarea:

Operaia de creare-iniializare este identic cu operaiile de la arborii binari de cutare.


Restul operaiilor sunt specifice arborelui de cutare 2-3 i vor fi detaliate n cele ce urmeaz.

b. Operaia de inserare.

Exist patru cazuri de analizat pentru operaia de inserare [Tre, 1884].. Acestea sunt:

Cazul 1. Arborele este vid. n acest caz alocm spaiu pentru noul nod frunz de inserat i acesta va
deveni noul nod rdcin.
Exemplu: n figura V.xx a se insereaz nodul cu cheia 4.

Cazul 2. Arborele conine un singur nod (acesta coincide cu nodul rdcin). n acest caz se creeaz
un nou nod non-frunz care va deveni noul nod rdcin, vechiul nod rdcin i noul nod de
inserat vor deveni fii nodului auxiliar de cutare.
Exemplu: n figura V.xx b se insereaz nodul cu cheia 9 n AC2-3 din figura V.xx.a.

________________________________________________________________________________

227
Structuri de date i algoritmi
_______________________________________________________________________________

Celelalte dou cazuri apar n situaia n care AC2-3 conine mai mult de un nod. Regula n
aceast situaie este urmtoarea: prima dat se determin locul unde ar urma s fie inserat noul nod,
dup care este determinat nodul tat, avnd grij ca s memorm drumul de cutare.

Cazul 3. Nodul tat are exact doi fii. Inserm noul nod la n poziia determinat de comparaia
cheilor de cutare.
Dac valoarea cheii de inserat este mai mic dect valoarea cheii nodului fiu stnga, atunci noul nod
de inserat va deveni fiul stng al nodului tat; dac valoarea cheii nodului de inserat este mai mare
dect cheia nodului fiu mijloc, atunci noul nod de inserat va deveni nodul fiu dreapta al nodului
tat; altfel noul nod de inserat va deveni nodul fiu mijloc al nodului tat. Aceast nserare este
prezentat n Figura III.11. .
Exemplu: n figura V.xx b se insereaz nodul cu cheia 9 n AC2-3 din figura V.xx.a.

Cazul 4. Nodul tat are trei fii. In acest caz, noul nod de inserat ar deveni al patrulea fiu al nodului
tat. Vom crea un nou nod non-frunz, nod frate cu nodul tat. Poziia nodului nod frate este
determinat de poziia i dispunerea nodurilor fiu. Cele patru noduri fii vor fi separate astfel: cei doi
frai din stnga i cei doi frai din dreapta vor fi ataai nodului tat iniial i nodului unchi nou
creat.
Exemplu: n figura V.xx se insereaz nodul cu cheia 9 n AC2-3 din figura V.xx.a.

Figura V.xx. Cazul 1 de inserare (a) i cazul 2 de inserare (b).

________________________________________________________________________________

228
Structuri de date i algoritmi
_______________________________________________________________________________

Figura V.xx. Cazul 3 de inserare. n AC2-3 din stnga se insereaz un nou nod cu cheia 7.

Figura V.xx. Cazul 4 de inserare. n AC2-3 din stnga se insereaz un nou nod cu cheia 7.

Specificarea problemei de inserare, avnd ca date de intrare ROOT, cheia_nou, info_nou,


este urmtoarea:

DATE root, cheia_nou, info_nou;


REZULTATE root;

________________________________________________________________________________

229
Structuri de date i algoritmi
_______________________________________________________________________________

Descrierea algoritmului de inserare n Pseudocod este:

ALGORITMUL INSERARE ESTE: { Se insereaz un nod nou }


CITETE cheia_nou, info_nou;
DAC ROOT = NIL ATUNCI { Cazul 1 de inserare }
CHEAM Creare_nod_frunza (cheia_nou, info_nou);
EXIT;
SFDAC
DAC ROOT^.tip = 1 ATUNCI { Cazul 2 de inserare }
CHEAM Creare_nod_frunza (cheia_nou, info_nou); {adresa noului nod = nou }
CHEAM Creare_nod_nonfrunza (nou, cheia_nou, info_nou); {adresa noului nod =
tata}
DAC ROOT^.cheia < cheia_nou ATUNCI
tata^.a := ROOT^.cheia;
tata^.b := cheia_nou;
tata^.fiu_st := ROOT;
tata^.fiu_mij := nou;
tata^.fiu_dr := NIL;
ALTFEL
DAC ROOT^.cheia > cheia_nou ATUNCI
tata^.a := cheia_nou;
tata^.b := ROOT^.cheia;
tata^.fiu_st := nou;
tata^.fiu_mij := ROOT;
tata^.fiu_dr := NIL;

ALTFEL
TIPRETE ( EROARE cheie dubl )
SFDAC
SFDAC
ROOT := tata ;
EXIT;
SFDAC
Tmp := ROOT ; { Cazul 3 sau 4 de inserare }
CTTIMP tmp^.tip <> 0 EXECUT { Cutm nodul tat}
DAC cheia_nou < tmp^.a ATUNCI
Push(stiva, top, tmp);
tmp := tmp^.fiu_st;
ALTFEL
Push(stiva, top, tmp);
tmp := tmp^.fiu_mijl;
SFCT { Adresa nodului tat este n vrful stivei}
tata := pop(stiva, top);
Dac tata^.fiu_dr := NIL
CHEAM Cazul_3_inserare (ROOT, tata, cheia_nou, info_nou);
________________________________________________________________________________

230
Structuri de date i algoritmi
_______________________________________________________________________________

ALTFEL
CHEAM Cazul_4_inserare (ROOT, tata, stiva, top, cheia_nou, info_nou);
SFALGORITM

Subalgoritmul Cazul_3_inserare este simplu de rezolvat. Se aloc spaiu pentru noul nod de
inserat, se compar cheia nodului de inserat cheia_nou cu limita inferioar tata^.a i limita
superioar tata^.b a nodului printe, inserndu-se n una din poziiile fiu_st, fiu_mij, fiu_dr. Se
actualizeaz corespunztor cmpurile nodului de inserat i cmpurile nodului tat.

Subalgorimul Cazul_4_inserare poate fi schiat astfel n Pseudocod astfel:

SUBALGORITMUL Cazul_4_inserare (rad, t, st, virf, ch_n, info_n) ESTE:


@ Creeaz un nou nod non-frunz unchi, frate pentru nodul tat;
@ Distribuie cei 4 fii ntre nodul tat i noul nod unchi;
@ Actualizeaz limita inferioar a, limita superioar b i legturile fiu_dr , fiu_mij ,fiu_st;
DAC @nodul printe nu are strmoi ATUNCI
@creeaz un nou nod rdcin;
@leag nodul printe de noul nod rdcin ca fiu stnga;
@leag noul nod unchi de noul nod rdcin ca fiu dreapta;
@actualizeaz cmpurile noului nod rdcin
EXIT
ALTFEL @extrage din stiva nodul tat al nodului tat; {nodul bunic}
@determin poziia de inserare al nodului unchi;
DAC @nodul bunic are numai doi fii ATUNCI
@insereaz nodul unchi al nodului tat;
@actualizeaz cmpurile nodului unchi;
EXIT
ALTFEL CHEAM Cazul_4_inserare (rad, bunic, st, virf, ch_n, info_n);
SFDAC
SFDAC
SF-Cazul_1

c. Operaia de cutare.

Specificarea problemei de cutare, avnd ca date de intrare ROOT i cheia_caut, este


urmtoarea:

DATE root, cheia_caut;


REZULTATE root;

________________________________________________________________________________

231
Structuri de date i algoritmi
_______________________________________________________________________________

Descrierea algoritmului de inserare n Pseudocod este:

ALGORITMUL CUTARE ESTE:


CITETE cheia_caut;
tmp := ROOT ; { Pn cnd se ajunge la un nod terminal }
CTTIMP tmp^.tip <> 0 EXECUT
DAC cheia_caut < tmp^.a ATUNCI
tmp := tmp^.fiu_st;
ALTFEL
DAC ( tmp^.a < cheia_caut ) i ( cheia_caut < tmp^.b ) ATUNCI
tmp := tmp^.fiu_mijl;
ALTFEL DAC tmp^.fiu_dr <> NIL ATUNCI
tmp := tmp^.fiu_dr;
ALFEL
TIPRETE ( EROARE cheia cutat nu exist )
@returneaz NIL;
SFDAC
SFDAC
SFDAC
SFCT { Adresa nodului tat este n vrful stivei}
Dac tmp^.cheia = cheia_caut ATUNCI
@returneaz adresa nodului gsit;
ALTFEL
@returneaz NIL;
SFDAC
SFALGORITM

d. Operaia de tergere.

Specificarea problemei de tergere, avnd ca date de intrare ROOT i cheia_terg, este


urmtoarea:

DATE root, cheia_terg;


REZULTATE root;

Algoritmul de tergere presupune ntr-o prim faz gsirea nodului de ters i a nodului tat
al nodului de ters, dac acesta exist. Dac am gsit nodul de ters, atunci va trebui s analizm n
care din cazurile de mai jos ne situm:
Dac arborele conine un singur nod frunz, atunci algoritmul de tergere este trivial:
o Se actualizeaz adresa nodului rdcin care devine NIL;
o Se elibereaz spaiul de memorie ocupat de nodul de ters.
________________________________________________________________________________

232
Structuri de date i algoritmi
_______________________________________________________________________________

Dac nodul tat al nodului de ters are 3 fii, algoritmul de tergere este urmtorul:
o Se actualizeaz cmpurile nodului tat;
o Se elibereaz spaiul de memorie ocupat de nodul de ters.
Dac nodul tat al nodului de ters are 2 fii, algoritmul de tergere este urmtorul:
o Nodul frate rmas al nodului de ters se leag de un nod unchi;
o Dac nodul unchi avea 2 fii, n urma alipirii nodului va avea 3 fii;
o Dac nodul unchi avea 3 fii, n urma alipirii nodului va avea 4 fii, deci va trebui s
facem:
Vom crea un nou nod non-frunz, nod frate cu nodul tat. Poziia nodului nod
frate este determinat de poziia i dispunerea nodurilor fiu;
Cele patru noduri fii vor fi separate astfel: cei doi frai din stnga i cei doi
frai din dreapta vor fi ataai nodului tat iniial i nodului unchi nou creat.

Descrierea detaliat a algoritmului de tergere poate fi gsit n referina bibliografic [Aho,


1987].

e. Operaia de traversare.

Spre deosebire de arborii binari de cutare la arborii de cutare 2-3, datele propriu-zise se
gsesc pe acelai nivel sub forma de noduri terminale. De aceea traversarea AC2-3 este mai
special necesitnd un test suplimentar corespunztor deciziei dac avem de-a face cu un nod
terminal sau nu.
La fel ca la arborii de cutare, seciunea 4.5.2, cele trei modaliti de traversare difer prin,
momentul n care se viziteaz nodul rdcina i anume, n cazul:
preordine: se viziteaz nti rdcina, apoi subarborele stng, subarborele din mijloc i
dup aceea subarborele drept dac exist;
inordine: se viziteaz subarborele stng, se viziteaz rdcina, subarborele din mijloc i
subarborele drept dac exist, sau, se viziteaz subarborele stng, subarborele din mijloc,
se viziteaz rdcina i subarborele drept dac exist;
postordine: se viziteaz subarborele stng, subarborele din mijloc, subarborele drept
dac exist i rdcina.

Descrierea algoritmilor de traversare, n limbajul Pascal este:

Procedure inordine_2_3 ( def : adresa ) ; { traversare inordine }


begin
if def <> NIL then
begin
inordine_2_3 ( def^.fiu_st ) ;
if def^.tip = 0 then
________________________________________________________________________________

233
Structuri de date i algoritmi
_______________________________________________________________________________

write ( def^.cheia : 3 ) ;
inordine_2_3 ( def^.fiu_mij ) ;
inordine_2_3 ( def^.fiu_dr ) ;
end ;
end ;

Procedure preordine_2_3 ( def : adresa ) ; { traversare preordine }


begin
if def <> NIL then
begin
if def^.tip = 0 then
write ( def^.cheia : 3 ) ;
preordine_2_3 ( def^.fiu_st ) ;
preordine_2_3 ( def^.fiu_mij ) ;
preordine_2_3 ( def^.fiu_dr ) ;
end ;
end ;

Procedure postordine_2_3 ( def : adresa ) ; { traversare postordine }


begin
if def <> NIL then
begin
postordine_2_3 ( def^.fiu_st ) ;
postordine_2_3 (def^.fiu_mij);
postordine_2_3 ( def^.fiu_dr ) ;
if def^.tip = 0 then
write ( def^.cheia : 3 ) ;
end ;
end ;

V.2.4.4. Performanele algoritmilor n AC2-3

Dac un AC2-3 are nlimea h, atunci numrul de noduri frunz este cuprins ntre 2 h i 3h
[Sed, 1990]. Aceasta nseamn c nlimea unui AC2-3 cu n noduri este cel mult log2n, adic
algoritmul de cutare este direct proporional cu O(log2n).

V.2.4.4. Probleme rezolvate

________________________________________________________________________________

234
Structuri de date i algoritmi
_______________________________________________________________________________

Exemplul V.x: Implementarea PASCAL a operaiilor efectuate ntr-un AC2-3: creare-iniializare,


inserare, cutare.

Program Arbori_2_3;
Const max=100;

Type
str14 = string [14] ;
tip_nod = (terminal,neterminal);
adresa =^nod ;
nod = record
case tag : tip_nod of
neterminal : (lkey : integer ;
lptr : adresa ;
mkey : integer ;
mptr : adresa ;
rptr : adresa ; ) ;
terminal : (key : integer ) ;
end ;
top = 0..max;
stiva = array [1..max] of adresa;

VAR head,tata:adresa;
STACK:stiva;
DIR:array [1..max] of char;
topdir ,valoare , nr :integer;
ind : top ;
p,nou : adresa ;
succes : boolean ;
c :char ;

Procedure reset_stack ; { iniializare stiv }


begin
ind := 0 ;
end ;

Function empty_stack ( ind:top ) : boolean ; { stiv goal }


begin
if ind = 0 then
empty_stack := true
else
empty_stack := false ;
end ;

Function full_stack ( ind : top ) : boolean ; { stiv plin }


________________________________________________________________________________

235
Structuri de date i algoritmi
_______________________________________________________________________________

begin
if ind = max then
full_stack := true
else
full_stack := false
end ;

Procedure push ( var st : stiva ; var ind : top ; var element : adresa ) ;
{ introducere n stiv }
begin
if not full_stack ( ind ) then
begin
st [ ind ] := element;
ind := ind+1;
end
else
begin
writeln ( ' stack owerflow ' ) ;
exit ;
end
end ;

Function pop ( var st : stiva ; var ind:top) : adresa ; { scoatere din stiv }
begin
if not empty_stack ( ind ) then
begin
ind := ind-1 ;
pop := st [ ind ] ;
end
else
writeln ( ' stack underflow ' ) ;
exit ;
end ;

Function inform ( b:adresa ) : integer ; { funcia returneaz valoarea cheii }


begin
if b^.tag = terminal then inform := b^.key
else if b^.rptr <> nil then inform := inform ( b^.rptr )
else inform := inform (b^.mptr) ;
end ;

Procedure Inserare_arbore ( nr:integer ) ;

Procedure Insert_caz1 ( x:integer ) ; { rdcina = nil }


var q : adresa;
begin
________________________________________________________________________________

236
Structuri de date i algoritmi
_______________________________________________________________________________

new (q ); { aloc memorie noului nod }


q^.tag := terminal ;
q^.key := x ;
head := q ;
succes := true ;
end ;

Procedure Insert_caz2 ( x:integer ) ; { arborele conine un singur nod }


var q,r,temp : adresa ;
begin
temp := head ;
new ( q ) ; q^.tag := neterminal ;
if temp^.key < x then begin
q^.lkey := temp^.key ; q^.lptr := temp ;
new(r) ; r^.tag := terminal ; r^.key := x ;
q^.mptr := r ; q^.mkey := x ;
end
else begin
new(r) ; r^.tag := terminal ; r^.key := x ;
q^.lkey := x ; q^.lptr := r ;
q^.mkey := temp^.key ; q^.mptr := temp ;
end ;
q^.rptr := nil ;
head := q ;
succes := true ;
end;
Procedure Insert_caz3 ; { nodul tat are doi copii}
var q,temp1,temp2 : adresa;
begin
if (nr <> p^.lkey ) and ( nr<>p^.mkey ) then
begin
new ( q ) ;
q^.tag := terminal ;
q^.key := nr ;
temp1 := p^.lptr ;
temp2:=p^.mptr;
if nr < temp1^.key
then begin
p^.lkey := nr ;
p^.lptr := q ;
p^.mkey := temp1^.key ;
p^.mptr := temp1 ;
p^.rptr := temp2 ;
end
else if (temp1^.key <nr) and (nr < temp2^.key)
then begin
________________________________________________________________________________

237
Structuri de date i algoritmi
_______________________________________________________________________________

p^.mkey := nr ;
p^.mptr := q ;
p^.rptr := temp2 ;
end

else p^.rptr := q ;
succes := true ;
end ;
end ;

Procedure Caut_tata ;
begin
p := head ;
Push (stack,ind,p) ;
while p^.lptr^.tag = neterminal do begin
if nr <= p^.lkey then begin
p := p^.lptr ;
Push (stack,ind,p) ;
end
else if nr <= p^.mkey then begin
p := p^.mptr ;
Push (stack,ind,p) ;
end
else if p^.rptr <> nil then begin
p := p^.rptr;
Push (stack,ind,p);
end
else begin
p := p^.mptr ;
Push (stack,ind,p);
end ;
end
end;

Procedure Insert_caz4 (nodnou:adresa); {nodul tat are 3 copii }


var tata,frate,temp1,temp2,temp3,newhead:adresa;
begin
tata := POP(stack,ind);
temp1 := tata^.lptr ;
temp2 := tata^.mptr ;
temp3 := tata^.rptr ;
if ( temp3 = nil )
then
begin
if nr <= inform(temp1)
then
________________________________________________________________________________

238
Structuri de date i algoritmi
_______________________________________________________________________________

begin
tata^.lkey := nr ;
tata^.lptr := nodnou ;
tata^.mkey := inform(temp1);
tata^.mptr := temp1;
tata^.rptr := temp2;
end
else if nr <= inform (temp2)
then begin
tata^.mkey := nr;
tata^.mptr := nodnou ;
tata^.rptr := temp2 ;
end
else begin
tata^.rptr := nodnou ;
end ;
end
else
begin
new (frate) ; frate^.tag:=neterminal;
if nr < inform (temp1)
then
begin
tata^.lkey := nr;
tata^.lptr := nodnou;
tata^.mkey := inform(temp1);
tata^.mptr := temp1;
tata^.rptr := nil;
frate^.lkey := inform(temp2);
frate^.lptr := temp2;
frate^.mkey := inform(temp3);
frate^.mptr := temp3;
frate^.rptr := nil;
end
else if nr < inform(temp2)
then
begin
tata^.mkey := nr;
tata^.mptr := nodnou;
tata^.rptr := nil;
frate^.lkey := inform(temp2);
frate^.lptr := temp2;
frate^.mkey := inform(temp3);
frate^.mptr := temp3;
frate^.rptr := nil;
end
________________________________________________________________________________

239
Structuri de date i algoritmi
_______________________________________________________________________________

else if nr < inform(temp3)


then
begin
tata^.rptr := nil;
frate^.lkey := nr ;
frate^.lptr := nodnou ;
frate^.mkey := inform(temp3) ;
frate^.mptr := temp3 ;
frate^.rptr := nil ;
end
else begin
tata^.rptr := nil ;
frate^.lkey := inform(temp3) ;
frate^.lptr := temp3 ;
frate^.mkey:= nr ;
frate^.mptr := nodnou ;
frate^.rptr := nil ;
end ;
if tata=head then begin
new (newhead) ;
newhead^.tag := neterminal ;
newhead^.lkey := inform(tata) ;
newhead^.lptr := tata ;
newhead^.mkey := inform(frate) ;
newhead^.mptr := frate ;
newhead^.rptr := nil ;
head := newhead ;
end
else Insert_caz4(frate) ;
end ;
end ;

begin
if head = nil then Insert_caz1(nr)
else if head^.tag = terminal then begin
if head^.key <> nr then Insert_caz2(nr)
end
else begin
caut_tata ;
if p^.rptr = nil then Insert_caz3
else begin
if ( nr <> p^.lkey) and (nr<>p^.mkey) and
(nr<>p^.rptr^.key) then
begin

new(nou) ; nou^.tag := terminal ;


________________________________________________________________________________

240
Structuri de date i algoritmi
_______________________________________________________________________________

nou^.key := nr ;
Insert_caz4(nou) ;
succes := true ;
end ;
end ;
end ;
if succes then begin
writeln ( ' OK ! ' ) ;
Indicator ;
end
else writeln( ' Eroare ! Cheie dubla ! ' ) ;

end;

Procedure Inserare ;
begin

writeln ;
write( ' Introduce informaia: ' ) ;
readln (valoare) ;
succes := false ;
reset_stack ;
Inserare_arbore(valoare) ;
end ;

Function caut(p:adresa;x:integer) : adresa ; forward ;


Procedure Cutare ;
var numar:integer;
adr : adresa ;

begin
write('Cheia de cutare: ');
readln(numar);
adr:=caut(head,numr);
if adr=nil
then begin
writeln('Element inexistent !');
readln;
end
else begin
writeln('Cutare cu succes !');
writeln('Numrul: ',adr^.key);
readln;
end;
end;
________________________________________________________________________________

241
Structuri de date i algoritmi
_______________________________________________________________________________

Function caut(p:adresa;x:integer):adresa;
begin
if p^.tag =terminal
then if p^.key=x
then caut:=p
else caut:=nil
else if x <= p^.lkey
then caut:=caut(p^.lptr,x)
else if (x > p^.lkey) and (x <= p^.mkey)
then caut:=caut(p^.mptr,x)
else if p^.rptr<>nil
then caut:=caut(p^.rptr,x)
else caut:=nil;
end;

begin
clrscr;
writeln('1 - inserare 2 - cutare esc - iesire');

head:=nil;
repeat
c:=readkey;
case c of
'1':begin
Inserare;
end;
'2' :begin
Cutare;
end;
end;
until c=#27;

end.

V.2.4.5. Probleme propuse

1. S se considere un arbore binar care cuprinde strmoii unei persoane, a crei nume figureaz n
rdcin arborelui. Nodul care figureaz n stnga cuprinde numele tatlui, iar cel din dreapta pe cel
al mamei. Fiind dat numele unei persoane oarecare din familie, s se afieze numele bunicilor, dac
acetia figureaz in arbore.

________________________________________________________________________________

242
Structuri de date i algoritmi
_______________________________________________________________________________

2. Reprezentai grafic arborele binar construit printr-o serie de inserri, pentru urmtorul ir de chei:
8, 17, 10, 15, 5, 2, 16, 19, 13, 1 , 4, 11.

3. Dup ce n elemente au fost nserate ntr-un arbore, ntr-o ordine aleatoare, care este numrul
mediu de comparaii necesare pentru a gsii al m lea cel mai mare numr ?

4. Demonstrai ca un AC2-3 de nlime h conine un numr de noduri terminale cuprins ntre


2 h i 3 h .

5. Formulai un algoritm specific care terge i rebalanseaz un arbore binar balansat n greutate .

6. Formulai un algoritm care s modifice un nod particular ntr-un ABCBG. Apelul algoritmului s
fie de forma:
SCHIMB ( CHEIE , GREUTATE_NOU )
unde CHEIE este cheia nodului care se modific i GREUTATE_NOU este noua greutatea a
nodului.
Observaie : GREUTATE _NOU poate s aib o valoare care poate cauza plasarea nodului la un
nivel superior sau inferior n arbore.

V.3. Funcii de cutare hash

V.3.1. Introducere

________________________________________________________________________________

243
Structuri de date i algoritmi
_______________________________________________________________________________

Cea mai bun metod de cutare studiat pn acuma este cutarea binar, care are timpul
de cutare proporional cu O(log2n). Tehnicile de cutare discutate pn acum se bazeaz exclusiv
pe compararea cheilor.
O alt abordare posibil ar fi calculul direct al locaiei sau adresei unei date cutate. Evident
c ntr-un astfel de scenariu avem nevoie de o funcie special care s transforme informaia
corespunztoare cheii de cutare ntr-o adres unde s regsim informaia cutat. Expresia de
calcul este n mod natural dependent de mulimea cheilor de cutare i de spaiul de memorie
cerut de structura de date care va stoca informaiile dorite. De exemplu, dac utilizm o alocare
static cu ajutorul unui tabel pentru a nregistra date referitoare la cei n studeni a unei specializri,
atunci fiecare student poate fi identificat printr-un numr, avnd valoare ntre 1 si n. Dac
cunoatem locaia a-i-a a studentului cutat atunci scrierea student[i] va reprezenta accesul direct
la datele studentului cutat. O astfel de relaie cheie-adres exist rareori n aplicaii reale, deoarece
n general, cheile de cutare sunt alese fr a se ine seama de o astfel de consecinele implementrii
ntr-un limbaj de programare, a relaiei cheie-adres.
Din punct de vedere matematic, aceasta problem de transformare a cheii ntr-o adresa este
definit ca o funcie, numit funcie hash H, care face maparea spaiului de chei K ntr-un spaiu
de adrese A. Funcia hash trebuie s genereze o adres pe baza unui calcul simplu aritmetic sau
logic efectuat asupra cheii n totalitate sau asupra unei pri din cheie.
Datorit faptului c dimensiunea spaiului de chei este de obicei mai mare dect
dimensiunea spaiului de adrese, se poate ntmpla ca mai multor chei de cutare s le corespund,
prin intermediul funciei hash, o aceeai adres. Este evident implicaia pentru funcia de hash de a
nu avea proprietatea de injectivitate, adic:
k1 K , k 2 K , k1 k 2 H k1 H k 2 (5.x)
Acest fenomen se numete coliziune ntre nregistrrile memorate n structura de date.
Pentru a rezolva aceast problem este nevoie s analizm tehnici de rezolvare a coliziunilor, s
construim algoritmi corespunztori care s ne permit manipularea informaiilor stocate n structura
de date.
Funciile hash se grupeaz n dou mari clase:
Funcii hash independente-distribuional;
Funcii hash dependente-distribuional.
Clasa de funcii hash independente-distribuional nu folosete distribuia cheilor unei tabele
pentru calculul adresei unei nregistrri.
Clasa de funcii hash dependente-distribuional se folosete de distribuia unor chei din
punct de vedere probabilistic pentru calculul adresei unei nregistrri.
S vedem n continuare cteva exemple de funcii hash, dup care vom analiza operaiile i
algoritmii corespunztori manipulrii nregistrrilor ntr-o structur de date, precum i modaliti de
a rezolva problema coliziunilor.

________________________________________________________________________________

244
Structuri de date i algoritmi
_______________________________________________________________________________

V.3.2. Funcii hash

Vom examina o serie de funcii hash simple. Dou dintre proprietile funciilor hash sunt
importante, i anume:
viteza mare de calcul a adresei;
distribuia uniform a adreselor.

nainte de a trece la descrierea funciilor hash, s introducem conceptul de codificare a


cheilor de cutare, numit uneori precondiionare. Codificarea cheilor de cutare se refer la spaiul
de chei K, care de cele mai multe ori este o mulime alfanumeric, care nu permite aplicarea
funciilor hash, care sunt funcii numerice. De aceea, avem nevoie de codificare care face o
transformare a mulimii cheilor de cutare alfanumerice ntr-o mulime numeric care poate fi
manipulat mai uor i care poate fi argumentul funciilor hash numerice [Knu, 1976].
Cel mai des folosit exemplu de codificare se bazeaz pe utilizarea codurilor ASCII sau
EBCDIC, nlocuind semnificaia alfanumeric a unui caracter cu codul su numeric corespunztor.
De exemplu, putem folosi n locul caracterului alfanumeric A numrul ntreg 11 care corespunde
codului su ASCII.
O problem care poate apare datorit procesului de codificare este dimensiunea prea mare a
cheii numerice obinut prin procesul de codificare. Presupunnd ca dimensiunea cheii de cutare
este de 10 caractere alfanumerice, codificarea ar transforma cheia de cutare alfanumeric ntr-o
cheie de cutare numeric de ordinul miilor de mii de miliarde, date care nu pot fi reprezentate n
memoria calculatorului utilnd metode clasice. De aceea, avem nevoie de o operaie pe care o vom
numi scalare, care s transforme intervalul [a,b] ntr-un interval [c,d]. Operaia de scalare se
bazeaz pe o transformare liniar de forma f : a, b c, d , f x x , unde coeficienii i ai
transformrii liniare se determin din sistemul:

f a c
(5.x)
f b d

V.3.2.1. Funcia hash - metoda mpririi

Una dintre cele mai utilizate funcii hash este cea bazat pe metoda mpririi. Aceasta este
definit n felul urmtor:
H : K A, H x x mod m 1 (5.x)
unde m este un divizor ntreg nenul, iar operatorul mod este operatorul modulo, adic restul
mpririi lui x la m. Adresele generate de aceast funcie hash vor fi 1,2,3, , m.
________________________________________________________________________________

245
Structuri de date i algoritmi
_______________________________________________________________________________

Funcia hash bazat metoda mpririi asigur, pn la o anumit limit, o distribuie


uniform a mulimii adreselor generate. Aceast distribuie uniform prezint ns dezavantajul
producerii de coliziuni pentru cheile de cutare din aceeai clas de echivalent modulo m.

V.3.2.2. Funcia hash - metoda ptratului mediu

O alt funcie hash care este folosit n multe aplicaii se bazeaz pe metoda ptratului
mediu. In aceast metod cheia de cutare este ridicat la ptrat, iar adresa unde va fi cutat
nregistrarea este obinut prin alegerea unui numr de cifre sau bii din mijlocul numrului obinut
prin ridicare la ptrat. Numrul de cifre ales este dependent de dimensiunea structurii de date care
stocheaz nregistrrile cutate.
De exemplu, s considerm o cheie din ase cifre: 123.456. Ridicm la ptrat i rezult
numrul 15.241.383.936. Dac avem nevoie de o adres format din trei numere, atunci putem alege
poziiile din mijloc de la 5 la 7, deci adresa va fi 138.

V.3.2.3. Funcia hash - metoda ndoirii

Pentru funcia hash bazat pe metoda ndoirii, numrul corespunznd cheii de cutare este
divizat n numere de lungime egal cu dimensiunea spaiului de adresare, cu o posibil excepie
corespunznd ultimei pri, care se poate completa cu zerouri nesemnificative pentru a avea aceeai
dimensiune cu celelalte diviziuni. Aceste pri sunt nsumate, este ignorat cifra carry, rezultatul
adunrii formnd adresa dorit.
Observaie: Dac cheia este binar, vom folosi operaia logic XOR n locul operaiei de
adunare.
Exemplu: Cheia de cutare 356.942.781 este mprit n trei numere de cte trei cifre pentru a
forma o adres de trei cifre, deoarece spaiul de stocare necesit cel mult 999 de locaii de memorie.
Cele trei numere obinute sunt 356, 942 si 781. Adunate, obinem:

356 +
942 renunm la cifra 2 de transfer i avem adresa 079.
781
--------
2079

V.3.2.4. Funcia hash - metoda cifrelor

________________________________________________________________________________

246
Structuri de date i algoritmi
_______________________________________________________________________________

Funcia hash, bazat pe metoda cifrelor formeaz adrese prin selectarea i translatarea cifrelor
din cheia de cutare original.
Exemplu: O cheie de cutare ce are valoarea numeric 7.546.123 este transformat n adresa 2164
prin selectarea cifrelor din poziiile 2 la 6 i inversarea ordinii lor.
Metoda de selectare i de inversare trebuie folosit cu consecven pentru o aceeai mulime
de chei de cutare. Pentru un set de chei aceeai poziie din cheie, aceeai rearanjare trebuie
folosit cu consisten.

V.3.2.5. Funcia hash - metoda dependent de lungimea cheii

O alta funcie hash des utilizat n structuri de date alocate static care folosesc tabele este
funcia hash bazat pe metoda dependent de lungimea cheii. n aceast metod lungimea cheii
este folosit singur sau mpreun cu o parte a cheii, pentru a produce direct o adres din tabel, ori
pentru a produce o cheie intermediar, care este folosit mai departe cu o alt metod, cum ar fi de
exemplu metoda mpririi, pentru a genera o adresa final din tabel.
O funcie hash de acest tip, sumeaz valoarea reprezentrii binare interne a primului i al
ultimului caracter al cheii i a lungimii cheii, translatat la stnga cu patru poziii binare (sau
multiplicat cu 24 = 16).
Exemplu: Avem cheia de cutare PROTEO. Ea va genera adresa:
215 + 214 + ( 6 * 16 ) = 525 dac utilizm codul EBCDIC.
Dac considerm 525 ca o cheie intermediar i aplicm metoda mpririi cu divizorul 49,
atunci adresa rezultat este 36.

V.3.2.6. Funcia hash metoda codificrii algebrice

Funcia hash bazat pe metoda codificrii algebrice are la baz teoria de codificare
algebric [Knu, 1976]. O cheie binar de n bii (k1 k2 ...kn)2 este codificat cu ajutorul unui polinom
de gradul n:
n
K x k i x i 1 (5.x)
i 1

Dac spaiul de adresare este n intervalul 0,2 m 1 , atunci vom construi un polinom
divizor al polinomului K, i anume:
m
P x x m p i x i 1 (5.x)
i 1
mprind polinomul K la polinomul P, folosind operaii n baza 2, vom obine polinomul
rest:

________________________________________________________________________________

247
Structuri de date i algoritmi
_______________________________________________________________________________

r
R x K x mod P x ri x i 1 (5.x)
i 1

Coeficienii polinomului rest R x , (h1h2 hr)2 vor genera adresa cutat.

V.3.2.7. Funcii hash - metoda multiplicativ

[Knu, 1976] a artat, ca funciile hash de cutare bazate pe metoda multiplicativ sunt
printre cele mai performante. Dac x Z , iar c este o constant c pozitiv subunitar, 0 < c < 1,
atunci funcia hash arat n felul urmtor:
H x m cx 1 (5.x)
Am notat cu x cel mai mare ntreg mai mic dect x i cu x partea fracionar a lui x.
Aceast funcie hash d rezultate foarte bune dac constanta c este aleas corespunztor.
Alegerea constantei c este dificil.

V.3.3. Performana funciilor hash

[Knu, 1973], prezint studii asupra funciilor hash prezentate anterior. n general, aceste
funii hash genereaz adrese uniforme, dar o generalizare a acestei afirmaii este dependent de
mulimile particulare de chei de cutare.
Este nevoie de introducerea unui sistem de referin pentru a compara performanele
diferitele funcii hash. Cel mai larg acceptat criteriu de referin este ALOS (Average Length of
Search), prezentat n (5.1).
De obicei, cea mai performant funcie hash de folosit pentru un anumit mulime de cutare
va minimiza ALOS. Sunt ns i ali factori, n afar de performana funciilor hash, care
minimizeaz ALOS, timpul mediu de cutare.

V.3.4. Tehnici de rezoluiune a coliziunilor

V.3.4.1. Introducere

Cu ajutorul funciilor hash se poate realiza transformarea cheie de cutare adres. Nu am


inut ns cont de problema prezentat n (5.x), i anume de problema coliziunilor. O coliziune
apare, aa cum am mai artat, atunci cnd dou chei de cutare distincte sunt mapate de funcia hash

________________________________________________________________________________

248
Structuri de date i algoritmi
_______________________________________________________________________________

la aceeai adres a structurii de date. In practic, un astfel de fenomen se ntmpl pentru c spaiul
cheilor de cutare este mai mare dimensional dect spaiul adreselor. ntr-o astfel de situaie, funcia
hash nu este injectiv, deci dou sau mai multe chei de cutare pot genera prin intermediul funciei
hash aceeai adres. Evident, c nu putem suprapune dou sau mai multe nregistrri, cu chei de
cutare diferite, la aceeai adres generat de funcia hash.
Rezolvarea acestei probleme se face cu ajutorul tehnicilor de rezoluiune a coliziunilor.
Tehnicile de rezoluiune a coliziunilor se mpart n dou clase:
adresare deschis;
adresare nlnuit.
Obiectivul general al tehnicilor de coliziune, este de a ncerca plasarea nregistrrilor aflate
n coliziune la alte adrese ale structurii de date. Dac structura de date este o tabel, atunci ne
propunem s plasm nregistrrile aflate n tabel n alte locaii libere ale tabelei. Aceasta va implica
o serie de operaii de cutare n tabel, pn cnd gsim o poziie liber unde se poate insera una
din nregistrrile aflate n coliziune.
Deci avem nevoie de un mecanism i de algoritmul corespunztor care s examineze toate
poziiile structurii de date n vederea realizrii operaiilor de inserare, cutare, tergere, actualizare.
Un astfel de mecanism trebuie s satisfac o serie de cerine, i anume [Tom, 1997]:
viteza (pentru a determina repede o nou poziie liber);
puterea de acoperire (pentru a putea cuta n toate poziiile existente n structura de date);
reproductibilitatea (pentru a regsi nregistrrile inserate n structura de date).

V.3.4.2. Tehnici de rezoluiune a coliziunilor prin adresare deschis

Ideea de baz n tehnica de rezoluiune a coliziunilor prin adresare deschis este de a cuta
pentru nregistrarea aflat n coliziune o nou poziie liber n structura de date. Dac structura de
date este alocat static n memorie, atunci vom folosi o tabel pentru reprezentare, tabela se va numi
tabel hash. O astfel de tabel hash, fiind alocat static are un numr finit de poziii de stocare a
nregistrrilor, aceast capacitate ne putnd fi modificat pe parcursul execuiei programului ce
implementeaz algoritmul de manipulare a nregistrrilor. De aceea, pentru a folosi ct mai eficient
spaiul de stocare fix oferit de o tabel hash, va trebui s facem disponibile toate spaiile eliberate n
urma unor operaii de tergere.
Putem a gestiona aceast problem vom introduce marcaje care s ne indice faptul c o
poziie a tabelei hash este liber sau nu. Vom avea urmtoarele valori posibile pentru o poziie liber
din tabel hash, n cmpul cheii de cutare:
Emtpy poziie liber n tabela hash n care nu s-a inserat nici o nregistrare;
DELETED - poziie liber n tabela hash, unde a existat o nregistrare dar a fost tears:

Mecanismul prin care realizm cutarea unei noi adrese pentru o cheie de cutare aflat n
coliziune prin tehnica adresrii deschise este de mai multe feluri, i anume:
________________________________________________________________________________

249
Structuri de date i algoritmi
_______________________________________________________________________________

a. Probare liniar
b. Probare aleatoare

a. Probarea liniar

Unul din cele mai simple mecanisme de cutare a unei locaii libere pentru o nregistrare
avnd o cheie de cutare n coliziune, este de a folosii o secven de cutare liniar. Presupunnd c
avem cheia k K , H k a A , iar adresa la adresa a avem o coliziune, atunci probarea liniar se
bazeaz pe urmtoarea secven de cutare liniar:

a,a+1,,m-1,m,1,2, , a-1 (5.x)

unde m reprezint capacitatea maxim de stocare a tabelei. Vom gsi o locaie liber dac tabela nu
este deja plin.
Cnd efectum o operaie de cutare a unei nregistrri cu cheia de cutare k, vom proceda
astfel:
- calculm adresa corespunztoare cheii de cutare k: a H k A ;
- comparm cheia de la adresa a cu cheia de cutare k;
- Dac cheia de la adresa a este cea cutat, atunci avem o cutare cu succes:
- Dac cheia de la adresa a nu este cea cutat, pornim mecanismul de probare liniar (5.x).
Dac an ajuns la locaia de adres a 1, atunci cutare nu este cu succes, nregistrarea
cutat nu exist n tabel. Altfel cutarea este cu succes.

Aceast tehnic de rezolvare a coliziunilor se numete probare liniar .


Operaia de inserare este prezentat cu ajutorul unui exemplu. S presupunem c avem
urmtoarele o tabel de dimensiune 11 i cteva nregistrri cu urmtoarele chei de cutare:
NINA, STOICAN, ANA, ADA, FUNCTIE, B, BRAND i PARAMETRU
Aplicnd o funcie hash H, s presupunem ca avem urmtoarea situaie:

Cheia de Adresa din tabela


cutare hash

NINA H (NINA) = 1

STOICAN H (STOICAN) = 2

ANA H (ANA) = 3

ADA H (ADA) = 3

________________________________________________________________________________

250
Structuri de date i algoritmi
_______________________________________________________________________________

FUNCTIE H (FUNCTIE) = 9

B H (B) = 9

BRAND H (BRAND) = 9

PARAMETRU H (PARAMETRU) = 9

Dup operaia de inserare, aplicnd mecanismul probrii liniare, vom avea urmtoarea tabel:

Figura 5.x: Coninutul tabelei hash dup aplicarea operaiilor de inserare i a cutrii
unei noi poziii libere prin mecanismul de probare liniar.

Primele trei nregistrri, avnd cheile de cutare, NINA, STOICAN, ANA sunt inserate
printr-o singur probare n primele trei poziii libere (Empty) ale tabelei.
nregistrarea cu cheia de cutare ADA trebuie plasat n poziia 4 a tabelei cci poziia 3 este
ocupat i astfel apare o coliziune. Este nevoie de dou probri.
nregistrarea cu cheia de cutare FUNCTIE este inserat n poziia 9 de la prima operaie de
probare cci poziia 9 din tabel era liber (Empty).
nregistrrile cu cheile de cutare B si BRAND, sunt n coliziune cu nregistrarea cu cheia
de cutare FUNCTIE, respectiv B. Pentru a insera nregistrarea cu cheia de cutare B, aplicm
mecanismul probrii liniare i obinem poziia liber 10 din tabel, n urma a 2 operaii de probare.
Pentru a insera nregistrarea cu cheia de cutare BRAND, aplicm mecanismul probrii liniare i
obinem poziia liber 11 din tabel, n urma a 3 operaii de probare.
n final, nregistrarea cu cheia de cutare PARAMETER va fi plasat prin mecanismul
probrii liniare n poziia 5 a tabelei, necesitnd 8 operaii de probare, fiind n coliziune cu
nregistrrile inserate anterior, fiind probate poziiile ocupate 9, 10, 11, 1, 2, 3, 4 i poziia liber 5.

________________________________________________________________________________

251
Structuri de date i algoritmi
_______________________________________________________________________________

Specificarea problemei de inserare-cutare, avnd ca date de intrare tabela de hash tab,


dimensiunea maxim a tabelei m, cheia de inserare-cutare cheia, INS = 1 pentru operaia de
inserare i INS = 0 pentru operaia de cutare, este urmtoarea:

DATE tab, m, cheia, INS;


REZULTATE tab;

Descrierea algoritmului de inserare n Pseudocod este:

ALGORITMUL INSERARE_CUTARE_Probare_liniar ESTE:


CITETE cheia, INS;
a := H (cheia);
PENTRU i:=a;(m+a-1) MOD MAX EXECUT {se genereaz adresele a, a+1,..,m}
{1,2,, a-1 probare liniar }
DAC tab [i] = cheia ATUNCI
DAC INS = 0 ATUNCI
@returneaz adresa a {Cutare cu succes}
ALTFEL
TIPRETE (EROARE INSERARE cheie dubl, a);
EXIT;
SFDAC
SFDAC
DAC (tab [i] = Empty) sau (tab [i] = DELETED) ATUNCI
DAC INS = 1 ATUNCI
@inserm noua nregistrare la adresa a din tabel
ALTFEL
DAC (tab [i] = Empty) ATUNCI
TIPRETE (EROARE CUTARE inf. nu exist);
SFDAC
SFDAC
SFDAC
SFPENTRU
DAC INS = 0 ATUNCI
TIPRETE (EROARE CUTARE inf. nu exist);
ALTFEL
TIPRETE (EROARE INSERARE tabela plin);
SFALGORITM

Algoritmul de cutare implementat n limbajul Pascal, ca o funcie ce returneaz adresa


poziiei cutate din tabela hash, n cazul unei cutri cu succes, este:

Function search( key : typekey; var r : dataarray ) : integer;

________________________________________________________________________________

252
Structuri de date i algoritmi
_______________________________________________________________________________

var i, last : integer;


begin
i := hashfunction( key ) ;
last := (i+n-1) mod m;
while (i<>last) and (not empty(r[i])) and (r[i].k<>key) do
i := (i+1) mod m;
if r[i].k=key then search := i {*** nregistrarea a fost gsit ***}
else search := -1; {*** nregistrarea nu a fost gsit ***}
end;

Operaia de tergere a unei nregistrri din tabela hash este simpl. Vom cuta nregistrarea
de ters din tabela hash. Dac nregistrarea exist, vom avea grij s marcm cmpul corespunztor
cheii de cutare cu marcajul DELETED. Acest marcaj este necesar pentru a optimiza operaiile de
cutare care se opresc n cazul unei cutri cu insucces dac avem valoarea marcajului DELETED,
i pentru a evita inserarea unor nregistrri cu cheie dubl. De exemplu n tabela (5.x), dac tergem
nregistrarea cu cheia de cutare FUNCTIE i nu marcm cmpul cheie cu marcajul DELETED,
atunci dac vrem s nserm o nou nregistrare cu cheia de cutare BRAND poziia 9 din tabela
hash va fi considerat liber i nregistrarea duplicat va fi inserat.
Specificarea problemei de tergere, avnd ca date de intrare tabela de hash tab, dimensiunea
maxim a tabelei m, cheia de tergere cheia, este urmtoarea:

DATE tab, m, cheia;


REZULTATE tab;

Descrierea algoritmului de inserare n Pseudocod este:

ALGORITMUL TERGERE_Probare_liniar ESTE:


CITETE cheia;
adresa := INSERARE_CUTARE(tab, MAX, cheia, 0);
DAC adresa <= 0 ATUNCI
TIPRETE (EROARE CUTARE inf. nu exist);
ALTFEL
@marcheaz locaia de ters cu marcajul DELETED

n lucrarea [Knu, 1976] gsim un model probabilistic pentru a analiza tehnicile de rezoluie
a coliziune i calculare pentru determinarea performanelor algoritmului de cutare n cazul
mecanismului de probare liniar. Modelul presupune ca fiecare cheie este echiprobabil pentru
cutare. Dac notm cu m capacitatea maxim a tabelei hash, atunci probabilitatea ca o nregistrare
1
s fie cutat este p i .
m
Dac dimensiunea spaiului cheilor de cutare este n, atunci vom avea un numr de mn

________________________________________________________________________________

253
Structuri de date i algoritmi
_______________________________________________________________________________

funcii posibile de la K la A.
n
Vom nota cu factorul de ncrcare a tabelei hash . Timpul mediu de cutare va fi
m
dependent de factorul de ncrcare. n [Knu, 1976] gsim urmtoarea formul:

1 1
2 1 1 , pentru cautare cu succes

ALOS (5.x)
1
1 1 , pentru cautare cu insucces
2 1 2

Pentru o distribuie uniform a mulimii chei de cutare, probarea liniar d rezultate


rezonabile, dac o comparm cu algoritmii de cutare secvenial sau de cutare binar,
presupunnd c tabela nu este plin. Factorul de ncrcare trebuie s fie mai mic dect 0,8. Pentru
o valoare mai mare a factorului de ncrcare probarea liniara degenereaz rapid.

b. Probarea aleatoare

Metoda probrii liniare are o serie de dezavantaje. Un prim dezavantaj este datorat faptului
ca trebuie s gestionm un indicator suplimentar de tergere, numit DELETED, n acest fel, o
nregistrare oarecare din tabel are trei stri, i anume, liber (Empty), ocupat sau tears
(DELETED). n mod normal, ar trebui ca o nregistrare din tabel s aib doar una din cele dou
stri posibile, i anume, liber sau ocupat.
Un alt dezavantaj al metodei de probare liniar este problema gruprii primare (primary
clustering). Acest fenomen apare datorit cutrii secveniale a unei poziii libere pentru
nregistrrile aflate n coliziune. De aceea, nregistrrile aflate n coliziune tind s se grupeze ntr-o
anumit poziie a tabelei, n loc ca ele s se distribuie ct mai uniform, fenomen care duce la
scderea performanelor algoritmului de cutare.
Efectele negative fenomenului ale gruprii primare, pot fi reduse prin selectarea unei alte
metode de probare, care s foloseasc un mecanism aleatoriu de cutare a unei poziii libere n
tabela hash, n loc de mecanismul de cutare secvenial. O astfel de metod de probare se numete
probare aleatoare (random probing)
Secvena de adrese de cutare pentru o poziie liber n tabela de hash va fi generat aleator,
dar va trebui s acopere toat mulimea de adrese cuprinse ntre 1 i m, exact o singur dat. O
tabel de hash va fi plin, n momentul n care, insernd o nou nregistrare, apelnd ca urmare a
coliziunii la mecanismul de probare aleatoare, se genereaz aleatoriu o adres duplicat [Tre, 1984].
Un exemplu de mecanism de generare aleatoare a adreselor pentru o tabel hash este :
a := ( a + c ) mod m (5.x)
unde a este adresa iniial generat de funcia hash, c este o constant ntreag, nenul, aleas astfel

________________________________________________________________________________

254
Structuri de date i algoritmi
_______________________________________________________________________________

nct s fie relativ prim cu m.


De exemplu, dac considerm c m = 11 i c = 5, atunci presupunnd c iniial a = 2, atunci
secvena de adrese generat pentru a cuta o poziie liber este 7, 1, 6, 0, 5, 10, 4, 9, 3, 8 i 2.
Specificarea problemei de inserare, avnd ca date de intrare tabela hash numit tab,
dimensiunea maxim a tabelei m, cheia de inserare cheia, este urmtoarea:

DATE tab, m, cheia;


REZULTATE tab;

Descrierea algoritmului de inserare n Pseudocod este:

ALGORITMUL INSERARE _Probare_aleatoare ESTE:


CITETE cheia;
a := H (cheia);
DAC (tab [i] = Empty) sau (tab [i] = DELETED) ATUNCI
@inserm noua nregistrare la adresa a din tabel;
CTTIMP @nu s-a gsit o poziie liber n tabela hash EXECUT
@calculeaz noua adres a utiliznd probarea aleatoare;
DAC @s-a generat o adres duplicat ATUNCI
TIPRETE (EROARE INSERARE tabela plin);
EXIT;
ALTFEL
DAC (tab [i] = Empty) sau (tab [i] = DELETED) ATUNCI
@inserm noua nregistrare la adresa a din tabel;
SFDAC
SFDAC
SFCT
SFALGORITM

Problemele legate de tergere devin i mai severe n cazul probrii aleatoare, dect n cazul
probrii liniare. Dei probarea aleatoare rezolv problema gruprii primare, din pcate nu elimin
problema gruprii secundare (secondary clustering). Gruparea secundar apare cnd se genereaz
aceeai secven de adrese libere pentru dou chei de cutare aflate n coliziune.
O soluie pentru problema gruprii secundare, este de a folosii o funcie hash secundar
care s genereze o valoare aleatoare pentru constanta c din formula (5.x), independent de prima
funcie hash. Prin aplicarea acestei metode se anuleaz efectul negativ al gruprii.
Fie H 1 : K A prima funcie de hash, i k1 , k 2 K dou chei de cutare distincte aflate n
coliziune, adic:
H 1 k1 H 2 k 2 a A

________________________________________________________________________________

255
Structuri de date i algoritmi
_______________________________________________________________________________

Fie H 2 : K A a doua funcie de hash, folosit pentru a genera valoarea constantei c din
formula de probare aleatoare (5.x). Atunci dac H 2 k1 H 2 k 2 putem alege c H 2 k1 . n acest
fel, la fiecare probare aleatoare se vor genera secvene diferite de adrese, iar problema gruprii
secundare va fi depit.
Metoda descris mai sus de a folosi dou funcii hash independente se numete hash dublu.

Exemplu: S considerm urmtoarele funcii hash:


H1 (k) = k mod m si H2 (k) = ( k mod ( m-2 )) + 1
unde k este valoarea cheii de cutare i m este mrimea tabelei hash. Pentru m = 11 i k1 = 75 vom
avea urmtoarele valori: H1 (75) = 9 i H2 (75)= 4.
Aplicnd formula probrii aleatoare (5.x), pentru a = 9 i c = 4, obinem secvena de adrese
n tabela hash: 9, 2, 6, 10, 3, 7, 0, 4, 8, 1, 5
Dac avem cheia de cutare k2 = 42, atunci H1(42) = 9. Cheile de cutare k1 i k2 sunt n
coliziune. Alegnd c = H2 (42) = 7 folosind formula de probare aleatoare, obinem secvena de
adrese n tabela hash: 9, 5, 1, 8, 4, 0, 7, 3, 10, 6, 2.

Implementarea n limbaj Pascal al algoritmului de cutare, utiliznd metoda hash dublu


este:

Function search( key : typekey; var r : dataarray ) : integer;


var i, inc, last : integer;

begin
i := hashfunction( key ) ;
inc := increment( key ) ;
last := (i+(n-1)*inc) mod m;
while (i<>last) and (not empty(r[i])) and (r[i].k<>key) do
i := (i+inc) mod m;
if r[i].k=key then search := i {*** cutare cu succes ***}
else search := -1; {*** cutare fr succes ***}
end;

Performana algoritmului de cutare bazat pe probare aleatoare cu hash dublu, n


conformitate cu [Knu, 1976], este dat de urmtoarea formul:
1
ln1 , pentru ctare cu succes
ALOS (5.x)
1
, pentru ctare cu insucces
1
Metoda probrii aleatoare cu hash dublu este o metod mai performant dect probarea
liniar, n special cnd tabela hash este plin. De exemplu, cnd o tabel hash are un grad de

________________________________________________________________________________

256
Structuri de date i algoritmi
_______________________________________________________________________________

umplere de 95 %, numrul mediu de operaii pentru metoda probrii liniare este 10,5, pe cnd la
metoda probrii aleatoare cu dublu hash este 3,2!

V.3.4.3. Tehnici de rezoluiune a coliziunilor prin adresare nlnuit

O alta metod de a rezolva problema coliziunilor este acea de a grupa cheile de cutare
aflate n coliziune n clase de echivalen. Reprezentantul unei clase de echivalen va fi capul unei
liste simplu nlnuite cu ajutorul creia se vor gestiona dinamic toate cheile de cutare aflate n
aceeai clas de coliziune, adic toate cheile de cutare care genereaz aceeai adres:


H : K A, K k1 , k2 , , kq , k i , k j kl , dac H k i H k 2 k i

Vom avea in acest fel o tabel hash fix, de dimensiune m mai mare sau egal cu numrul
claselor de echivalen. n aceast tabel hash vom stoca doar cheia de cutare reprezentant al clasei
de echivalen i adresa de nceput a listei simplu nlnuite care stocheaz restul cheilor de cutare
aflate n coliziune cu cheia reprezentant al clasei de echivalen.
Aceast tehnic de rezoluiune a coliziunilor se numete adresare nlnuit.

Exemplu: n figura de mai jos avem un exemplu de reprezentare a metodei adresrii nlnuite,
pentru m = 11 si n = 9. Presupunem c cheile sunt nserate n ordinea urmtoare :

NODE , STORAGE , AN ,ADD , FUNCTION , B ,BRAND i PARAMETER

Figura 5.x.: Modelul de rezolvare a coliziunilor prin adresare nlnuit.

________________________________________________________________________________

257
Structuri de date i algoritmi
_______________________________________________________________________________

S analizm algoritmul de inserare. Dac inserarm n structura noastr de date nregistrri


cu o cheie de cutare k, facem urmtorii pai:
Aplicm funcia hash i obinem adresa a pentru nregistrarea de inserat;
Cutm n tabela de hash la adresa a existena unei alte nregistrri;
Dac poziia a din tabela hash este liber, nregistrarea de inserat nu este n coliziune i
crem primul nod al listei simplu nlnuite corespunztoare clasei de echivalen a .
Dac poziia a din tabela hash este ocupat, nregistrarea de inserat este n coliziune i
inserm la sfritul listei simplu nlnuite noul element.

Specificarea problemei de inserare, avnd ca date de intrare tabela hash numit tab,
dimensiunea maxim a tabelei m, cheia de inserare cheia, este urmtoarea:

DATE tab, m, cheia;


REZULTATE tab;

Descrierea algoritmului de inserare n Pseudocod este:

ALGORITMUL INSERARE _adresare_nlnuit ESTE:


CITETE cheia;
a := H (cheia);
DAC (tab [i] = Empty) ATUNCI
@inserm noua nregistrare la adresa a din tabel;
@inserare la sfrit lista simplu nlnuit;
ALTFEL
@inserare la sfrit lista simplu nlnuit;
SFDAC
SFALGORITM

Specificarea problemei de cutare, avnd ca date de intrare tabela hash numit tab, cheia de
cutare cheia_caut, este urmtoarea:

DATE tab, cheia_caut;


REZULTATE adresa;

ALGORITMUL CUTARE _adresare_nlnuit ESTE:


CITETE cheia_caut;
a := H (cheia_caut);
DAC (tab [i] = Empty) ATUNCI
TIPRETE (EROARE CUTARE inf. nu exist);

________________________________________________________________________________

258
Structuri de date i algoritmi
_______________________________________________________________________________

@returneaz NIL;
ALTFEL
adr := caut_list (LIST, cheia_caut); {se caut n lista simplu nlnuit }
DAC adr = NIL ATUNCI
TIPRETE (EROARE CUTARE inf. nu exist);
@returneaz NIL;
ALTFEL
@returneaz adr;
SFDAC
SFDAC
SFALGORITM

Performana algoritmului de cutare bazat pe adresare nlnuit este, conform [Tre, 1984]:


1 , pentru cutar cu succes
ALOS 2 (5.x)
e , pentru cutar cu insucces

V.3.5. Probleme propuse pentru funcii hash i tehnici de rezoluiune


a coliziunilor
1. Descriei modul de implementare a unei funcii hash folosind un generator de numere aleatoare.
Are sens implementarea unui generator de numere aleatoare folosind o funcie hash ?

2. Ilustrai coninutul tabelei hash care rezult cnd inserm cheile: U N E X E M P L U D E N T


R E B A R E sunt inserate n aceast ordine ntr-o tabel iniial goal, de dimensiune 13, folosind
tehnica probrii liniar. ( Folosii ca funcie hash H(k) = k mod 13 pentru litera a-k a alfabetului).

3. Ilustrai coninutul tabelei hash care rezult cnd inserm cheile: U N E X E M P L U D E N T


R E B A R E sunt nserate n aceast ordine ntr-o tabela iniial goal, de dimensiune 13, folosind
probarea aleatoare i hash dublu ( Folosii ca funcie hash primar funcia H din exemplul 2, iar ca
funcie hash secundar funcia H2(k) = 1+ ( k mod 11) ) .

4. Cte probri sunt necesare, cnd este folosit tehnica probrii aleatoare pentru a insera n chei de

________________________________________________________________________________

259
Structuri de date i algoritmi
_______________________________________________________________________________

cutare egale?

5. Care metoda de probare este mai eficient n situaia n care se insereaz mai multe chei de
cutare egale ?

6. S presupunem c numrul de nregistrri care trebuie inserate ntr-o tabel hash este cunoscut n
prealabil. n ce condiii metoda adresrii nlnuite este preferabil fat de metoda adresrii
deschise?

7. Folosind metoda divizrii, calculai adresa generat de funcia hash pentru urmtoarele seturi de
chei de cutare: PAX, ARC, RATE i NUMR. Se va folosi reprezentarea ASCII a cheilor de
cutare i m = 111.

8. Rezolvai problema 8 folosind o reprezentare EBCDIC a cheilor de cutare.

9. Avem urmtoarele chei de cutare numerice: 66, 47, 87, 90, 126, 140, 145, 153, 177, 285, 393,
395, 476, 566, 620, 735. Stocai nregistrrile ntr-o tabel hash cu 20 de poziii, folosind metoda
divizrii pentru funcia hash i metoda probrii liniare pentru rezolvarea coliziunilor.

10. Folosind aceleai chei de cutare ca la exerciiul 9, stocai nregistrrile ntr-o tabel hash cu 20
de poziii folosind metoda mpririi pentru funcia hash i metoda probrii aleatoare pentru
rezolvarea coliziunilor.

VI.TEHNICI DE SORTARE

VI.1. ISTORIC

Cutarea originii metodelor actuale de sortare ne conduce n secolul al XIX-lea, cnd au fost
inventate primele maini de sortat. n Statele Unite, cu ocazia recensmntului din 1880, Herman
Hollerith, angajat al Biroului de Recensmnt, a inventat o main electric de tabelat pentru a
rspunde necesitilor de prelucrare statistic. Un om putea prelucra 49 de cartele pe minut. n 1901
a inventat o main mai modern care lucra automat. Maina de sortat al lui Hollerith este baza
metodelor de sortare dup ranguri, folosite n prezent pe calculatoare.
Ideea interclasrii provine de la o alt main cu cartele, numit "collator" din 1938, care
putea interclasa dou pachete de cartele ntr-unul singur, ntr-o singur trecere.
Primul program scris pentru un calculator cu program memorat a fost o rutin de sortare. John von
Neumann a pregtit programe de sortare intern n 1945, pentru a testa valabilitatea unor coduri de
instruciuni propuse de el pentru calculatorul ENIAC. Jonh Mauchly a confereniat despre "Sortare

________________________________________________________________________________

260
Structuri de date i algoritmi
_______________________________________________________________________________

si Fuziune" la sesiunea special asupra calculatoarelor inut la Moore School n 1946, iar notele
acestei conferine constituie prima discuie public a sortrii pe calculator. Prima metod de sortare
folosea numrarea comparaiilor; apoi urmau o serie de treceri de interclasare echilibrat cu dou
ci.
n 1952 Daniel Goldenberg, a codificat 5 metode diferite: interclasarea direct cu dou ci,
sortarea cu baz 2, selecia direct, metoda bulelor. Seward a introdus idea de numrare a
distribuiilor si de selecie cu nlocuire.
Astfel istoria sortrii este strns legat de multe premiere din domeniul calculatoarelor:
primele maini de prelucrare a datelor primele programe memorate, primul software, primele
metode de utilizare a zonelor tampon de intrare-ieire, primele lucrri asupra analizei algoritmilor si
asupra complexitii calculelor.
n 1959 Donald L. Shell a propus sortarea prin micorarea incrementului; sortarea cu
interclasare si interschimb a fost descoperit de K. E. Batcher n 1964; C. A. R. Hoare a descoperit
metoda sortrii rapide; n 1964 a fost descoperit sortarea de ansambluri de ctre J. W. J. Williams.
Pe parcursul anilor s-au mbuntit aceste metode de sortare si s-au descoperit si metode noi,
metode hibride.

VI.2. Algoritmi de sortare

n acest capitol vom prezinta pe scurt cele mai importante informaii despre caracteristicile
principalelor metode de sortare i a algoritmilor corespunztori, ncepnd de la cele mai simple
metode de sortaare pn la cele complexe metode de sortare, folosind diferite structuri de date:
matrice, liste nlnuite, stive, arbori, ., etc.
Exist urmtoarea clasificare a metodelor de sortare [Lew, 1991]:
Metode de sortare simple : selecie, inserare, bule, Shell;
Metode de sortare complexe : rapid, interclasare, ansambluri, Radix.

Metodele simple de sortare au de obicei complexitatea O(N2) adic pot sorta N elemente
ntr-un timp proporional cu N2 si sunt eficiente pentru tabele mici n care numrul de elemente este
mai mic dect 500. Totui, pentru multe aplicaii de sortare este mai bine s folosim metode simple
dect complexe. De exemplu, dac tabela este deja sortat, n cazul metodei de sortare rapid
pivotul ales (elementul n jurul creia se face sortarea) este primul element, metoda de sortare prin
selecie este mai rapid. Metodele simple sunt ntotdeauna mai potrivite pentru un numr de
elemente mai mic dect 50. Tabelele parial sau total sortate, sau cele care conin un numr mare de
chei identice, sunt relativ uor de sortat cu ajutorul algoritmilor simplii. Necesit relativ puin timp
de programare si ntreinere.
Metodele complexe pot sorta N elemente ntr-un timp proporional cu NlogN. Nici un
algoritm nu poate folosi mai puin de NlogN comparaii ntre chei. Aceste metode complexe sunt
eficiente mai ales pentru sortarea unui numr mare de elemente. Necesit mai mult timp pentru
programare dar sunt mai eficiente. Unul dintre cei mai populari algoritmi de sortare cu scop general

________________________________________________________________________________

261
Structuri de date i algoritmi
_______________________________________________________________________________

este sortare rapid (Quicksort), care are o complexitate de O(NlogN), exprimat pentru mediu
necesar operaiei de sortare. Acest algoritm de sortare are performane bune n general, chiar dac n
caz nefavorabil complexitatea devine O(N2).
Ideea "divide et impera" a fost aplicat problemelor de sortare n mai multe feluri rezultnd
urmtorii algoritmii de sortare: rapid, interclasare, ansambluri, Radix care sunt mult mai eficiente
dect cele simple. Sortarea prin ansambluri si sortarea prin interclasare au complexitatea egal cu
O(NlogN), dei n cazul general comportarea lor nu este chiar aa de bun ca la algoritmul de
sortare rapid. Exist metode care folosesc proprietile digitale ale cheilor ca s obin o
complexitate proporional cu N, ca de exemplu sortarea Radix.
La baza studiului complexitii unui algoritm st detectarea, n descrierea algoritmului, a
operaiei sau a operaiilor de baz, adic acea operaie aflate n cel mai interior corp de ciclu
repetitiv si a crei analiz permite estimarea n avans, nainte de lansarea n execuie, a algoritmului
ce descrie metoda de sortare respectiv.
n majoritatea cazurilor exist o legtur foarte strns ntre operaia de baz (cea mai repetat
operaie) si operaia care este dedus n etapa de analiz a problemei ca fiind operaia inevitabil
pentru rezolvarea problemei.
De exemplu, n cazul problemei sortrii unui sir de N chei prin comparaii este limpede c
operaia de comparare a mrimii cheilor este operaia inevitabil si de asemenea ea va fi i
operaia de baz a crei contorizare va permite estimarea, nainte de execuia programului ce
implementeaz algoritmul, a duratei de execuie a programului ce implementeaz algoritmul de
sortare respectiv.
n aceast situaie, toi algoritmii diferii care soluioneaz aceeasi problem si care se
bazeaz pe aceeai operaie de baz (inevitabil) formeaz clasa algoritmilor de soluionare a
problemei. De obicei numele clasei va fi dat chiar de numele acelei operaii de baz ce este
coninut de fiecare algoritm al clasei n mod inevitabil.
De exemplu, n cazul problemei sortrii unui sir de N chei prin comparaii, algoritmii diferii
ce soluioneaz aceast problema sunt grupai n clasa algoritmilor de sortare prin comparaii, spre
deosebire de clasa algoritmilor de sortare prin distribuire ce soluioneaz aceeai problem
bazndu-se ns pe alt operaie de baz: distribuirea cheilor de sortat.
Astfel, algoritmi de sortare prin comparare descrii in aceasta lucrare sunt: algoritmul de
sortare prin inserare, algoritmul de sortare prin selecie, algoritmul de sortare Shell, algoritmul de
sortare combinat, algoritmul de sortare simplu, algoritmul de sortare rapid, algoritmul de sortare
prin ansambluri, algoritmul de sortare prin interclasare, iar algoritm de sortare prin distribuire este
algoritmul de sortare Radix.
Compararea eficienei a doi algoritmi diferii ce soluioneaz aceeai problem se face prin
determinarea teoretic a numrului de repetiii a operaiei de baz n fiecare algoritm si compararea
celor dou valori. n final rezultatul comparrii va permite estimarea comparativ a timpului de
sortare a programelor ce implementeaz acei algoritmi i alegerea celui mai bun.
Compararea eficientei a doi algoritmi din punct de vedere practic se face prin compararea
timpilor medii de execuie a celor dou programe ce i implementeaz. Aceast metod pragmatic
are dezavantajul c necesit rularea programelor care, n anumite situaii, poate dura un timp
surprinztor de mare.

________________________________________________________________________________

262
Structuri de date i algoritmi
_______________________________________________________________________________

Analiznd complexitatea algoritmilor factorul cel mai important este timpul de execuie
exprimat prin "O-mare". Trebuie s folosim mai multe criterii pentru evaluarea timpului de execuie
al algoritmului de sortare cum ar fi, numrul de pai ai algoritmului si numrul de comparaii dintre
chei necesare pentru a sorta N elemente. Aceast msur este de folos cnd compararea dintre
perechile de chei este costisitoare, cnd cheile sunt iruri lungi de caractere, sau cnd mrimea
nregistrrii este mare.
Al doilea factor important este cantitatea (volumul) de memorie suplimentar folosit de un
algoritm de sortare. Metodele se mpart n trei tipuri: cei care sorteaz pe loc, nu folosesc memorie
suplimentar, cu excepia poate unei tabele sau stive mici; cei care au o reprezentare de list
nlnuit deci folosesc N cuvinte de memorie n plus pentru pointerii listei; cei care au nevoie de
memorie suplimentar pentru o copie a tabelei iniiale.
Caracteristica care este uneori important n practic este stabilitatea. O metod de sortare
este stabil dac pstreaz ordinea relativ a cheilor egale n tabel. (Dac sortm un sir de nume,
numele cu aceeai liter de nceput sunt sortate n ordine alfabetic). Majoritatea metodelor simple
sunt stabile dar muli dintre algoritmii de sortare compleci nu au aceast proprietate.

ALGORITMUL ORDINEA DE MAGNITUDINE SPATIU


DE SORTARE FOLOSIT
Caz Caz Caz
Favorabil General Nefavorabil

Sortare prin O(N2) O(N2) O(N2) Sorteaz pe loc


selecie

Sortare cu bule O(N2) O(N2) O(N2) Sorteaz pe loc

Sortare cu bule, O(N) O(N2) O(N2) Sorteaz pe loc


"flag"
mbuntit

Sortare prin O(N) O(N2) O(N2) Sorteaz pe loc


inserare ir sortat

Sortare Shell O(N2) O(N2) O(N2) Sorteaz pe loc

________________________________________________________________________________

263
Structuri de date i algoritmi
_______________________________________________________________________________

Sortare O(Nlog N) O(N2) O(N2) Sorteaz pe loc


combinat

Sortare simpl O(N2) O(N2) O(N2) Sorteaz pe loc

Sortare rapid O(Nlog N) O(Nlog N) O(N2) LogN nregistrri


depinde de ir suplimentare
i de pivot

Sortare prin O(Nlog N) O(Nlog N) O(Nlog N) N nregistrri


interclasare suplimentare

Sortare prin O(Nlog N) O(Nlog N) O(Nlog N) Sorteaz n loc


ansambluri

Sortare Radix O(M+N) O(M+N) Spaiu suplimentar


pentru legturi

Tabela 6.1. Compararea algoritmilor de sortare.

Metodele de sortare particulare nu sunt n totdeauna superioare celorlalte metode pentru


orice set de chei. Proprietile unui set de chei joac un rol important n alegerea algoritmului de
sortare potrivit. Proprieti ca numrul de nregistrri, mrimea nregistrrii, distribuia si ordinea
cheilor dicteaz des care metoda de folosit. De exemplu, sortarea cu bule poate fi folosit dac
numrul elementelor din tabel este mic. Dac N este mare si cheile de comparat sunt mici este mai
performant algoritmul de sortare Radix. Dac N este mare si cheile de comparat sunt lungi se poate
folosi algoritmul de sortare rapid, algoritmul de sortare prin interclasare, sau algoritmul de sortare
prin ansambluri. Dac tabela iniial este aproape sortat, algoritmul de sortare rapid nu are
performane bune, algoritmul de sortare prin inserare fiind alegerea cea mai bun.

VI.2.1. Algoritmul de sortare prin metoda bulelor (bubble sort)

VI..2.1.1. Descrierea general a metodei

S ne imaginm o tabel n poziie vertical care conine elemente (nregistrri) nesortate.


nregistrrile cu chei mici, fiind mai uoare, asemenea bulelor de aer urc spre vrful tabelei.
Sortarea bulelor se bazeaz pe cutarea celui mai mare (mic) element. Comparm elementele
tabelei, dac dou elemente adiacente nu sunt n ordine cresctoare, le interschimbm. Astfel
elementul cu cheia cea mai mare va ajunge primul la locul potrivit, iar elementul cu cheia cea mai
mic, urc tot timpul spre vrf tabelei.
________________________________________________________________________________

264
Structuri de date i algoritmi
_______________________________________________________________________________

VI.2.1.2. Descrierea algoritmului

Fie dat o tabel A cu N nregistrri Ri, fiecare nregistrare avnd cheia de cutare Ki. Pentru
sortarea tabelei este nevoie de N-1 pai.
Parcurgem tabela n felul urmtor: comparm cheia primului element K1, cu cheia celui de al
doilea element K2 i dac nu sunt n ordine cresctoare, interschimbm primul element R1 cu cel de-
al doilea element R2.
Procesul se repet pentru nregistrrile R2, R3,, RN.. Dup prima parcurgere a tabelei,
nregistrarea cu cea mai mare cheie va ajunge pe ultima poziie N a tabelei.
n continuare vom lua n considerare primele N 1 nregistrri. Dup aceea vom lua n
considerare primele N -2 nregistrri, , etc. Dup fiecare pas, elementele cu chei mari vor ajunge
pe poziiile N - 1, N - 2, , 2, n final rezultnd o tabel sortat n ordine cresctoare.

Exemplul VI.1: Sortarea tabelei A din Figura VI.1, n ordine cresctoare, folosind algoritmul de
sortare prin metoda bulelor:
Pasul 1: Prelucrm primele 10 nregistrri ale tabelei.
- comparm 6 cu 4, interschimbm;
- comparm 6 cu 5 si interschimbm:
- comparm 6 cu 10, nu interschimbm;
- comparm 10 cu 3, interschimbm;
- comparm 10 cu 1, interschimbm;
- comparm 10 cu 8, interschimbm;
- comparm 10 cu 9, interschimbm;
- comparm 10 cu 7, interschimbm;
- comparm 10 cu 2, interschimbm;
nregistrarea cu cheia cea mai grea, 10, a ajuns la partea inferioar a tabelei.
Pasul 2: Prelucrm primele 9 nregistrri ale tabelei.
- comparm 6 cu 4, interschimbm;
- comparm 4 cu 5 si nu interschimbm:
- comparm 5 cu 6, nu interschimbm;
- comparm 6 cu 3, interschimbm;
- comparm 6 cu 1, interschimbm;
- comparm 6 cu 8, nu interschimbm;
- comparm 8 cu 9, nu interschimbm;
- comparm 9 cu 7, interschimbm;
________________________________________________________________________________

265
Structuri de date i algoritmi
_______________________________________________________________________________

- comparm 9 cu 2, interschimbm;
nregistrarea cu cheia cea mai grea, 9, a ajuns la partea inferioar a tabelei.
..
Algoritmul de sortare prin metoda bulelor ordoneaz cele 10 nregistrri ale tabelei A n 8
pai.

Figura VI.1. Sortarea unei tabele A cu 10 elemente prin algoritmul de sortare bazat pe metoda
bulelor.

VI.2.1.3. Implementarea algoritmului

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Bubble_sort ESTE:


CITETE A, N;
k := N;
REPET

________________________________________________________________________________

266
Structuri de date i algoritmi
_______________________________________________________________________________

Ok := TRUE;
PENTRU i := 1;k EXECUT
DAC A[i] > A[i+1] ATUNCI
temp := A[i];
A[i] := A[i+1];
A[i+1] := temp;
Ok := FALSE;
SFDAC
SFPENTRU
k := k -1;
PNCND Ok SFREP
SFALGORITM

Implementarea algoritmului de sortare prin metoda bulelor n limbajul Pascal este:

Procedure bubble;
Begin
K := n;
Repeat
Ok := true;
For i := 1 to k do
If A[i] >A[i+1] then
Begin
temp := A[i];
A[i] := A[i+1];
A[i+1] := temp;
Ok := false;
End;
k :=k-1;
Until Ok;
End;

VI.2.1.4. Complexitatea algoritmului

Algoritmul de sortare prin metoda bulelor este o metod de sortare simpl, eficient pentru
un numr mic de elemente (mai puin de 15), dar nu pentru tabele mari.
Nu necesit mult memorie, dar este de dou ori mai lent dect algoritmul de sortare prin
inserare n aproape orice situaie. Timpul de execuie depinde de structura iniial a datelor de
intrare, adic de ordinea iniial al elementelor [Ski, 1997]. Dac tabela de dimensiune N este deja
sortat e nevoie de un singur pas, adic de N-1 operaii de comparaie, n aceast situaie algoritmul

________________________________________________________________________________

267
Structuri de date i algoritmi
_______________________________________________________________________________

fiind de ordinul O(N).


n cazul cel mai nefavorabil sunt necesare N (N - 1) / 2 operaii de comparaie i de N (N
1) / 2 operaii de interschimbare. Complexitatea algoritmului de sortare prin metoda bulelor este
O n 2 n aceast situaie. Este o metod stabil.
Performana algoritmul de sortare se poate mbunti prin introducerea unei variabile de tip
boolean care ne arat cnd tabela este sortat, nainte de terminarea numrului maxim de iteraii
[Tom, 1997].

VI.2.2. Algoritmul de sortare prin selecie

VI.2.2.1. Descrierea general a metodei

Selecia direct este una dintre cele mai simple metode de sortare ce are performane foarte
bune pentru tabele mici, fiecare element (nregistrare) al tabelei, fiind mutat n procesul de sortare
cel mult o dat. Este o metod de sortare liniar pentru nregistrri lungi si chei de cutare mici.
Implementarea algoritmului este simpl, dar necesit spaiu de memorie destul de mare pentru a
stoca dou tabele, acest lucru fiind un neajuns al algoritmului de sortare.

VI.2.2.2. Descrierea algoritmului

Se caut cel mai mic element din tabela de sortat A si se schimb cu elementul de pe
prima poziie. Dup aceea se caut al doilea element minim si se schimb cu elementul de
pe poziia a doua, .a.m.d. n general, n pasul i se selecteaz elementul cu cea mai mic
cheie dintre nregistrrile A[i], A[i+1],, A[N] si se schimb cu A[i]. Ca rezultat, dup i
pai, al i-lea element minim va ocupa poziiile A[i], A[i+1],, A[N] n ordine sortat. Se
continu pn cnd toate elementele vor fi sortate n ordine cresctoare.

Exemplul VI.2: Sortarea tabelei A din Figura VI.2 folosind algoritmul de sortare prin selecie, n
ordine cresctoare:

________________________________________________________________________________

268
Structuri de date i algoritmi
_______________________________________________________________________________

Figura VI.2. Sortarea unei tabele A cu 10 elemente prin algoritmul de sortare prin selecie.

Pasul 1: Prelucrm nregistrrile 1-10 ale tabelei.


- cutm nregistrarea cu cheia de cutare minim. Acesta este nregistrarea cu cheia 1 de pe poziia
6 a tabelei;
- interschimbm nregistrarea de pe poziia 1 cu nregistrarea minim de pe poziia 6;
nregistrarea cu cheia cea mai uoar, 1, a ajuns n poziia 1 a tabelei.

Pasul 2: Prelucrm nregistrrile 2-10 ale tabelei.


- cutm nregistrarea cu cheia de cutare minim. Acesta este nregistrarea cu cheia 2 de pe poziia
10 a tabelei;
- interschimbm nregistrarea de pe poziia 2 cu nregistrarea minim de pe poziia 10;
nregistrarea cu cheia cea mai uoar, 2, a ajuns n poziia 2 a tabelei.

Pasul 3: Prelucrm nregistrrile 3-10 ale tabelei.


- cutm nregistrarea cu cheia de cutare minim. Acesta este nregistrarea cu cheia 3 de pe poziia
5 a tabelei;
- interschimbm nregistrarea de pe poziia 3 cu nregistrarea minim de pe poziia 5;
nregistrarea cu cheia cea mai uoar, 3, a ajuns n poziia 3 a tabelei.

..

Algoritmul de sortare prin metoda seleciei ordoneaz cele 10 nregistrri ale tabelei A n 8
pai.

VI.2.2.3. Implementarea algoritmului


________________________________________________________________________________

269
Structuri de date i algoritmi
_______________________________________________________________________________

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Inserie ESTE:


CITETE A, N;
PENTRU i := 1;N-1 EXECUT
min := i;
PENTRU j := i +1;N EXECUT
DAC A[j] < A[min] ATUNCI
Min := j;
SFDAC
SFPENTRU
temp := A[i];
A[i] := A[min];
A[min] := temp;
SFPENTRU
SFALGORITM

Implementarea algoritmului de sortare prin metoda seleciei n limbajul Pascal este:

Procedure selection (var A:arraytype; n:integer);


Var i, min:integer; {index }
Begin
For i := 1 to n-1 do
Begin
min := i;
For j := i+1 to n do
If A[j]<A[min] then min := j;
temp := A[i];
A[i] := A[min];
A[min] := temp;

________________________________________________________________________________

270
Structuri de date i algoritmi
_______________________________________________________________________________

End;
End;

VI.2.2.4. Complexitatea algoritmului

Algoritmul de sortare prin metoda seleciei este o metod de sortare eficient pentru un
numr mic de elemente de sortat, dar nu pentru tabele mari.
Operaiile cele mai costisitoare sunt cele de cutare a nregistrrii cu cheia minim din
partea rmas nesortat n tabel. Dup fiecare pas de cutare este necesar o intershimbare, deci
numrul interschimbrilor pentru N elemente este N - 1. Numrul total de operaii de comparaie
pentru a gsi cheia minim este [Knu, 1976]:
n 1
n n 1 n n 1
n i n n 1
i 1 2

2

Atunci performana algoritmului de sortare prin metoda seleciei este O n . Aceleai


2

performane se obin i n medie i n cazul cel mai nefavorabil, chiar i atunci cnd tabela este deja
sortat. Dac avem nregistrri mari si chei mici, algoritmul de sortare prin metoda seleciei va fi
alegerea cea mai bun.

VI.2.3. Algoritmul de sortare prin inserare

VI.2.3.1. Descrierea general a metodei

Este un algoritm aproape la fel de simplu ca algoritmul de sortare prin selecie, dar poate
mai flexibil.
Dac considerm c elementele A[1]...A[i-1] sunt deja sortate, atunci va trebui s inserm
elementul A[i] n locul potrivit pentru a menine ordinea de sortare aleas.

VI.2.3.2. Descrierea algoritmului

Fiind dat o tabel A cu N elemente nesortate, parcurgem tabela si inserm fiecare element
n locul potrivit pentru a menine ordinea de sortare aleas ntre celelalte elemente considerate deja
sortate.
Pentru fiecare i = 2,.., N , dac elementele A[1], A[2],, A[i] sunt sortate, vom insera
elementul A[i] ntre lista elementelor sortate: A[1], A[2],, A[i].
Elementele aflate n stnga indexului i sunt sortate dar nu sunt nc n poziia lor final.
Tabela este complet sortat cnd indexul ajunge la captul drept al tabelei.

________________________________________________________________________________

271
Structuri de date i algoritmi
_______________________________________________________________________________

Putem uura procesul inserrii (ex: cnd cel mai mic element e greu de definit), prin introducerea
unul element de "limit" A[0], cheia care va avea o valoare mai mic dect orice valoare posibil a
unei chei din tabel. Vom considera c aceast cheie are valoarea .
Exemplul VI.3: Sortarea tabelei A din Figura VI.3 folosind algoritmul de sortare prin inserare,
n ordine cresctoare:

A[j] 6 4 5 10 3 1 8 9 7 2

pas 1 4 6 5 10 3 1 8 9 7 2

pas 2 4 5 6 10 3 1 8 9 7 2

pas 3 4 5 6 10 3 1 8 9 7 2

pas 4 3 4 5 6 10 1 8 9 7 2

pas 5 1 3 4 5 610 8 9 7 2

pas 6 1 3 4 5 6 8 10 9 7 2

pas 7 1 3 4 5 6 8 910 7 2

pas 8 1 3 4 5 6 7 8 910 2

pas 9 1 2 3 4 5 6 7 8 9 10

Figura VI.3. Sortarea unei tabele A cu 10 elemente prin algoritmul de sortare prin inserare.

Pasul 1: Avem sortate nregistrrile dintre poziiile 1-1 ale tabelei.


- avem nregistrarea de pe poziia 2 cu cheia 4. Se caut poziia de inserare, care este poziia 1;
- se insereaz cheia 4, naintea poziiei de inserare;
Secvena de chei din poziiile 1-2 ale tabelei sunt sortate.

Pasul 2 Avem sortate nregistrrile dintre poziiile 1-2 ale tabelei.


- avem nregistrarea de pe poziia 3 cu cheia 5. Se caut poziia de inserare, care este poziia 2;
- se insereaz cheia 5, naintea poziiei de inserare;
Secvena de chei din poziiile 1-3 ale tabelei sunt sortate.

Pasul 3: Avem sortate nregistrrile dintre poziiile 1-3 ale tabelei.


- avem nregistrarea de pe poziia 4 cu cheia 10. Se caut poziia de inserare, care este poziia 4;

________________________________________________________________________________

272
Structuri de date i algoritmi
_______________________________________________________________________________

- se insereaz cheia 10, naintea poziiei de inserare;


Secvena de chei din poziiile 1-4 ale tabelei sunt sortate.

Pasul 4: Avem sortate nregistrrile dintre poziiile 1-4 ale tabelei.


- avem nregistrarea de pe poziia 5 cu cheia 3. Se caut poziia de inserare, care este poziia 1;
- se insereaz cheia 3, naintea poziiei de inserare;
Secvena de chei din poziiile 1-5 ale tabelei sunt sortate.

..

Algoritmul de sortare prin metoda inserrii ordoneaz cele 10 nregistrri ale tabelei A n 9
pai.

VI.2.3.3. Implementarea algoritmului

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Inserare ESTE:


CITETE A, N;
A[0] := ;
PENTRU i := 2;N EXECUT
j := i;
CTTIMP A[j] < A[j -1]
temp := A[j];
A[j] := A[j -1];
A[j -1] := temp;
j := j -1;
SFCT
SFPENTRU
SFALGORITM

________________________________________________________________________________

273
Structuri de date i algoritmi
_______________________________________________________________________________

Implementarea algoritmului de sortare prin metoda inserrii n limbajul Pascal este:

Procedure insertion ( var A: arraytype; n:integer );


Var i, j: integer;
Begin
A[0] := minus_infinit; {minus_infinit este o constant de valoare foarte mic}

For i:=2 to n do {i,j - variabila de tip index}


Begin
j := i;
While A[j]<A[j-1] do
Begin
temp := A[j];
A[j] := A[j -1];
A[j -1] := temp;
j := j-1;
End;
End;
End;

VI.2.3.4. Complexitatea algoritmului

Algoritmul de sortare prin inserare sort este un algoritm de sortare liniar: Complexitatea
algoritmului este O(N) pentru tabele care conin N elemente sortate sau aproape sortate.
Complexitatea algoritmului de sortare prin inserare depinde de numrul de inserri i
N2
translatri, care este influenat de ordinea iniial al elementelor. n caz general sunt necesare 4
N2
operaii de comparaie i 8 operaii de interschimbare, deci ordinea complexitii este O(N2).
[Tre, 1984]

VI.2.4. Algoritmul de sortare Shell

VI.2.4.1. Descrierea general a metodei

Sortarea prin micorarea incrementului, numit i sortare Shell este o extensie simpl al
________________________________________________________________________________

274
Structuri de date i algoritmi
_______________________________________________________________________________

metodei de sortare prin inserare, mbuntind performanele algoritmului prin interschimbarea


elementelor cele mai ndeprtate. Ideea de baz o constituie rearanjarea elementelor din tabela A n
aa fel nct, lund fiecare al h-lea element (ncepnd de oriunde), s obinem o tabel sortat.
Astfel, spunem c tabela este h-sortat. O tabel h-sortat este format din h subtabele sortate
independent. Folosind astfel o procedur pentru fiecare secven de valori ale lui h, care se termin
pentru valoarea 1, va rezulta o tabel sortat.
S considerm tabela A i un increment mai mare dect 1, fie acesta h. Vom avea atunci
urmtoarele subtabele:

Subtabelul1: A[1], A[h +1], A[2h +1], .


Subtabelul2: A[2], A[h +2], A[2h +2], .
Subtabelul3: A[3], A[h +3], A[2h +3], .
...
Subtabelul h: A[h], A[2h], A[3h], .

Dac sortm fiecare din cele h subtabele, folosind de exemplu algoritmul de sortare prin
inserare, atunci elementele ndeprtate se vor apropia, srind cu pasul h ctre stnga. n final, vom
proceda la o sortare prin inserare cu incrementul 1, ceea ce va necesita un timp foarte scurt cci
tabela nu mai necesit corecii importante, majoritatea nregistrrilor fiind n poziia cresctoare
dorit.
Algoritmul de sortare Shell, necesit o mulime de incremeni ht , ht 1 , , h1 , ultimul
increment h1 fiind egal cu 1.
O formula des utilizat n practic propune urmtoarele formule pentru secvena de
incremeni:
h1 1; hi 1 3hi 1 (6.1)
Secvena este 1,4,13, 40, 121, ., cu formula general:
3i 1
hi (6.2)
2
Deci numrul total de incremeni va fi:
t log 3 2n 1 (6.3)

VI.2.4.2. Descrierea algoritmului

Algoritmul de sortare Shell necesit mai multe operaii dect algoritmul de sortare prin
inserare, dar la fiecare pas elementele ce urmeaz a fi interschimbate efectueaz salturi lungi spre
poziia corect, ceea ce ar trebui s duc la mbuntirea performanelor algoritmului de sortare.
n general, algoritmul de sortare Shell poate fi descris astfel [Aho, 1997]:

PENTRU k := t;1 EXECUT


PENTRU d := 0; hk 1 EXECUT
CHEAM SORTARE_Inserare(@Subtabela d);

________________________________________________________________________________

275
Structuri de date i algoritmi
_______________________________________________________________________________

Exemplul VI.4: Sortarea tabelei A din Figura VI.4 (a) folosind algoritmul de sortare Shell, n ordine
cresctoare:

Pasul 1: Crearea celor h subtabele (Fig. VI.4. (b))


- S presupunem c am ales incrementul h = 5. Se creeaz cele 5 subtabele:
Subtabela 1: 11, 6, 1
Subtabela 2: 10, 5, 0
Subtabela 3: 9, 4
Subtabela 4: 8, 3
Subtabela 5: 7, 2

A[ ] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12]

(a) 11 10 9 8 7 6 5 4 3 2 1 0

(b) 11 6 1

10 5 0

9 4

8 3

7 2

(c) 1 6 11

0 5 10

4 9

3 8

2 7

(d) 1 0 4 3 2 6 5 9 8 7 11 10

(e) 0 1 2 3 4 5 6 7 8 9 10 11

Figura VI.4. Sortarea unei tabele A cu 12 elemente prin algoritmul de sortare Shell.

________________________________________________________________________________

276
Structuri de date i algoritmi
_______________________________________________________________________________

Pasul 2 Sortarea celor 5 subtabele (Fig. VI.4. (c))

Pasul 3: Tabela iniial dup pasul de sortare cu incrementul 5 (Fig. VI.4. (d))

Pasul 3: Tabela iniial dup pasul de sortare cu incrementul 1 (Fig. VI.4. (d))

..

VI.2.4.3. Implementarea algoritmului

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Shell ESTE:


CITETE A, N;
inc := Increment_intial(n);
CTTIMP inc >= 1 EXECUT
PENTRU i := inc; n-1 EXECUT
j := i;
x := A[i];
CTTIMP j >= inc i A[j - inc] > x EXECUT
A[j] := A[j - inc];
j := j - inc;
SFCT
A[j] := x;
SFPENTRU
inc := Increment_urmtor(inc, n);
SFALGORITM

________________________________________________________________________________

277
Structuri de date i algoritmi
_______________________________________________________________________________

Observaie:
Secvena de incrementare este determinat iterativ, folosind funciile Increment_intial(n) i
Increment_urmtor(inc, n). Funcia Increment_intial(n) va returna cel mai mare increment
utilizabil pentru sortarea unei tabele de dimensiune n.
Funcia Increment_urmtor(inc, n) va returna cel mai mare increment dar mai mic dect inc,
utilizabil pentru sortarea unei tabele de dimensiune n.
Funciile Increment_intial(n) i Increment_urmtor(inc, n) vor genera irul descresctor de
incremeni ht , ht 1 , , h1 =1.
Se presupune c Increment_urmtor(1, n) = 0. Ciclul exterior se va termina cnd inc = 1.

Implementarea algoritmului de sortare prin metoda inserrii n limbajul Pascal este:

Procedure Shellsort ( var A: array[1.. N] of integer);


Var i, j, incr:integer;
Begin
incr := N div 2; { Funcia Increment_intial(n)}
While incr > 0 do
Begin
For i := 1 to incr do
Begin
k := i+incr;
While k<= N do
Begin
x :=A[k]; {x = elementul de comparat}
j := k-incr;
While j>0 do
Begin
If x.key < A[j].key then
Begin
Schimba (A[j+incr], A[j]);
j := j - incr;
End;
k := k+incr
End
End;
incr := incr div 2; {Funcia Increment_urmator(inc,n)}
End;
End;
End;

VI.2.4.4. Complexitatea algoritmului

________________________________________________________________________________

278
Structuri de date i algoritmi
_______________________________________________________________________________

Complexitatea algoritmului de sortare Shell sort este greu de analizat, greu de comparat cu
alte metode, fiind dependent i de mulimea de incremeni. Pentru acest algoritm de sortare,
cercetri empirice au artat c complexitatea este, n general O N log N [Aho, 1997]. Exist

mulimi de incremeni pentru care s-a dovedit c complexitatea este O N log N 2 . Nu se cunoate
pn n prezent o mulime optimal de incremeni pentru algoritmul de sortare Shell.

VI.2.5. Algoritmul de sortare rapid (quicksort)

VI.2.5.1. Descrierea general a metodei

Algoritmul de sortare, considerat a fi cel mai rapid, de complexitate O N log N este numit
algoritm de sortare rapid (quicksort), folosind partiionarea ca idee de baz. Este mai rapid dect
orice metod de sortare simpl, se comport eficient pentru fiiere sau tabele mari, dar ineficient
pentru cele de mici dimensiuni.
Strategia de baz are la baz o tehnic de tip "divide et impera" [Liv, 1986], pentru c este
mai uor de sortat dou tabele mici, dect o tabbel mare. Algoritmul este uor de implementat,
consum mai puine resurse dect orice alt metod de sortare.

VI.2.5.2. Descrierea algoritmului

Avnd o tabel A cu N elemente, alegem o cheie pivot v n jurul creia rearanjm


elementele. Pivotul poate fi ales n mai multe moduri. O modalitate simpl ar fi s alegem ca pivot
primul element.
Dup ce avem pivotul, partiionm tabela. Prin partitionare toate elementele cu chei mai
mici dect pivotul le vom plasa n partiia stng a tabelei, iar elementele cu chei mai mari dect
pivotul n partiia dreapt.
Dup aceea apelm recursiv algoritmul de sortare rapid relativ la cele dou subtabele
formate prin partiionare.
Se consider urmtoarea schem de comparaie-interschimb:
- folosindu-se 2 indicatori i, j, cu valorile iniiale i = 1 i j = N, se compar nregistrarea cu
numrul de ordine i cu nregistrarea cu numrul de ordine j;

________________________________________________________________________________

279
Structuri de date i algoritmi
_______________________________________________________________________________

- algoritmul mut pe i la dreapta, pn cnd gsete o cheie mai mare dect pivotul v si mut
pe j la stnga pn cnd gsete o cheie mai mic dect pivotul v.
- dac nu este necesar interschimbarea se decrementeaz j cu 1 si se repet procesul de
comparaie;
- dac apare un interschimb, se incrementeaz i cu 1 si se continu compararea, mrind i pn
la apariia unui nou interschimb;
- se decrementeaz j, continundu-se acest proces de numit "ardere a lumnrii la ambele
capete", pn cnd i >= j.
Procedura se apeleaz recursiv printr-un apel de forma: SORTARE_Rapida(A, 1, N);

Exemplul VI.5: Sortarea tabelei A din Figura VI.4 (a) folosind algoritmul de sortare Shell, n ordine
cresctoare:

Pasul 1: Alegem pivotul, elementul cu cheia 7 de pe poziia 1


- Comparm pe 7 cu 4, 7 > 4, i interschimbm;

Pasul 2: Caut de la stnga la dreapta elementul cu cheia mai mare dect 7 (indexul i)
- Acesta este 8, comparm pe 7 cu 8, 8 > 7, i interschimbm;

Pasul 3: Caut de la dreapta la stnga elementul cu cheia mai mic dect 7 (indexul j)
- Acesta este 6, i interschimbm cu elementul de pe poziia i;

Procesul de "ardere a lumnrii la ambele capete" se continu pn cnd i >= j, atunci tabela
se mparte n dou subtabele care se sorteaz separat recursiv pn cnd fiecare subtabel va conine
doar un element.

________________________________________________________________________________

280
Structuri de date i algoritmi
_______________________________________________________________________________

Figura VI.5. Sortarea unei tabele A cu 12 elemente prin algoritmul de sortare Shell.

VI.2.5.3. Implementarea algoritmului

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea general a algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Rapid (i , j) ESTE:


DAC @ntre A[i] i A[j] exist cel puin dou chei distincte ATUNCI
@fie v := cea mai mare dintre cele dou chei distincte;
@permutm A[i], ., A[j] astfel nct pentru i 1 k j s avem:
elementele A[i], ., A[k-1] au chei strict mai mici dect pivotul v;
elementele A[k], ., A[j] au chei mai mari sau egale cu pivotul v;
CHEAM SORTARE_Rapid (i , k-1)
CHEAM SORTARE_Rapid (k , j)

________________________________________________________________________________

281
Structuri de date i algoritmi
_______________________________________________________________________________

SFALGORITM

Implementarea algoritmului de sortare prin metoda rapid n limbajul Pascal este:

Variabilele left si right reprezint nceputul si sfritul tabelei sau subtabelei.

Procedure QUICK(var A:arraytype; left, right: integer);


Var i,j: integer;
v, t: elem;
Begin
i := left; j := right; v := A[l];
Repeat
While A[i].key < v.key do
i := i+1;
While A[j].key > v.key do
j := j-1;
If i < j then
Begin
t := A[i];
A[i] := A[j];
A[j] := t;
End
Until i >= j {pentru siguran; conform algoritmului era suficient i = j}
If left < j-1 then
QUICK (left, j-1);
If i+1 < right then
QUICK (i+1, right);
End;

VI.2.5.3. Complexitatea algoritmului

n algoritmului de sortare rapid, fiecare element este comparat cu pivotul, adic avem
complexitatea O(N).
In continuare tabela este divizat n dou pri, fiecare parte este iari divizat n dou pari,
., .a.m.d. Dac fiecare parte este mprit aproximativ n dou jumti egale, vom avea log 2N
operaii de mprire.
Deci complexitatea algoritmului de sortare rapid este n caz mediu O(Nlog2N), iar n caz
nefavorabil este O N 2 [Knu, 1976].
Dup cum am artat mai sus, algoritmul de sortare rapid este o metod bun n cazul
general, dar nu i n cazul nefavorabil, cnd este preferabil alegerea pivotului conform formulei

________________________________________________________________________________

282
Structuri de date i algoritmi
_______________________________________________________________________________

(6.2). Performanele algoritmului de sortare rapid sunt dependente de ordinea datelor de intrare. De
aceea nu este o metod de sortare stabil.

VI.2.6. Algoritmul de sortare prin interclasare (mergesort)

VI.2.6.1. Descrierea general a metodei

Algoritmul de sortare prin interclasare se bazeaz pe urmtoarea idee: pentru a sorta o tabel
cu N elemente, mprim tabela iniial n dou subtabele pe care le sortm separat si le interclasm.
Este o metod de sortare care folosete ca strategie de baz tehnica "divide et impera", conform
creia o problema care se poate descompune n alte dou subprobleme de acelai tip, se rezolv cale
dou subprobleme, iar rezultatele subproblemelor se combin pentru a genera rezultatul problemei
iniiale. Algoritmul de sortare prin interclasare sorteaz elementele n ordine cresctoare.

VI.2.6.2. Descrierea algoritmului

Fiind dat o tabel A cu N elemente, mprim tabela n dou pri, sortm separat fiecare
parte si mbinm prin interclasare cele dou pri ntr-o tabel auxiliar temporar. Dac o parte
conine doar un singur element, atunci considerm acea parte sortat.

mprirea tabelei n dou pri presupune gsirea elementului de mijloc:

(prim + ultim) / 2 (6.4)

Pentru a mbina jumtile sortate, interclasm fiecare subtabel, comparm succesiv


perechile de chei (din fiecare parte) si punem valoarea mai mic ntr-o tabela temporal. Algoritmul
general necesit urmtorii pai:

1. mparte tabela n dou


2. Sorteaz jumtatea stng
3. Sorteaz jumtatea dreapt
4. mbin prin interclasare cele dou jumti sortate ntr-o tabel sortat.

mbinarea celor dou pri necesit un numr de operaii de ordinul O(N). Algoritmul se
termin cnd o subtabel nu mai are nici o nregistrare si mutm nregistrrile rmase din cealalt
subtabel n tabela temporar. Dup pasul de interclasare putem copia tabela temporar sortat n
tabela original.

________________________________________________________________________________

283
Structuri de date i algoritmi
_______________________________________________________________________________

Figura VI.6. mbinarea prin interclasare a unei tabele A cu 100 elemente.

Pasul 1: Aflm mijlocul tabelei, utiliznd formula 6.4


- mijloc := (1 + 9) / 2 = 5;

Pasul 2 mprim tabela n dou subtabele fat de elementul de mijloc.


- avem subtabela format din nregistrrile 1, 2, 3, 4;
- avem subtabela format din nregistrrile 5, 6, 7, 8, 9;

Pasul 3: Sortm subtabela stng.


- avem nregistrrile cu cheile sortate: 2, 5, 7, 8.

Pasul 4: Sortm subtabela dreapt.


- avem nregistrrile cu cheile sortate: 1, 3, 4, 6, 9.

Pasul 5: Interclasm subtabela stng i dreapt n tabela Temp.

Pasul 6: Copiem nregistrrile din tabela Temp n tabela original A.

________________________________________________________________________________

284
Structuri de date i algoritmi
_______________________________________________________________________________

Figura VI.7. Sortarea unei tabele A cu 9 elemente prin algoritmul de sortare prin interclasare.

VI.2.6.3. Implementarea algoritmului

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea general a algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Interclasare ESTE:


CITETE A, N;
Index := PrimStng;
CTTIMP @mai sunt elemente n jumtatea stng si n cea dreapt
DAC cheia_Index_curent_stng < cheia_Index_curent_drept ATUNCI
Temp[Index] := A[Index curent stng]
Index_curent_stng := Index_curent_stng + 1;
ATFEL
Temp[Index] := A[Index curent_ drept];

________________________________________________________________________________

285
Structuri de date i algoritmi
_______________________________________________________________________________

Index_curent_drept := Index_curent_drept + 1;
@Copiaz toate elemente rmas din jumtatea stng n tabela Temp;
@Copiaz toate elemente rmas din jumtatea deapt n tabela Temp;
@Copiaz toate elemente sortate din tabela Temp n tabela A;
SFALGORITM

Implementarea algoritmului de interclasare n limbajul Pascal este:

Variabilele lfirst, llast, rfirst, rlast indic cele dou capete ale subtabelei din stnga si ale
subtabelei din dreapta. Variabilele curent_left si curent_right reprezint elementul curent din stnga
respectiv din dreapta. Temp este tabela temporar folosit pentru sortare.

Procedure Interclasare (var A:arraytype; lfirst, llast, rfirst, rlast: integer);


var
temp: arraytype;
index, curent_left, curent_right: integer;
Begin
curent_left:=lfirst;
curent_right:=rfirst;
index:=lfirst;
While (curent_left<=llast) and (curent_right<=rlast) do
Begin
If A[curent_left< A[curent_right] then
Begin
Temp[index]:=A[curent_left];
curent_left:=curent_left+1;
End
Else
Begin
Temp[index]:=A[curent_right];
curent_right:=curent_right+1;
End;
index := index+1;
End;
While curent_left<=llast do
Begin
Temp[index]:=A[curent_left];
curent_left:=curent_left+1;
index:=index+1;
End;
While curent_right<=rlast do
Begin
Temp[index]:=A[curent_right];
curent_right:=curent_right+1;
index:=index+1;
________________________________________________________________________________

286
Structuri de date i algoritmi
_______________________________________________________________________________

End;
For index:=lfirst to rlast do
A[index] := Temp[index]
End;

Implementarea algoritmului de sortare prin interclasare, n limbajul Pascal este:

Procedure SORTARE_Interclasare (var A: arraytype; first,last:integer);


var
middle: integer;
Begin
If first < last then
Begin
middle:=(first+last) div 2;
SORTARE_Interclasare (A, first, middle);
SORTARE_Interclasare (A, middle +1, last);
Interclasare (A, first, middle, middle +1, last);
End;
End;

VI.2.6.3. Complexitatea algoritmului

Majoritatea operaiilor efectuate de algoritmul de sortare prin interclasare sunt efectuate de


operaiile de comparare i de copiere.
n cadrul operaiilor de interclasare, fiecare nregistrare din cele dou subtabele este
comparat, aceast nsemnnd o complexitate de ordinul O(N).
Copierea nregistrrilor din tabela temporar Temp n tabela original A necesit un numr
de operaii tot de ordinul O(N).
Procedura de sortare propriu-zis este recursiv i este apelat recursiv pentru jumtatea
stng i pentru jumtatea dreapt. Tabela iniial A poate fi mprit de cel mult log2N ori. La
fiecare mprire se execut operaia de interclasarere care este de ordinule O(N).
Atunci algoritmul de sortare prin interclasare va avea o complexitate de ordinul O(N log2 N)
n toate dintre cele trei cazuri [Tom, 1997]. Este o metod stabil. Algoritmul de sortare prin
interclasare nu este dependent de ordinea iniial a elementelor.
Dezavantajul algoritmului de sortare prin interclasare este c necesit o tabel auxiliar
Temp de dimensiune N egal cu dimensiunea tabelei de sortat A.

VI.2.6. Algoritmul de sortare prin ansambluri (heapsort)

________________________________________________________________________________

287
Structuri de date i algoritmi
_______________________________________________________________________________

VI.2.6.1. Descrierea general a metodei

Definiia 6.1.: Un arbore binar posed proprietatea de ansamblu dac orice nod al su verific
proprietatea: cheia de cutare a nodului este mai mare sau egal dect cheia de cutare a nodului
fiu_stnga sau dect cheia de cutare a nodului fiu_dreapta.

Definiia 6.2.: Un ansamblu (heap) este un arbore binar complet ce posed proprietatea de
ansamblu (Definiia 6.1).

Caracteristica de baz a acestei structuri de date, numit ansamblu, este c modificarea


valorii cheii de cutare a unui nod se poate face uor pstrnd totui proprietatea de ansamblu.
Presupunnd c cheia de cutare a unui nod_fiu depete cheia de cutare a nodului_tat, este
suficient s interschimbm ntre ele cele dou noduri, s continum procedeul pe drumul ascendent
ctre nodul rdcin, pn cnd proprietatea de ansamblu este restabilit. Vom spune c valoarea
modificat a fost filtrat ctre noua poziie [And, 1995].
Dac, dimpotriv, cheia de cutare a nodului_tat scade, devenind mai mic dect cheia de
cutare a unui nod_fiu, atunci este suficient s schimbm ntre ele nodul_tat cu nodul_fiu avnd
cheia de cutare cea mai mare, apoi s continum procesul n mod descendent, pn cnd
proprietatea de ansamblu este restabilit. Vom spune c valoarea modificat a fost cernut ctre
noua sa poziie [And, 1995].
Metoda de sortare prin ansambluri, se bazeaz pe reprezentarea arborescent al unei tabele
date.

VI.2.6.2. Descrierea algoritmului

a. Construirea ansamblului : Descrierea general a algoritmului n Pseudocod este:

Specificarea problemei de construire a ansamblului, avnd ca date de intrare tabela A,


dimensiunea maxim a tabelei N, este urmtoarea:

DATE A, N;
REZULTATE Ansamblu; { Ansamblul construit din tabela nesortat A }

Descrierea general a algoritmului de creare al ansamblului n Pseudocod este:

ALGORITMUL Creare_Ansamblu ESTE:


CITETE A, N; { Ansamblul construit din tabela nesortat A }
PENTRU i := (N div 2); 1 EXECUT
CHAM Cernere (A, N, i);

________________________________________________________________________________

288
Structuri de date i algoritmi
_______________________________________________________________________________

SF-PENTRU
SFALGORITM

ALGORITMUL Cernere (B, M, j) ESTE:


k := j: { Se cerne valoarea din tabela B[j] }
REPET
l := k; { Gsete fiul cu valoarea cea mai mare }
DAC (2l <= M) i (B[2l] > B[k]) ATUNCI
k := 2l;
SFDAC
DAC (2l < M) i (B[2l +1] > B[k]) ATUNCI
k := 2l +1;
SFDAC
temp := B[l];
B[l] := B[k];
B[k] := temp;
PNCND l = k SFREP
SFALGORITM

n Figura VI.8 avem un exemplu de construire a unui ansamblu. Nodurile reprezentate cu


cercuri semnific elementele care constituie ansamblul, iar nodurile reprezentate cu cercuri
reprezint noduri care violeaz proprietatea ansamblului.

(a) (b) (c)

(d) (e) (f)ansamblu

Figura VI.8. Construirea unui ansamblu A cu 9 elemente.

Pozitia 1 2 3 4 5 6 7 8 9

________________________________________________________________________________

289
Structuri de date i algoritmi
_______________________________________________________________________________

tabela 7 5 8 2 3 9 1 6 4
originala
dupa (b) 7 5 8 6 3 9 1 2 4

dupa (c) 7 5 9 6 3 8 1 2 4

dupa (d) 7 6 9 5 3 8 1 2 4

dupa (e) 9 6 8 5 3 7 1 2 4

Pasul 1: Construim arborele binar corespunztor tabelei originale


- secvena de noduri este: 7, 5, 8, 2, 3, 9, 1, 6, 4;
- arborele binar este reprezentat n Figura VI.8.a.

Pasul 2: Nodul cu cheia 2 violeaz proprietatea de ansamblu (arborele binar este reprezentat n
Figura VI.8.b.)
- cernem valoarea nodului cu cheia 2;
- interschimbm nodul cu cheia 2 cu nodul cu cheia 9;
- arborele binar este reprezentat n Figura VI.8.d.

Pasul 3: Nodul cu cheia 8 violeaz proprietatea de ansamblu (arborele binar este reprezentat n
Figura VI.8.d.)
- cernem valoarea nodului cu cheia 8;
- interschimbm nodul cu cheia 2 cu nodul cu cheia 6;
- arborele binar este reprezentat n Figura VI.8.c.

Pasul 4: Nodul cu cheia 5 violeaz proprietatea de ansamblu (arborele binar este reprezentat n
Figura VI.8.d.)
- cernem valoarea nodului cu cheia 5;
- interschimbm nodul cu cheia 5 cu nodul cu cheia 6;
- arborele binar este reprezentat n Figura VI.8.e.

Pasul 5: Nodul cu cheia 7 violeaz proprietatea de ansamblu (arborele binar este reprezentat n
Figura VI.8.e.)
- cernem valoarea nodului cu cheia 7;

________________________________________________________________________________

290
Structuri de date i algoritmi
_______________________________________________________________________________

- interschimbm nodul cu cheia 5 cu nodul cu cheia 9;


- arborele binar este reprezentat n Figura VI.8.f.

n Figura VI.8.f aven reprezentat ansamblul construit din tabela A.

Implementarea algoritmului de creare al ansamblului n limbajul Pascal este:

Procedure Creare_Ansamblu (var A: arraytype, first, last: integer);


var
r, max: integer;
ok: boolean;
Begin
r := first; ok:=false;
While (r*2 <= last) and not ok do
Begin
If r*2 = last then
max :=r*2
Else
If A[r*2] > A[r*2+1] then
max := r*2
Else
max := r*2+1;
If A[r] < A[max] then
Begin
Swap( A[r], A[max] );
r := max;
End
Else
ok := true;
End
End;

b. Sortare cu ansambluri: Fiind dat o tabel nesortat A, de dimensiune N, s presupunem c am


construit ansamblul corespunztor tabelei A. Astfel vom putea accesa uor elementul maxim din
tabel pentru c acesta este chiar nodul rdcin al ansamblului si n reprezentarea cu ajutorul
tabelei va fi nregistrarea A[1]. Aceast nregistrare va fi interschimbat cu nregistrarea A[N]. Ne
vom ocupa n continuare de primele N -1 nregistrri A[1], , A[N-1], care alctuiesc aproape un
ansamblu, iari apelm la algoritmul de creare al ansamblului pentru aceste nregistrri, .,
.a.m.d., pn cnd toate nregistrrile vor fi la locul potrivit, adic toate nregistrrile vor fi sortate.

VI.2.6.3. Implementarea algoritmului

________________________________________________________________________________

291
Structuri de date i algoritmi
_______________________________________________________________________________

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N;
REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea general a algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_Ansamblu ESTE:


CITETE A, N;
CHEAM Creare_Ansamblu:
PENTRU i := N; 2 EXECUT
temp := A[l];
A[1] := A[i];
A[i] := temp;
CHEAM Cernere (B, i -1, 1);
SF-PENTRU
SFALGORITM

Algoritmul Sortare_Ansambluri construiete ansamblul original pentru elementele nesortate


si sorteaz elementele n ansamblu prin schimbarea nodului rdcin A[1], cu ultimul element
nesortat A[i], apoi rearanjeaz elementele rmase.

Implementarea algoritmului de sortare prin ansambluri n limbajul Pascal


este:

Procedure SORTARE_Ansamblu (var A: arraytype; N: integer);


Var i: integer;
Begin
Creare_Ansamblu (A, 1, N);
For i:= N downto 2 do {sortare}
Begin
Swap(A[1],A[i]);
Creare_Ansamblu (A,1,i-1);
End
End;

VI.2.6.4. Complexitatea algoritmului

________________________________________________________________________________

292
Structuri de date i algoritmi
_______________________________________________________________________________

Un arbore binar complet cu N noduri are nevoie de log2(N +1) operaii, n cazul cel mai
nefavorabil, pentru a cerne nodul rdcin, astfel nct s ajung n poziia de nod frunz.
Algoritmul Creare_Ansamblu efectueaz un numr de log2N interschimbri, deci complexitatea sa
va fi O(log2N). [Tom, 1997]
Ciclul PENTRU din algoritmul de sortare se va executa de N-1 ori, deci complexitatea
algoritmului de sortare este O(Nlog2N).
Algoritmul de sortare prin ansambluri are complexitatea O(Nlog2N) n toate din cele trei
cazuri de analizat: cazul general, favorabil i nefavorabil [Knu, 1976].
Pentru tabele mici algoritmul de sortare prin ansambluri este ineficient, dar foarte eficient
pentru cele tabele mari. Nu necesit memorie suplimentar. Eficiena algoritmul de sortare prin
ansambluri nu este afectat de ordinea iniial a elementelor.

VI.2.7. Algoritmul de sortare RADIX

VI.2.7.1. Descrierea general a metodei

Sortarea RADIX (sau sortarea digital ) este o metod de sortare care precede apariia
calculatoarelor electronice, fiind inspirat dintr-o metod de sortare mecanic a cartelelor perforate.
Este una din cele mai eficiente metode de sortare intern, cu condiia ca dimensiunea N a numrului
de nregistrri de sortat s nu fie prea mic, iar cheile dup care se face ordonarea s nu fie prea mici.
Algoritmul de sortare Radix trateaz cheile ca i cum ar fi numere reprezentate ntr-o baz
M, utiliznd cifrele din reprezentarea individuale a numerelor (de exemplu, caracterele pot fi
reprezentate n baz 128).
Dac folosim clasica reprezentare zecimal, deci M = 10, vom folosi 10 buzunare
corespunznd celor 10 cifre zecimale ale sistemului de numeraie zecimal. Fiecare coloan este
sortat ncepnd cu rangul cel mai puin semnificativ al cheilor (primul din dreapta), mutnd
nregistrrile din zona de intrare a algoritmului de sortare ntr-o zon auxiliar a algoritmului de
sortare. Procesul de sortare continu apoi cu urmtorul rang semnificativ, pn cnd, n pasul final
se ordoneaz toate nregistrrile.

VI.2.7.2. Descrierea algoritmului

Putem organiza nregistrrile de sortat n buzunare (pocket), fiecare buzunar corespunznd

________________________________________________________________________________

293
Structuri de date i algoritmi
_______________________________________________________________________________

unei cifre din reprezentarea cheilor de sortat n baza M. Fiecare buzunar poate fi reprezentat ca o
structur de date de tip coad (list FIFO). La sfritul fiecrui pas al procesului de sortare, cozile
pot fi combinate uor n ordine potrivit.
Dac numrul maxim de cifrei ntr-o cheie este M, atunci vor fi necesari M pai de sortare,
pornind de la cifra cea mai puin semnificativ la cifra cea mai semnificativ. Este recomandat a se
folosi reprezentarea nlnuit, sub forma de list simpl nlnuit, a structurii de date
corespunznd buzunarelor, deoarece nu putem ti cte nregistrri vor intra ntr-un buzunar.
Prima dat, vom sorta nregistrrile dup cifra cea mai puin semnificativ a cheii,
interclasm apoi buzunarele. Repetm procesul de la primul pas, sortnd nregistrrile dup cifra
urmtoare, interclasm iari buzunarele, .a.m.d.

Exemplu: S considerm urmtoarea secven de numere de sortat n ordine cresctoare:


42, 23, 74, 11, 65, 57, 94, 36, 99, 87, 70, 81, 61
Fiind vorba de o reprezentare zecimal vom avea nevoie de 10 buzunare pentru procesul de
sortare. Datorit ordinului de mrime al numerelor de sortat, avem doar 2 cifre de reprezentare, cifra
unitilor i cifra zecilor.

Pasul 1: Prelucrm datele de sortat dup cifra unitilor n cele 10 buzunare

Pasul 2: Interclasm buzunarele


- obinem secvena de chei: 70, 11, 81, 61, 42, 23, 74, 94, 65, 36, 57, 87, 99

Pasul 3: Prelucrm datele de sortat dup cifra zecilor n cele 10 buzunare

Pasul 4: Interclasm buzunarele


- obinem secvena de chei: 11, 23, 36, 42, 57, 61, 65, 70, 74, 81, 87, 94, 99

VI.2.7.3. Implementarea algoritmului

________________________________________________________________________________

294
Structuri de date i algoritmi
_______________________________________________________________________________

Specificarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea maxim a


tabelei N, este urmtoarea:

DATE A, N, M; { M reprezint baza sistemului de numeraie }


REZULTATE A; { tabela A sortat n ordine cresctoare }

Descrierea general a algoritmului de sortare n Pseudocod este:

ALGORITMUL SORTARE_RADIX ESTE:


CITETE A, N, M;
k:= @numrul maxim de cifre necesar reprezentrii cheilor din tabela A;
PENTRU i := 1; k EXECUT
@golete buzunarul B[i];
PENTRU j := 1; N EXECUT
@analizeaz cifra i a cheii A[j] i introducem nregistrarea n buzunarul B[];
SF-PENTRU
@ interclaseaz buzunarele B[1], B[2],, B[M];
SF-PENTRU
SFALGORITM

Implementarea algoritmului de sortare prin ansambluri n limbajul Pascal este:


Fie dat o mulime de N nregistrri, organizat ca o list nlnuit cu cmpurile cheie (key)
si legtur (next). Vectorii head si tail contin adresele primelor i respectiv ultimelor nregistrri din
fiecare buzunar (coad). Variabila i este indexul pasului de sortare, variabila j este indexul
buzunarelor, variabila r este variabila pointer al nregistrrii curente. Variabila h de tip ntreg
corespunde cifrei de analizat din cheie, variabila M reprezint numrul maxim de cifre care
alctuiesc cheia (key = c1c2c3cM-1cM).

Function SORTARE_RADIX (r : list ) : list;


var head, tail : array[0..9] of list;
i, j, h : integer;
Begin
For i:=M downto 1 do {numrul de pai necesari}
Begin
For j:= 0 to 9 do
head[j] := nil; {iniializeaz listele corespunztoare buzunarelor}
While r <>nil do {pune nregistrrile n buzunarul corespunztor}
Begin
h := charac( i, r^.key ); {obtine bitul i al cheii }
If head[h]= nil then
head[h] := r

________________________________________________________________________________

295
Structuri de date i algoritmi
_______________________________________________________________________________

Else
tail[h]^.next := r;
tail[h] := r;
r := r^.next;
End;
r := nil; { interclasm buzunarele }
For j:=9 downto 0 do
If head[j] <> nil then
Begin
tail[j]^.next := r;
r := head[j]
End;
End;
SORTARE_RADIX := r;
End;

VI.2.7.4. Complexitatea algoritmului


Pentru ca algoritmul de sortare RADIX fie performant este necesar s folosim structuri de
date potrivite De exemplu, este preferabil ca s avem nregistrrile de sortat organizate ca o list
simplu nlnuit si nu ca o tabel static. Dac folosim organizarea sub form de list simpli
nlnuit, atunci nu va trebui s copiem nregistrrile efectiv din structura iniial n buzunare, ci
doar s mutm adresa nregistrrii dintr-o list n alta. De asemenea, pentru ca interclasarea s fie
rapid avem nevoie de pointeri la sfritul fiecrei liste.
Complexitatea algoritmului de sortare Radix este liniar, adic de complexitate O(N), dac
cheile de sortare sunt de tip ntreg sau de tip ir de caractere cu lungime fix [Tre, 1984].
Dac avem N nregistrri de sortat cu maximum M cifre necesare pentru reprezentare, atunci
complexitatea algoritmul de sortare RADIX este O(MN).

BIBLIOGRAFIE

Atanasiu, A. , R. Pintea [1996]. Culegere de probleme Pascal, Editura Petrion, Bucureti.


________________________________________________________________________________

296
Structuri de date i algoritmi
_______________________________________________________________________________

Aho, A. V., J. E. Hopcroft, J. D. Ullman [1974]. The Design and Analysis of Computer
Algorithms, AddisonWesley,Reading,Massachusetts.

Aho, A. V., J. E. Hopcroft, J. D. Ullman [1987]. Data Structures and Algorithms, Addison
Wesley,Reading,Massachusetts.

Albeanu, G. [1994]. Programare n Pascal i Turbo Pascal .Culegere de probleme, Editura


Tehnic, Bucureti.

Andonie, R., I. Grbacea [1995]. Algoritmi fundamentali. O perspectiv C++, Editura Libris,
Cluj-Napoca.

Baase, S. [1987]. Computer Algorithms. Introduction to Design and Analysis, Addison-Wesley,


Reading,Massachusetts.

Blaga P., G. Coman, S. Groze [1978]. Bazele Informaticii I. Culegere de probleme, Litografia
Universitii Babe-Bolyai, Cluj-Napoca.

Bhm, C., T. C. Jacopini [1966]. Flow Diagrams, Turing Machines and Languages with only
two Formation Rules, Comm. A.C.M. 9:5.

Boian F., M. Frentiu [1992]. Bazele Informaticii. Limbajul Pascal, ediia a II-a, Litografia
Universitii Babe-Bolyai, Cluj-Napoca.

Burdescu, D.D. [1998]. Analiza complexitii algoritmilor, Editura Albastr, Bucureti.

Cook, S. A. [1970]. The complexity of theorem-proving procedure, 3-rd ACM Symposium of


Computing, pg 151-158.

Cristea, V., I. Athanasiu, E. Kalisz, A. Pnoiu [1992]. Turbo Pascal 6.0, Editura Teora,
Bucureti.

Cristea, V., I. Athanasiu, E. Kalisz, V. Iorga, [1993]. Tehnici de programare, Editura Teora,
Bucureti.

Dale N., S. C. Lilly [1988]. Pascal Plus Data Structures, D. C. Heath and Company, Lexington,
Massachusetts.

Fortune, S., C. J. Van Wyk [1993]. Efficient Exact Arithmetic for Computational Geometry,
Proceedings of the 9th ACM Symposium Computational Geometry.

________________________________________________________________________________

297
Structuri de date i algoritmi
_______________________________________________________________________________

Frentiu M., S. Groze [1986]. Bazele Informaticii, ediia a II-a, Litografia Universitii Babe-
Bolyai, Cluj-Napoca.

Giumale, C.A. [2004]. Introducere n analiza algoritmilor. Teorie i aplicaie, Editura Polirom,
Bucureti.

Horowitz E., S. Sahni [1978]. Fundamentals of Computer Algorithms, Computer Science Press,
Rockville.

Knuth D. E, [1976]. Tratat de programarea calculatoarelor. Algoritmi fundamentali, Editura


Tehnic, Bucureti.

Knuth, D. E. [1976]. Tratat de programare a calculatoarelor. Sortare i cutare, Editura


Tehnic, Bucureti.

Korsh, J. F., L. J.Garrett [1988]. Data Structures, Algorithms and Program Style Using C, PWS-
Kent Publishing Co., Boston.

Lewis, H.R., L. Denenberg [1991]. Data Structures & Their Algorithms, Harper Collins
Publishers, New/York.

Livovschi L., [1980]. Scheme logice. Semnificaie, elaborare, verificare, testare, Editura
Tehnic, Bucureti.

Livovschi L., H. Georgescu, [1986]. Sinteza i analiza algoritmilor, Editura Stiinific i


Enciclopedic, Bucureti.

Mocanu, M., G. Marian, C. Bdic, C. Bdic [1993]. 333 probleme de programare, Editura
Teora, Bucureti.

Sedgewitz, R. [1988]. Algorithms, AddisonWesley,Reading,Massachusetts.

Sedgewitz, R. [1990]. Algorithms in C, AddisonWesley,Reading,Massachusetts.

Shewchuk, J. R. [1997]. Floating-point arithmetic and fast robust geometric predicates,


Discrete and Computational Geometry, 18.

Skiena, S. [1997]. The Algoritm Design Manual, Editura Springer-Verlag, New-York.

Tomescu, I., [1972]. Introducere n combinatoric, Editura Tehnic, Bucureti.

Tomescu, I. [1981].Probleme de combinatoric i teoria grafurilor, Editura Didactic i


Pedagogic, Bucureti.

Tomescu, I., [1997]. Data Structures, Editura Universitii din Bucureti, Bucureti.

________________________________________________________________________________

298
Structuri de date i algoritmi
_______________________________________________________________________________

Tremblay J. P., P. G. Sorenson [1984]. An Introduction to Data Structures with Applications,


second edition, McGraw-Hill, New-York.

Tudor, S. [1993]. Tehnici de programare i structuri de date, vol. II, Editura Turbo Rabbit,
Bucureti.

________________________________________________________________________________

299

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