Documente Academic
Documente Profesional
Documente Cultură
Prefa
Progresele tehnologice n domeniul informaticii au condus la creterea puterii de cal-
cul i a memoriei calculatoarelor electronice, la ieftinirea acestor calculatoare, per-
mind abordarea unor probleme extrem de complexe, din toate sferele activitii
umane. Calculatorul a devenit un instrument indispensabil pentru viaa omului mo-
dern. Penetrarea Internetului i a accesului la resursele informatice mondiale, lrgirea
considerabil a spectrului de aplicaii a contribuit i contribuie la impunerea calcula-
torului ca instrument de lucru vital n activitatea omului. n consecin, cerina de
noi programe n toate domeniile activitii umane a crescut mereu.
De aceea, se impune tot mai pregnant creterea importanei metodologiilor de
realizare a produselor program, necesitatea unei instruiri corespunztoare a noilor
generaii de specialiti i de utilizatori ai calculatoarelor. n formarea specialitilor
n informatic este important dobndirea unor cunotine i deprinderi de a realiza
produse program de o complexitate variat, care s satisfac cerinele beneciarului.
Pentru aceasta este necesar respectarea unei discipline de lucru i cunoaterea unei
metodologii adecvate de proiectare i realizare a acestor produse software. n trecutul
nu prea ndeprtat, n activitatea de instruire a specialitilor n informatic s-a pus
un mai mare accent pe nvarea unor limbaje de programare i pe programarea
propriu-zis, acordndu-se o pondere mai mic analizei i proiectrii programelor.
Specializarea n informatic nu nseamn doar cunoaterea limbajelor de programare,
ci n primul rnd nsuirea metodelor moderne de analiz i proiectare a aplicaiilor
software.
Scopul acestei cri este de a contribui la nvarea programrii ca o disciplin
unitar avnd o fundaie tiinic solid, necesar programatorilor. Pentru aceasta
este nevoie s ncercm s denim mai clar noiunea de programare.
Conform cu [Sed, 1990], programarea poate privit ca o activitate general de
a extinde sau a de a modica funcionalitile unui sistem. Este o activitate general
deoarece ea poate efectuat att de specialiti (programatori) ct i de nespecialiti
(setarea unui telefon celular sau a unei alarme de acces ntr-o ncpere). Din acest
3
4
punct de vedere, activitatea de programare const din dou elemente fundamentale:
o component tehnologic i o component tiinic. Partea tiinic include ele-
mente printre care se regsesc structurile de date i algoritmii necesari descrierii
operaiilor de manipulare a acestor structuri de date. Aceast abordare ne permite o
independena a acestor structuri de date fa de limbajele de programare i fa de
tehnologiile de proiectare utilizate n activitatea de programare.
Programele sunt fcute pentru a rezolva probleme din viaa de zi cu zi. Informaia
prelucrat de un program este stocat cu ajutorul structurilor de date. Aceste
structuri de date grupeaz ntr-o form ecient datele. O structur de date corect
denit poate simplica operaia care prelucreaz acele date sau o poate complica.
De aceea structurile de date au o importan major n activitatea de proiectare
i programare. Programele prelucreaz informaii. Informaiile sunt organizate sub
form de structuri de calcul. Modul n care reprezentm structurile de date afecteaz
claritatea, conciziunea, viteza de rulare i capacitatea de stocare a programului. Dez-
voltarea unui program complex este dicil dac programatorul nu posed cunotine
n domeniul structurilor de date, algoritmicii i a tehnicilor de programare.
Dac nu se cunoate o soluie pentru rezolvarea unei probleme nu exist o soluie
magic de a scrie un program care s rezolve acea problema. Un proverb arm c
dac nu tii cum s ajungi ntr-un anumit loc atunci nu are importan cum ajungi
n acel loc. Mai mult chiar, Murphi arm c orice problem complex are o soluie
simpl eronat. De aceea, nainte de a implementa un program ntr-un anumit limbaj
de programare, este necesar nelegerea problemei, descrierea pas cu pas a soluiei,
cu alte cuvinte este necesar a descrie problema prin intermediul unui algoritm. Din
pcate nu exist un algoritm care s aleag algoritmul care rezolv orice problem.
Ceea ce exist sunt o serie de tehnici de dezvoltare a algoritmilor, numite n general
tehnici de programare.
Scopul principal al lucrrii de fa este familiarizarea celor care doresc s o nvee,
cu activitatea de programare. Vom vedea n ce const aceast activitate i vom
remarca accentul pus pe gndirea omului, pe proiectarea algoritmilor i corectitudinea
lor, calculatorul ind doar unealta care execut ceea ce "dicteaz" programatorul.
Pentru a putea dicta calculatorului avem nevoie de un limbaj neles de ambele pri;
limbajul ales n acest scop este Pascal. De asemenea, vom prezenta metodele de
programare cunoscute n prezent i discutate n literatura de specialitate. Vom nva
s analizm algoritmii, dar vom mai puin preocupai de msurarea complexitii
unui program, accentul ind pus pe modul n care el poate obinut. Noiunile i
conceptele prezentate sunt nsoite de exemple simple, n care s-au folosit: limbajul
Pseudocod n descrierea algoritmilor, un limbaj de specicare informal n descrierea
tipurilor abstracte de date i limbajul Pascal pentru codicare.
Cuprins
1 Bazele algoritmilor 11
1.1 Descrierea algoritmilor . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.1.1 Algoritm, program, programare . . . . . . . . . . . . . . . . . . 11
1.1.2 Scheme logice . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.1.3 Limbajul PSEUDOCOD . . . . . . . . . . . . . . . . . . . . . . 12
1.1.3.1 Algoritmi liniari . . . . . . . . . . . . . . . . . . . . . 15
1.1.3.2 Algoritmi cu ramicaii . . . . . . . . . . . . . . . . . 17
1.1.3.3 Algoritmi ciclici . . . . . . . . . . . . . . . . . . . . . 19
1.1.4 Calculul efectuat de un algoritm . . . . . . . . . . . . . . . . . 22
1.1.5 Ranare n pai succesivi . . . . . . . . . . . . . . . . . . . . . 24
1.1.6 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.1.7 Subalgoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.1.7.1 Conceptul de subalgoritm . . . . . . . . . . . . . . . . 26
1.1.7.2 Apelul unui subalgoritm . . . . . . . . . . . . . . . . . 29
1.2 Elaborarea algoritmilor. Propoziii nestandard . . . . . . . . . . . . . 31
1.3 Proiectarea ascendent i proiectarea descendent . . . . . . . . . . . . 34
1.4 Proiectarea modular . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.5 Apel recursiv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.6 Programarea structurat . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.7 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2 Complexitatea algoritmilor 51
2.1 Etapele rezolvrii unei probleme . . . . . . . . . . . . . . . . . . . . . 51
2.2 Noiunea de algoritm i cea de program . . . . . . . . . . . . . . . . . 51
2.3 Modelul abstract al Mainii Turing. Teza Turing-Church . . . . . . . . 52
2.4 Analiza, proiectarea i implementarea algoritmilor i complexitatea al-
goritmilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5
6 CUPRINS
2.5 Operaia de baz, cheia studiului complexitii . . . . . . . . . . . . . 53
2.6 Clase de algoritmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.7 Eciena algoritmilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.8 Funciile de complexitate . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.9 Apartenena la o clas de complexitate . . . . . . . . . . . . . . . . . . 55
2.10 Limita inferioar sau efortul minimal. Algoritm optimal . . . . . . . . 58
2.11 Complexitatea algoritmilor i dicultatea problemelor . . . . . . . . . 59
2.12 Complexitatea de timp . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.13 Probleme rezonabile i probleme nerezonabile. Clasa problemelor P-
polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.14 Probleme de decizie i probleme de optimizare . . . . . . . . . . . . . . 60
2.15 Clasa problemelor NP (non - deterministic polinomiale) . . . . . . . . 61
2.16 Reducia polinomial a problemelor . . . . . . . . . . . . . . . . . . . 61
2.17 Teorema lui Cook. Probleme NP-Complete . . . . . . . . . . . . . . . 62
2.18 Clasa problemelor NP-Complete . . . . . . . . . . . . . . . . . . . . . 62
2.19 Marea ntrebare a Complexitii algoritmilor . . . . . . . . . . . . . . 63
2.20 Algoritmi aproximativi . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.21 Probleme insolvabile algoritmic . . . . . . . . . . . . . . . . . . . . . . 65
2.22 Complexitatea algoritmilor, calculatorul i viitorul . . . . . . . . . . . 66
3 Pogramare n limbajul PASCAL 67
3.1 Mediul de programare Turbo Pascal . . . . . . . . . . . . . . . . . . . 67
3.2 Programe simple Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.3 Structura unui program Pascal . . . . . . . . . . . . . . . . . . . . . . 73
3.4 Constante i variabile Pascal . . . . . . . . . . . . . . . . . . . . . . . 74
3.5 Tipuri de date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3.5.1 Tipul ntreg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.5.2 Tipul real . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.5.3 Tipul boolean . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.5.4 Tipul caracter . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.5.5 Tipul enumerare . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.5.6 Tipul subdomeniu . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.6 Expresii Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.6.1 Funcii predenite . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.6.2 Expresii aritmetice . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.6.3 Expresii relaionale . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.6.4 Expresii logice . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
3.7 Declaraii Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
CUPRINS 7
3.8 Denirea constantelor . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.9 Denirea tipurilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.10 Declararea variabilelor . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
3.11 Instruciuni Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
3.11.1 Instruciunea de atribuire . . . . . . . . . . . . . . . . . . . . . 86
3.11.2 Instruciunea compus i instruciunea vid . . . . . . . . . . . 87
3.11.3 Citirea i scrierea datelor . . . . . . . . . . . . . . . . . . . . . 87
3.11.4 Instruciuni condiionale . . . . . . . . . . . . . . . . . . . . . . 89
3.11.5 Instruciuni repetitive . . . . . . . . . . . . . . . . . . . . . . . 91
3.12 Subprograme Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
3.13 Funcii Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
3.14 Instruciunea apel de procedur . . . . . . . . . . . . . . . . . . . . . . 99
3.15 Apel recursiv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.16 Tipuri de date structurate . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.17 Tipul referin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
3.18 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
4 Structuri de date 121
4.1 Lista liniar simplu nlnuit . . . . . . . . . . . . . . . . . . . . . . 121
4.1.1 Deniii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
4.1.2 Operaii specice listei . . . . . . . . . . . . . . . . . . . . . . . 123
4.1.3 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . 128
4.2 Lista dublu nlnuit . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
4.2.1 Deniii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
4.2.2 Operaii specice listei . . . . . . . . . . . . . . . . . . . . . . . 131
4.2.3 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . 138
4.3 Stiva (stack) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
4.3.1 Generaliti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
4.3.2 Stiva alocare static . . . . . . . . . . . . . . . . . . . . . . . 140
4.3.3 Stiva alocare dinamic . . . . . . . . . . . . . . . . . . . . . . 141
4.3.4 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.4 Coada (queue) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
4.4.1 Generaliti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
4.4.2 Coada alocare static . . . . . . . . . . . . . . . . . . . . . . 144
4.4.3 Coada alocare dinamic . . . . . . . . . . . . . . . . . . . . . 146
4.4.4 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . 147
4.5 Arborele binar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
4.5.1 Deniii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
8 CUPRINS
4.5.2 Operaii ntr-un arbore binar AB . . . . . . . . . . . . . . . . . 150
4.5.3 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . 153
4.6 Grafuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
4.6.1 Grafuri orientate . . . . . . . . . . . . . . . . . . . . . . . . . . 153
4.6.1.1 Deniii i generaliti . . . . . . . . . . . . . . . . . . 153
4.6.1.2 Reprezentarea grafurilor orientate . . . . . . . . . . . 155
4.6.2 Grafuri neorientate . . . . . . . . . . . . . . . . . . . . . . . . . 157
4.6.2.1 Deniii i generaliti . . . . . . . . . . . . . . . . . . 157
4.6.2.2 Reprezentarea grafurilor neorientate . . . . . . . . . . 158
4.6.3 Grafuri planare . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
5 Tehnici de cutare 161
5.1 Introducere n tehnicile de cutare . . . . . . . . . . . . . . . . . . . . 161
5.1.1 Cutare secvenial . . . . . . . . . . . . . . . . . . . . . . . . 162
5.1.1.1 Descrierea general a metodei . . . . . . . . . . . . . 162
5.1.1.2 Probleme rezolvate pentru cutare secvenial . . . . 165
5.1.1.3 Probleme propuse . . . . . . . . . . . . . . . . . . . . 169
5.1.2 Cutare binar . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
5.1.2.1 Descrierea general a metodei . . . . . . . . . . . . . 171
5.1.2.2 Descrierea algoritmului de cutare n Pseudocod . . . 172
5.1.2.3 Performana algoritmului de cutare . . . . . . . . . . 174
5.1.2.4 Probleme rezolvate pentru cutarea binar . . . . . . 175
5.1.2.5 Probleme propuse . . . . . . . . . . . . . . . . . . . . 181
5.2 Arbori de cutare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
5.2.1 Arbore binar de cutare ABC . . . . . . . . . . . . . . . . . . . 181
5.2.1.1 Descrierea general a arborelui binar de cutare . . . 181
5.2.1.2 Implementarea unui nod al arborelui ABC . . . . . . 183
5.2.1.3 Operaii ntr-un ABC . . . . . . . . . . . . . . . . . . 183
5.2.1.4 Probleme rezolvate . . . . . . . . . . . . . . . . . . . . 189
5.2.2 Arbore binar de cutare balansat n nlime . . . . . . . . . . 192
5.2.2.1 Descrierea general a arborelui balansat n nlime . 192
5.2.2.2 Implementarea unui nod al arborelui ABCBI . . . . . 194
5.2.2.3 Operaii ntr-un ABCBI . . . . . . . . . . . . . . . . 195
5.2.2.4 Probleme rezolvate . . . . . . . . . . . . . . . . . . . . 200
5.2.2.5 Performanele algoritmilor n ABCBI . . . . . . . . . 206
5.2.3 Arbore binar de cutare balansat n greutate ABCBG . . . . . 206
5.2.3.1 Descrierea general a arborelui balansat n greutate . 206
5.2.3.2 Implementarea unui nod al arborelui ABCBG . . . . 209
CUPRINS 9
5.2.3.3 Operaii ntr-un ABCBG . . . . . . . . . . . . . . . . 209
5.2.3.4 Probleme rezolvate . . . . . . . . . . . . . . . . . . . . 213
5.2.4 Arbore de cutare 2-3 AC2-3 . . . . . . . . . . . . . . . . . . . 221
5.2.4.1 Descrierea general a arborelui de cutare 2-3 . . . . 221
5.2.4.2 Implementarea nodurilor AC2-3 . . . . . . . . . . . . 222
5.2.4.3 Operaii ntr-un AC2-3 . . . . . . . . . . . . . . . . . 223
5.2.4.4 Performanele algoritmilor n AC2-3 . . . . . . . . . . 231
5.3 Funcii de cutare hash . . . . . . . . . . . . . . . . . . . . . . . . . . 241
5.3.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
5.3.2 Funcii hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
5.3.2.1 Funcia hash - metoda mpririi . . . . . . . . . . . . 243
5.3.2.2 Funcia hash - metoda ptratului mediu . . . . . . . . 244
5.3.2.3 Funcia hash - metoda ndoirii . . . . . . . . . . . . . 244
5.3.2.4 Funcia hash - metoda cifrelor . . . . . . . . . . . . . 245
5.3.2.5 Funcia hash - metoda dependent de lungimea cheii 245
5.3.2.6 Funcia hash metoda codicrii algebrice . . . . . . 245
5.3.2.7 Funcii hash - metoda multiplicativ . . . . . . . . . . 246
5.3.3 Performana funciilor hash . . . . . . . . . . . . . . . . . . . . 246
5.3.4 Tehnici de rezoluiune a coliziunilor . . . . . . . . . . . . . . . 246
5.3.4.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . 246
5.3.4.2 Tehnici de rezoluiune a coliziunilor prin adresare de-
schis . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
5.3.4.3 Tehnici de rezoluiune a coliziunilor prin adresare n-
lnuit . . . . . . . . . . . . . . . . . . . . . . . . . . 256
6 Tehnici de sortare 259
6.1 Istoric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
6.2 Algoritmi de sortare . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
6.2.1 Algoritmul de sortare prin metoda bulelor (bubble sort) . . . . 264
6.2.1.1 Descrierea general a metodei . . . . . . . . . . . . . 264
6.2.1.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 264
6.2.1.3 Implementarea algoritmului . . . . . . . . . . . . . . . 266
6.2.1.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 267
6.2.2 Algoritmul de sortare prin selecie . . . . . . . . . . . . . . . . 267
6.2.2.1 Descrierea general a metodei . . . . . . . . . . . . . 267
6.2.2.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 267
6.2.2.3 Implementarea algoritmului . . . . . . . . . . . . . . . 269
6.2.2.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 270
10 CUPRINS
6.2.3 Algoritmul de sortare prin inserare . . . . . . . . . . . . . . . . 270
6.2.3.1 Descrierea general a metodei . . . . . . . . . . . . . 270
6.2.3.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 271
6.2.3.3 Implementarea algoritmului . . . . . . . . . . . . . . . 272
6.2.3.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 273
6.2.4 Algoritmul de sortare Shell . . . . . . . . . . . . . . . . . . . . 274
6.2.4.1 Descrierea general a metodei . . . . . . . . . . . . . 274
6.2.4.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 275
6.2.4.3 Implementarea algoritmului . . . . . . . . . . . . . . . 276
6.2.4.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 278
6.2.5 Algoritmul de sortare rapid (quicksort) . . . . . . . . . . . . . 278
6.2.5.1 Descrierea general a metodei . . . . . . . . . . . . . 278
6.2.5.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 278
6.2.5.3 Implementarea algoritmului . . . . . . . . . . . . . . . 280
6.2.5.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 281
6.2.6 Algoritmul de sortare prin interclasare (mergesort) . . . . . . . 282
6.2.6.1 Descrierea general a metodei . . . . . . . . . . . . . 282
6.2.6.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 282
6.2.6.3 Implementarea algoritmului . . . . . . . . . . . . . . . 283
6.2.6.4 Complexitatea algoritmului . . . . . . . . . . . . . . 286
6.2.7 Algoritmul de sortare prin ansambluri (heapsort) . . . . . . . . 287
6.2.7.1 Descrierea general a metodei . . . . . . . . . . . . . 287
6.2.7.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 287
6.2.7.3 Implementarea algoritmului . . . . . . . . . . . . . . . 291
6.2.7.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 292
6.2.8 Algoritmul de sortare RADIX . . . . . . . . . . . . . . . . . . . 293
6.2.8.1 Descrierea general a metodei . . . . . . . . . . . . . 293
6.2.8.2 Descrierea algoritmului . . . . . . . . . . . . . . . . . 293
6.2.8.3 Implementarea algoritmului . . . . . . . . . . . . . . . 294
6.2.8.4 Complexitatea algoritmului . . . . . . . . . . . . . . . 296
Bibliograe 297
Capitolul 1
Bazele algoritmilor
1.1 Descrierea algoritmilor
1.1.1 Algoritm, program, programare
Ce este un algoritm? O deniie matematic, riguroas, este greu de dat, chiar
imposibil fr a introduce i alte noiuni [Giu, 2004]. Vom ncerca n continuare o
descriere a ceea ce se nelege prin algoritm.
Vom constata c un algoritm este un text nit, o secven nit de propoziii ale
unui limbaj. Din cauz c este inventat special n acest scop, un astfel de limbaj este
numit limbaj de descriere a algoritmilor. Fiecare propoziie a limbajului precizeaz o
anumit regul de calcul, aa cum se va observa atunci cnd vom prezenta limbajul
Pseudocod.
Algoritmii au urmtoarele caracteristici: generalitate, nitudine i unicitate [Liv,
1980].
n descrierea algoritmilor se folosesc mai multe limbaje de descriere, dintre care
cele mai des folosite sunt:
- limbajul schemelor logice;
- limbajul Pseudocod.
1.1.2 Scheme logice
Schema logic este un mijloc de descriere a algoritmilor prin reprezentare grac. Re-
gulile de calcul ale algoritmului sunt descrise prin blocuri (guri geometrice) reprezen-
tnd operaiile (paii) algoritmului, iar ordinea lor de aplicare (succesiunea operaiilor)
11
12 1. Bazele algoritmilor
este indicat prin sgei. Fiecrui tip de operaie i este consacrat o gur geome-
tric (un bloc tip) n interiorul creia se va nscrie operaia din pasul respectiv [Liv,
1980].
Prin execuia unui algoritm descris printr-o schem logic se nelege efectuarea tu-
turor operaiilor precizate prin blocurile schemei logice, n ordinea indicat de sgei.
n descrierea unui algoritm, deci i ntr-o schem logic, intervin variabile care
marcheaz att datele cunoscute iniial, ct i rezultatele dorite, precum i alte rezul-
tate intermediare necesare n rezolvarea problemei. Deoarece variabila joac un rol
central n programare este bine s denim acest concept.
Variabila denete o mrime care i poate schimba valoarea n timp. Ea are un
nume i o valoare. Este posibil ca variabila nc s nu aib asignat o valoare, situaie
n care vom spune c ea este neiniializat.
Valorile pe care le poate lua variabila aparin unei mulimi D pe care o vom numi
domeniul variabilei. Variabila este folosit cu un anumit scop, ea noteaz o anumit
mrime, cu o anumit semnicaie. n concluzie o variabil este cunoscut prin (nume,
domeniul D, valoare, semnicaie), unde valoarea aparine mulimii D.
Pentru claritatea textului unui algoritm este important s se cunoasc semnicaia
ecrei variabile, s e menionat expres aceast semnicaie. n nici un caz nu se
recomand s se foloseasc acelai nume pentru variabile cu semnicaii diferite, caz
care provoc confuzii i chiar erori grave. Vom enuna acestea sub forma unor reguli
cu care e bine s ne obinuim i s le respectm n activitatea de programare.
1.1.3 Limbajul PSEUDOCOD
Limbajul Pseudocod este un limbaj folosit n scopul proiectrii algoritmilor i este
format din propoziii asemntoare propoziiilor limbii romne, care corespund struc-
turilor de calcul folosite n construirea algoritmilor. Acesta va limbajul folosit de
noi n proiectarea algoritmilor i va denit n cele ce urmeaz.
innd seama c realizarea unui algoritm pentru rezolvarea unei probleme nu
este ntotdeauna o sarcin simpl, c n acest scop sunt folosite anumite metode pe
care le vom descrie n capitolele urmtoare, n etapele intermediare pentru obinerea
algoritmului vom folosi propoziii curente din limba romn [Fre, 1986].
Acestea sunt considerate elemente nenisate din algoritm, asupra crora trebuie
s se revin i le vom numi propoziii nestandard. Deci limbajul Pseudocod are dou
tipuri de propoziii: propoziii standard, care vor prezentate ecare cu sintaxa i
semnicaia (semantica) ei i propoziii nestandard. Aa cum se va arta mai trziu,
propoziiile nestandard sunt texte care descriu pri ale algoritmului nc incomplet
elaborate, nenisate, asupra crora urmeaz s se revin. Ele se recunosc prin faptul
1.1. Descrierea algoritmilor 13
c ncep ntotdeauna cu semnul @ i se termin cu caracterul ;.
Pe lng aceste propoziii standard i nestandard, n textul algoritmului vom mai
introduce propoziii explicative, numite comentarii. Pentru a le distinge de celelalte
propoziii, comentariile vor nchise ntre acolade. Rolul lor va explicat puin mai
trziu.
Prin execuia unui algoritm descris n Pseudocod se nelege efectuarea operaiilor
precizate de propoziiile algoritmului, n ordinea citirii lor (de sus n jos i de la stnga
spre dreapta).
Propoziiile standard ale limbajului Pseudocod folosite n aceast lucrare, core-
spund structurilor de calcul prezentate n Figura 1.1 i vor prezentate n continuare.
Da
Nu
cond
A
A
Nu Da
A
cond
B
B
(a) structura
secvenial
(b) structura
alternativ
(c) structura
repetitiv
Figura 1.1: Structuri elementare de calcul
n Figura 1.1, prin A, B s-au notat subscheme logice, adic secvene de oricte
structuri construite conform celor trei reguli menionate n continuare.
Structura secvenial (Figura 1.1 a) este redat prin concatenarea propoziiilor,
simple sau compuse, ale limbajului Pseudocod, care vor executate n ordinea ntl-
nirii lor n text.
Propoziiile simple din limbajul Pseudocod sunt CITETE, TIPARETE, FIE
i apelul de subprogram. Propoziiile compuse corespund structurilor alternative i
repetitive.
Structura alternativ din Figura 1.1 b este redat n Pseudocod prin propoziia
DAC, prezentat n seciunea 1.1.3.2, iar structura repetitiv din Figura 1.1 c este
redat n Pseudocod prin propoziia CTTIMP, prezentat n seciunea 1.1.3.3.
Bohm i Jacopini [Bh, 1966] au demonstrat c orice algoritm poate descris
folosind numai aceste trei structuri de calcul.
14 1. Bazele algoritmilor
Propoziiile DATE i REZULTATE sunt folosite n faza de specicare a prob-
lemelor, adic enunarea riguroas a acestora.
Fiecare propoziie standard ncepe cu un cuvnt cheie, aa cum se va vedea n
cele ce urmeaz. Pentru a deosebi aceste cuvinte de celelalte denumiri, construite de
programator, n acest capitol vom scrie cuvintele cheie cu litere mari. Menionm c
propoziiile simple se termin cu caracterul ; n timp ce propoziiile compuse, deci
cele n interiorul crora se a alte propoziii, au un marcaj de sfrit propriu. De
asemenea, menionm c propoziiile limbajului Pseudocod vor luate n seam n
ordinea ntlnirii lor n text, asemenea oricrui text al limbii romne.
Propoziia DATE se folosete pentru precizarea datelor iniiale, deci a datelor
considerate cunoscute n problem (numite i date de intrare) i are sintaxa:
DATE list ;
unde list conine toate numele variabilelor a cror valoare iniial este cunoscut.
n general, prin list se nelege o succesiune de elemente de acelai fel desprite
prin virgul. Deci n propoziia DATE, n dreapta acestui cuvnt se vor scrie acele
variabile care marcheaz mrimile cunoscute n problem.
Pentru precizarea rezultatelor dorite se folosete propoziia standard:
REZULTATE list;
n construcia "list" ce urmeaz dup cuvntul REZULTATE ind trecute numele
variabilelor care marcheaz (conin) rezultatele cerute n problem.
Acum putem preciza mai exact ce nelegem prin cunoaterea complet a problemei
de rezolvat. Evident, o problem este cunoscut atunci cnd se tie care sunt datele
de intrare ce denesc problema dat i rezultatele ce trebuiesc obinute.
Deci, pentru cunoaterea unei probleme este necesar precizarea variabilelor care
marcheaz datele considerate cunoscute n problem, care va reectat printr-o
propoziie DATE i cunoaterea exact a rezultatelor problemei, care se va reecta
prin propoziia REZULTATE.
Variabilele prezente n aceste propoziii au anumite semnicaii, presupuse cunos-
cute. Cunoaterea acestora, scrierea lor explicit, formeaz ceea ce vom numi n
continuare specicarea problemei. Specicarea unei probleme este o activitate foarte
important dar nu i simpl.
De exemplu, pentru rezolvarea ecuaiei de gradul al doilea, specicarea problemei,
poate :
DATE a,b,c; { Coecienii ecuaiei }
REZULTATE x1,x2; { Rdcinile ecuaiei }
1.1. Descrierea algoritmilor 15
Aceast specicaie este ns incomplet. Nu ntotdeauna ecuaia are rdcini
reale. n cazul n care rdcinile sunt complexe putem nota prin x1, x2 partea re-
al, respectiv partea imaginar a rdcinilor. Sau, pur i simplu, nu ne intereseaz
valoarea rdcinilor n acest caz, ci doar faptul c ecuaia nu are rdcini reale.
Cu alte cuvinte avem nevoie de un mesaj care s ne indice aceast situaie (vezi
exemplul 1.1.2), sau de un indicator, e el numit ind. Acest indicator va lua valoarea
1 dac rdcinile sunt reale i valoarea 0 n caz contrar. Deci specicaia mai complet
a problemei este:
DATE a,b,c; { Coecienii ecuaiei }
REZULTATE ind, {ind=1 pt. rdcini reale, 0 pt complexe}
x1,x2; {Rdcinile ecuaiei, n cazul ind=1, respectiv}
{partea real i cea imaginar n cazul ind=0}
Evident c specicarea problemei este o etap important pentru gsirea unei
metode de rezolvare i apoi n proiectarea algoritmului corespunztor. Nu se poate
rezolva o problem dac aceasta nu este bine cunoscut, adic nu avem scris speci-
carea problemei.
"Cunoate complet problema" este prima regul ce trebuie respectat pentru a
obine ct mai repede un algoritm corect pentru rezolvarea ei.
1.1.3.1 Algoritmi liniari
Propoziiile CITETE i TIPRETE sunt folosite pentru iniializarea variabilelor
de intrare cu datele cunoscute n problem, respectiv pentru tiprirea (aarea) rezul-
tatelor obinute. n etapa de programare propriu-zis acestor propoziii le corespund,
ntr-un limbaj de programare, instruciuni de intrare-ieire.
Propoziia CITETE se folosete pentru precizarea datelor iniiale, deci a datelor
considerate cunoscute n problem (numite i date de intrare) i are sintaxa:
CITETE list ;
unde list conine toate numele variabilelor a cror valoare iniial este cunoscut.
Deci n propoziia CITETE, n dreapta acestui cuvnt se vor scrie acele variabile
care apar n propoziia DATE n specicarea problemei. Se subnelege c aceste
variabile sunt iniializate cu valorile cunoscute corespunztoare.
Pentru aarea rezultatelor dorite, pe care calculatorul o va face prin tiprirea lor
pe hrtie sau aarea pe ecran, se folosete propoziia standard:
TIPRETE list ;
16 1. Bazele algoritmilor
n construcia list ce urmeaz dup cuvntul TIPRETE ind trecute numele vari-
abilelor a cror valori dorim s le am. Ele sunt de obicei rezultatele cerute n
problem, specicate i n propoziia REZULTATE.
Blocului de atribuire dintr-o schem logic i corespunde n Pseudocod propoziia
standard:
[FIE] var := expresie ;
Aceast propoziie este folosit pentru a indica un calcul algebric, al expresiei
care urmeaz dup simbolul de atribuire ":=" i de atribuire a rezultatului obinut
variabilei var. Expresia din dreapta semnului de atribuire poate orice expresie
algebric simpl, cunoscut din manualele de matematic din liceu i construit cu
cele patru operaii: adunare, scdere, nmulire i mprire (notate prin caracterele
+, -, *, respectiv /).
Prin scrierea cuvntului FIE ntre paranteze drepte se indic posibilitatea omiterii
acestui cuvnt din propoziie. El s-a folosit cu gndul ca ecare propoziie s nceap
cu un cuvnt al limbii romne care s reprezinte numele propoziiei. De cele mai multe
ori vom omite acest cuvnt. Atunci cnd vom scrie succesiv mai multe propoziii de
atribuire vom folosi cuvntul FIE numai n prima propoziie, omindu-l n celelalte.
Din cele de mai sus rezult c o variabil poate iniializat att prin atribuire
(deci dac este variabila din stnga semnului de atribuire :=) ct i prin citire (cnd
face parte din lista propoziiei CITETE). O greeal frecvent, pe care o fac n-
ceptorii este folosirea variabilelor neiniializate. Evident, c o expresie n care apar
variabile care nu au valori nu poate calculat, ea nu este denit. Deci nu se folosesc
variabile neiniializate.
Pentru a marca nceputul descrierii unui algoritm vom folosi propoziia:
ALGORITMUL nume ESTE:
De asemenea, prin propoziia:
SFALGORITM
vom marca sfritul unui algoritm.
Algoritmii care pot descrii folosind numai propoziiile prezentate mai sus se
numesc algoritmi liniari.
Ca exemplu de algoritm liniar prezentm un algoritm ce determin viteza V cu
care a mers un autovehicul ce a parcurs distana D n timpul T.
1.1. Descrierea algoritmilor 17
Exemplul 1.1.1.
ALGORITMUL Viteza ESTE: { Calculeaz viteza }
{ D = Distana (spaiul) }
{ T = Timpul; V = Viteza }
CITETE D,T; { V:= spaiu/timp }
FIE V:=D/T;
TIPRETE V;
SFALGORITM
1.1.3.2 Algoritmi cu ramicaii
Foarte muli algoritmi execut anumite calcule n funcie de satisfacerea unor condiii.
Aceste calcule sunt redate de structura alternativ prezentat n Figura 1.1 b, creia
i corespunde propoziia Pseudocod:
DAC cond
ATUNCI A
ALTFEL B
SFDAC
sau varianta redus a ei:
DAC cond
ATUNCI A
SFDAC
folosit n cazul n care grupul de propoziii B este vid.
Aceste propoziii redau n Pseudocod structura alternativ de calcul. n primul
rnd, este necesar vericarea condiiei scrise dup cuvntul DAC. n cazul c
aceast condiie este adevrat se va executa grupul de propoziii A. n cazul n care
aceast condiie este fals se va executa grupul de propoziii B, dac este prezent
ramura ALTFEL. Indiferent care dintre secvenele A sau B a fost executat, se va
continua cu propoziia urmtoare propoziiei DAC, ce urmeaz dup marcatorul de
sfrit SFDAC.
O generalizare a structurii alternative realizat de propoziia DAC este structura
selectiv:
SELECTEAZ i DINTRE
v1: A1;
v2: A2;
. . .
vn: An
SFSELECTEAZ
18 1. Bazele algoritmilor
structur echivalent cu urmtorul text Pseudocod:
DAC i=v1
ATUNCI A1
ALTFEL
DAC i=v2
ATUNCI A2
ALTFEL
. . .
DAC i=vn
ATUNCI An
SFDAC
...
SFDAC
SFDAC
Cu propoziiile prezentate pn acum putem descrie un numr nsemnat de algo-
ritmi. Acetia se numesc algoritmi cu ramicaii.
De exemplu, vom descrie un algoritm pentru rezolvarea ecuaiei de gradul al doilea.
Am prezentat n 1.1.3 aceast problem i am precizat semnicaia variabilelor res-
pective. Pe lng aceste variabile, pentru rezolvarea problemei mai avem nevoie de
dou variabile auxiliare:
delta - pentru discriminantul ecuaiei;
r - pentru valoarea radicalului folosit n calculul rdcinilor.
Exemplul 1.1.2.
ALGORITMUL EcGrDoi ESTE: { Rezolvarea }
{ ecuaiei de gradul doi }
CITETE a,b,c; { a,b,c = coecienii ecuaiei }
FIE delta:=b*b-4*a*c;
DAC delta<0
ATUNCI ind:=0; {Cazul rdcini complexe }
@r:=radical din (-delta);
x1:=-b/(a+a);
x2:=r/(a+a);
ALTFEL ind:=1; {cazul rdcini reale }
@r:=radical din delta;
x1:=(-b-r)/(a+a);
x2:=(-b+r)/(a+a);
SFDAC
1.1. Descrierea algoritmilor 19
TIPRETE ind, x1,x2;
SFALGORITM
1.1.3.3 Algoritmi ciclici
n rezolvarea multor probleme trebuie s efectum aceleai calcule de mai multe ori,
sau s repetm calcule asemntoare. De exemplu, pentru a calcula suma a dou
matrice va trebui s adunm un element al primei matrice cu elementul de pe aceeai
poziie din a doua matrice, aceast adunare repetndu-se pentru ecare poziie n
parte. Alte calcule trebuiesc repetate n funcie de satisfacerea unor condiii.
n acest scop n limbajul Pseudocod exist trei propoziii standard: CTTIMP,
REPET i PENTRU. Propoziia CTTIMP are sintaxa:
CTTIMP cond EXECUT A SFCT
i cere execuia repetat a grupului de propoziii A, n funcie de condiia "cond". Mai
exact, se evalueaz condiia "cond"; dac aceasta este adevrat se execut grupul A
i se revine la evaluarea condiiei. Dac ea este fals execuia propoziiei se termin
i se continu cu propoziia care urmeaz dup SFCT.
Dac de prima dat condiia este fals grupul A nu se va executa niciodat, altfel
se va repeta execuia grupului de propoziii A pn cnd condiia va deveni fals. Din
cauz c nainte de execuia grupului A are loc vericarea condiiei, aceast structur
se mai numete structur repetitiv condiionat anterior. Ea reprezint structura
repetitiv prezentat n Figura 1.1 c.
Ca exemplu de algoritm n care se folosete aceast structur ciclic s rezolvm
algoritmul lui Euclid pentru calculul celui mai mare divizor comun a dou numere.
Exemplul 1.1.3.
ALGORITMUL Euclid ESTE: { Cel mai mare divizor comun}
CITETE n1,n2; {Cele dou numere a cror divizor se cere}
FIE d:=n1; i:=n2;
CTTIMP i0 EXECUT
r:=d modulo i; d:=i; i:=r
SFCT
TIPRETE d; { d= cel mai mare divizor comun}
SFALGORITM {al numerelor n1 i n2 }
n descrierea multor algoritmi se ntlnete structura repetitiv condiionat pos-
terior:
REPET A PNCND cond SFREP
20 1. Bazele algoritmilor
structur echivalent cu:
A
CTTIMP not (cond) EXECUT A SFCT
Deci ea cere execuia necondiionat a lui A i apoi vericarea condiiei "cond".
Va avea loc repetarea execuiei lui A pn cnd condiia devine adevrat. Deoarece
condiia se veric dup prima execuie a grupului A aceast structur este nu-
mit structura repetitiv condiionat posterior, prima execuie a blocului A ind
necondiionat.
Ca exemplu de algoritm n care se folosete aceast propoziie, vom scrie un al-
goritm pentru aproximarea numrului e cu o precizie dat de numrul eps pozitiv,
folosindu-ne de dezvoltarea n serie:
e = 1 + 1/1! + 1/2! + 1/3! + ... + 1/n! + ...
Specicaia problemei n Pseudocod este:
DATE eps ; { eps>0 }
REZULTATE ve; { aproximarea seriei cu o eroare < eps }
{ deci r= [ e-ve [<eps }
Pentru rezolvarea problemei trebuie s tim c restul r
n
din scrierea
e = 1 + 1/1! + 1/2! + 1/3! +... + 1/n! +... = s
n
+r
n
este mai mic dect ultimul termen adunat la s
n
, deci r
n
< t
n
, unde t
n
= 1/n!
Variabilele auxiliare folosite n descrierea algoritmului sunt:
n - precizeaz ultima fracie adunat;
t - este valoarea acestei fracii.
Exemplul 1.1.4.
ALGORITMUL Nre ESTE: { Calculul lui e cu precizia eps }
CITETE eps; { eps > 0 }
FIE ve:=2.5; t:=0.5; n:=2;
REPET
n:=n+1
t:=t/n;
ve:=ve+t;
PNCND t<eps SFREP
TIPRETE ve;
SFALGORITM
1.1. Descrierea algoritmilor 21
O alt propoziie care cere execuia repetat a unei secvene A este propoziia
PENTRU c:=li; lf [;p] EXECUT A SFPENTRU
Ea denete o structura repetitiv predenit, cu un numr determinat de execuii
ale grupului de propoziii A i este echivalent cu secvena:
c:=li ; nal:=lf ;
REPET
A
c:=c+p
PNCND (c>nal i p>0) sau (c<nal i p<0) SFREP
Se observ c, n sintaxa propoziiei PENTRU, pasul p este nchis ntre paranteze
drepte. Prin aceasta indicm faptul c el este opional, putnd s lipseasc. n cazul
n care nu este prezent, valoarea lui implicit este 1.
Semnicaia propoziiei PENTRU este clar. Ea cere repetarea grupului de
propoziii A pentru toate valorile contorului c cuprinse ntre valorile expresiilor li
i lf (calculate o singur dat nainte de nceperea ciclului), cu pasul p. Se subnelege
c nu trebuie s modicm valorile contorului n nici o propoziie din grupul A. De
multe ori, aceste expresii sunt variabile simple, iar unii programatori modic n A
valorile acestor variabile, nclcnd semnicaia propoziiei PENTRU.
Observaie. Nu recalcula limitele i nu modica variabila de ciclare (contorul) n
interiorul unei structuri repetitive PENTRU.
S observm, de asemenea, c prima execuie a grupului A este obligatorie, abia
dup modicarea contorului vericndu-se condiia de continuare a execuiei lui A.
Ca exemplu, s descriem un algoritm care gsete minimul i maximul componen-
telor unui vector de numere reale.
Vom nota prin X acest vector, deci X = (x
1
, x
2
, ... , x
n
).
Observaie. Vom nota n limbajul Pseudocod componenta x
i
a unui vector cu x[i].
Specicaia problemei este urmtoarea:
DATE n,(x[i] ,i=1,n);
REZULTATE valmin,valmax;
iar semnicaia acestor variabile se nelege din cele scrise mai sus. Pentru rezolvarea
problemei vom examina pe rnd cele n componente. Pentru a parcurge cele n com-
ponente avem nevoie de un contor care s precizeze poziia la care am ajuns. Fie i
acest contor. Avem urmtorul algoritm:
22 1. Bazele algoritmilor
Exemplul 1.1.5.
ALGORITMUL MinMax ESTE: { Calculul }
{ valorii minime i maxime }
CITETE n,( x[i],i=1,n);
FIE valmin:=x[1]; valmax:=x[1];
PENTRU i:=2;n EXECUT
DAC x[i]<valmin
ATUNCI valmin:=x[i]
SFDAC
DAC x[i]>valmax
ATUNCI valmax:=x[i]
SFDAC
SFPENTRU
TIPRETE valmin,valmax;
SFALGORITM
Un rol important n claritatea textului unui algoritm l au denumirile alese pentru
variabile. Ele trebuie s reecte semnicaia variabilelor respective. Deci alege denu-
miri sugestive pentru variabile, care s reecte semnicaia lor. Putem formula astfel
regula de mai jos:
Observaie. Alege denumiri sugestive pentru variabile! n exemplul de mai sus
denumirile valmin i valmax spun clar cititorului ce s-a notat prin aceste variabile.
1.1.4 Calculul efectuat de un algoritm
Fie X
1
, X
2
, ..., X
n
, variabilele ce apar n algoritmul A. n orice moment al execuiei
algoritmului, ecare variabil are o anumit valoare, sau este nc neiniializat.
Vom numi stare a algoritmului A cu variabilele menionate, vectorul s =
(s
1
, s
2
, ..., s
n
) format din valorile curente ale celor n variabile ale algoritmului.
Este posibil ca variabila X
j
s e nc neiniializat, deci s nu aib valoare
curent, caz n care valoarea s
j
este nedenit, lucru notat n continuare prin semnul
ntrebrii ?.
Prin executarea unei anumite instruciuni unele variabile i schimb valoarea, deci
algoritmul i schimb starea.
Se numete calcul efectuat de algoritmul A o secven de stri s
0
, s
1
, s
2
, ..., s
m
unde s
0
este starea iniial cu toate variabilele neiniializate, iar s
m
este starea n
care se ajunge dup execuia ultimei propoziii din algoritm.
1.1. Descrierea algoritmilor 23
Exemplul 1.1.6. Algoritmul Nrdivizori calculeaz numrul de divizori proprii ai
unui numr dat X1.
P1 CITESTE X1;
P2 FIE X2:=1;
P3 FIE X3:=0;
P4 CTTIMP X1 ,= X2 EXECUT
P5 X2:=X2+1;
P6 DAC X1 modulo X2 = 0
ATUNCI X3:=X3+1
SFDAC
SFCT
P7 TIPRETE X1,X3
Presupunnd c X1 = 6, atunci strile prin care trece acest algoritm, deci calculul
efectuat de el, este redat mai jos.
s0 = ( ?, ?, ?)
P1(s0) = s1 = ( 6, ?, ?)
P2(s1) = s2 = ( 6, 1, ?)
P3(s2) = s3 = ( 6, 1, 0)
P5(s3) = s4 = ( 6, 2, 0)
P6(s4) = s5 = ( 6, 2, 1)
P5(s5) = s6 = ( 6, 3, 1)
P6(s6) = s7 = ( 6, 3, 2)
P5(s7) = s8 = ( 6, 4, 2)
P6(s8) = s9 = ( 6, 4, 2)
P5(s9) = s10= ( 6, 5, 2)
P6(s10)= s11= ( 6, 5, 2)
P6(s11)= s12= ( 6, 5, 2)
P5(s12)= s13= ( 6, 6, 2)
P7(s13)= s14= ( 6, 6, 2)
Execuia (calculul) se va ncheia cu tiprirea valorilor 6 i 2 a celor dou variabile
din propoziia P7. Se poate observa c cele dou valori tiprite reprezint, prima
(X1), numrul citit, iar a doua (X3), rezultatul obinut. Rezultatul X3 reprezint
numrul divizorilor proprii ai lui X1.
24 1. Bazele algoritmilor
1.1.5 Ranare n pai succesivi
Adeseori, algoritmul de rezolvare a unei probleme este rezultatul unui proces complex,
n care se iau mai multe decizii. Observaia este adevrat mai ales n cazul prob-
lemelor complicate, dar i pentru probleme mai simple din procesul de nvmnt.
Este vorba de un proces de detaliere pas cu pas a specicaiei problemei, proces de-
numit i proiectare descendent, sau ranare n pai succesivi. Algoritmul apare n
mai multe versiuni succesive, ecare versiune ind o detaliere a versiunii precedente.
n versiunile iniiale apar propoziii nestandard, clare pentru cititor, dar nepre-
cizate prin propoziii standard. Urmeaz ca n versiunile urmtoare s se revin
asupra lor. Algoritmul apare astfel n versiuni succesive, tot mai complet de la o
versiune la alta.
Ca exemplu de algoritm obinut prin ranare succesiv vom proiecta un algoritm
care s rezolve urmtoarea problem:
Exemplul 1.1.7. Se dau numerele ntregi X = (x
1
, x
2
, ..., x
n
). Se cere s se rein
ntr-un vector Y toate componentele distincte ale vectorului X (deci Y are numai
componente distincte).
Specicarea problemei:
DATE n, (x[i], i=1,n);
REZULTATE (y[j], j=1,k); X=Y, unde X este mulimea ce
conine toate numerele x[i], iar Y = mulimea
ce conine pe y[j], j=1,k i y[l] ,= y[j] pentru l ,= j
Variabilele intermediare folosite i semnicaia lor, precum i metoda folosit vor
rezultatul ranrilor succesive i vor nelese din versiunilor respective.
Exemplul 1.1.8.
ALGORITMUL Distinct ESTE: { Versiunea 1 }
CITETE n, (x[i], i=1,n);
FIE y[1]:=x[1]; k:=1;
@Examineaz celelalte numere i dac trebuie adaug-le n Y;
TIPRETE (y[j], j=1,k);
SFALGORITM
Pentru a parcurge celelalte numere avem nevoie de un contor, e el i, i de folosirea
propoziiei PENTRU. Ajungem la varianta:
Exemplul 1.1.9.
ALGORITMUL Distinct ESTE: { Versiunea 2 }
1.1. Descrierea algoritmilor 25
CITETE n, (x[i], i=1,n);
FIE y[1]:=x[1]; k:=1;
PENTRU i:=2;n EXECUT
@Veric dac x[i] aparine mulimii Y;
@Dac nu aparine atunci adaug pe x[i] la Y;
SFPENTRU
TIPRETE (y[j], j=1,k);
SFALGORITM
Decizia ce trebuie luat este cum s vericm apartenena unui elementul x
i
la
mulimea Y format din k elemente. Pentru aceasta calculm indicatorul r, egal cu
0 dac rspunsul este negativ i egal cu 1 n caz contrar. Aceasta se poate face cu
secvena de propoziii:
FIE r:=0; j:=1;
CTTIMP (r=0) i (j<=k) EXECUT
DAC x[i]=y[j]
ATUNCI r:=1;
ALTFEL j:=j+1;
SFDAC
SFCT
Ajungem la versiunea nal a algoritmului dorit:
Exemplul 1.1.10.
ALGORITMUL Distinct ESTE: { Versiunea 3 }
CITETE n, (x[i], i=1,n);
FIE y[1]:=x[1]; k:=1;
PENTRU i:=2;n EXECUT
FIE r:=0; j:=1;
CTTIMP (r=0) i (j<=k) EXECUT
DAC x[i]=y[j]
ATUNCI r:=1;
ALTFEL j:=j+1;
SFDAC
SFCT
DAC r=0
ATUNCI k:=k+1; y[k]:=x[i];
SFDAC
SFPENTRU
26 1. Bazele algoritmilor
TIPRETE (y[j], j=1,k);
SFALGORITM
Rezult ca o consecin, o alt regul important n proiectarea algoritmului:
Observaie. Amn pe mai trziu detaliile nesemnicative; concentreaz-i atenia
la deciziile importante ale momentului.
1.1.6 Probleme propuse
S se descrie n Pseudocod algoritmii pentru rezolvarea urmtoarelor probleme:
1. Se d numrul natural n. S se determine primele n numere prime.
2. Se d n N. S se determine primele n triplete de numere pitagorice. (Tripletul
(i, j, k) constituie numere pitagorice dac i < j < k i i
2
+j
2
= k
2
).
3. Tripletul (z,l,a) reprezint o dat curent zi, lun, an. Determinai a cta zi din
an este aceast dat.
4. Se cunoate data curent (zc,lc,ac) i ziua de natere a unei persoane (zn,ln,an).
Determinai vrsta n zile a acestei persoane.
5. Cunoscnd n ce zi din sptmn a fost 1 ianuarie, determinai ce zi din sp-
tmn va n ziua precizat prin tripletul (z,l,a).
1.1.7 Subalgoritmi
1.1.7.1 Conceptul de subalgoritm
Orice problem poate apare ca o subproblem S a unei probleme mai complexe C.
Algoritmul de rezolvare a problemei S devine n acest caz o parte din algoritmul de
rezolvare a problemei C, parte numit subalgoritm.
Pentru a deni un subalgoritm vom folosi propoziia standard:
SUBALGORITMUL nume(lpf ) ESTE:
unde nume este numele subalgoritmului denit, iar lpf este lista parametrilor for-
mali. Acetia sunt formai din variabilele care marcheaz datele de intrare (cele pre-
supuse cunoscute) i variabilele care marcheaz datele de ieire (rezultatele obinute
de subalgoritm).
Aceast propoziie este urmat de textul efectiv al subalgoritmului, text care pre-
cizeaz calculele necesare rezolvrii subproblemei corespunztoare. Descrierea se va
ncheia cu cuvntul SFSUBALGORITM sau SF-nume.
1.1. Descrierea algoritmilor 27
Exemplul 1.1.11. S considerm ca exemplu un subalgoritm cu numele Maxim,
care determin maximul dintre componentele vectorului X = (x
1
, x
2
, . . . , x
n
).
Datele cunoscute pentru acest subalgoritm sunt vectorul X i numrul n al com-
ponentelor vectorului X. Ca rezultat vom obine maximul cerut, pe care-l vom nota
cu max. n concluzie, specicarea subproblemei este:
DATE n, X;
REZULTATE max;
Deci lista parametrilor formali conine trei variabile, n, X i max. Pentru a gsi
maximul parcurgem toate componentele vectorului X, reinnd n variabila max val-
oarea cea mai mare ntlnit. Evident, trebuie s ncepem cu max = x
1
. Subalgorit-
mul este prezentat n continuare.
SUBALGORITMUL Maxim(n,X,max) ESTE: {Calculeaz valoarea maxim}
{dintre cele n componente ale lui X}
FIE max:=x[1];
PENTRU i:=2;n EXECUT
DAC x[i]>max
ATUNCI max:=x[i];
SFDAC
SFPENTRU
SF-Maxim
Una dintre greelile frecvente ale nceptorilor const n introducerea n corpul
subalgoritmului a unor instruciuni de citire a datelor presupuse cunoscute, sau de
tiprire a rezultatelor obinute. Acest lucru denot o nenelegere a conceptului de
subalgoritm i a rolului subalgoritmilor n programare. Subalgoritmul rezolv o sub-
problem - care e o parte dintr-o problema complex de rezolvat.
De obicei, datele presupuse cunoscute pentru subproblem, nu sunt datele iniiale
cunoscute n problema iniial; ele sunt rezultatul unor calcule efectuate nainte de
apelul subalgoritmului. n general, ele nu sunt cunoscute de programator, ind rezul-
tatul unor calcule fcute de algoritm. Analog, rezultatele obinute de subalgoritm
sunt adesea doar valori intermediare, necesare n continuare, fr a ns obligato-
riu i rezultate ale problemei iniiale. De aceea nu este necesar s le tiprim; este
sarcina algoritmului apelant s trateze rezultatele obinute de subalgoritm cum crede
de cuviin.
Observaie. Evit s citeti i s tipreti date ntr-un subalgoritm.
Excepie de la aceast regul o fac subalgoritmii dedicai citirii unor date, sau
tipririi unor rezultate. n acest caz, citirea, respectiv tiprirea unor date este cerut
28 1. Bazele algoritmilor
expres n enunul subproblemelor corespunztoare. Mai mult, un subalgoritm este
scris pentru a rezolva subproblema corespunztoare indiferent de locul, timpul sau
complexitatea problemei n care este folosit. De aceea, trebuie s concepem subalgo-
ritmii cu gndul la refolosirea lor.
S considerm n cele ce urmeaz, urmtorul exemplu. n cadrul multor algoritmi
este necesar calculul valorilor unei funcii n diferite puncte. Este necesar s denim
funcia printr-un subalgoritm de tip funcie.
Pentru denirea unui subalgoritm de tip funcie se folosete un antet care pre-
cizeaz numele funciei i variabilele de care depinde ea. Subalgoritmul are forma:
FUNCIA nume(lpf) ESTE: {Antetul funciei}
ext {corpul funciei}
SF-nume {marca de sfrit}
n corpul funciei trebuie s existe cel puin o instruciune de atribuire n care
numele funciei apare n membrul stng, deci prin care funcia primete o valoare.
Exemplul 1.1.12. S considerm funcia numar : R {2,3,4,5}, denit matematic
astfel:
numar(x) =
_
_
2, dac x < 0, 2
3, dac 0, 2 x < 0, 5
4, dac 0, 5 0, 9
5, dac x 0, 9
n Pseudocod descrierea este urmtoarea:
FUNCIA numar(x) ESTE:
DAC x<0.2
ATUNCI numar:=2;
ALTFEL
DAC x<0.5
ATUNCI numar:=3;
ALTFEL
DAC x<0.9
ATUNCI numar:=4;
ALTFEL numar:=5;
SFDAC
SFDAC
SFDAC
SF-numar
1.1. Descrierea algoritmilor 29
Am vzut c deniia unei funcii const dintr-un antet i dintr-un bloc care va
deni aciunile prin care se calculeaz valoarea funciei. n antet se precizeaz numele
funciei i lista parametrilor formali.
n concluzie, exist dou categorii de subalgoritmi: de tip funcie i subalgoritmi
propriu-zii, crora li se mai spune i proceduri. Importana lor va subliniat prin
toate exemplele care urmeaz n acest curs. n ncheiere, menionm c subprogramele
de tip funcie se folosesc n scopul denirii funciilor, aa cum sunt cunoscute ele din
matematic, n timp ce subalgoritmii de tip procedur se refer la rezolvarea unor
probleme ce apar ca subprobleme, ind algoritmi de sine stttori.
1.1.7.2 Apelul unui subalgoritm
Am vzut c un subalgoritm este dedicat rezolvrii unei subprobleme S care apare
ntr-o problem mai complex C. Algoritmul corespunztor problemei C va folosi toate
operaiile necesare rezolvrii problemei S, deci va folosi ca parte ntregul subalgoritm
conceput pentru rezolvarea subproblemei S. Spunem c el va apela acest subalgoritm.
n Pseudocod apelul unei funcii se face scriind ntr-o expresie numele funciei
urmat de lista parametrilor actuali. Trebuie s existe o coresponden biunivoc
ntre parametrii actuali i cei formali folosii n deniia funciei. Dei denumirile
variabilelor din cele dou liste pot s difere, rolul variabilelor care se corespund este
acelai. Mai exact, parametrul formal i parametrul actual corespunztor trebuie
s se refere la aceeai entitate, trebuie s aib aceeai semnicaie, s reprezinte
aceeai structur de date. Putem considera c n timpul execuiei algoritmului cei doi
parametri devin identici.
Folosirea unui subalgoritm n cadrul unui algoritm se face apelnd acest subalgo-
ritm prin propoziia standard:
CHEAM nume(lpa);
unde nume este numele subalgoritmului apelat, iar lpa este lista parametrilor ac-
tuali. Aceast list conine toate datele de intrare (cele cunoscute n subproblema
corespunztoare) i toate rezultatele obinute n subalgoritm. i n acest caz ntre
lista parametrilor formali din deniia subalgoritmului i lista parametrilor actuali
din propoziia de apel trebuie s existe o coresponden biunivoc, ca i n cazul
funciilor.
Ca o prim vericare a respectrii acestei corespondene, subliniem c numrul
parametrilor actuali trebuie s coincid cu numrul parametrilor formali.
Ca exemplu de apelare a funciilor, prezentm n continuare un algoritm pentru
a calcula a cta zi din anul curent este ziua curent (zi,luna,an). El folosete un
30 1. Bazele algoritmilor
subalgoritm de tip funcie pentru a obine numrul zilelor lunii cu numrul de ordine
i i un altul pentru a verica dac un an este bisect sau nu. Aceste dou funcii sunt:
- NRZILE(i) furnizeaz numrul zilelor existente n luna i a unui an nebisect;
- BISECT(an) adevrat dac anul dintre paranteze este bisect.
Exemplul 1.1.13.
ALGORITMUL NUMR_ZILE ESTE: {A cta zi dintr-un an?}
CITETE zi, luna, an; {introducei data curent}
FIE nr:=zi; {nr va numrul care reprezint a cta zi }
{din an este data curent}
DAC luna>1 ATUNCI
PENTRU i:=1; luna-1 EXECUT
nr:=nr+NRZILE(i);
SFPENTRU
SFDAC
DAC luna>2 ATUNCI
DAC BISECT(an) ATUNCI
nr:=nr+1;
SFDAC
SFDAC
TIPRETE nr;
SFALGORITM
S observm c n proiectarea acestui algoritm nu este necesar s cunoatem deta-
liat subalgoritmii folosii, ci doar specicarea acestor subalgoritmi, numele lor i lista
parametrilor formali. La acest nivel accentul trebuie s cad pe proiectarea algorit-
mului apelant, urmnd s se revin ulterior la proiectarea subalgoritmilor apelai,
conform specicaiei acestora. n cazul de fa este necesar descrierea funciilor
NRZILE(i) i BISECT(an). Lsm aceast descriere ca exerciiu pentru cititor.
Exemplul 1.1.14. Un alt exemplu de apelare a unei proceduri este algoritmul care
efectueaz suma a dou polinoame. Un polinom P(X) este determinat prin gradul su,
m, i prin vectorul coecienilor P = (p
0
, p
1
, . . . , p
m
) (prin p
i
s-a notat coecientul
lui X
i
).
Procedura SUMAPOL(m,P,n,Q,r,S) trebuie s efectueze suma S(X) =
P(X)+Q(X), unde P este un polinom de gradul m, iar Q este un polinom de gradul
n, date. Suma lor, S, va un polinom de gradul r calculat de subalgoritm. Pentru
efectuarea acestui calcul este util folosirea unui alt subalgoritm care adun la suma
1.2. Elaborarea algoritmilor. Propoziii nestandard 31
S(X) un alt polinom, T(X), de grad mai mic sau egal dect gradul polinomului S(X).
Un astfel de subalgoritm se prezint n continuare.
SUBALGORITMUL SUMAPOL1(n,T,r,S) ESTE: { n r}
{S(X):=S(X)+T(X)}
PENTRU i:=0;n EXECUT
s[i] := s[i]+t[i];
SFPENTRU
SF-SUMAPOL1
Subalgoritmul SUMAPOL apeleaz acest subalgoritm, aa cum se poate vedea n
continuare.
SUBALGORITMUL SUMAPOL(m,P,n,Q,r,S) ESTE: {S(X):=P(X)+Q(X)}
DAC m<n
ATUNCI r:=n; S:=Q;
CHEAM SUMAPOL1(m,P,r,S)
ALTFEL r:=m; S:=P;
CHEAM SUMAPOL1(n,Q,r,S)
SFDAC
SF-SUMAPOL
S observm c n textul acestui subalgoritm am extins semnicaia propoziiei de
atribuire, permind atribuirea S:=Q. Acest lucru este normal ntruct S corespunde
unui polinom, iar Q este un polinom cunoscut; prin atribuire S primete o valoare
iniial, cea dat de polinomul Q.
Subliniem c atribuirea v := u va corect n cazul n care variabilele u i v
reprezint aceleai obiecte matematice, deci au aceeai semnicaie.
1.2 Elaborarea algoritmilor. Propoziii nestandard
Prin elaborarea (proiectarea) unui algoritm nelegem ntreaga activitate depus de la
enunarea problemei pn la realizarea algoritmului corespunztor rezolvrii acestei
probleme.
n elaborarea unui algoritm deosebim urmtoarele activiti importante [And,
1995]:
specicarea problemei;
descrierea metodei alese pentru rezolvarea problemei;
32 1. Bazele algoritmilor
proiectarea propriu-zis. Ea const n descompunerea problemei n subprob-
leme, obinerea algoritmului principal i a tuturor subalgoritmilor apelai, con-
form metodelor prezentate n seciunile urmtoare. Ea se termin cu descrierea
algoritmului principal i a subalgoritmilor menionai, dar i cu precizarea denu-
mirilor i semnicaiilor variabilelor folosite;
vericarea algoritmului obinut.
Astfel, s considerm urmtorul exemplu, calculul radicalului de ordinul 2 din x.
a. n partea de specicare a problemei vom meniona:
Se d un numr real notat prin x, care trebuie s e nenegativ. Se cere s gsim
un alt numr pozitiv r astfel nct
x = r.
Vom folosi un algoritm de aproximare a lui r. Deci specicarea fcut nu este com-
plet, neputnd gsi un algoritm care s rezolve direct problema n forma enunat.
Vom modica aceast specicare, cernd s se calculeze r aproximativ, cu o eroare
ce nu depete un numr real pozitiv eps prestabilit. Ajungem astfel la urmtoarea
specicare:
DATE eps,x; { eps,x R, eps>0 i x 0 }
REZULTATE r; { [r
x[ < eps }
b. Urmeaz s precizm metoda de rezolvare a problemei. Se tie c exist mai multe
metode de calcul a radicalului. Menionm urmtoarele dou posibiliti:
- ca limit a unui ir convergent la r (denit printr-o relaie de recuren);
- prin aproximarea soluiei ecuaiei
x = r.
Alegem pentru exemplicare metoda a doua, deci l vom calcula pe r rezolvnd
ecuaia
x = r.
a
r
(b, f(b))
a
b b
(a, f(a))
Figura 1.2: Grac pentru metoda coardei i a tangentei
1.2. Elaborarea algoritmilor. Propoziii nestandard 33
Pentru rezolvarea ecuaiei generale f(x) = 0 exist mai multe metode. Alegem
pentru rezolvare metoda coardei i a tangentei.
Aceast metod const n micorarea repetat a intervalului [a,b] care conine
rdcina r cutat, la intervalul [a,b], aa cum se poate vedea n Figura 1.2. Vari-
abilele folosite n descrierea algoritmului sunt:
a i b, reprezentnd capetele intervalului n care se a rdcina;
r mijlocul intervalului (a,b) n momentul n care b-a < eps, deci valoarea cutat.
Algoritmul propriu-zis (secvena de propoziii care obine rezultatele dorite
pornind de la datele iniiale) este descris n continuare:
Exemplul 1.2.1. {Algoritmul: Metoda coardei}
@Iniializeaz pe a i b;
REPET
@Atribuie lui a abscisa punctului de intersecie a axei OX cu coarda ce
unete punctele (a,f(a)) i (b,f(b));
@Atribuie lui b abscisa punctului de intersecie a axei OX cu tangenta n
punctul (b,f(b)) dus la graculfunciei f(t) =
t x;
PNCND b-a<eps SFREP
FIE r:=(a+b)/2;
n textul de mai sus apar trei propoziii nestandard care sugereaz ns foarte
bine ce aciuni trebuiesc ntreprinse. Prima stabilete intervalul iniial n care se a
rdcina, care depinde de mrimea lui x: (x,1) cnd x este mai mic dect 1 sau (1,x)
n caz contrar. Deci ea se va transcrie n propoziia standard:
DAC x<1
ATUNCI a:=x; b:=1;
ALTFEL a:=1; b:=x;
SFDAC
Celelalte dou propoziii nestandard se vor transcrie n propoziiile standard:
FIE a := E1; b := E2 ;
unde E1 este expresia care reprezint abscisa punctului de intersecie a axei OX
cu coarda ce unete punctele (a, f(a)) i (b,f(b)), iar E2 este expresia care reprezint
abscisa punctului de intersecie a axei OX cu tangenta n punctul (b, f(b)) dus la
gracul funciei f(t) =
t x.
Se ajunge la urmtoarea variant nal:
Exemplul 1.2.2.
ALGORITMUL Extrageradical ESTE: { Radical }
{ r := radical din x }
34 1. Bazele algoritmilor
CITESTE eps,x; { eps, x R, eps>0 i x 0 }
DAC x<1
ATUNCI a:=x; b:=1; { Iniializeaz }
ALTFEL a:=1; b:=x; { pe a i b }
SFDAC
REPET
a := E1; {abscisa punctului de intersecie a axei OX cu}
{coarda ce unete punctele (a,f(a)) i (b,f(b))}
b := E2; {abscisa punctului de intersecie a axei OX cu tangenta}
{ n punctul (b,f(b)) dus la gracul funciei f(t) = t2-x }
PNCND b-a<eps SFREP
FIE r:=(a+b)/2;
TIPRETE r; { [ r-rad(x) [<eps }
SF-Extrageradical
1.3 Proiectarea ascendent i proiectarea descen-
dent
Exist dou metode generale de proiectare a algoritmilor, a cror denumire provine
din modul de abordare a rezolvrii problemelor: metoda descendent i metoda ascen-
dent. Proiectarea descendent (top-down) pornete de la problema de rezolvat, pe
care o descompune n pri rezolvabile separat. De obicei, aceste pri sunt subprob-
leme independente, care la rndul lor pot descompuse n subprobleme. La prima
descompunere accentul trebuie pus pe algoritmul (modulul) principal nu asupra sub-
problemelor. La acest nivel nu ne intereseaz amnunte legate de rezolvarea subprob-
lemelor, presupunem c le tim rezolva, eventual c avem deja subalgoritmii pentru
rezolvarea lor. Urmeaz s considerm pe rnd, ecare subproblem n parte i s
proiectm (n acelai mod) un subalgoritm pentru rezolvarea ei. n nal, se va descrie
subalgoritmul de rezolvare al ecrei subprobleme, dar i interaciunile dintre aceti
subalgoritmi i ordinea n care ei sunt folosii.
Noiunea de modul va denit n seciunea urmtoare. Deocamdat nelegem
prin modul orice subalgoritm sau algoritmul principal. Legtura dintre module se
prezint cel mai bine sub forma unei diagrame numit arbore de programare [Bla,
1978]. Fiecrui modul i corespunde n arborele de programare un nod, ai crui
descendeni sunt toate modulele apelate direct. Nodul corespunztor algoritmului
principal este chiar nodul rdcin.
1.3. Proiectarea ascendent i proiectarea descendent 35
Astfel, n arborele de programare din Figura 1.3 exist un algoritm principal (modu-
lul PRINC), care apeleaz trei subalgoritmi (modulele CITDATE, CALCULE i
TIPREZ). La rndul su, modulul CALCULE apeleaz trei subalgoritmi (modulele
M1, M2 i M3).
PRINC
CALCULE TIPREZ CITDATE
M
2
M
3 M
1
Figura 1.3: Arbore de programare
Din arborele de programare nu reiese ns de cte ori se apeleaz un subalgoritm,
sau dac doi subalgoritmi se exclud unul pe cellalt. Este posibil nlocuirea arborelui
de programare cu o diagram de structur construit pe concepia NESTED-LOGIC.
n construirea unei astfel de diagrame se folosesc structurile din Figura 1.4, bazate pe
urmtoarele reguli [Liv, 1986]:
a) Operaia de trecere de la un nivel superior la unul inferior se interpreteaz prin
expresia "CONST DIN" (g. 1.4 a);
b) Operaia de trecere de la un bloc la altul de pe acelai nivel se interpreteaz cu
expresia "URMAT DE" (g. 1.4 a);
c) Caracterul o prezent n bloc n colul din dreapta sus este descendentul unui
bloc de tip selectiv (g 1.4.b);
d) Caracterul * prezent n bloc n colul din dreapta sus identic un bloc repet-
itiv i se interpreteaz cu expresia "MAI MULTE" (g.1.4 c).
A
X
A B
X
A B
X
(a) (b) (c)
Figura 1.4: Diagrame de structur construit pe concepia NESTED-LOGIC
Teorema de structur NESTED-LOGIC arm c oricare ar schema logic S
exist o schem S de structur NESTED-LOGIC echivalent cu S (deci care rezolv
36 1. Bazele algoritmilor
aceeai problem).
Ca exemplu de proiectare descendent, descriem n continuare un algoritm pentru
rezolvarea unui sistem liniar de n ecuaii cu n necunoscute:
A*X = B
La primul nivel de descompunere deosebim trei activiti distincte:
- citirea datelor problemei;
- rezolvarea sistemului menionat;
- tiprirea rezultatelor.
Pentru rezolvarea sistemului vom proiecta un subalgoritm, ntruct aceast pro-
blem poate apare adesea ca subproblem i dorim s refolosim subalgoritmul obinut.
Pentru rezolvarea sistemului identicm dou subprobleme independente:
- reducerea sistemului, prin metoda lui Gauss, la un sistem triunghiular echivalent;
- rezolvarea sistemului triunghiular obinut.
Mai mult, subproblema reducerii sistemului conine ca subprobleme determinarea
ecuaiei n care rmne x
i
i care este folosit la reducerea acestei necunoscute din
celelalte ecuaii, schimbarea a dou ecuaii ntre ele, deci interschimbarea a dou
linii din matricea extins i eliminarea propriu-zis. Subalgoritmul PIVOT, cores-
punztor primei subprobleme, determin care dintre ecuaiile de rang i, i + 1, ..., n
are coecientul lui x
i
maxim n valoare absolut, caz n care erorile introduse din
cauza aproximrilor n calcule cu numere reale sunt minime. Subalgoritmii INTER-
SCHIMB i ELIMIN corespund celorlalte dou subprobleme. Arborele de programare
corespunztor se d n Figura. 1.5.
REZISTEM
SISTEM TIPSOL CITSIST
INTERSCHIMB ELIMIN PIVOT
REDUTRI REZOLV
Figura 1.5: Arborele de programare pentru rezolvarea sistemului
1.3. Proiectarea ascendent i proiectarea descendent 37
Exemplul 1.3.1.
ALGORITMUL REZSISTEM ESTE:
Cheam CITSISTEM(n, A, B);
Cheam SISTEM(n, A, B, kod);
DAC kod = 1 ATUNCI Cheam TIPSOL(n, B);
ALTFEL TIPRETE "Sistemul nu este compatibil determinat.";
SFDAC
SF-REZSISTEM
Subalgoritmul SISTEM pentru rezolvarea unui sistem liniar de n ecuaii cu n ne-
cunoscute este prezentat n continuare.
SUBALGORITMUL SISTEM(n,A,B,kod) ESTE:
{Rezolv sistemul AX=B, de n ecuaii cu n necunoscute}
{A este matricea sistemului, B vectorul termenilor liberi i}
{Soluia se depune n vectorul B, iar A se distruge}
{kod = 1 pentru sistem compatibil, altfel kod = 0 }
CHEAM REDUTRI(n,A,B,kod);
{Reduce sistemul la un sistem triunghiular echivalent}
DAC kod = 1 ATUNCI {kod = 1 cnd sistemul e compatibil}
CHEAM REZOLV(n,A,B,kod); {Rezolv sistemul triunghiular}
SFDAC {Soluia se depune n vectorul B}
SF-SISTEM
SUBALGORITMUL REDUTRI(n,A,B,kod) ESTE: {Reduce sistemul liniar
A.X=B, de n ecuaii cu n necunoscute la un sistem triunghiular echivalent}
{ A.X = B, matricea A avnd sub diagonal numai zerouri}
{A este matricea sistemului iar B - vectorul termenilor liberi}
{kod = 0 pentru sistem nedeterminat sau incompatibil}
FIE kod:=1; {Ipoteza sistem determinat}
i:=1;
CTTIMP (i<n) I (kod=1) EXECUT {Se reduce necunoscuta x
i
din ecuaiile
i+1,...,n}
CHEAM PIVOT(n,A,i,j);
{j = numrul ecuaiein care se pstreaz necunoscuta x[j] }
DAC a[i,j]=0
ATUNCI kod:=0 ALTFEL
DAC j>i
38 1. Bazele algoritmilor
ATUNCI CHEAM INTERSCHIMB(i,j,n,A,B)
SFDAC
CHEAM ELIMIN(n,A,B,i);
SFDAC
FIE i:=i+1;
SFCT
SF-REDUTRI
SUBALGORITMUL REZOLV(n,A,B,ind) ESTE: {Rezolva sistemul triunghiular
A.X=B}
{deci matricea A are sub diagonala}
{numai zerouri. ind=1 pt.sistem determinat}
{in care caz solutia se pune in vectorul B}
{si ind=0 dac e nedeterminat sau incompatibil}
FIE r1:=b[n]; ind:=1;
DAC a[n,n]=0
ATUNCI ind:=0
ALTFEL b[n]:=r1/a[n,n]
SFDAC
FIE i:=n-1;
CTTIMP (ind=1) I (i>=1) EXECUT
DAC a[i,i]=0
ATUNCI ind:=0
ALTFEL
r1:=b[i];
PENTRU k:=i+1,n EXECUT
r:=a[i,k]*b[k]; r1:=r1-r;
SFPENTRU
b[i]:= r1/a[i,i]
SFDAC
Fie i:=I-1
SFCT
SF-REZOLV
SUBALGORITMUL PIVOT(n,A,i,j) ESTE: {j primete o valoare >=i pentru }
FIE j:=i; { care a[j,i] e maxim n valoare absolut}
PENTRU l:=i+1, n EXECUT
DAC a[l,i] > a[j,i]
1.3. Proiectarea ascendent i proiectarea descendent 39
ATUNCI j:=l
SFDAC
SFPENTRU
SF-PIVOT
SUBALGORITMUL INTERSCHIMB(i,j,n,A,B) ESTE:
{Schimb ntre ele liniile i i j din matricea A}
{ de ordinul n i termenii liberi corespunztori}
PENTRU l:=1; n EXECUT
r:=a[i,l]; a[i,l]:=a[j,l]; a[j,l]:=r
SFPENTRU
FIE r:=b[i]; b[i]:=b[j]; b[j]:=r
SF-INTERSCHIMB;
SUBALGORITMUL ELIMIN(n,A,B,i) ESTE: {Elimin necunoscuta x[i] din
ecuaiile i+1,...,n}
FIE r:=a[i,i]; { x[i] din ecuaiile n ipoteza a[i,i] ,= 0}
PENTRU k:=i,n EXECUT {Imparte ecuaia nr i cu r}
FIE a[i,k]:=a[i,k]/r
SFPENTRU
FIE b[i] := b[i]/r
PENTRU j:=i+1,n EXECUT {Elimin necunoscuta}
FIE r:=a[j,i]; {x[i] din ecuaia nr.j}
PENTRU k:=1,n EXECUT
a[j,k]:=a[j,k]-r*a[i,k];
SFPENTRU
FIE b[j]:=b[j]-r*b[i]
SFPENTRU
SF-ELIMIN
n multe cri metoda top-down este ntlnit i sub denumirea stepwise-renement,
adic ranare n pai succesivi. Este vorba de un proces de detaliere pas cu pas a
specicaiei, denumit proiectare descendent. Algoritmul apare n diferite versiuni
succesive, ecare ind o detaliere a versiunii precedente. n aceste versiuni succesive
apar multe enunuri nestandard ce urmeaz a precizate treptat prin propoziii
standard. Se recomand ca ele s rmn comentarii n versiunea nal. Algoritmul
apare n versiuni succesive, tot mai complet de la o versiune la alta. n versiunea
nal n algoritm apar numai propoziii standard.
40 1. Bazele algoritmilor
Diferena ntre metoda top-down i metoda ranrii succesive este neesenial,
scopul urmrit ind acelai: concentrarea ateniei asupra prilor importante ale mo-
mentului i amnarea detaliilor pentru mai trziu. Dac ar necesar s le deosebim
am spune c metoda top-down se refer la nivelul macro iar metoda ranrii succesive
la nivelul micro. La nivel macro se dorete descompunerea unei probleme complexe n
subprobleme. La nivel micro se dorete obinerea unui modul n versiune nal. ntr-o
versiune intermediar pot prezente numai prile importante ale acestuia, urmnd
s se revin asupra detaliilor n versiunile urmtoare, dup ce aspectele importante
au fost rezolvate.
Avantajele proiectrii top-down (cunoscut i sub denumirea "Divide et impera")
sunt multiple. Avantajul principal const n faptul c ea permite programatorului s
reduc complexitatea problemei, subproblemele n care a fost descompus ind mai
simple, i s amne detaliile pentru mai trziu. n momentul n care descompunem
problema n subprobleme nu ne gndim cum se vor rezolva subproblemele ci care sunt
ele i conexiunile dintre ele.
Proiectarea descendent permite lucrul n echipe mari. Prin descompunerea pro-
blemei n mai multe subprobleme, ecare subproblem poate dat spre rezolvare
unei subechipe. Fiecare subechip nu cunoate dect subproblema pe care trebuie s
o rezolve.
Metoda "Divide et Impera" poate folosit nu numai la mprirea problemei n
subprobleme ci i la mprirea datelor n grupe mai mici de date [Cri, 1993].
Metoda ascendent (bottom-up) pornete de la propoziiile limbajului i de la
subalgoritmi existeni, pe care i asambleaz n ali subalgoritmi pentru a ajunge n
nal la algoritmul dorit. Cu alte cuvinte, n cazul metodei ascendente va scris
mai nti subalgoritmul apelat i apoi cel care apeleaz. Ca rezultat al proiectrii
ascendente se ajunge la o mulime de subalgoritmi care se apeleaz ntre ei. Este
important s se cunoasc care subalgoritm apeleaz pe care, lucru redat printr-o
diagram de structur, ca i n cazul programrii descendente.
Aceast metod are marele dezavantaj c erorile de integrare vor detectate
trziu, abia n faza de integrare. Se poate ajunge abia acum la concluzia c unii
subalgoritmi, dei coreci, nu sunt utili.
De cele mai multe ori nu se practic o proiectare ascendent sau descendent pur
ci o combinare a lor, o proiectare mixt [Ski, 1997].
1.4. Proiectarea modular 41
1.4 Proiectarea modular
Prin proiectare (programare) modular nelegem metoda de proiectare (programare)
a unui algoritm pentru rezolvarea unei probleme prin folosirea modulelor.
Dar ce este un modul? Modulul este considerat [Fre, 1986] o unitate structural
de sine stttoare, e program, e subprogram, e o unitate de program. Un modul
poate conine sau poate coninut ntr-alt modul. Un modul poate format din mai
multe submodule. Astfel, n Pseudocod, ecare subalgoritm i algoritmul principal
sunt considerate module. n limbajele de programare cu structur de bloc, de exemplu
n Turbo Pascal, UNIT-urile pot considerate module. La compilarea separat un
grup de subprograme compilate deodat constituie un modul, dar acest modul poate
considerat ca o mulime de submodule din care este compus.
Este ns important ca ecare modul s-i aib rolul su bine precizat, s realizeze
o funcie n cadrul ntregului program. El apare n mod natural n descompunerea
top-down.
Indiferent c privim modulul ca un singur subalgoritm, un grup de subalgoritmi,
sau un algoritm de sine stttor ce apeleaz ali subalgoritmi, considerm modulele
relativ independente, dar cu posibiliti de comunicare ntre ele. Astfel, un modul nu
trebuie s e inuenat de maniera n care se lucreaz n interiorul altui modul. Orice
modicare ulterioar n structura unui program, dac funcia pe care o realizeaz un
modul M nc este necesar, acest modul trebuie s e util i folosit n continuare
fr modicri.
Rezult c programarea modular se bazeaz pe descompunerea problemei n sub-
probleme i proiectarea i programarea separat a subalgoritmilor corespunztori. De
altfel, considerm c ntr-o programare serioas nu se poate ajunge la implementare
fr a avea n prealabil algoritmii descrii ntr-un limbaj de descriere (la noi Pse-
udocod). Deci programarea modular se refer n primul rnd la proiectarea mo-
dular a algoritmilor i apoi la traducerea lor n limbajul de programare ales, innd
seama de specicul acestui limbaj. Programarea modular este strns legat de pro-
gramarea ascendent i de programarea descendent, ambele presupunnd folosirea
subalgoritmilor pentru toate subproblemele ntlnite.
Avantajele programrii modulare sunt multiple. Menionm n cele ce urmeaz
cteva dintre ele [Sed, 1988]:
Descompunerea unei probleme complexe n subprobleme este un mijloc conve-
nabil i ecient de a reduce complexitatea (Principiul Divide et impera
acioneaz i n programare). Este evident c probabilitatea apariiei erorilor n
conceperea unui program crete cu mrimea programului, lucru conrmat i de
42 1. Bazele algoritmilor
experiena practic. De asemenea, rezolvnd o problem mai simpl, testarea
unui modul se poate face mult mai uor dect testarea ntregului algoritm.
Apoi, faptul c trebuiesc proiectate mai multe subprograme pentru subprob-
lemele ntlnite, permite munca mai multor programatori. S-a ajuns astfel la
munca n echip, modalitate prin care se ajunge la scurtarea termenului de
realizare a produsului program.
Modulele se pot refolosi ori de cte ori avem nevoie de ele. Astfel, s-a ajuns la
compilarea separat a subprogramelor i la pstrarea subprogramelor obinute
n biblioteci de subprograme, de unde ele se pot refolosi la nevoie. Sunt cunos-
cute astzi multe astfel de biblioteci de subprograme. Reutilizabilitatea acestor
subprograme este o proprietate foarte important n activitatea de programare.
Ea duce la mrirea productivitii n programare, dar i la creterea siguranei
n realizarea unui produs corect.
Uneori, n timpul proiectrii algoritmului sau a implementrii lui, se ajunge la
concluzia c proiectarea a fost incomplet sau c unele module sunt ineciente.
i n aceast situaie programarea modular este avantajoas, ea permind
nlocuirea modulului n cauz cu altul mai performant.
Una din activitile importante n realizarea unui program este vericarea corec-
titudinii acestuia [Liv, 1980]. Experiena a artat c modulele se pot verica cu att
mai uor cu ct sunt mai mici. Abilitatea omului de a nelege i analiza corectitudinea
unui subalgoritm este mult mai mare pentru texte scurte. n unele cri chiar se re-
comand a nu se folosi subalgoritmi mai mari dect 50 de propoziii. Sigur c o astfel
de limit nu exist, dar se recomand descompunerea unui subalgoritm n ali subal-
goritmi oricnd acest lucru este posibil n mod natural, deci aceti noi subalgoritmi
rezolv subprobleme de sine stttoare, sau realizeaz funcii bine denite.
Ca exemplu de proiectare modular, ne propunem s prezentm un algoritm pen-
tru rezolvarea urmtoarei probleme:
Exemplul 1.4.1. Dirigintele unei clase de elevi dorete s obin un clasament al
elevilor n funcie de media general. n plus, pentru ecare disciplin n parte, dorete
lista primilor ase elevi [Alb, 1994].
n rezolvarea acestei probleme este necesar gsirea ordinii n care trebuiesc tiprii
elevii n funcie de un anumit rezultat: nota la disciplina "j", sau media general. Am
identicat prin urmare dou subprobleme independente, referitoare la:
(1) aarea ordinii n care trebuie tiprite n numere pentru a le obine ordonate;
1.4. Proiectarea modular 43
(2) tiprirea elevilor clasei ntr-o anumit ordine.
Prima subproblem se poate specica astfel:
Dndu-se numerele x
1
, x
2
, ..., x
n
, gsii ordinea o
1
, o
2
, ..., o
n
, n care aceste numere
devin ordonate descresctor, adic
x[o
1
]x[o
2
]...x[o
n
].
Pentru rezolvarea ei vom pezenta un subalgoritm ORDINE n care intervin trei
parametri formali:
- n, numrul valorilor existente;
- X, vectorul acestor valori;
- O, vectorul indicilor care dau ordinea dorit.
Primii doi parametrii marcheaz datele presupuse cunoscute, iar al treilea, rezul-
tatele calculate de subalgoritm.
SUBALGORITMUL ORDINE(n,X,O) ESTE: {n, numrul valorilor existente; X,
vectorul acestor }
{ valor; O, vectorul indicilor care dau ordinea dorit }
PENTRU i:=1; n EXECUT
O[i] :=i;
SFPENTRU
REPET ind:=0;
PENTRU i:=1;n-1 EXECUT
DAC x[O[i]] < x[O[i+1]] ATUNCI
FIE ind:=1; t:=O[i+1] ;
O[i+1]:=O[i]; O[i] :=t;
SFDAC
SFPENTRU
PANCND ind=0 SFREP
SF-ORDINE
A doua subproblem se poate specica astfel:
Dndu-se ordinea o
1
, o
2
, ..., o
n
, a elevilor clasei, numele i mediile acestora, s se
tipreasc numele i mediile primilor k elevi n ordinea specicat.
Subalgoritmul TIPAR, dat n continuare, rezolv aceast problem.
44 1. Bazele algoritmilor
SUBALGORITMUL TIPAR(k, NUME, O) ESTE:
PENTRU i:=1;k EXECUT
@Tiprete datele elevului de rang o
i
;
SFPENTRU
SF-TIPAR
Variabilele folosite pentru problema dat sunt urmtoarele:
- n reprezint numrul elevilor clasei;
- m este numrul disciplinelor la care elevii primesc note;
- NUME este vectorul care reine numele elevilor: NUME[i] este numele elevului
cu numrul de ordine i;
- NOTE este matricea notelor elevilor, avnd n linii i m coloane;
NOTE[i,j] este nota elevului cu numele NUME[i] la disciplina cu numrul de ordine
j;
NOTE[j] este coloana a j-a a matricei NOTE i reprezint notele elevilor la disciplina
j;
- MEDII este vectorul mediilor generale.
Algoritmul este:
ALGORITMUL CLASAMENT ESTE: { Ordonare }
CITETE m, {numrul disciplinelor i}
n, {al elevilor}
NUME[i], i=1,n, {numele elevilor}
NOTE[i,j], j=1,m, i=1,n; {notele elevilor}
PENTRU i:=1;n EXECUT { calculeaz media general}
FIE S:=0; {a elevului i}
PENTRU j:=1;m EXECUT
S:=S+NOTE[i,j];
SFPENTRU
FIE MEDII[i]:=S/m;
SFPENTRU
CHEAM ORDINE(n,MEDII,O);
CHEAM TIPAR(n,NUME,O);
PENTRU j:=1;m EXECUT
CHEAM ORDINE(n,NOTE.j,O);
CHEAM TIPAR(n,NUME,O);
SFPENTRU
1.4. Proiectarea modular 45
SF-ALGORITM
ntr-un algoritm, parametrii formali i actuali pot funcii sau proceduri. n
continuare, este prezentat un astfel de exemplu, n care se calculeaz radicalii de
ordinul doi i trei din constanta mm rezolvnd ecuaiile:
x
2
- mm = 0, notat g(x) = 0,
respectiv
x
3
- mm = 0, notat h(x) = 0.
Pentru rezolvarea unei ecuaii se pot folosi mai multe metode. n program am
ales dou: metoda njumtirii i metoda coardei. Metoda coardei este descris
amnunit n seciunea urmtoare. Metoda njumtirii const n njumtirea
intervalului [a,b] care conine rdcina i reinerea aceluia n care se a rdcina,
subinterval care va noua valoare a lui [a,b]. Calculul se ncheie n momentul n care
lungimea intervalului [a,b] este mai mic dect , care ne d eroarea cu care dorim s
am rdcina.
ntruct metoda coardei folosete i prima derivat, am notat prin f1, respectiv g1
derivatele funciilor f i g. Prin c i t s-au notat cele dou extremiti ale intervalului
care conine rdcina, t ind extremitatea n care se duce tangenta [Ata, 1996].
SUBALGORITMUL coarda(c,t,r,f,f1) ESTE: {Se rezolv ecuaia f(x)=0 prin
metoda coardei}
{c,t sunt extremitile intervalului care conine}
{rdcina, iar f1este derivata lui f }
{r este rdcina care se calculeaz}
REPET
c:=c-f(c)*(t-c)/(f(t)-f(c));
t:=t-f(t)/f1(t);
PNCND [t c[ < 0.00001;
FIE r:=(c+t)/2;
SF-coarda
SUBALGORITMUL juma(a,b, r, f,f1) ESTE: {Se rezolv prin metoda n-
jumtirii}
{ecuaia f(x)=0, care are o rdcin n [a,b]}
{r= rdcina obinut, iar f1 este derivata lui f}
REPET
r:=(a+b)/2;
DAC f(a)*f(r) <0 ATUNCI
b:=r;
46 1. Bazele algoritmilor
ALTFEL
a:=r;
SFDAC
PNCND [b a[ < .00001 SFREPET
SF-juma
SUBALGORITMUL Rezec(a,b, r, f,f1, met) ESTE:
CHEAM met(a,b,r,f,f1);
SF-Rezec
ALGORITMUL punctii ESTE:
TIPRETE njumtire Coarda ;
CHEAM Rezec(1,2,rj,g,g1,juma);
CHEAM Rezec(1,2,rc,g,g1,coarda);
TIPRETE rj,rc ;
CHEAM Rezec(1,2,rj,h,h1,juma);
CHEAM Rezec(1,2,rc,h,h1,coarda);
TIPRETE rj,rc ;
SFALGORITM
1.5 Apel recursiv
n exemplele anterioare se observ c apelul unui subprogram se face dup ce el a fost
denit. Este ns posibil ca un subalgoritm s se apeleze pe el nsui. ntr-un astfel de
caz, spunem c apelul este recursiv, iar subalgoritmul respectiv este denit recursiv.
Ca exemplu, denim n continuare o funcie care calculeaz recursiv valoarea n!.
Se va folosi formula:
n! =
_
_
_
n (n 1)!, n > 0
1, n = 0
Recursivitatea const n faptul c n deniia funciei Factorial n argumentul n se
folosete aceeai funcie Factorial dar de argument n-1. Deci, funcia Factorial se
apeleaz pe ea nsi. Este important ca numrul apelurilor s e nit, deci ca
procedeul de calcul descris s se termine.
FUNCTIA Factorial(n) ESTE:
DAC n=0 ATUNCI
Factorial:=1;
1.7. Probleme propuse 47
ALTFEL
Factorial:= n*Factorial(n-1);
SFDAC
SF-Factorial;
1.6 Programarea structurat
Programarea structurat este un stil de programare aprut n urma experienei primi-
lor ani de activitate. Ea cere respectarea unei discipline de programare i folosirea
riguroas a ctorva structuri de calcul. Ca rezultat se va ajunge la un algoritm uor
de urmrit, clar i corect [Baa, 1987].
Termenul programare, folosit n titlul acestei seciuni i consacrat n literatura
de specialitate, este folosit aici n sens larg i nu este identic cu cel de programare
propriu-zis. Este vorba de ntreaga activitate depus pentru obinerea unui program,
deci att proiectarea algoritmului ct i traducerea acestuia n limbajul de programare
ales.
Bohm i Jacopini [Bh, 1966] au demonstrat c orice algoritm poate compus din
numai trei structuri de calcul:
- structura secvenial;
- structura alternativ;
- structura repetitiv.
1.7 Probleme propuse
I. Descriei n Pseudocod subalgoritmi care calculeaz urmtoarele funcii:
1. Pentru n N funcia Prim(n) calculeaz al n-lea numr prim.
2. Pentru z, l, a N dai, 1 z 31, 1 l 12, 1900 < a, funcia NRZI(z, l, a)
spune a cta zi din anul a este data (z, l, a);
3. Pentru n N funcia UrmatorPrim(n) d numrul prim imediat superior lui n.
4. Pentru polinomul P de gradul n cu coecieni reali dat i x R funcia
VALPOL(x, n, P) d valoarea polinomului P n punctul x.
5. Pentru k, n N, 0 k n, funcia C(n, k) calculeaz numrul combinrilor de
n obiecte luate cte k.
48 1. Bazele algoritmilor
6. Pentru vectorii X i Y cu n componente, funcia E(n, X, Y ) d valoarea 0 dac
X = Y, respectiv i dac i este cel mai mic indice pentru care x
i
< y
i
.
7. Cunoscnd mulimile A i B funcia INCLUS(A, B) veric dac mulimea A
este inclus n mulimea B;
8. Fie f o funcie de forma f : 1, 2, ..., m 1, 2, ..., n.
Denim T(f) egal cu 1 dac f este o funcie injectiv, egal cu 2 dac f este
surjectiv, egal cu 3 dac f este bijectiv, i 0 n caz contrar. Se d funcia f
prin perechile de elemente (x, f(x)) care denesc gracul su. S se calculeze
T(f).
9. Se d o relaie binar R prin gracul su. S se calculeze E(R) prin deniie
egal cu 0 dac R este o relaie de recuren i egal cu 1 n caz contrar.
10. irul Fibonacci este denit astfel: f
0
= f
1
= 1 i f
n
= f
n1
+ f
n2
, pentru
n > 1. Pentru n N dat calculai F(n) = f
n
.
11. Pentru n N dat calculai j(n), unde j este funcia lui Euler, deci j(n) este
numrul numerelor mai mici dect n i relativ prime cu n.
12. Pentru n N dat calculai P(n), unde P(n) este 0 dac numrul n este perfect
i 1 n caz contrar (un numr n este perfect dac este egal cu suma divizorilor
si mai mici dect el nsui. Exemplu: 6=1+2+3)
II. Scriei subalgoritmi pentru rezolvarea urmtoarelor probleme:
1. Cunoscnd mulimile A i B calculai C = A B;
2. Cunoscnd mulimile A i B calculai C = A B;
3. Dndu-se vectorul X cu n componente, tergei toate componentele care se
repet;
4. Dndu-se vectorul X cu n componente numere ntregi ordonate cresctor i
a Z inserai pe a n X astfel nct X s rmn ordonat cresctor;
5. Dndu-se dou polinoame calculai suma lor;
6. Dndu-se dou polinoame calculai produsul lor;
7. Dndu-se dou matrice calculai suma lor;
8. Dndu-se dou matrice ptrate de ordinul n calculai produsul lor;
1.7. Probleme propuse 49
9. Dndu-se dou numere A i B prin reprezentrile lor n baza p gsii suma lor
A+B prin reprezentarea ei n baza p;
10. Dndu-se numerele reale x
1
, x
2
, ..., x
n
, determinai secvena de termeni conse-
cutivi care are suma maxim.
11. Se dau p, q N i numrul A prin reprezentarea sa n baza p. Determinai
reprezentarea sa n baza q.
12. Se d n B, n 2. S se formeze matricea ptrat A de ordinul n ale crei
coloane scrise una dup alta constituie primii n
2
termeni ai irului
1,2,3,4,5,6,7,8,9,1,0,1,1,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,2,0, ... obinut din scrierea
cifrelor semnicative ale numerelor naturale.
III. Proiectai prin metoda top-down algoritmi pentru rezolvarea urm-
toarelor probleme:
1. Se d un ir de numere naturale x
1
, x
2
, ..., x
n
. Spunem c dou numere naturale
sunt prietene dac scrierea unui numr (n baza 10) este obinut prin scrierea
cifrelor celuilalt n ordine invers (de exemplu 3678 i 8763). S se gseasc toate
perechile de numere consecutive prietene din irul dat i frecvenele cifrelor n
scrierea numerelor date.
2. Se d un ir de numere naturale x
1
, x
2
, ..., x
n
. S se gseasc toate subsirurile
de elemente consecutive de lungime maxima formate din numere prime i toate
numerele prime distincte ntlnite.
3. Se d o matrice ptrat A de ordinul n i numrul natural m > 0. Se cere s se
tipreasc matricele A, A
2
, ..., A
m
i suma lor.
4. Se d polinomul P cu coecieni ntregi, e prin monoamele sale, e prin grad
i coecieni. S se scrie un algoritm care determin rdcinile raionale ale
polinomului P.
5. Se dau numerele naturale n
1
i n
2
. Determinai mulimea numerelor prime
aate ntre n
1
i n
2
i mulimea perechilor de gemeni (numerele prime p i q se
numesc gemeni dac q p = 2).
6. Fiind date mai multe polinoame cu coecieni reali s se determine suma lor i
polinomul de grad maxim. Un polinom se d e prin monoamele sale, e prin
grad i coecieni.
50 1. Bazele algoritmilor
7. Se citesc mai multe iruri de numere naturale. Pentru ecare ir citit, tiprii cea
mai lung scar (secvena de termeni consecutivi strict cresctori) i depunei
aceast scar ntr-un ir (rezultat) R. La sfrit tiprii cea mai lung scar din
R. Citirea unui ir se termin la ntlnirea unui numr negativ, iar citirea se
oprete la ir de lungime 0 (deci fr nici un termen).
8. Se dau mai multe mulimi de numere ntregi pozitive. S se determine reuniunea
i intersecia acestor mulimi.
9. Se dau mai multe mulimi de numere naturale. Fie I(M) numrul mulimilor
diferite de M si care conin pe M. S se determine mulimea pentru care I(M)
este maxim.
10. O matrice rar A este o matrice n care majoritatea termenilor sunt nuli. O
astfel de matrice se poate reprezenta prin tripletele (linie, coloan, valoare)
corespunztoare valorilor nenule ale matricei; deci A(linie,coloan) = valoare.
Dndu-se mai multe matrice rare determinai suma lor.
11. Se dau mai multe numere naturale prin reprezentrile lor n baza p. Gsii suma
lor i maximul acestor numere (reprezentate n baza p i toate operaiile se fac
n baza p).
12. Se dau mai multe matrice cu coecieni ntregi. Se cere suma matricelor care
au determinantul nenul, matricele care au determinantul nul i matricea care
are determinantul maxim.
Capitolul 2
Complexitatea algoritmilor
2.1 Etapele rezolvrii unei probleme
Este cunoscut faptul c rezolvarea unei probleme presupune n principal trei etape:
1. Analiza problemei ;
2. Proiectarea soluiei ;
3. Implementarea i testarea soluiei n practic.
n funcie de gradul de generalitate a analizei efectuate, n a doua etap se ntlnesc
dou situaii: proiectarea unei soluii particulare, valabil doar pentru acea problem,
i proiectarea unei soluii generale, valabil pentru orice instaniere a acelei probleme,
soluia generalizat.
n timp ce soluia particular este valabil doar pentru o instan a problemei,
soluia general este independent de parametrii problemei i ofer o metod general
de rezolvare a problemei.
Astfel, soluionarea imediat a ecuaiei x
3
+ 1 = 0 este particular fa de
soluionarea ecuaiei generalizate ax
3
+bx
2
+c = 0.
2.2 Noiunea de algoritm i cea de program
Atunci cnd metoda general de rezolvare a unei probleme este prezentat precis, pe
pai ce se efectueaz ntr-o ordine bine precizat i care conduc n timp nit la soluia
oricrei instanieri a problemei, vorbim de algoritmul de rezolvare a problemei.
51
52 2. Complexitatea algoritmilor
De exemplu, algoritmul de determinare a unei soluii reale a ecuaiei polinomiale
P(x) = 0, cu o aproximare dat, prin metoda tangentei.
Avantajul major al proiectrii unui algoritm de soluionare a problemei este dat
de faptul c efortul de rezolvare poate transferat unei maini automate (calculator)
sub forma programului executabil ce implementeaz algoritmul general de soluionare.
Implementarea algoritmului general de soluionare a problemei ntr-un program
pe calculator permite o important economie prin faptul c efortul major de analiz i
proiectare a soluiei a fost efectuat o singur dat iar rezolvarea problemei se reduce
la efortul foarte redus de executare (rulare) a programului cu ajutorul calculatorului
pentru ecare instan diferit a problemei.
2.3 Modelul abstract al Mainii Turing. Teza
Turing-Church
Primul model teoretic riguros de main automat de calcul este Modelul mainii
abstracte Turing (1936). Acest model teoretic a stat la baza apariiei efective a
primei maini electronice de calcul, denumit mai trziu computer (calculator) dup
denumirea operatorului uman (tehnicianului) care era angajat s fac toate calculele
inginereti sau contabile ale unui proiect sau ale unei rme.
Puterea de rezolvare a unui calculator se reduce la puterea de calcul a mainii
Turing. Iar puterea de calcul a acestei maini abstracte riguroase este exprimat sub
forma Tezei Turing-Church: O main Turing poate face tot ceea ce poate face un
computer uman nzestrat cu creion, oricte foi de hrtie i reguli precise ( mecanice
sau automate ) de calcul.
Exist, pe lng aceast formulare iniial a lui Turing, o serie de alte formulri
echivalente ale acestei teze unanim acceptate de teoreticienii ce au pus bazele teoriei
informatice i a tiinei calculatoarelor (computer science). S observm c aceast
tez (propoziie acceptat fr demonstraie ca avnd valoarea logic de adevrat)
stabilete o echivalen perfect ntre puterea de calcul a unui computer uman i
puterea de calcul a unui computer main.
Echivalarea subneles (tacit) a noiunii teoretice vagi de algoritm cu noiunea
matematic riguroas de Main Turing a nsemnat acceptarea unanim a Tezei
Turing-Church de ctre iniiatorii informaticii. n consecin, studiul ecienei unui
algoritm n soluionarea unei probleme revine n studiul ecienei n funcionare a
mainii Turing i implicit a ecienei n funcionare a programului ce implementeaz
acel algoritm de rezolvare.
Aceasta este consecina faptului c, n accepiunea original, algoritmul de
2.4. Analiza, Proiectarea i Implementarea algoritmilor 53
soluionare a unei probleme este destinat unui computer uman, dar puterea de calcul
a acestuia este aceeai cu puterea de calcul a unei maini Turing = computer main
care este pus n micare printr-un program executabil.
2.4 Analiza, proiectarea i implementarea algorit-
milor i complexitatea algoritmilor
Relund ideea iniial, n rezolvarea automat a unei probleme (adic rezolvarea cu
ajutorul calculatorului a oricrei instane diferite problemei) se trece prin cele trei
etape: Analiza teoretic a problemei, Proiectarea algoritmului de soluionare i Im-
plementarea algoritmului ntr-un program executabil pe calculator.
n timp ce n prima etap analiza problemei - rezultatul cheie, pe care se concen-
treaz preponderent efortul de analiz, este demonstrarea corectitudinii soluiei, n a
doua etap proiectarea algoritmului de soluionare - cuvntul cheie este eciena de
rezolvare. Studiul cu un pronunat caracter teoretic coninut n aceast a doua etap
i propune s prevad eciena n funcionare (necesarul de timp i spaiu calcula-
tor) a programului executabil ce va implementa algoritmul, eventual prin compararea
teoretic a algoritmilor de soluionare diferii [Aho, 1974].
De exemplu, n cazul problemei sortrii unui ir de n chei prin comparaii se poate
estima teoretic comparativ c algoritmul de sortare QuickSort este printre cele mai
eciente soluii.
Disciplina informaticii care se ocup cu studiul teoretic al ecienei algoritmilor
este numit Complexitatea algoritmilor.
2.5 Operaia de baz, cheia studiului complexitii
La baza studierii complexitii unui algoritm st detectarea n descrierea algoritmului
a operaiei sau a operaiilor de baz, acea operaie (acele operaii) aat (aate) n cel
mai interior corp de ciclu repetitiv i a crei (a cror) contorizare permite estimarea n
avans, nainte de lansarea n execuie, a timpului de execuie a programului executabil
corespunztor.
n majoritatea cazurilor exist o legtur foarte strns ntre operaia de baz (cea
mai repetat operaie) i operaia care este dedus n etapa de analiz a problemei
ca ind operaia inevitabil pentru rezolvarea problemei.
De exemplu, n cazul problemei sortrii unui ir de n chei prin comparaii este
limpede c operaia de comparare a mrimii cheilor este operaia inevitabil i de
asemenea ea va i operaia de baz a crei contorizare va permite estimarea, nainte
54 2. Complexitatea algoritmilor
de execuie, a duratei de funcionare a programului ce implementeaz algoritmul de
sortare respectiv.
2.6 Clase de algoritmi
n aceast situaie, toi algoritmii diferii care soluioneaz aceeai problem i care
se bazeaz pe aceeai operaie de baz (inevitabil) formeaz clasa algoritmilor de
soluionare a problemei. De obicei, numele clasei va dat chiar de numele acelei
operaii de baz ce este coninut de ecare algoritm al clasei n mod inevitabil.
De exemplu, n cazul problemei sortrii unui ir de n chei prin comparaii, algo-
ritmii diferii ce soluioneaz 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.
2.7 Eciena algoritmilor
Compararea ecienei a doi algoritmi diferii ce soluioneaz aceeai problem se face
prin determinarea teoretic a numrului de repetiii a operaiei de baz n ecare
algoritm i compararea celor dou valori. n nal, rezultatul comparrii va permite
estimarea comparativ a duratei de funcionare a programelor i alegerea celui mai
bun.
Compararea ecienei 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.
2.8 Funciile de complexitate
Numrul de repetiii al operaiei de baz se exprim matematic printr-o funcie de
complexitate individual asociat algoritmului, funcie ce depinde n mod inevitabil
de dimensiunea (mrimea) vectorului datelor de intrare.
De exemplu, n cazul algoritmului de determinare a maximului dintr-un ir de n
elemente prin comparaii, este evident c numrul de comparaii efectuat de orice
algoritm de maxim va o funcie de n. Iat descrierea n Pseudocod a algoritmului
[Liv, 1986]:
2.9. Apartenena la o clas de complexitate 55
Citete n, a
1
, a
2
, . . . , a
n
; Dup cum se observ vectorul de intrare (irul a) are
dimensiunea n.
Max := a
1
;
Pentru i := 2 pn la n execut Este evident c operaia de baz comparaia
< se execut de
Dac Max < a
i
atunci Max := a
i
; n 1 ori, adic pentru valorile contorului i
cuprinse ntre 2 i n.
Scrie Max; Deci, funcia care descrie numrul operaiilor de baz este: f(n) = n1
n studiul complexitii algoritmilor, pentru a permite realizarea comparailor
necesare pentru clasicarea algoritmului din punct de vedere al ecienei, dimensiunea
vectorului de intrare este mpins spre innit.
Compararea complexitii algoritmilor dintr-o clas de algoritmi cere n mod ine-
vitabil gruparea funciilor de complexitate n clase de funcii de complexitate i studiul
comportamentului asimptotic al acestora (cnd n dimensiunea vectorului de intrare
tinde ctre innit).
2.9 Apartenena la o clas de complexitate
Complexitatea unui algoritm se poate exprima prin precizarea clasei de apartenen a
funciei de complexitate a respectivului algoritm. Notaiile clasice care exprim felul
apartenenei funciei de complexitate f(n) a unui algoritm la diverse clase de funcii
sunt , i O.
n aceast introducere snt prezentate noiuni de baz folosite n capitolele urm-
toare ale lucrrii.
Deniia 2.9.1. Un algoritm este un set de instruciuni care trebuie executate pentru
a se obine un rspuns la o problem dat.
Un algoritm are urmtoarele proprieti [Knu, 1976], [Bur, 1998]:
nitudine: trebuie s se termine ntotdeauna dup un numr nit de pai (in-
struciuni);
determinism: ecare pas trebuie s e exact precizat, n mod riguros i neam-
biguu;
generalitate: trebuie s rezolve problema pentru orice date de intrare din dome-
niul precizat;
efectivitate: ecare instruciune trebuie s e exact i de durat nit.
56 2. Complexitatea algoritmilor
Ultima proprietate trebuie nuanat, avnd n vedere faptul c memoria oricrui
calculator este limitat. Nu ntotdeauna operaiile aritmetice se efectueaz exact,
n unele cazuri obinndu-se o aproximare a rezultatelor. Exist i soluii propuse
pentru respectarea acestei proprieti, care presupun implementarea software a oper-
aiilor elementare cu numere ntregi [For, 1993], dar acestea duc la scderea vitezei de
prelucrare. De aceea, abordri recente iau n considerare modelul bazat pe aritmetica
n virgul mobil, implementat pe toate calculatoarele actuale [She, 1997].
Avnd un algoritm care rezolv o problem dat, urmeaz s determinm resursele
acestuia [Liv, 1986]. Concret, de ct memorie i timp avem nevoie ca s obinem
soluia problemei? n acest scop facem urmtoarele simplicri: ecare operaie ele-
mentar a algoritmului se execut ntr-o unitate de timp, informaiile despre un obiect
elementar se memoreaz ntr-o locaie de memorie.
Fie f : N N o funcie care indic relaia dintre numrul de valori (date de
intrare) prelucrate de un algoritm, i numrul de operaii elementare efectuate de
acesta pentru obinerea rezultatelor. Funcia f poate avea o expresie analitic destul
de complicat, de aceea considerm nc o funcie g : N N cu o expresie analitic
simplicat.
Deniia 2.9.2. Funcia f are ordinul de mrime cel mult g(n), notaie: f O(g(n)),
dac i numai dac exist valori c > 0 i n
0
N astfel nct pentru orice n > n
0
s
avem f(n) cg(n).
O(g) = h : N N [ c > 0, n
0
N a. v > n
0
, h(n) cg(n). (2.1)
Deniia 2.9.3. Funcia f are ordinul de mrime cel puin g(n), notaie: f
(g(n)), dac i numai dac exist valori c > 0 i n
0
N astfel nct pentru orice
n > n
0
s avem f(n) cg(n).
(g) = h : N N [ c > 0, n
0
N a. v > n
0
, h(n) cg(n). (2.2)
Deniia 2.9.4. Funcia f are ordinul de mrime g(n), notaie: f (g(n)), dac i
numai dac exist valori c
1
, c
2
> 0 i n
0
N astfel nct pentru orice n > n
0
s avem
c
1
g(n) f(n) c
2
g(n).
(g) = h : N N [ c
1
, c
2
> 0, n
0
N a. v > n
0
, c
1
g(n) h(n) c
2
g(n).
(2.3)
Prezentm dou rezultate remarcabile care vor folosite foarte frecvent pe par-
cursul lucrrii [Knu, 1976]:
2.9. Apartenena la o clas de complexitate 57
(1) Se d un ir de n valori dintr-un domeniu pe care este denit o relaie de
ordine total. Cel mai ecient algoritm de ordonare a irului dat, care se bazeaz pe
comparaii, are complexitate de ordin (nlog n).
(2) Se d un ir de n valori ordonate. Cutarea unei valori (localizarea poziiei
acesteia sau obinerea unui rspuns negativ) n irul dat necesit un timp de ordin
O(log n).
O categorie special de probleme, numite NP-complete, se caracterizeaz prin
urmtoarele:
nu se cunosc algoritmi ecieni (de complexitate polinomial), se cunosc n
schimb algoritmi de complexitate exponenial pentru rezolvarea acestora;
problem NP-complet este polinomial transformabil ntr-o alt problem tot
NP-complet: dac se rezolv o problem A, soluia unei alte probleme B se
poate obine printr-o transformare n timp polinomial din soluia problemei A.
Cea mai general problem NP-complet este problema satisabilitii: ind dat
o expresie logic n forma normal conjunctiv cu n variabile, s se determine dac
pot atribuite valori logice variabilelor astfel nct expresia s e adevrat [Coo,
1970].
Complexitatea medie. Considerm un algoritm care proceseaz n valori date
la intrare. Pentru o anumit conguraie a valorilor, probabilitatea conguraiei ind
p
i
, sunt necesare f
i
(n) operaii. Complexitatea medie a algoritmului este o sum
ponderat:
i
p
i
f
i
(n).
Exemplul 2.9.1. Algoritmul Quick-sort necesit un timp de ordin O(nlog n) n ma-
joritatea cazurilor pentru a ordona un ir de n valori. Exist ns cteva conguraii
(foarte puine) care au nevoie de un timp de ordin O(n
2
) pentru a procesate. Com-
plexitatea medie a acestui algoritm este de ordin O(nlog n) [Knu, 1976].
ntr-un mod similar se poate deni noiunea de complexitate pentru necesarul de
memorie. Aceasta arat ct memorie este necesar pentru rezultatele intermediare
i cele de ieire.
Deniiile date mai sus asigur o estimare a ecienei unui algoritm independent
de o implementare practic a acestuia folosind un anumit limbaj de programare,
urmrindu-se ascunderea factorului multiplicativ. Totui acest factor nu poate
ntotdeauna ignorat, deoarece exist probleme care admit mai muli algoritmi cu
acelai ordin de complexitate, i atunci trebuie s se efectueze o ranare a studiului
complexitii. Rezultate recente arat c aceast constant poate inuena eciena
58 2. Complexitatea algoritmilor
unor implementri, de aceea abordrile clasice ale acestui subiect trebuie privite cu
rezerve.
Unele probleme de optimizare se rezolv cu ajutorul unor algoritmi de complexitate
mare, exemplu: probleme NP-complete sau de complexitate O(n
d
). n asemenea
situaii ne mulumim cu soluii aproximative obinute cu ajutorul unor algoritmi
euristici, mult mai ecieni i de cele mai multe ori mai simpli.
O categorie special, frecvent ntlnit mai ales n probleme de geometrie, este
aceea a algoritmilor incrementali. Un algoritm din aceast categorie proceseaz val-
orile de intrare una cte una, la ecare pas obinndu-se o soluie parial pentru
datele deja procesate.
Dac algoritmul de determinare a maximului din n chei prin comparaii efectueaz
un numr liniar de comparaii (adic proporional cu n) atunci se spune c el este
un algoritm (n) (adic are funcia de complexitate din (n) = mulimea funciilor
lineare de forma c n), iar dac efectueaz cel puin, respectiv cel mult, tot attea
comparaii (adic proporional cu n) se spune c algoritmul este (n), respectiv O(n).
Clasele de funcii de complexitate, i implicit clasele de complexitate a algoritmilor,
cele mai des ntlnite, n ordine cresctoare a complexitii sunt: (lnn) - clasa
algoritmilor cu complexitate logaritmic(timpul de execuie va egal cu c lnn), (n)
- liniar (timpul de execuie va egal cu c n), (n lnn) - liniar-logaritmic (timpul
de execuie va egal cu c n lnn), (P(n)) - polinomial (timpul de execuie va
egal cu c P(n)), (e
x
) - exponenial (timpul de execuie va egal cu c Exp(n)) sau
(n!) - factorial (timpul de execuie va egal cu c n!). Peste tot c este o constant
de proporionalitate care depinde de calculatorul pe care se ruleaz programele.
Iat cte un exemplu de algoritm din literatura de specialitate, corespunztor
ecrei clase: algoritmul de cutare binar BinarynSearch - (log n), algoritmul de
determinare a maximului Max - (n) , algoritmul de sortare prin comparaii Quick-
Sort - n log n), algoritmul comun de nmulire a matricelor - (n
3
), algoritmul de
colorare optim cu k culori a unui graf cu n noduri prin ncercri repetate - (k
n
),
respectiv, algoritmul de generare a permutrilor - (n!), toi algoritmii avnd vectorul
de intrare cu n elemente (de dimensiune n).
2.10 Limita inferioar sau efortul minimal. Algoritm
optimal
Atunci cnd ntr-o clas de algoritmi, toi bazai pe aceeai operaie de baz, se poate
stabili o limit inferioar a numrului de operaii de baz inevitabile ce trebuiesc efec-
tuate pentru soluionarea problemei, putem vorbi despre efortul minimal de rezolvare
2.11. Complexitatea algoritmilor i dicultatea problemelor 59
i despre algoritmul optimal de rezolvare a problemei respective.
Algoritmul optimal este acel algoritm care efectueaz cel mai mic numr de operaii
de baz dintre toi algoritmii clasei sale, cunoscui sau neinventai nc (o clas de
algoritmi prin criteriul su de apartenen - prezena operaiei de baz inevitabile -
include obligatoriu n acea clas toi algoritmii ce rezolv problema bazndu-se pe
operaia respectiv, chiar i algoritmii nedescoperii nc !).
De exemplu, n clasa algoritmilor de sortare prin comparaii se nelege c este
aparintor orice algoritm de sortare bazat pe comparaii cunoscut sau necunoscut
nc. n plus, limita inferioar a numrului de comparaii necesar pentru sortarea
listei de n elemente (efortul minimal ) prin comparaii este demonstrat riguros ca
ind log
2
n! dar un algoritm optimal care s efectueze exact attea operaii de baz
(comparaii) nu se cunoate.
n clasa algoritmilor de determinare a maximului prin comparaii, algoritmul clasic
de determinare a maximului este un algoritm optimal ntruct el efectueaz un numr
minimal de comparaii inevitabile: n 1.
2.11 Complexitatea algoritmilor i dicultatea prob-
lemelor
Din perspectiva rezolvrii problemelor cu ajutorul calculatorului putem studia i com-
para dicultatea problemelor studiind i comparnd complexitatea algoritmilor opti-
mali de soluionare a acestora.
Astfel, problema sortrii prin comparaii cere un efort minimal liniar-logaritmic.
Ea nu este totui o problem de efort liniar-logaritmic((n log n)) ntruct ea poate
soluionat cu efort liniar((n) operaii) atunci cnd cheile de sortare pot dis-
tribuite folosind un algoritm de sortare prin distribuire.
2.12 Complexitatea de timp
Msurarea n practic a duratei de execuie (adic a complexitii de timp) a im-
plementrii algoritmilor a condus la urmtoarea concluzie categoric: singurii algo-
ritmi ce soluioneaz n mod ecient o problem oarecare sunt acei algoritmi care
au complexitatea polinomial (sau mai mic dect exponenial). O astfel de soluie
se numete soluie rezonabil, fa de cealalt situaie cu soluie nerezonabil avnd
o complexitate de timp exponenial sau factorial (total inecient ca durat de
execuie).
60 2. Complexitatea algoritmilor
De exemplu, dac pentru colorarea unui graf cu n vrfuri cu doar trei culori, se
ncearc toate cele 3
n
variante de colorare (printr-un algoritm de tip backtracking),
timpul necesar unui program pentru epuizarea tuturor cazurilor, n cazul n care
n = 100, este direct proporional cu uriaa valoare de 3
100
= 387420489
10
ceea ce face
acel program cu totul inutilizabil (chiar dac am presupune c o instruciune s-ar
executa ntr-o pico-secund = 10
12
s).
2.13 Probleme rezonabile i probleme nerezonabile.
Clasa problemelor P-polinomiale
Dup efortul de rezolvare necesar, reductibil n ultim instan la durat de execuie a
programului, problemele se pot mpri n probleme rezonabile i nerezonabile. innd
cont de cele de mai sus, problemele rezonabile sunt problemele de dicultate polino-
mial i ele sunt grupate n clasa problemelor P (Clasa problemelor Polinomiale).
Pentru ecare problem din aceast clas se cunoate un algoritm de soluionare cu
complexitate polinomial, adic programul ce implementeaz acest algoritm are o du-
rat de execuie proporional cu o funcie polinomial de n, unde n este dimensiunea
datelor de intrare.
Exist cu siguran probleme ce nu fac parte din aceast clas P: de exemplu,
problema generrii tuturor celor n! permutri ale unui ir de n elemente distincte,
care are inevitabil dicultatea (durata de execuie) factorial n!.
2.14 Probleme de decizie i probleme de optimizare
n ncercarea de a studia i clasica dicultatea problemelor ne-polinomiale (nerezon-
abile ca durat de rezolvare cu ajutorul calculatorului) ele au fost grupate n dou
categorii: probleme n varianta de decizie, n care se cere doar s se decid prin DA
sau NU dac exist pentru problema respectiv o soluie bine precizat, i probleme n
varianta de optimizare, n care se cere determinarea soluiei optime pentru problema
respectiv.
De exemplu, problema colorrii grafului n varianta de decizie cere s se decid
dac un graf poate colorat cu k culori, unde k este precizat dinainte. Aceeai
problem, n varianta de optimizare, cere s se determine X - numrul minim de
culori necesar (numrul cromatic) pentru colorarea unui graf (astfel nct oricare
dou vrfuri adiacente s e colorate diferit), X ind evident un numr ce nu poate
precizat dinainte.
2.15. Clasa problemelor NP (non - deterministic polinomiale) 61
2.15 Clasa problemelor NP (non - deterministic poli-
nomiale)
Exist o clas larg de probleme de decizie cu extrem de numeroase aplicaii practice
numit clasa problemelor NP(non-deterministic polinomiale). Aceast clas include
pe lng toate problemele de decizie din P i o mulime foarte mare de probleme de
decizie (toate inspirate din practic) crora nu li se cunoate o soluie polinomial.
Pentru a putea explica de ce sunt numite NP (non-deterministice), este necesar s
revenim la echivalarea unanim acceptat de teoreticienii informaticii ntre noiunea
de algoritm i noiunea de main Turing. Astfel, pentru ecare din problemele NP
se cunoate o soluie sub forma unei maini Turing nedeterministice(!) (care la o
tranziie de stare poate trece dintr-o stare ntr-una din oricare alte k stri posibile,
fr a se putea preciza exact n care) care se oprete furniznd soluia dup un numr
polinomial de pai.
n termenii algoritmici, aceeai non-determinarea este exprimat astfel: o prob-
lem NP este o problem ce are un algoritm de soluionare care decide n timp poli-
nomial dac o soluie propus (prin "ghicire" sau "inventare" ) este sau nu valid.
n aceti termeni, nedeterminarea const mai exact n faptul c sub-algoritmul
de ghicire sau inventare de soluii, din cauz c nu poate parcurge ntreg spaiul
soluiilor posibile pentru c nu ar mai rmne un algoritm polinomial, nu ofer nici
o garanie c gsete sau c se apropie mcar n vreun fel de soluia problemei prin
simpl ghicire.
2.16 Reducia polinomial a problemelor
n intenia de a compara dicultatea problemelor de decizie ntre ele s-a sesizat c
dac exist un algoritm de transformare T a datelor de intrare D
) s se potriveasc ca date
de intrare unei probleme de decizie P, ce are ca soluie un algoritm de soluionare
cunoscut A, atunci un algoritm de soluionare A
a problemei P
se obine imediat
prin compunerea algoritmului A cu transformarea T astfel nct A
= A T.
Dac complexitatea algoritmului de transformare T este rezonabil (polinomial)
atunci nseamn c complexitatea algoritmului A
, y : 5, z : 5);
End; {S1}
Begin
102 3. Pogramare n limbajul PASCAL
For x := 2 To 4 Do
Begin
S1(x);
Writeln(In program x, z =
, x : 5, z : 5);
End
End.
La execuia acestui program se obin urmtoarele rezultate:
In procedura y, z = 4 0
In program x, z = 2 0
In procedura y, z = 9 5
In program x, z = 3 5
In procedura y, z = 16 11
In program x, z = 4 11
Se poate observa c valorile variabilei locale y nu au fost retransmise n programul
principal, parametrul actual x nemodicndu-i valorile prin execuia procedurii S1.
Parametrii de tip referin
Parametri de tip referin se folosesc pentru a transmite valori ntre unitatea apelant
i subprogramul apelat, n ambele sensuri. De obicei, sunt folosii pentru a nota rezul-
tatele obinute n subprogram. Parametrul actual a corespunztor unui parametru
formal de tip referin f este obligatoriu o variabil de acelai tip cu parametrul formal
f. La apelul unui subprogram parametrul formal se consider identic cu parametrul
actual corespunztor. Practic, acest lucru se realizeaz prin faptul c amndoi au
aceeai adres n memorie. Astfel, parametrul actual a devine parametru global;
orice modicare a parametrului formal f este i o modicare a parametrului actual a.
Se recomand ca parametrii actuali corespunztori parametrilor formali variabil
s e distinci. Unele implementri consider eroare cnd la doi parametri formali
corespunde acelai parametru actual, altele accept o astfel de coresponden. Atenie
ns la o asemenea situaie ntruct ind identici cu acelai parametru actual, cei doi
parametri formali devin identici ntre ei, ceea ce poate duce la efecte neateptate. De
aceea, recomandm s se evite o asemenea utilizare, chiar dac ea este permis.
Parametrii funcie i parametrii procedur
Din deniia sintactic a listei parametrilor formali se observ c un parametru formal
poate i o funcie sau o procedur. Parametrul actual trebuie s e o funcie,
respectiv o procedur similar parametrului formal corespunztor.
3.14. Instruciunea apel de procedur 103
Un exemplu de program n care se folosesc parametrii formali i actuali funcii i
proceduri este cel de mai jos, n care se calculeaz radicalii de ordinul doi i trei din
constanta mm (n program egal cu 2) rezolvnd ecuaiile:
x
2
- mm = 0, notat g(x) = 0,
respectiv
x
3
- mm = 0, notat h(x) = 0.
Pentru rezolvarea unei ecuaii se pot folosi mai multe metode. n program am ales
dou: metoda njumtirii i metoda coardei. ntruct metoda coardei folosete i
prima derivat, am notat prin f1, respectiv g1 derivatele funciilor f i g.
Exemplul n Pseudocod, a fost prezentat n seciunea 1.4.
Exemplul 3.14.3.
Program lpf; { P.F. funcii si proceduri}
Const mm = 2;
Type
fct = Function (x: real): Real;
sub1 = Procedure (a, b: Real; Var r:Real; f,f1:fct);
Var r: Real;
i: Integer;
Function g(s: Real): Real;
Begin
g := s*s - mm;
End;
Function h(s: real): Real;
Begin
h:= s*s*s - mm;
End;
Function g1(s: real): Real;
Begin
g1 := s + s;
End;
Function h1(s: Real): Real;
Begin
h1 := 3*s*s;
End;
Procedure coarda(a, b: Real; Var r: Real; f, f1: fct); {Se rezolva ecuatia
104 3. Pogramare n limbajul PASCAL
f(x) = 0 prin metoda coardei}
Var c, t: Real;
Begin
c := a; t := b;
Repeat
c := c - f(c)*(t-c)/(f(t)-f(c));
t := t - f(t)/f1(t);
Until t - c < 0.00001;
r := (c+t)/2
End;
Procedure juma(a, b: Real; Var r: Real; f, f1: fct); {Se rezolva ecuatia
f(x)=0 prin metoda injumatatirii}
Begin
Repeat
r := (a+b)/2;
If f(a)*f(r) < 0 Then
b := r
Else
a := r;
Until b - a < 0.00001
End;
Procedure Rezec(a, b: Real; Var r: Real; f, f1: fct; met: sub1);
Begin
met(a, b, r, f, f1);
End;
Begin
Eriteln(injumatatire coarda: );
Writeln(radical din 2);
Rezec(1, 2, r, g, g1, juma);
Write(r = , r:9:5);
Rezec(1, 2, r, g, g1, coarda);
Writeln( , r:9:5);
Writeln(radical din 3);
Rezec(1, 2, r, h, h1, juma);
Write(r = , r:9:5);
Rezec(1, 2, r, h, h1, coarda);
3.15. Apel recursiv 105
Writeln( , r:9:5);
End.
3.15 Apel recursiv
n exemplele date se observ c apelul unui subprogram se face dup ce el a fost
denit. Este ns permis ca n interiorul unei proceduri s e denit o alt procedur.
Aceast procedur poate utilizat numai n interiorul procedurii n care a fost
declarat i numai dup ce a fost denit.
Este posibil, ca un subprogram s se apeleze pe el nsui, recursiv. Ca exemplu,
prezentm n continuare un program care folosete o funcie care calculeaz recursiv
valoarea n! cu ajutorul formulei n! = n.(n 1)!.
Exemplul 3.15.1.
Program ApelRecursiv; { n Factorial }
Type nat = 0..maxint;
Var i: nat;
Function Fact(n: nat): nat;
Begin
If n = 0 Then
Fact := 1
Else
Fact := n * Fact(n-1)
End;
Begin
For i:=3 to 7 do
Writeln(i, ! = , Fact(i))
End.
S urmrim execuia apelului FACT(n) pentru n = 3. S observm c funcia
Fact nu are nici o variabil local n afar de parametrul formal de valoare n. Deci,
la apelul acestei funcii se vor rezerva dou locaii de memorie, una pentru n i una
pentru valoarea funciei FACT, ecare apel nsemnnd o astfel de rezervare.
Deci, dup primul apel, zona de memorie alocat este cea situaia a) de mai jos.
Pentru a efectua atribuirea Fact(1) := 3*Fact(2) se apeleaz Fact(2) i se rezerv
din nou dou locaii de memorie, ajungnd la situaia din situaia b) de mai jos.
La execuia acestui apel trebuie efectuat atribuirea Fact(2) := 2*Fact(1). Deci are
106 3. Pogramare n limbajul PASCAL
loc un al treilea apel, Fact(1), pentru care se rezerv din nou memorie, ajungndu-
se la situaia c) de mai jos. De aceast dat se cere efectuarea atribuirii Fact(3) :=
1*Fact(0) i are loc un al patrulea apel, Fact(0), ajungndu-se la situaia d) de mai jos.
Cnd ultimul apel s-a executat, el ntoarce valoarea Fact(4) := 1 i se elibereaz zona
de memorie corespunztoare ajungndu-se la situaia situaia e) de mai jos. ntruct
i apelul Fact(1) a fost executat, se ajunge la situaia f) de mai jos. Se efectueaz
i atribuirea Fact(2) := 2*Fact(1) = 2 cu care se termin execuia apelului Fact(2),
ajungndu-se la situaia g) de mai jos. n aceast situaie se ncheie i execuia
primului apel cu valoarea Fact(1) := 6.
3 ?
n Fact1
a) 3 ? 2 ?
n Fact1 n Fact2
b) 3 ? 2 ? 1 ?
n Fact1 n Fact2 n" Fact3
c) 3 ? 2 ? 1 ? 0 1
n Fact1 n Fact2 n" Fact3 n" Fact4
d) 3 ? 2 ? 1 1
n Fact1 n Fact2 n" Fact3
e) 3 ? 2 2
n Fact1 n Fact2
f) 3 6
n Fact1
g)
S observm att modul de execuie al unui apel recursiv ct i faptul c necesarul
de memorie crete la ecare apel. Iar n cazul n care zona de date locale ale procedurii
este mare, volumul de memorie utilizat poate crete foarte mult.
Din aceast cauz apelul recursiv nu este indicat. Consumul de memorie i timpul
necesar execuiei sunt mult mai mari dect n cazul unui program nerecursiv core-
spunztor aceleai probleme. Totui, folosirea procedurilor recursive are avantajul
unei descrieri mai clare i mai apropiat de limbajul matematic.
3.16 Tipuri de date structurate
Am vzut c prin termenul de dat nelegem o valoare a unei informaii folosit
ntr-un algoritm, cum ar numrul 1394, sau caracterul A, sau (1, Martie, 1996).
O dat atomic este o dat pe care o putem considera, cel puin pentru un moment,
3.16. Tipuri de date structurate 107
o entitate nedecompozabil. De exemplu, numrul 1394 poate considerat o dat
atomic memorat, scris pe aceast hrtie. Dar, putem vedea acest ntreg i ca o
dat compus, ca o secven de cifre scrise aici de la stnga spre dreapta; n acest caz
ecare cifr este considerat atomic, ns ntregul va o dat compus. O cifr la
rndul ei ar putea considerat compus, de exemplu, din puncte. Astfel putem alege
orice nivel la care s oprim descompunerea unei date, considernd-o apoi atomic.
Dac descompunem o dat, ca i mai sus ntregul 1394, atunci valorile obinute
le vom numi elemente componente, sau simplu elemente. O dat care se compune
din mai multe elemente o numim dat structurat. O dat structurat are elemente
componente i o structur, care denete modul de aranjare sau relaiile ce se pot
stabili ntre elemente.
n ncercarea de a grupa datele dup caracteristici comune a fost introdus noi-
unea de tip. Printr-un tip de date nelegem o mulime de valori (de date) i o mulime
de operaii ntre aceste valori. Dac valorile din mulime sunt atomice atunci avem
un tip de date atomic, iar dac valorile sunt structurate atunci avem un tip de date
structurat, sau o structur de date. Deci o structur de date este un tip de date ale
crui valori:
(1) pot descompuse ntr-o mulime de elemente de date, ecare element putnd
atomic sau o alt structur de date;
(2) includ o mulime de asocieri, sau relaii (structura) ntre elementele componente.
Operaiile unui tip de date structurat pot s acioneze nu numai asupra valorilor
tipului de date ci i asupra elementelor componente ale structurii de date.
Alegerea unei reprezentri potrivite pentru obiectele de date pe care le folosim
ntr-un program este de importan major. Dar, s denim nti ce nelegem prin
reprezentarea datelor. Termenul reprezentarea datelor nseamn o alegere particular,
din mai multe care sunt posibile, a componentelor, a tipului lor, i a organizrii acestor
valori memorate ntr-un obiect.
n acest capitol sunt prezentate cteva alternative disponibile n limbajul Pascal
pentru reprezentarea datelor structurate.
1. Structura de tablou
Una din structurile de date eseniale n programare sunt cele de tip tablou. Cel mai
simplu mod de a folosi tablourile este de a reprezenta date organizate ca i un ir
elemente. La fel, cu ajutorul lor se pot reprezenta diferite tipuri de tablouri. De
exemplu, un tabel al notelor obinute la un examen de studenii dintr-o grup, ar
putea arta astfel
108 3. Pogramare n limbajul PASCAL
Student Nota
1 9
2 7
3 10
. . . . . .
25 8
Un astfel de tabel ar putea reprezentat ntr-un program printr-un tablou.
Un tablou const dintr-un ir elemente, ecare element ind identicat printr-un
indice. Elementele sunt toate de acelai tip de date, care poate orice tip. Indicii
sunt dintr-un subdomeniu al unui tip ordinal. Caracteristicile eseniale ale unui tablou
sunt dou: elementele sunt ordonate prin irul valorilor indicilor, respectiv elementele
sunt de acelai tip.
Pentru a deni reprezentarea unui tablou trebuie s precizm dou lucruri: sub-
domeniul indicilor i tipul de date al elementelor componente. Sintaxa specicrii n
Pascal a unei structuri de tablou este
<tablou> ::= Array [<tip1>] of <tip2>
unde parantezele drepte i tipurile <tip1> i <tip2> sunt obligatorii. Tipul <tip1>
se numete tip de indexare i precizeaz valorile pe care le poate lua indicele tabloului.
El poate orice tip ordinal diferit de Integer, putnd ns un subdomeniu al tipului
Integer. Tipul elementelor tabloului este <tip2>, care poate orice tip denit
anterior: predenit sau denit de ctre utilizator, sau orice tip anonim.
Astfel, prin array [1...25] of integer
se specic un tip de tablou cu componente ntregi, ale crui elemente sunt indexate
prin numere ntregi de la 1 la 25.
Prin Array[A..Z] Of Real
se specic o structur de tablou cu componente reale ale crui elemente sunt indexate
prin caractere aate n subdomeniul A...Z. Dac tabloul Tab are acest tip atunci
elementele sale sunt Tab[c] pentru c n subdomeniul A...Z.
Un element al tabloului se refer prin scrierea numelui tabloului urmat de rangul
elementului n acest tablou (indicele) scris ntre parantezele drepte, [ i ]. Un element
selectat al tabloului poate folosit ca i orice variabil de tipul elementelor tabloului.
Singura operaie predenit asupra tablourilor este atribuirea, A := B, care are
ca efect copierea valorilor elementelor tabloului B n elementele corespunztoare
tabloului A. Cele dou tablouri trebuie s e de acelai tip.
Un tablou este reprezentat n memoria calculatorului ca i un ir de locaii de me-
morare, ecrui element corespunzndu-i o locaie. Tabloul Pascal este o abstractizare
3.16. Tipuri de date structurate 109
care ascunde detaliile despre cum este organizat un tablou n memoria calculatorului.
n gura urmtoare este sugerat reprezentarea unui tablou n memorie, ecrei locaii
de memorare corespunzndu-i un dreptunghi, valoarea unui element ind nscris n
dreptunghiul corespunztor. S notm c indicii nu sunt memorai ca i parte a
tabloului.
Nota[1] Nota[2] Nota[3] . . . Nota[25]
9 7 10 . . . 8
Elementele unui tablou pot la rndul lor tablouri. Astfel, elementele unui tablou
de tipul
Array[1..10] Of Array[1..6] Of Real
sunt vectori cu 6 componente reale. Dac T este un tablou de acest tip atunci T are
10 componente, ecare component ind un vector cu 6 componente. De fapt este
vorba de o matrice cu 10 linii i 6 coloane. Componenta T[i] a acestui tablou va un
vector cu 6 componente numere reale. Selectarea elementului cu indicele j al tabloului
T[i] poate fcut prin T[i][j].
Menionm c se accept o prescurtare a declaraiei de mai sus sub forma
Array[1..10, 1..6] Of Real
Dei nu este o declaraie echivalent cu cea de mai nainte, ea permite totui declararea
unei matrice cu 10 linii i 6 coloane. Diferena const n faptul c folosind aceast
declaraie o linie a matricei nu mai este considerat ca o entitate de sine stttoare.
Referirea la linia i prin T[i] este greit n acest caz, iar prin T[i, j] se refer elementul
din linia i coloana j.
n continuare, vom scrie un program n care se folosete un subprogram pentru
ordonarea cresctoare a unui ir de numere reale, pe care-l vom apela pentru a ordona
mai nti un ir dat de numere reale x[1], x[2], ..., x[n], iar apoi pentru a ordona
ptratele acestor numere.
Exemplul 3.16.1.
Program Tablou1; { Tablouri}
Type Vector = array[1..100] Of Real;
Var i, n: Integer;
x : Vector;
Procedure Tipar(n:Integer; x:vector); {Tipareste, vectorul X cu n elemente}
Begin
Writeln;
For i:=1 To n Do Write(x[i])
End; {Tipar}
110 3. Pogramare n limbajul PASCAL
Procedure Ordonare(n: Integer; var X: Vector); {Ordoneaz nedescrescator }
{ primele n componente ale vectorului X}
Var i, kod: Integer;
t: Real;
Begin
Repeat kod := 0;
For i:=1 To n-1 Do
If x[i] > x[i+1] Then
Begin
kod := 1; t := x[i];
x[i] := x[i+1];
x[i+1] := t
End {if}
Until kod = 0
End; {Ordonare}
Begin
Write(n = ); Readln(n);
For i:=1 To n Do
Read(x[i]);
Writeln(Sirul ordonat este:);
Ordonare(n, X);
Tipar;
For i:=1 To n Do
x[i] := x[i]*x[i];
Writeln(Sirul patratelor dupa ordonare:);
Ordonare(n, X);
Tipar(n,X)
End.
Dm i un exemplu de program n care apar matrici. Programul rezolv urm-
toarea problem:
Exemplul 3.16.2. Se d o matrice patrat A i se cere s se tipreasc matricele
A, A
2
, A
3
i A
4
. Pentru tiprirea unei matrice i pentru nmulirea a dou matrice se
folosesc procedurile TipMat, respectiv ProdMat. Programul Pascal este urmtorul:
Program PuteriMat; { Puterile unei matrice}
Const n = 5;
Type Mat = Array[1..n, 1..n] Of Real;
Var A, B, C: Mat;
3.16. Tipuri de date structurate 111
Procedure CitMat(n: Byte; var A: Mat); {Citeste matricea A}
Var i, j: Byte; {patrata de ordinul n}
Begin
For i:=1 To n Do
For j:=1 To n Do
Begin
Write(A(, i, ,, j, )=);
Readln(A[i,j])
End;
End;
Procedure TipMat(n: Integer; {Tiparete mesajul s si}
A: Mat; s: String); {matricea A de ordinul n}
Var i, j: Integer;
Begin
Writeln; Writeln;
Writeln(s);
For i:=1 To n Do
Begin
Writeln;
For j:=1 To n Do
Write(A[i,j]:8:1);
End
End; {TipMat}
Procedure ProdMat(n: Byte; A, B: Mat; var C: Mat); {n = ordinul matricelor}
{C := A * B}
Var i, j, k: Integer;
s : Real;
Begin
For i:=1 To n Do
For j:=1 To n Do
Begin
s:=0;
For k:=1 To n Do
s := s+A[i,k]*B[k,j];
C[i,j] := s
End
End; {ProdMat}
112 3. Pogramare n limbajul PASCAL
Begin
Writeln(Se tiparesc puterile unei matrice);
Writeln(Dati matricea !);
CitMat(n, A);
TipMat(n, A, Matricea A este: );
ProdMat(n, A, A, B);
TipMat(n, B, Matricea A*A este: );
ProdMat(n, A, B, C);
TipMat(n, C, Matricea A*A*A este: );
ProdMat(n, B, B, C);
TipMat(n, C, Matricea A*A*A*A este:);
End.
Structura de date nregistrare
Multe obiecte din lumea real le descriem de obicei prin enumerarea unor atribute
importante pe care le au. Atributele servesc la descrierea clasei generale de obiecte -
tipul obiectului. Un obiect particular de acel tip este denit prin asocierea unei valori
particulare ecrui atribut. De exemplu, o noti dintr-o agend telefonic personal
poate referi o persoan prin atributele Nume, Telefon i Adres, iar o persoan notat
n agend ar putea :
Ioana Pop; 174563; G. Enescu, 25/A.
n programare putem descrie date compuse (deci i tipul de date corespunztor)
ntr-un mod asemntor. Precizarea (denirea) tipului de date se va face prin enu-
merarea numelor unor atribute i precizarea unui tip de date asociat ecrui atribut.
Un obiect particular de acest tip nou va conine o valoare particular pentru ecare
atribut specicat. Un astfel de tip de date l vom numi tip de date nregistrare.
Fiecare atribut l numim cmp al nregistrrii. Un obiect de date de tip nregistrare
va numit o nregistrare.
Observm c structura de date nregistrare modeleaz produsul cartezian din
matematic. O nregistrare const dintr-un numr x de elemente componente de
diferite tipuri. Caracteristica esenial a unei nregistrri este c ea grupeaz ele-
mente de dat de diferite tipuri ntr-o singur entitate. Acest aspect contribuie la o
exprimare concis i uor de urmrit n programare.
Sintaxa specicrii unui tip nregistrare n limbajul Pascal este:
Record <selector> : <tip> { ; <selector> : <tip> } End
3.16. Tipuri de date structurate 113
unde <selector> este un identicator sau o list de identicatori iar <tip> este un tip
predenit sau denit anterior i specic tipul selectorului din stnga sa. Selectorii
care apar dup cuvntul record trebuie s e distinci ntre ei i constituie numele dat
componentelor corespunztoare ale produsului cartezian.
Un astfel de tip nregistrare poate primi un nume folosind declaraia type, prezen-
tat anterior. De exemplu, prin
Type Data = Record
zi : 1..31;
luna: 1..12;
an : 1900..1999
End;
se denete un tip nregistrare cu numele Data i care are trei componente: zi, luna,
an. Se observ c este un tip ce conine toate datele din secolul nostru, sub forma
unor triplete (z,l,a).
Operaiile asupra nregistrrilor sunt atribuirea nregistrrilor i selectarea unui
cmp al unei nregistrri. Dac A i B sunt dou nregistrri de acelai tip, atunci
atribuirea A := B, va avea ca efect copierea valorilor cmpurilor nregistrrii B n
cmpurile nregistrrii A. Pentru selectarea unui cmp particular al unei nregistrri
vom folosi notaia
<variabila-nregistrare> . <selector>
Astfel, pentru variabila V de tipul Data vom avea urmtoarele trei componente
(variabile selectate):
V.zi, V.luna, V.an.
Vom scrie o procedur care rezolv problema de mai jos i care folosete tipul
Data, denit mai sus. Problema este urmtoarea:
Exemplul 3.16.3. S se determine vrsta unei persoane n numr de zile dac se
cunoate data naterii persoanei i data curent. Subalgoritmul pentru determinarea
vrstei, dat sub form de funcie, este urmtorul:
Pseudocod:
FUNCIA VARSTA(Dnas, Dazi) ESTE:
FIE nr := NRZIAN(Dazi);
@Pentru (ecare an ntreg din via) adun la nr
numrul zilelor anului respectiv;
FIE VARSTA := nr - NRZIAN(Dnas);
sf-VARSTA
114 3. Pogramare n limbajul PASCAL
Acest subalgoritm folosete funcia NRZIAN(zi) pentru a determina a cta zi din
an este o dat curent. Funcia menionat este descris n continuare.
FUNCIA NRZIAN(zian) ESTE:
FIE nr := ziua curent a lunii;
DAC@(nu suntem n ianuarie) ATUNCI
PENTRU@ ecare lun ntreag EXECUT
FIE nr := nr + numrul zilelor lunii i;
SFPENTRU
DAC@ (a trecut februarie) ATUNCI
DAC@ anuI este bisect ATUNCI
nr:=nr+1
SFDAC
SFDAC
SFDAC
FIE NRZIAN:=nr;
SF-NRZIAN
Procedura Pascal corespunztoare se denete n programul urmtor:
Program ApelFunctie; { Tipul inregistrare}
Const NZile: Array[1..12] Of Integer =(31, 28, 31, 30, 31, 30, 31, 31, 30, 31,
30, 31);
Type Data = Record
zi : 1..31;
luna: 1..12;
an : 1900..1999
End;
Var Dnas, { Data nasterii }
Dazi: Data; { Data curenta }
Function Bisect(a: Integer): Boolean; { Adevarata daca }
Begin { a e bisect }
If a Mod 4 = 0 Then
Bisect := True
Else
Bisect := False
End;
Procedure CitData(Var D: Data); { Citete un triplet }
Begin { zi, lun, an care }
3.16. Tipuri de date structurate 115
Write(ziua=); Readln(D.zi); { reprezint o dat }
Write(luna=); Readln(D.luna);
Write(anul=); Readln(D.an);
End;
Function NrZiAn(V: Data): Integer; { NRZIAN := a cata zi }
Var i, nr: Integer; { in an este data V }
Begin
nr := V.zi;
If V.luna > 1 Then
For i:=1 To V.Luna-1 Do
nr := nr + NZile[i];
If V.luna > 2 Then
If Bisect(V.an) Then
nr := nr + 1;
NrZiAn := nr
End; {NRZIAN}
Function Varsta(Dnas, Dazi: Data): Integer; { Varsta := }
Var i, nr: Integer; {numarul de zile aate}
Begin {intre datele Dnas si Dazi}
nr := NrZiAn(Dazi);
For i := Dnas.an To Dazi.an-1 Do
Begin
nr:=nr+365;
If Bisect(i) Then
nr:=nr+1
End; {For}
Varsta := nr - NrZiAn(Dnas);
End; {Varsta}
Begin {Programul principal}
Writeln(Dati data nasterii: ); CitData(Dnas);
Writeln(Dati data curenta: ); CitData(Dazi);
Writeln(Persoana nascuta in: );
Writeln((, Dnas.zi, ,, Dnas.luna, ,, Dnas.an, ));
Writeln(are varsta , Varsta(Dnas,Dazi), zile.);
End.
116 3. Pogramare n limbajul PASCAL
n denirea unui tip nregistrare o component poate la rndul ei de tipul nre-
gistrare. Un astfel de exemplu se d n continuare:
Type Student = Record
nume, prenume: Array[1..8] Of Char ;
datan: record
zi : 1..31 ;
luna: 1..12 ;
an : 1900..1989
End;
note: Array[1..12] Of 1..10
End;
n acest caz, dac X are tipul Student atunci prin X.datan se noteaz tripletul
X.datan.zi X.datan.luna X.datan.an
care reprezint data naterii studentului X, iar X.nume este numele acestui student.
3.17 Tipul referin
n multe aplicaii practice care folosesc prelucrri de date, nu este posibil s cunoatem
a priori dimensiunea datelor. Din aceast cauz, utilizarea unui tablou pentru a stoca
aceste date este inecient, deoarece e facem risip de memorie printr-o alocare
static acoperitoare, e sub dimensionm tabloul pentru stocarea datelor, ceea ce
poate duce la fenomene de depire a zonei de memorie alocat datelor, acest fenomen
ind un fenomen sever care poate duce la blocarea execuiei programului i chiar
la blocarea sistemului de calcul. Limbajul de programare Turbo Pascal stabilete
dimensiunea de memorie alocat datelor de la nivelul codului surs, care, compilat
i editat, se transform n cod executabil. Pe parcursul execuiei nu se pot modica
dinamic alocrile de date declarate la nivelul codului surs.
De aceea, pentru a rezolva problema unei alocri dinamice a memoriei trebuie
s utilizm un tip de dat special, numit tip referin sau pointer i o serie de
proceduri speciale care s aloce memorie sau s elibereze zona de memorie folosit i
care nu mai este necesar. Tipul de date referin (pointer) va conine adresa unui
anumit tip de dat. Declaraia de tip este:
nume_dat = tip;
unde nume_dat este numele noului tip de dat referin, iar tip reprezint tipul
datelor referite de ctre datele de tip nume_dat.
3.17. Tipul referin 117
Declaraia de mai sus este o declaraie generic de tip, neavnd ca efect rezervarea
propriu-zis de memorie.
Pentru a realiza efectiv alocarea unei zone de memorie de dimensiunea dat de
tipul de dat tip, va trebui s folosim procedura New. Apelul procedurii se face
astfel:
New(variabil _referin);
Unde variabil_referin este o variabil numit variabil dinamic [Cri, 1992].
Procedura New realizeaz alocarea dinamic a memoriei heap pe parcursul exe-
cuiei programului. n urma apelrii procedurii New, variabilei dinamice vari-
abil_referin i se va atribui o adres de memorie de dimensiune egal cu zona
de memorie ocupat de o dat de tipul referit. Asupra variabilelor dinamice pot
efectuate orice operaii permise de tipul acestora. Variabilele dinamice pot primi
valori i prin operaii de atribuire, pot apare n expresii relaionale care utilizeaz
operatorii relaionali = i <>.
Limbajul Turbo Pascal permite utilizarea tipului pre-denit pointer. Acest tip de
dat este compatibil cu orice tip referin denit de utilizator. Unei variabile de tip
pointer i poate atribuit valoarea adresei oricrei variabile, proceduri sau funcii
denite de utilizator. O astfel de adres poate obinut prin utilizarea operatorului
@, astfel:
@variabil;
Dac o variabil de referin are valoarea Nil nseamn c variabila respectiv conine
o adres imposibil, care nu exist n zona de memorie. Eliberarea efectiv a spaiului
de memorie ocupat se face cu ajutorul procedurii DISPOSE, dup urmtoarea regul:
Dispose(variabil_referin);
unde adresa zonei de memorie ce se va elibera este coninut n variabil_referin.
Dimensiunea zonei de memorie eliberat este dat de dimensiunea tipului de dat
referit de variabil_referin.
Dac dorim s alocm sau s eliberm n mod explicit un anumit numr de octei
putem folosi procedurile GetMeM i FreeMem.
118 3. Pogramare n limbajul PASCAL
3.18 Probleme propuse
1. Se d un ir de numere naturale al crui sfrit este marcat prin valoarea 0.
Spunem c dou numere naturale sunt asemenea dac scrierile lor n baza 10 se
face cu aceleai cifre (Ex. 36668 i 8363). S se gseasc secvena de numere
consecutive asemenea de lungime maxim din irul dat i frecvenele cifrelor n
scrierea numerelor date.
2. Se citesc mai multe iruri de numere naturale nenule ecare ir terminndu-se
la citirea valorii zero. Pentru ecare ir s se tipreasc secvena de elemente
consecutive de lungime maxim format din numere prime. La sfrit se vor
tipri i toate numerele prime ntlnite. Citirea se va ncheia cnd irul citit are
0 termeni (altfel spus la citirea a doi de zero consecutivi)
3. S se scrie un program pentru determinarea reuniunii unor mulimi de numere
ntregi pozitive. O mulime se d ntotdeauna ncepnd pe un rnd nou, iar
sfritul elementelor sale este marcat prin numrul 0. Mulimile se termin la
ntlnirea mulimii vide. Se va tipri reuniunea acestor mulimi i mulimea cu
cele mai multe elemente, tiprirea elementelor unei mulimi se va face n ordinea
cresctoare a valorilor elementelor.
4. Fiind date mai multe polinoame cu coecieni reali s se determine suma lor i
polinomul de grad maxim. Un polinom se d e prin monoamele sale, e prin
grad i coecieni. Citirea polinoamelor se va ncheia la introducerea gradului
negativ.
5. Participanii la un concurs sunt identicai printr-un numr strict pozitiv
(numr legitimaie), i obin un punctaj (numr ntreg). S se scrie un program
Pascal care citete rezultatele obinute la acest examen i tiprete toi candi-
daii ordonai cresctor dup numrul legitimaiilor, cu punctajul corespunztor
i primii m (m > 0) candidai n ordinea descresctoare a punctajelor (dac doi
dintre acetia au punctaje egale atunci ei se difereniaz n ordine cresctoare
dup numrul legitimaiei).
6. S se scrie un program care citete cte un polinom cu coecieni ntregi (in-
trodus e prin grad i coecieni e prin monoamele sale), pn la ntlnirea
unui polinom de grad 0. Pentru ecare polinom P citit, determin rdcinile
naturale ale lui P i le tiprete sub forma:
Rdcinile naturale ale polinomului P cu coecienii
. . .
3.18. Probleme propuse 119
sunt ...
7. Se dau un polinom P (grad + irul coecienilor), i un ir de triplete (a, b, e)
pentru care P(a) P(b) <= 0 si e > 0, irul terminndu-se cu un triplet n
care e < 0. S se gseasc rdcina ecuaiei P(x) = 0 din intervalul [a, b], prin
metoda njumtirii, cu eroarea e, i s se tipreasc:
"n intervalul [a, b] polinomul are rdcina ..., aproximat cu precizia ...(valoarea
lui e)".
pentru ecare triplet, iar la sfrit s se tipreasc toate rdcinile pozitive
gsite.
8. S se scrie un program care creeaz matricea ptratic de ordinul n (dat),
format din scrierea cifrelor semnicative ale numerelor naturale n ordinea
liniilor i tiprete matricele A, A
2
, ..., A
m
.
9. Fiind date dou numere naturale s se scrie un program Pascal pentru a deter-
mina cel mai mic i cel mai mare dintre ele. Un numr poate avea cel mult 100
cifre. Numerele se introduc de la tastatur prin cifrele lor (reprezentare n baza
10).
10. S se scrie un program Pascal care citete mai multe matrice i tiprete matricea
care are determinantul cel mai mare. Pentru ecare matrice programul citete
ordinul matricei i elementele n ordinea liniilor. Execuia programului se ncheie
cnd se introduce 0 pentru ordinul unei matrice.
11. S se scrie un program care citete dou numere naturale nenule a i b si tiprete
restul mpririi lui a la b. Numerele pot avea cel mult 50 cifre i sunt reprezen-
tate n baza 10.
12. S se scrie un program care tiprete rdcinile raionale ale unui polinom cu
coecieni ntregi (dac exist), polinom dat prin grad i coecienii si.
120 3. Pogramare n limbajul PASCAL
Capitolul 4
Structuri de date
4.1 Lista liniar simplu nlnuit
Multe din informaiile prelucrate de calculator sunt organizate ca liste: elementele
unui vector, irul format de numele din cartea de telefon (lista abonailor), lista
candidailor la admitere ntr-o facultate, lista materialelor necesare dintr-o secie in-
dustrial, lista locatarilor unui imobil. De aceea, lista ocup un loc important ntre
structurile de date uzuale. n cele ce urmeaz, prezentm cteva elemente de baz
referitoare la liste, modalitile de reprezentare a listelor n calculator i unele aplicaii
semnicative.
4.1.1 Deniii
Prin list nelegem un ir (eventual vid) de elemente aparinnd unei mulimi de
date [Tom, 1997]. Memorarea listelor liniare se poate face n mai multe moduri, n
continuare prezentndu-se unele dintre ele.
Alocarea secvenial (static) const n a memora elementele listei n locaii
succesive de memorie, conform ordinii acestor elemente n list; n acelai timp se
memoreaz adresa de baz (adresa primului element al listei). Un exemplu tipic
este cel n care elementele listei sunt memorate ntr-un vector, adresa de baz ind
adresa primului element al vectorului.
Alocarea nlnuit (dinamic) presupune c ecare element al listei liniare
este nlocuit cu o celul format din dou pri: o parte conine o informaie
specic al elementului i o parte cu informaia de legtur, care conine adresa
celulei corespunztor urmtorului element.
121
122 4. Structuri de date
succesor info
nod
Figura 4.1: Structura unui nod al listei simplu nlnuite
Ca i la alocarea secvenial, mai trebuie memorat o adres de baz; n plus,
partea de legtur a ultimei celule primete o valoare ce nu poate desemna o legtur.
Utilizm forma de alocare dinamic, ceea ce nseamn c n timpul rulrii progra-
mului, n funcie de necesiti, se aloc memorie suplimentar sau se renun la ea.
Pentru alocarea dinamic utilizm tipul de date referin (seciunea 3.17). Se con-
sider secvena de program cu implementarea elementelor, element oarecare al listei
care este format din informaia util (info) i un pointer care se refer la urmtorul
element al listei :
O list liniar simplu nlnuit este o structur de forma:
adr3 inf2 adr2 inf1
adr2
. . .
NIL inf
adrn
LIST
Figura 4.2: Structura unei liste simplu nlnuite
unde semnicaia notaiilor folosite este urmtoarea:
adr1, adr2, ..., adrn reprezint adresele din memorie ale celor n nregistrri;
inf1, inf2, ..., infn reprezint informaiile utile din cele n nregistrri
Implementarea unui element al acestei structuri se face n felul urmtor n limbajul
Pascal:
Type
adresa = nod ;
nod=Record
info : tip ;
succesor : adresa ;
end;
Var
List : adresa ;
4.1. Lista liniar simplu nlnuit 123
Numele de "list simplu nlnuit" provine din faptul c ecare element al listei
conine o singur adres i anume adresa elementului urmtor din list. Aici avem
o excepie pentru ultimul element, care are cmpul de adres cuvntul cheie NIL
(semnicnd "nici o adresa").
4.1.2 Operaii specice listei
Coninutul listei se poate modica prin urmtoarele operaii:
a. iniializarea unei liste ca o list vid;
b. inserarea de noi elemente n orice loc din list;
c. cutarea unor elemente n orice poziie din list;
d. tergerea unor elemente din orice poziie a listei;
e. modicarea unui element dintr-o poziie dat;
Alte operaii sunt cele de caracterizare. Acestea nu modic structura listelor,
ci furnizez informaii despre ele. Dintre operaiile de caracterizare vom considera n
continuare:
determinarea lungimii listei ( numrul de elemente ) ;
localizarea elementului din list care ndeplinete o anumit condiie ;
a. Algoritmul Creare (Iniializare)
Operaia realizeaz iniializarea listei ca o list vid, adic o list fr elemente:
Procedure Creare
List = NIL;
End;
b. Algoritmul Inserare
b1. Inserare_nceput : inserm un element la nceputul listei;
- alocarea de spaiu elementului nou;
- modicare de legturi ( a i b );
Procedure Inserare_nceput ( List , info_nou )
Begin
new(adr);
adr.succesor : = List;
124 4. Structuri de date
adr
b
a
adr2 inf1
adr1
inf1 adr1
List
. . .
NIL inf
adrn
Figura 4.3: Operaia de inserare la nceputul unei liste simplu nlnuite
List : = adr;
adr.info : = info_nou;
end.
b2. Inserare_Sfrit : inserm un element la sfritul listei ;
adr ultim
b
a
adrn
infn NIL inf_nou NIL
a no dr_
inf1
u
adr2
adr1
List
. . .
Figura 4.4: Operaia de inserare la sfritul unei liste simplu nlnuite
Secvena de operaii necesar:
- gsirea adresei ultimului element;
- alocarea spaiului elementului nou;
- a ( ultimul devine penultimul);
- b ( noul element devine ultimul);
- introducerea de informaii;
Procedure Inserare_Sfrit ( List, info_nou )
Var
ultim : adresa;
Begin
ultim = List;
While ultim.succesor <> NIL Do
ultim : = ultim.succesor;
New (adr);
ultim. succesor : = adr;
4.1. Lista liniar simplu nlnuit 125
adr.succesor : = NIL;
adr.info : = info_nou;
end;
b3. Inserare_Mijloc inserm un element nou dup un element dat din list, a crui
adres este numit dup;
adr
b
dup
a
inf_nou succesor
. . . . . .
Figura 4.5: Operaia de inserare n interiorul unei liste simplu nlnuite
Secvena de operaii necesar:
- alocare de spaiu ;
- succesorul noului element devine elementul listei ( a. );
- succesorul elementului dup devine noul element ( b. ) ;
- introducem informaia nou ;
Procedure Inserare_Interior ( List , dup , info_nou )
Begin
New(adr);
adr.succesor : = dup.succesor;
dup.succesor : = adr;
adr.info : = info_nou;
End;
c. Algoritmul cutare
Algoritmul caut n lista simplu nlnuit nodul care conine informaia info_cutat.
Dac ea exist, funcia de cutare va returna adresa nodului ce conine informaia
cutat. Dac informaia nu exist, atunci funcia va returna o adres vid (NIL).
126 4. Structuri de date
Function Cutare ( List , info_cutat ): adresa;
Var
adr: adresa;
Begin
adr: = List;
While adr <> NIL Do
if adr.info = info_cutat
then Begin
cutare: = adr;
Exit;
End
Else
adr: = adr.succesor;
Cutare = NIL;
End.
d. Algoritmul tergere
d1. tergere_nceput : tergerea elementului de la nceputul listei;
Secvena de operaii necesar:
- salvarea adresei de eliberat;
- primul element devine succesorul fostului prim element;
- eliberarea memoriei;
LIST
a
Figura 4.6: Operaia de tergere la nceputul unei liste simplu nlnuite
Procedure tergere_nceput ( Var List )
Var liber: adresa;
Begin
liber : = List;
List : = List.succesor;
Dispose ( liber );
4.1. Lista liniar simplu nlnuit 127
End;
d2. tergere_Sfrit: tergerea ultimului element din list;
penultim
LIST
Figura 4.7: Operaia de tergere la sfritul unei liste simplu nlnuite
Secvena de operaii necesar:
- gsirea adresei penultimului element din list ;
- salvarea adresei elementului de ters ;
- succesorul penultimului element devine NIL;
- eliberarea memoriei ;
Procedure tergerea_Sfrit (List )
Var penultim, liber : adresa;
Begin
penultim : = List;
While penultim.succesor.succesor <> NIL do
penultim : = penultim.succesor;
liber : = penultim. succesor;
penultim.succesor : = NIL;
Dispose ( liber );
End;
d3. tergere_Mijloc: tergerea unui element dup un element dat din list, a
crui adres este numit dup;
Secvena de operaii necesar:
- salvarea adresei de eliberat;
- succesorul lui dup devine succesorul succesorului acestuia ( pas a.);
- eliberarea memoriei;
Procedure tergere_Mijloc ( List , dup )
Var liber : adresa;
Begin
liber : = dup.succesor;
128 4. Structuri de date
a
dup
adr_no
Figura 4.8: Operaia de tergere n interiorul unei liste simplu nlnuit
dup.succesor : = dup.succesor.succesor;
DISPOSE ( liber );
End;
e. Algoritmul modicare
Algoritmul apeleaz funcia de cutare n lista simplu nlnuit, cutnd nodul care
conine informaia nrcutat. Dac ea exist, se modic informaia existent n acel
nod cu informaia nrmodicat. Dac informaia nu exist, atunci procedura va returna
o adres vid (NIL).
Procedure MODIFICARE ( List , nrcutat , nrmodicat )
Begin
adr:= CUTARE ( List , nrcutat );
if adr = NIL then
write (
X
2
astfel nct pentru orice
(x, y) U avem x X
1
i y X
2
.
Un graf G
U.
Un graf G
U.
Deniia 4.6.4. Fiind dat un graf orientat G = (X, U), un drum n graful G este
o succesiune de arce cu proprietatea c extremitatea terminal a unui arc coincide
cu extremitatea iniial a arcului urmtor din drum. Un drum se poate deni i
prin succesiunea de vrfuri care sunt extremiti ale arcelor ce compun drumul: o
succesiune de vrfuri cu proprietatea c orice dou vrfuri consecutive sunt unite
printr-un arc [Tom, 1981].
Un drum ntr-un graf este:
simplu, dac nu folosete de dou ori un acelai arc;
compus, dac nu e simplu;
4.6. Grafuri 155
elementar, dac nu trece de dou ori prin acelai vrf;
eulerian, dac este simplu i folosete toate arcele grafului;
hamiltonian, dac este elementar i trece prin toate vrfurile grafului;
circuit, dac extremitatea iniial a drumului coincide cu cea nal.
4.6.1.2 Reprezentarea grafurilor orientate
a. Reprezentarea cu ajutorul matricelor de adiacen
Fie un graf orientat G = (X, U), unde presupunem c G = 1, 2, . . . , n. Matricea de
adiacen A asociat grafului este o matrice ptratic de ordinul n, denit astfel:
A[i, j] =
_
_
_
1, dac (i, j) U
0, dac (i, j) / U
(4.2)
Exemplul 4.6.1. S considerm graful reprezentat n gura de mai jos:
1
4 3
2
Figura 4.22: Exemplu de graf orientat
Atunci matricea de adiacen ataat grafului este:
A =
_
_
_
_
_
0 1 1 0
0 0 0 1
0 1 0 0
0 0 1 0
_
_
_
_
_
Dezavantajul utilizrii reprezentrii grafurilor orientate cu ajutorul matricelor de adi-
acen este dat de faptul c spaiul ocupat este de ordinul (n
2
). Orice operaie
efectuat asupra grafului orientat necesit parcurgerea matricei de adiacen asociat,
care este o operaie de ordinul O(n
2
).
156 4. Structuri de date
b. Reprezentarea cu ajutorul listelor de adiacen
Pentru a elimina dezavantajele reprezentrii grafurilor orientate cu ajutorul ma-
tricelor de adiacen putem folosi o metod bazat pe reprezentarea cu liste nlnuite,
numit reprezentare cu liste de adiacen.
Lista de adiacen pentru un vrf i este o list simplu nlnuit a tuturor nodurilor
adiacente cu i. n acest fel reprezentarea grafului orientat G = (X, U), se face cu o
tabel n dimensional numit CAP, elementul CAP[i] reprezentnd un pointer ctre
capul listei de adiacen al vrfului i.
Exemplul 4.6.2. Reprezentarea grafului din Figura 4.22 cu ajutorul listelor de adi-
acen:
CAP
1
4
3
2
3
2
4
3
2
Figura 4.23: Reprezentarea grafului orientat din Figura 4.22 cu ajutorul listelor de
adiacen
Reprezentrii grafurilor orientate cu ajutorul listelor de adiacen necesit un
spaiu de memorare ocupat este de ordinul (n+nr.de_arce). De aceea, aceast
form de reprezentare este preferabil atunci cnd expresia n+nr.de_arce este mai
mic dect n
2
. De asemenea constatarea faptului dac exist sau nu un arc de la
vrful i la vrful j necesit un timp proporional cu O(n).
4.6. Grafuri 157
4.6.2 Grafuri neorientate
4.6.2.1 Deniii i generaliti
Deniia 4.6.5. Un graf neorientat este un cuplu G = (X, U), unde X este o mulime
de elemente numite vrfuri, i U este o mulime de perechi neordonate de vrfuri
numite muchii. O muchie (x, y) nu are orientare, astfel c (x, y) = (y, x).
O muchie este incident vrfurilor care sunt extremiti ale sale. Dou vrfuri
sunt adiacente dac ntre ele exist o muchie. Dou muchii sunt adiacente dac au o
extremitate comun. Gradul unui vrf x este numrul de muchii incidente cu acesta
i se noteaz g(x).
Deniia 4.6.6. Un lan este o succesiune de muchii cu proprietatea c orice muchie
are un vrf comun cu muchia precedent i cellalt vrf comun cu muchia succesoare.
n mod analog denim noiunea de ciclu corespunztoare noiunii de circuit de la
grafuri orientate.
Deniia 4.6.7. Un graf neorientat este conex dac ntre orice dou vrfuri exist
un lan.
O component conex a unui graf neorientat este un subgraf conex maximal n
raport cu operaia de incluziune. Cu alte cuvinte, nu exist o submulime de vrfuri
mai numeroas care s induc un subgraf conex.
Deniia 4.6.8. Un arbore este un graf conex fr cicluri.
Lema 4.6.1. Un arbore cu n vrfuri are n 1 muchii.
Demonstraie [Liv, 1986]. Considerm pentru nceput un graf cu dou vrfuri unite
printr-o muchie, care este evident un arbore. La ecare pas adugm un vrf nou pe
care l unim printr-o muchie cu un vrf deja existent. Presupunem c dup un numr
de pai avem un arbore cu k vrfuri i k 1 muchii. La urmtorul pas obinem un
arbore parial cu k +1 vrfuri i k muchii. Nu se obine nici un ciclu: pentru aceasta
ar trebuit ca noul vrf ales s fost deja conectat cu unul din cele k vrfuri, fapt
imposibil.
158 4. Structuri de date
4.6.2.2 Reprezentarea grafurilor neorientate
a. Reprezentarea cu ajutorul matricelor de adiacen
Fie un graf neorientat G = (X, U), unde presupunem c G = 1, 2, . . . , n. Matricea
de adiacen A asociat grafului este o matrice ptratic de ordinul n, denit astfel:
A[i, j] =
_
_
_
1, dac (i, j) U
0, dac (i, j) / U
(4.3)
Observaie. Se observ c matricea de adiacen ataat grafului este simetric n
raport cu diagonala principal.
Exemplul 4.6.3. S considerm graful reprezentat n gura de mai jos:
1 2
4
3
Figura 4.24: Exemplu de graf neorientat
Atunci matricea de adiacen ataat grafului este:
A =
_
_
_
_
_
0 1 0 1
1 0 1 1
0 1 0 1
1 1 1 0
_
_
_
_
_
b. Reprezentarea cu ajutorul listelor de adiacen
Pentru a elimina dezavantajele reprezentrii grafurilor neorientate cu ajutorul ma-
tricelor de adiacen putem folosi o metod bazat pe reprezentarea cu liste nlnuite,
numit reprezentare cu liste de adiacen.
4.6. Grafuri 159
Lista de adiacen pentru un vrf i este o list simplu nlnuit a tuturor nodurilor
adiacente cu i. n acest fel reprezentarea grafului orientat G = (X, U), se face cu o
tabel n dimensional numit CAP, elementul CAP[i] reprezentnd un pointer ctre
capul listei de adiacen al vrfului i.
Exemplul 4.6.4. Reprezentarea grafului din Figura 4.24 cu ajutorul listelor de adi-
acen:
CAP
4 2
1
4
3
2
3 2 1
4
2
4 3 1
Figura 4.25: Reprezentarea grafului orientat din Figura 4.24 cu ajutorul listelor de
adiacen
4.6.3 Grafuri planare
Pentru a reprezenta unele structuri geometrice n plan sau n spaiu se folosete o
categorie special de structuri de date: grafuri planare.
Deniia 4.6.9. Un graf G este planar dac este posibil s e reprezentat pe un
plan astfel nct vrfurile s e distincte, muchiile curbe simple i dou muchii s nu
se intersecteze dect la extremitile lor (dac sunt adiacente).
Reprezentarea grafului conform cu condiiile impuse se numete graf planar topo-
logic i se noteaz tot prin G. Nu se consider distincte dou grafuri planare topologice
dac le putem face s coincid prin deformarea elastic a planului.
Deniia 4.6.10. O fa a unui graf planar este o regiune a planului delimitat de
muchii, care are proprietatea c orice dou puncte din aceast regiune pot unite
printr-o curb simpl care nu ntlnete nici muchii i nici vrfuri.
160 4. Structuri de date
Deniia 4.6.11. Frontiera unei fee este mulimea muchiilor care ating faa respec-
tiv. Dou fee sunt adiacente dac frontierele lor au cel puin o muchie comun.
ntr-un graf topologic, frontiera unei fee este format din unul sau mai multe ci-
cluri elementare disjuncte, din muchii suspendate sau care unesc dou cicluri disjuncte
(istmuri).
Deniia 4.6.12. Conturul unei fee este conturul ciclurilor elementare care conin
n interiorul lor toate celelalte muchii ale frontierei.
Exist ntotdeauna o fa innit i care are frontier, dar nu are contur; toate
celelalte fee sunt nite i admit un contur.
Teorema 4.6.1. ntr-un graf planar topologic conex cu n vrfuri, m muchii i f fee
avem relaia:
n m+f = 2.
Demonstraie [Tom, 1981]. Dac f = 1 atunci m = n 1 pentru un arbore (lema
4.6.1), deci relaia este adevrat.
Presupunem armaia adevrat pentru orice graf planar conex cu f 1 fee, i s
considerm un graf planar conex cu f fee. Fie (x, y) o muchie a unui ciclu; aceasta
se a pe frontiera a dou fee S i T. Dac eliminm muchia (x, y) se obine un graf
planar conex cu n
= n vrfuri, m
= m1 muchii i f
+f
i=1
p
i
nr
i
(5.1)
unde p
i
reprezint probabilitatea ca informaia a-i-a s e cutat, iar nr
i
reprezint
numrul de operaii necesar accesrii informaiei a-i-a. Probabilitatea ca o dat s
e cutat poate exprimat prin raportul:
p
i
=
nr_de_cautari_al_datei_i
nr_total_de_cautari
(5.2)
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:
ALOS =
n
i=1
1
n
i =
1 + 2 +. . . n
n
=
n(n + 1)
2
n
=
n + 1
2
(5.3)
n cazul n care probabilitatea de accesare a datelor din tabel nu este echiprob-
abil, atunci cea mai ecient metod de organizare a datelor este cea n ordine
descresctoare a probabilitilor de cutare, datele cele mai probabile a cutate
ind dispuse la nceputul tabelei. S dovedim aceast armaie:
e datele organizate ntr-o tabel n ordinea descresctoare a probabilitilor de
cutare, i anume:
Data
1
Data
2
. . . . . . . . . . . . .. Data
i
. . . . . . . . . . . . .. Data
n
5.1. Introducere n tehnicile de cutare 165
astfel nct:
p
1
> p
2
> . . . > p
i
. . . p
n
(5.4)
Pentru aceast organizare a datelor n tabel avem performana:
ALOS
1
=
n
i=1
p
i
nr
i
=
n
i=1
p
i
i = 1 p
1
+ 2 p
2
+. . . +i p
i
+. . . +j p
j
+. . . +n p
n
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.4), i s
msurm performana ALOS a algoritmului de cutare. Este sucient s presupunem
c exist o simpl permutare a datelor, i anume c avem permutate Data
i
cu Data
j
n tabel. n aceast situaie, performana algoritmului de cutare este:
ALOS
2
=
n
i=1
p
i
nr
i
=
n
i=1
p
i
i = 1 p
1
+ 2 p
2
+. . . +i p
j
+. . . +j p
i
+. . . +n p
n
S comparm cele dou performane:
ALOS
1
ALOS
2
= i p
i
+j p
j
i p
j
j p
i
= p
i
(i j) +p
j
(j i)(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.
5.1.1.2 Probleme rezolvate pentru cutare secvenial
Exemplul 5.1.2. Problema cutrii unei nregistrri particulare ntr-o tabel
Fiind dat un tablou cu o capacitate de maxim MAX nregistrri posibile (nreg-
istrri de tip numr ntreg ), se cere implementarea n limbajul Pascal a unui algo-
ritm algoritmi care s realizeze 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 ;
166 5. Tehnici de cutare
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 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 ] ) ;
readln ;
end ;
Procedure CAUTARE ;
var
ok : boolean ;
5.1. Introducere n tehnicile de cutare 167
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 a 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 ;
168 5. Tehnici de cutare
1 : STERGERE;
2 : CAUTARE ;
end ;
until a = # 27 ;
END.
Exemplul 5.1.3. 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) ;
5.1. Introducere n tehnicile de cutare 169
creare := prad ;
end ;
end ;
Function numr (p1 : plista) : pv ;
var
plucru : pv ;
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.
5.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 ier voluminos, nu dup criteriul egali-
tii, ci pentru a gsi 1000 de nregistrri cele mai apropiate unei chei date,
170 5. Tehnici de cutare
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 < X
1
, X
2
, . . ., X
n
> i < Y
1
, Y
2
, . . . , Y
n
> de numere
reale, care permutare a
1
a
2
. . . a
n
a indiciilor va determina valoarea maxim
al lui (X
i
Y
a
i
)? 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 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 aeze 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) (X
1
, X
2
, . . . , X
n
) (X
n
, X
1
, X
2
, . . . , X
n1
)
b) (X
1
, X
2
, . . . , X
n
) (X
n
, X
n1
, X
n2
, . . . , X
2
, X
1
)
c) (X
1
, X
2
, . . . , X
n
) (X
i
1
, X
i
2
, . . . , X
i
n
)
astfel nct X
i
1
< X
i
2
< . . . < X
i
n
iar 1 <= i
k
<= 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 aeze numrul
de apariii ale ecrui 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 de dimensiune n
din domeniul 0 . . . 9. S se verice 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 aeze toate numerele de n cifre care adunate cu rsturnatul lor dau un
ptrat perfect.
5.1. Introducere n tehnicile de cutare 171
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 me-
morate vectorial s determine suma, produsul, ctul i restul mpririi primului
numr la al doilea numr. Rezultatele se vor obine sub forma vectorial.
5.1.2 Cutare binar
5.1.2.1 Descrierea general a metodei
O alt metod relativ simpl de accesare a unei tabele este metoda cutrii binare.
Organizarea datelor n aceast tabel se bazeaz pe ordonarea liniar 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 capitol ulterior.
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 semnic
lipsa cheii cutate.
n gura 5.1 avem un exemplu de cutare binar a cheii m aat 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 ecare pas, deci numai patru comparaii snt necesare n
acest caz.
x s r p n m l i h g e e e c a a a
x s r p n m l i
m l i
m
Figura 5.1: Exemplu de cutare binar
172 5. Tehnici de cutare
Operaia de inserare (metoda inserrii binare ) realizeaz n ecare 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 inserare 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 presupune ca elementele din tablou, aate naintea elemen-
tului care va ters, vor rmne pe loc, poziiile lor nu se schimb, elementele care
se a dup elementul care va ters, vor translatate cu o poziie.
5.1.2.2 Descrierea algoritmului de cutare n Pseudocod
Un algoritm pentru o astfel de procedur de cutare este prezentat n rndurile ur-
mtoare.
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, 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 {Pasul 1}
HIGH := N
CTTIMP LOW <= HIGH EXECUT {Pasul 2}
MIDDLE := [(LOW +HIGH ) / 2 ] {Pasul 3}
DAC X < K [MIDDLE] {Pasul 4}
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 5}
Pasul 1 iniializeaz variabilele LOW i HIGH, pasul 3 calculeaz valoarea vari-
abilei 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.
5.1. Introducere n tehnicile de cutare 173
Cutarea binar poate 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 sunt 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
SFDAC
SF-CAUTARE_BINARA;
Exemplul 5.1.4. 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
174 5. Tehnici de cutare
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;
5.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 locaia
_
n + 1
2
_
(am notat cu [ ] funcia parte ntreag). n
aceast situaie este necesar doar o 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]).
n procesul de cutare binar recursiv, cheia cutat este gsit n maximum
log N 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 simplica analiza, vom pre-
supune 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 com-
pleta o structur de date cu elemente care nu sunt cutabile, ca s o aducem la forma
2
k
1. Oricum, timpul de execuie al structurii de date originale va mai mic sau
egal dect a structurii de date aduse la forma n = 2
k
1.
S notm cu S
i
, 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 = 2
1
; S
3
= 4 = 2
2
; . . . ; S
i
= 2
i1
, i k
5.1. Introducere n tehnicile de cutare 175
Aplicnd formula (5.1) vom avea:
T(n) =
k
i=1
p
i
d
i
=
k
i=1
S
i
n
i =
1
n
k
i=1
i 2
i1
=
1
n
k
i=1
i (2
i
2
i1
) =
=
1
n
_
k
i=1
i 2
i
k1
i=0
(i + 1) 2
i
_
=
1
n
_
k
i=1
i 2
i
k1
i=1
i 2
i
k1
i=0
2
i
_
=
=
1
n
(k 2
k
2
k
+ 1) =
1
n
[(k 1) (2
k
1) +k] = (k 1) +
k
n
=
= log
2
(n + 1) 1 +
log
2
(n + 1)
n
=
_
1 +
1
n
_
log
2
(n + 1) 1 log
2
n
Putem considera c avem: T(n) = O(log
2
n), att pentru cazul general ct i pentru
cel mai nefarorabil caz.
n 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 ecare 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(log
2
n) operaii de cutare , adic n nal avem nevoie de un spaiu de memorie
proporional cu O(nlog
2
n).
Observaie. Tehnica de cutare binar are i unele proprieti nedorite. Inserarea
unei noi nregistrri impune ca o serie de nregistrri existente n tabel s e mutate
zic 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.
5.1.2.4 Probleme rezolvate pentru cutarea binar
Exemplul 5.1.5. 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 ecare element care este gsit i n vectorul b
va memorat ntr-un vector nou c construit de ctre subprogram .
Acest program funcioneaz att pentru vectori ordonai cresctor, ct i pentru
vectori ordonai descresctor.
176 5. Tehnici de cutare
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 ; varnumr : 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 aeaz ( x : vector ; numr : val_indice ) ;
var
i : val_indice ;
begin
for i : = 1 to numr do
begin
write ( x [ , I : 2 , ] = , x [ I ] ) ;
If ( i mod 5 ) = 0
5.1. Introducere n tehnicile de cutare 177
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 ;
gsit := 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 }
178 5. Tehnici de cutare
end;
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 gsit (c , numr , x [ indice ])) or ( numr = 0 )
then
begin
Numr := numr + 1 ;
c [ numr ] := x [ indice ]
end
end;
5.1. Introducere n tehnicile de cutare 179
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 ;
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 snt : ) ;
writeln ;
aeaza ( c , ic );
end
else
writeln ( Nu exist elemente comune );
END.
Exemplul 5.1.6. Cutare binar ntr-un ir dat.
180 5. Tehnici de cutare
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 : ) ;
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.
5.2. Arbori de cutare 181
5.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 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 ecient 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 ier:
14, 27, 95, 12, 26, 5, 33, 15, 9, 99 i elementele ar sortate n ordine cresctoare?
ListaOrdonata
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
5.2 Arbori de cutare
5.2.1 Arbore binar de cutare ABC
5.2.1.1 Descrierea general a arborelui binar de cutare
ntr-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 i care formeaz nivelul 1; de acestea
sunt legate elementele de pe nivelul 2, .a.m.d. (vezi gura 5.2).
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 u stnga < Cheia nodului tat < Cheia nodului u stnga (5.5)
Utiliznd formula de mai sus se obin arbori binari speciali, utilizai pentru orga-
nizarea i cutarea datelor, numii arbori binari de cutare ABC.
182 5. Tehnici de cutare
Un nod situat pe un anumit nivel este nod tat pentru nodurile legate de el,
situate pe nivelul urmtor, acestea reprezentnd i 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
identicarea datelor stocate n structura arborescent. De exemplu, dac datele sunt
datele relative la studenii unei faculti, atunci cheia poate aleas ca ind 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 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 identicare, 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 identicate printr-o valoare X a cheii ncepe de la
rdcin i se termin n cel mai ru caz la unul din nodurile terminale, cutarea pre-
supunnd 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 e mult mai mic dect n cazul listelor ordonate.
Metoda cutrii binare prezentate n capitolul anterior, poate explicat cu uur-
in cu ajutorul arborilor de cutare.
4
8
6 9
7 10 Nivelul 3
Nivelul 2
Nivelul 1
Nivelul 0
2
3 1
5
Figura 5.2: Exemplu de arbore binar de cutare
5.2. Arbori de cutare 183
5.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 5.3: Structura nodului ABC
unde:
Fiu_st : reprezint adresa ului stnga;
Cheia: reprezint cmpul ales dup care este ordonat ABC i care veric relaia
(5.5);
Alte_info : alte informaii adiacente;
Fiu_dr : reprezint adresa ului dreapta;
Structura nodului, n implementarea Pascal este urmtoarea:
Type
Adresa = Nod
Nod = RECORD
Fiu_st : Adresa;
Cheia : tipcheia;
Alte_info : tipinfo;
Fiu_dr : Adresa;
end
5.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 (sectiunea 4.5.2), ne vom ocupa de celelalte operaii specice arborilor
binari de cutare.
184 5. Tehnici de cutare
a. Operaia de creare-inializare. Specicarea problemei de creare-iniializare,
avnd ca date de intrare ABC specicat 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. Specicarea 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;
Vom folosi subalgoritmul numit Creare_nod care va aloca dinamic spaiul de
memorie necesar noului nod de inserat i va completa cmpurile nodului ABC.
Observaie. 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.u_st := NIL; {sistemul returneaz adresa noului nod n
variabila adres NOU}
NOU.u_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 }
5.2. Arbori de cutare 185
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 complet. cmpurile}
EXIT;
SFDAC
tmp := ROOT;
CTTIMP tmp <> NIL EXECUT
Tata := tmp;
DAC cheia_nou < tmp.cheia
ATUNCI tmp := tmp.u_st;
ALTFEL DAC cheia_nou > tmp.cheia
ATUNCI tmp := tmp.u_dr;
ALTFEL
TIPRETE (EROARE CHEIE DUBL);
EXIT;
SFDAC
SFDAC
SFCT
CHEAM Creare_nod (cheia_nou, info_nou);
DAC cheia_nou < tata.cheia
ATUNCI
tata.u_st := NOU;
ALTFEL
tata.u_dr := NOU;
SFDAC
SFALGORITM
c. Operaia de cutare. Specicarea 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;
Observaie. 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 o adres nul.
186 5. Tehnici de cutare
ALGORITMUL CAUT ESTE:
CITETE cheia_caut;
tmp := ROOT;
CTTIMP (tmp <> NIL) EXECUT
DAC cheia_caut < tmp.cheia
ATUNCI tmp := tmp.u_st;
ALTFEL
DAC cheia_caut > tmp.cheia
ATUNCI tmp := tmp.u_dr;
ALTFEL @returneaz adresa tmp;
SFDAC
SFDAC
SFCT
@returneaz adresa NIL;
SFALGORITM
d. Operaia de tergere. Specicarea general a problemei de tergere este:
DATE root, cheia_de_sters;
REZULTATE root;
Exist mai multe situaii posibile, n funcie de numrul de i ai nodului de ters [Tre,
1984],:
Cazul 1. Nodul de ters este un nod terminal, deci fr i. 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 gura 5.2.
Cazul 2. Nodul de ters are un singur u. Operaia de tergere necesit realizarea
legturii nod_tat i nod_u (stnga sau dreapta) al nodului de ters i eliberarea
spaiului ocupat de nodul de ters.
Exemplu: nodurile cu cheia 3, 6, 9 din ABC gura 5.2.
Cazul 3. Nodul de ters are doi i. n aceast situaie, nodul de ters trebuie nlocuit
i abia dup aceea poate eliminat. Nodul nlocuitor poate nodul cu cheia cea mai
mare din punct de vedere lexicograc 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 gura 5.2. Nodul nlocuitor al nodului
cu cheia 2 este nodul cu cheia 1 din subarborele stng sau nodul cu cheia 3 din
5.2. Arbori de cutare 187
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.
Observaie. Pentru a gsi nodul nlocuitor al unui nod de ters n Cazul 3, acesta
poate gsit astfel: dac nodul nlocuitor este nodul cu cheia cea mai mare din punct
de vedere lexicograc 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 lexicograc 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.u_st;
ALTFEL tmp := tmp.u_dr;
SFDAC
SFCT
DACA tmp = NIL ATUNCI
TIPRETE (EROARE NODUL NU EXIST N ABC);
EXIT;
SFDAC
DAC tmp.u_st = NIL i tmp.u_dr = NIL ATUNCI
CHEAM Cazul_1 (ROOT, tata, tmp); { Cazul 1 }
EXIT;
SFDAC
DAC tmp.u_st = NIL XOR tmp.u_dr = NIL ATUNCI
188 5. Tehnici de cutare
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.u_st = adr ATUNCI
t.u_st := NIL;
ALTFEL
t.u_dr := NIL;
@Eliberare spaiu (adr); { Eliberarea spaiului de la adresa adr }
SF-Cazul_1
SUBALGORITMUL Cazul_2 (rad, t, adr) ESTE:
DAC t.u_st = adr ATUNCI { Nodul de ters este ul stnga al nodului tata}
DAC adr.u_st = NIL ATUNCI
t.u_st := adr.u_dr;
ALTFEL
t.u_st := adr.u_st;
ALTFEL { Nodul de ters este ul dreapta al nodului tata}
DAC adr.u_dr = NIL ATUNCI
t.u_dr := adr.u_st;
ALTFEL
t.u_dr := adr.u_dr;
@Eliberare spaiu (adr); { Eliberarea spaiului de la adresa adr }
SF-Cazul_2
SUBALGORITMUL Cazul_3 (rad, t, adr) ESTE:
tmp := adr.u_st; { Se caut nodul nlocuitor un pas la stnga}
tata := tmp;
CTTIMP tmp.u_dr <> NIL EXECUT { Orici pai la dreapta}
tata := tmp;
tmp := tmp.u_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}
5.2. Arbori de cutare 189
tata.u_dr := tmp.u_st; { Eliminm legtura tata - nodul nlocuitor}
@Eliberare spaiu (tmp); { Eliberarea spaiului nod nlocuitor de la adresa tmp }
SF-Cazul_3
5.2.1.4 Probleme rezolvate
Exemplul 5.2.1. Problema arborilor asociai expresiilor aritmetice. Fiind date n ex-
presii aritmetice, sintactic corecte, care cuprind paranteze, operanzi notai cu literele
mici din alfabet i operatori binari sau unari din mulimea +, , , /, s se con-
struiasc i s se aeze n postordine arborele binar asociat ecrei expresii [Dal,
1988].
Arborele binar asociat expresiei aritmetice (a+b) c d este prezentat n gura
urmtoare:
- binar
$ unar
b
a
c
d $
*
+
-
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 ).
190 5. Tehnici de cutare
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
begin
citire ;
expresie (p) ; { aici car =) }
end ; else
begin
5.2. Arbori de cutare 191
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 ;
192 5. Tehnici de cutare
termen ( p );
end
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+
5.2.2 Arbore binar de cutare balansat n nlime
5.2.2.1 Descrierea general a arborelui balansat n nlime
Primul tip de arbore balansat este Arborele Binar de Cutare Balansat n
nlime - ABCBI . ntr-un astfel de arbore ncercm meninerea tuturor nodurilor
5.2. Arbori de cutare 193
frunz la aceeai distant fa de rdcin.
n Figura 5.4 a) este prezentat un arbore binar de cutare balansat n
nlime, iar n Figura 5.4 b) este prezentat un arbore binar debalansat [Tre, 1984].
B
B
B
B
L B
a) b)
Figura 5.4:
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)
Deniia 5.2.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.
Deniia 5.2.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.
Deniia 5.2.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.
194 5. Tehnici de cutare
Deniia 5.2.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 ecare nod trebuie se ae in una din aceste trei stri, adic s
e nod greu dreapta, nod greu stnga sau nod balansat.
Deniia 5.2.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.
Dac exist un nod care nu satisface nici una din aceste trei stri, atunci arborele
se numete arbore binar debalansat.
Deniia 5.2.6. Un ABCBI se numete arbore binar de cutare debalansat n
nlime dac conine cel puin un nod critic.
5.2.2.2 Implementarea unui nod al arborelui ABCBI
Un nod al unui arbore ABCBI are urmtoarea structur:
Fiu_st Cheia Alte_info IB Fiu_dr
Figura 5.5: Structura nodului ABCBI
unde:
Fiu_st : reprezint adresa ului stnga;
Cheia: reprezint cmpul ales dup care este ordonat ABCBI ;
Alte_info : alte informaii;
IB : indicatorul de balansare;
Fiu_dr : reprezint adresa ului 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
5.2. Arbori de cutare 195
5.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;
e. traversare.
Operaiile creare-iniializare, cutare i traversare sunt identice cu operaiile de
la arborii binari de cutare. Doar operaiile de inserare-balansare i tergere sunt
specice i vor detaliate n cele ce urmeaz.
a. Operaia de inserare. n 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 inserri, care se a pe un drum cuprins ntre rdcin arborelui
i noul nod terminal inserat, numit drum de inserare. Posibilele schimbri pentru
un nod, aat 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, aate pe drumul de inserare, rmn neschimbate, cu
excepia noului tat. Acest exemplu este prezentat n Figura 5.6 Cazul 1. n acest
exemplu nodul inserat este nodul cu cheia 3.
n Cazul 2, dup cum se vede i n Figura 5.6 Cazul 2., indicatorii de balansare
(IB) a nodurilor strmo, situate pe drumul de inserare se pot modica. 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 5.6 Cazul 3. 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.
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 specice, numit rebalansare a arborelui, care s duc la eliminarea
nodurilor critice i la transformarea lor n noduri greu dreapta, greu stnga sau ba-
196 5. Tehnici de cutare
lansat.
Sunt dou cazuri de rebalansare, care se divid ecare n dou subcazuri, corespun-
ztoare direciei grele stnga sau dreapta care a dus la apariia nodului critic [Tre,
1984].
B
B
B
B B
R
4
B
B
B
L
3
R
8
6 1
7
2
5
B B B
B
L
B
B 3 8
6 1
7
B
2
5
Cazul 2
Cazul 1
R
B
R
B
L Critic
4
3
1
6 2
5
B
Cazul 3
Figura 5.6:
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 5.7, unde T1, T2 i T3 reprezint
5.2. Arbori de cutare 197
subarbori, iar NOU reprezint noul nod de inserat. Expresia din partea de jos a
dreptunghiurilor reprezint nlimea subarborilor, nainte i dup inserare.
De exemplu, n Figura 5.7 (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 5.7 (a.2).
T3
n
T2
n
NOU
T1
n+1
Y
X
NOU
T1
n+1
T3
n
T2
n
X
Y
a.2 a.1
Figura 5.7: Exemplu de soluionare a debalansrii ABCBI, prin rotaie simpl la
dreapta n jurul nodului Y
De exemplu, n Figura 5.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 5.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.
198 5. Tehnici de cutare
NOU
T3
n+1
T2
n
T1
n
X
Y
T1
n
T3
n+1
T2
n
Y
X
NOU
b.2
b.1
Figura 5.8: Exemplu de soluionare a debalansrii ABCBI, prin rotaie simpl la
stnga n jurul nodului Y
X
Y
T4
n+1
NOU
Y
T1
n+1
NOU
T2
n+1
T3
n
T2
n+1
Z
T4
n+1
T3
n
X
Z
a.1
T1
n
a.2
Figura 5.9: Exemplu de soluionare a debalansrii ABCBI, prin rotaie dubl la
stnga n jurul nodului Z
5.2. Arbori de cutare 199
X
Y
T4
n+1
T1
n+1
NOU
X
T1
n+1
NOU
T2
n+1
T3
n
T2
n+1
Z
T4
n+1
T3
n
Y
Z
b.1 b.2
Figura 5.10: Exemplu de soluionare a debalansrii ABCBI, prin rotaie dubl la
dreapta n jurul nodului Z
Cazul doi, care este reprezentat n Figura 5.9 i Figura 5.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.
Specicarea 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;
200 5. Tehnici de cutare
EXIT;
SFDAC
@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. Specicarea general a problemei de tergere este:
DATE root, cheia_de_sters;
REZULTATE root;
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 i
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 ul (dac exist )
SFDAC
@Rebalanseaz arborele pe drumul de cutare;.
5.2.2.4 Probleme rezolvate
Exemplul 5.2.2. 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 ;
5.2. Arbori de cutare 201
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
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 ;
202 5. Tehnici de cutare
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 u , predec , tatap : adresa ;
begin
if ( temp.lptr = nil ) and ( temp.rptr = nil ) then {nodul de ters nu
are nici un u}
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
{ nodul de ters are un singur u }
begin
if temp.lptr = nil then u := temp.rptr
else u := temp.lptr ;
if temp.key < tata.key then tata.lptr := u
else tata.rptr := u ;
5.2. Arbori de cutare 203
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
if def <> nil then
begin
inordine ( def.lptr ) ;
204 5. Tehnici de cutare
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
5.2. Arbori de cutare 205
C : begin
writeln ; writeln ( * CREARE * : 15 ) ; writeln ;
write ( Creez rdcina... ) ;
creare ( root ) ; writeln ( OK! ) ;
readkey ;
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 ) ;
206 5. Tehnici de cutare
readkey ;
end ;
else writeln ( Ai apsat o tast gresit ! ) ;
end ;
end ;
end ;
until c = # 27 ;
end ;
BEGIN
meniu ;
END.
5.2.2.5 Performanele algoritmilor n ABCBI
Performana algoritmului ce corespunde operaiei de inserare n arborele binar bal-
ansat n nlime cu n noduri este de ordinul O(1.5 log
2
(n + 1)) [Knu, 1976].
Performana algoritmului ce corespunde operaiei de cutare este identic cu per-
formana algoritmului de cutare a arborilor binari de cutare, adic este de ordinul
O(log
2
n).
n referina [Tre, 1984], se arat c performana algoritmului ce corespunde opera-
iei de tergere este de ordinul O(log
2
n).
5.2.3 Arbore binar de cutare balansat n greutate ABCBG
5.2.3.1 Descrierea general a arborelui balansat n greutate
Am vzut n (5.4) faptul c organizarea datelor inueneaz semnicativ perfor-
manele 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 n-
ceputul 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 echiproba-
bile, 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.
5.2. Arbori de cutare 207
Introducem astfel o nou structur de date arborescent, i anume, arborele
binar de cutare balansat n greutate ABCBG, a crei regul de organizare
poate formulat astfel: cele mai des cutate noduri se a 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 meninut dinamic, dac avem grij s incrementm la ecare acces
al unei date, variabila corespunztoare numrului de accesri al acelei date precum i
numrul total de accesri a structurii de date arborescente.
Rezult resc c ecare nod al unui astfel de ABCBG are nevoie de un cmp
suplimentar de informaie, i anume, numrul de cte ori a fost accesat acea infor-
maie i pe care o vom numi greutatea nodului respectiv.
Observaie. n orice arbore (subarbore) nodul rdcin este cel mai greu nod.
Arborele prezentat n gura de mai jos, este o structur de date de tip ABCBG.
Se observ c n primul rnd avem un ABC deoarece, lexicograc, 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, 1984].
T
1
Lalea 5 Tei 3
Garoaf 4 Molid 2 Zorele 1
4 Dalie
6 Pin
Figura 5.11: Exemplu de arbore binar de cutare T
1
balansat n greutate ABCBG
208 5. Tehnici de cutare
Regula de plasare al unui nod n arborele binar de cutare balansat n greutate
poate exprimat n mod recursiv, dup urmtoarea regul [Aho, 1987]:
1. Nodul rdcin al oricrui arbore (subarbore) este nodul cu cea mai mare greu-
tate 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 ecare 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 poziionat
conform cu regulile generale de inserare de la arborii binari de cutare, ca i nod
terminal, greutatea nodului ind iniializat cu 1.
S considerm n continuare acelai arbore binar de cutare, dar care s nu mai
e balansat n greutate.
T
2
Lalea 5 Zorele 1 6 Pin 4 Dalie
Molid
4 Garoaf 3 Tei
2
Figura 5.12: Exemplu de arbore binar T
2
de cutare debalansat n greutate
S comparm performanele algoritmilor de cutare n cei doi arbori de cutare
T
1
(balansat n greutate) i T
2
(debalansat n greutate):
ALOS
T
1
=
6
25
1 +
5
25
2 +
3
25
2 +
4
25
3 +
2
25
3 +
1
25
3 +
4
25
4 = 2.36
ALOS
T
2
=
2
25
1 +
4
25
2 +
3
25
2 +
4
25
3 +
5
25
3 +
6
25
3 +
1
25
3 = 2.56
5.2. Arbori de cutare 209
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.
5.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 5.13: Structura nodului ABCBG
unde:
Fiu_st : reprezint adresa ului stnga;
Cheia: reprezint cmpul ales dup care este ordonat ABCBG;
Alte_info: alte informaii;
Greutate: greutatea nodului, reprezentat prin numrul de accesri ale nodului;
Fiu_dr: reprezint adresa ului 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
5.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:
210 5. Tehnici de cutare
Operaiile creare-iniializare, inserare i traversare sunt identice cu operaiile de la
arborii binari de cutare. Doar operaiile de cutare i tergere sunt specice i vor
detaliate n cele ce urmeaz. Operaia de cutare poate modica greutatea unui nod
i debalansa arborele.
c. Operaia de cutare
Balansarea unui ABCBG este ilustrat n Figura 5.14 [Tre, 1984]:
Subarbore stng
COPIL
PARINTE
Subarbore drept
COPIL
Subarbore drept
PARINTE
COPIL
BUNIC
a)
Subarbore stng
COPIL
Subarbore drept
COPIL
Subarbore drept
PARINTE
COPIL
PARINTE
BUNIC
b)
Figura 5.14: Operaia de balansare a unui ABCBG
5.2. Arbori de cutare 211
n gura 5.14 a), presupunem c n urma unei accesri a nodului COPIL, greu-
tatea acestuia devine mai mare dect greutatea nodului PARINTE, deci arborele
devine debalansat n greutate. n gura 5.14 b), se prezint strategia de balansare.
Observaie. 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
necesar pentru operaia de tergere.
Specicarea 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 }
212 5. Tehnici de cutare
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
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,
1984].
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 u stnga. n acest caz ul stng al nodului printe va deveni egal cu
ul 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 u stnga. n acest caz ul stng al nodului printe va deveni egal cu
ul 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,
5.2. Arbori de cutare 213
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
Specicarea general a problemei de tergere este:
DATE root, cheia_de_sters;
REZULTATE root;
Descrierea general a algoritmului recursiv de tergere, n Pseudocod este:
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
5.2.3.4 Probleme rezolvate
Exemplul 5.2.3. 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 ;
214 5. Tehnici de cutare
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
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 overow) ;
exit ;
end;
end;
Function pop (st:stiva;var indic:top) : adresa ;
{ scoate elementele din stiv }
begin
5.2. Arbori de cutare 215
if not emptystack (indic) then
begin
indic := indic-1 ;
pop := st [indic] ;
end
else
begin writeln (stack underow) ;
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 }
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 ului stng al nodului curent }
begin
tata := curent ;
curent := curent.lptr ;
end
else if cheia > curent.key then { inserarea ului drept al nodului curent }
begin
216 5. Tehnici de cutare
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 ;
end
else
begin
tata.rptr := temp.lptr ;
temp.lptr := tata ;
root := temp ;
exit ;
end
else
5.2. Arbori de cutare 217
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
begin
if cheiac<temp.key then begin { se caut n subarborele stng }
218 5. Tehnici de cutare
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 u , predec , tatap : adresa ;
begin
if (temp.lptr=nil) and (temp.rptr=nil) then {tergerea unui nod terminal-
Cazul1}
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 }
5.2. Arbori de cutare 219
begin { singur u Cazul 2, 3 }
if temp.lptr<>nil then u:=temp.lptr
else u:=temp.rptr;
if temp.key<tata.key then begin
tata.lptr:=u;
dispose(temp);
end
else begin
tata.rptr:=u;
dispose(temp);
end;
end
else begin {tergerea unui nod cu doi i 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;
220 5. Tehnici de cutare
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-Aare 4-tergere );
write(5-Ieire);
end;
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
5.2. Arbori de cutare 221
writeln;
write(introducei cheia de sters:);
readln(student.key);
stergere(root,student.key);
end;
end;
until ch=5;
end.
5.2.4 Arbore de cutare 2-3 AC2-3
5.2.4.1 Descrierea general a arborelui de cutare 2-3
Un alt tip de arbore de cutare este arborele de cutare 23 (AC23). Un arbore
2-3 este denit ca un arbore de cutare n care nodurile non-frunz (neterminale)
au 2 sau 3 i, 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 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 5.14 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.
11 7
7:11 1:3
6 3 1
6:11
Figura 5.15: Exemplu de arbore de cutare 2-3
222 5. Tehnici de cutare
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 denumit nod auxiliar de cutare. Un astfel de nod auxi-
liar 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 i, atunci se consid-
er c ul lips este ul 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 u_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 u_mijloc.
Altfel, dac cheia de cutare este mai mare dect limita superioar de cutare
i dac exist legtura u_dreapta atunci cutarea se face pe legtura
u_dreapta, altfel cutarea se face pe legtura u_mijloc .
5.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):
u_st a b tip u_mij u_st
Unde:
u_st : reprezint adresa ului 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 = 0;
u_mij : reprezint adresa ului din mijloc;
u_dr : reprezint adresa ului dreapta;
5.2. Arbori de cutare 223
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 = 0;
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);
non-frunza: ( Fiu_stg : adresa;
a : integer;
b : integer;
u_mij : adresa;
u_dr : adresa;
end
5.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 specice arborelui de cutare 2-3 i vor detaliate n
cele ce urmeaz.
224 5. Tehnici de cutare
b. Operaia de inserare.
Exist patru cazuri de analizat pentru operaia de inserare [Tre, 1984]. 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 gura 5.16 a se insereaz nodul cu cheia 4.
4
9
4
4:9
b) a)
Figura 5.16: Cazul 1 de inserare a) i cazul 2 de inserare b)
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 i nodului auxiliar de cutare.
Exemplu: n gura 5.16 b) se insereaz nodul cu cheia 9 n AC2-3 din gura 5.16
a).
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 e inserat noul nod, dup care este determinat nodul tat, avnd grij ca
s memorm drumul de cutare.
Cazul 3. Nodul tat are exact doi i. Inserm noul nod la n poziia determinat
de comparaia cheilor de cutare.
Dac valoarea cheii de inserat este mai mic dect valoarea cheii nodului u stnga,
atunci noul nod de inserat va deveni ul stng al nodului tat; dac valoarea cheii
nodului de inserat este mai mare dect cheia nodului u mijloc, atunci noul nod de
inserat va deveni nodul u dreapta al nodului tat; altfel noul nod de inserat va deveni
nodul u mijloc al nodului tat. Aceast nserare este prezentat n Figura 5.17.
Exemplu: n gura 5.17 b) se insereaz nodul cu cheia 9 n AC2-3 din gura 5.16
b).
Cazul 4. Nodul tat are trei i. n acest caz, noul nod de inserat ar deveni al
5.2. Arbori de cutare 225
patrulea u 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
u. Cele patru noduri i vor separate astfel: cei doi frai din stnga i cei doi frai
din dreapta vor ataai nodului tat iniial i nodului unchi nou creat.
Exemplu: n gura 5.17 se insereaz nodul cu cheia 9 n AC2-3 din gura 5.16 a).
9 4
4:9
9 7 4
4:7
Figura 5.17: Cazul 3 de inserare. n AC2-3 din stnga se insereaz un nou nod cu
cheia 7
11 9 7 4
4:7
7 11 9
9:11
4:7
7:11
4
4 9 7
4:7
Figura 5.18: Cazul 4 de inserare. n AC2-3 din stnga se insereaz un nou nod cu
cheia 11
Specicarea problemei de inserare, avnd ca date de intrare ROOT, cheia_nou,
info_nou, este urmtoarea:
DATE ROOT, cheia_nou, info_nou;
REZULTATE root;
226 5. Tehnici de cutare
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.u_st := ROOT;
tata.u_mij := nou;
tata.u_dr := NIL;
ALTFEL
DAC ROOT.cheia > cheia_nou ATUNCI
tata.a := cheia_nou;
tata.b := ROOT.cheia;
tata.u_st := nou;
tata.u_mij := ROOT;
tata.u_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);
5.2. Arbori de cutare 227
tmp := tmp.u_st;
ALTFEL
Push(stiva, top, tmp);
tmp := tmp.u_mijl;
SFCT { Adresa nodului tat este n vrful stivei}
tata := pop(stiva, top);
Dac tata.u_dr := NIL
CHEAM Cazul_3_inserare (ROOT, tata, cheia_nou, info_nou);
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
u_st, u_mij, u_dr. Se actualizeaz corespunztor cmpurile nodului de inserat
i cmpurile nodului tat.
Subalgorimul Cazul_4_inserare poate 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 i ntre nodul tat i noul nod unchi;
@ Actualizeaz limita inferioar a, limita superioar b i legturile u_dr , u_mij,
u_st;
DAC @nodul printe nu are strmoi ATUNCI
@creeaz un nou nod rdcin;
@leag nodul printe de noul nod rdcin ca u stnga;
@leag noul nod unchi de noul nod rdcin ca u 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 i 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);
228 5. Tehnici de cutare
SFDAC
SFDAC
SF-Cazul_1
c. Operaia de cutare.
Specicarea problemei de cutare, avnd ca date de intrare ROOT i cheia_caut,
este urmtoarea:
DATE root, cheia_caut;
REZULTATE root;
Descrierea algoritmului de inserare n Pseudocod este:
ALGORITMUL CUTARE ESTE:
CITETE cheia_caut;
tmp := ROOT ;
CTTIMP tmp.tip <> 0 EXECUT {Pn cnd se ajunge la un nod terminal}
DAC cheia_caut < tmp.a ATUNCI
tmp := tmp.u_st;
ALTFEL
DAC ( tmp.a < cheia_caut ) i ( cheia_caut < tmp.b ) ATUNCI
tmp := tmp.u_mijl;
ALTFEL DAC tmp.u_dr <> NIL ATUNCI
tmp := tmp.u_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
5.2. Arbori de cutare 229
d. Operaia de tergere.
Specicarea 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:
Se actualizeaz adresa nodului rdcin care devine NIL;
Se elibereaz spaiul de memorie ocupat de nodul de ters.
Dac nodul tat al nodului de ters are 3 i, algoritmul de tergere este urm-
torul:
Se actualizeaz cmpurile nodului tat;
Se elibereaz spaiul de memorie ocupat de nodul de ters.
Dac nodul tat al nodului de ters are 2 i, algoritmul de tergere este urm-
torul:
Nodul rmas, frate al nodului de ters se leag de un nod unchi;
Dac nodul unchi avea 2 i, n urma alipirii nodului va avea 3 i;
Dac nodul unchi avea 3 i, n urma alipirii nodului va avea 4 i, deci va
trebui s facem:
2 Vom crea un nou nod non-frunz, nod frate cu nodul tat. Poziia
nodului nod frate este determinat de poziia i dispunerea nodurilor
u;
2 Cele patru noduri i vor separate astfel: cei doi frai din stnga i
cei doi frai din dreapta vor ataai nodului tat iniial i nodului
unchi nou creat.
Descrierea detaliat a algoritmului de tergere poate gsit n referina biblio-
grac [Aho, 1987].
230 5. Tehnici de cutare
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 form 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.u_st ) ;
if def.tip = 0 then
write ( def.cheia : 3 ) ;
inordine_2_3 ( def.u_mij ) ;
inordine_2_3 ( def.u_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.u_st ) ;
5.2. Arbori de cutare 231
preordine_2_3 ( def.u_mij ) ;
preordine_2_3 ( def.u_dr ) ;
end ;
end ;
Procedure postordine_2_3 ( def : adresa ) ; { traversare postordine }
begin
if def <> NIL then
begin
postordine_2_3 ( def.u_st ) ;
postordine_2_3 (def.u_mij);
postordine_2_3 ( def.u_dr ) ;
if def.tip = 0 then
write ( def.cheia : 3 ) ;
end ;
end ;
5.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 3
h
[Sed, 1990]. Aceasta nseamn c nlimea unui AC2-3 cu n noduri este cel
mult log
2
n, adic algoritmul de cutare este direct proporional cu O(log
2
n).
Probleme rezolvate
Exemplul 5.2.4. 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 ;
232 5. Tehnici de cutare
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 }
begin
if ind = max then
full_stack := true
else
full_stack := false
5.2. Arbori de cutare 233
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 owerow ) ;
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 underow ) ;
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 ;
234 5. Tehnici de cutare
Procedure Inserare_arbore ( nr:integer ) ;
Procedure Insert_caz1 ( x:integer ) ; { rdcina = nil }
var q : adresa;
begin
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 ) ;
5.2. Arbori de cutare 235
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
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;
236 5. Tehnici de cutare
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
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
5.2. Arbori de cutare 237
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
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 ;
238 5. Tehnici de cutare
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 ;
nou.key := nr ;
Insert_caz4(nou) ;
5.2. Arbori de cutare 239
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);
240 5. Tehnici de cutare
readln;
end;
end;
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.
5.3. Funcii de cutare hash 241
Probleme propuse
1. S se construiasc un arbore binar care cuprinde strmoii unei persoane, a
crui nume gureaz n rdcin arborelui. Nodul care gureaz n stnga
cuprinde numele tatlui, iar cel din dreapta pe cel al mamei. Fiind dat numele
unei persoane oarecare din familie, s se aeze numele bunicilor, dac acetia
gureaz in arbore.
2. Reprezentai grac 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 gsi 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 specic care terge i rebalanseaz un arbore binar ba-
lansat n greutate .
6. Formulai un algoritm care s modice un nod particular ntr-un ABCBG.
Apelul algoritmului s e de forma:
SCHIMB ( CHEIE , GREUTATE_NOU )
unde CHEIE este cheia nodului care se modic 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.
5.3 Funcii de cutare hash
5.3.1 Introducere
Cea mai bun metod de cutare studiat pn acuma este cutarea binar, care
are timpul de cutare proporional cu O(log
2
n). Tehnicile de cutare discutate pn
acum se bazeaz exclusiv pe compararea cheilor.
O alt abordare posibil ar calculul direct al locaiei sau adresei unei date
cutate. Evident, 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
242 5. Tehnici de cutare
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 ecare student poate identicat 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 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 denit 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:
k
1
K, k
2
K, k
1
,= k
2
H(k
1
) = H(k
2
)
Acest fenomen se numete coliziune ntre nregistrrile memorate n structura de
date. Pentru a rezolva aceast problem este nevoie s analizm tehnici de re-
zolvare 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.
5.3. Funcii de cutare hash 243
5.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 codi-
care a cheilor de cutare, numit uneori precondiionare. Codicarea 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 codicare care face o transformare a mulimii cheilor de
cutare alfanumerice ntr-o mulime numeric care poate manipulat mai uor i
care poate argumentul funciilor hash numerice [Knu, 1976].
Cel mai des folosit exemplu de codicare se bazeaz pe utilizarea codurilor ASCII
sau EBCDIC, nlocuind semnicaia alfanumeric a unui caracter cu codul su nu-
meric 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 codicare este dimensiunea
prea mare a cheii numerice obinut prin procesul de codicare. Presupunnd ca
dimensiunea cheii de cutare este de 10 caractere alfanumerice, codicarea ar trans-
forma cheia de cutare alfanumeric ntr-o cheie de cutare numeric de ordinul miilor
de mii de miliarde, date care nu pot 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 coecienii
i ai transformrii liniare se determin din sistemul:
_
_
_
f(a) = c
f(b) = d
(5.6)
5.3.2.1 Funcia hash - metoda mpririi
Una dintre cele mai utilizate funcii hash este cea bazat pe metoda mpririi.
Aceasta este denit n felul urmtor:
H : K A, H(x) = x mod m+ 1 (5.7)
244 5. Tehnici de cutare
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
1, 2, 3, . . ., m.
Funcia hash bazat metoda mpririi asigur, pn la o anumit limit, o dis-
tribuie 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.
5.3.2.2 Funcia hash - metoda ptratului mediu
O alt funcie hash care este folosit n multe aplicaii se bazeaz pe metoda ptra-
tului mediu. n aceast metod, cheia de cutare este ridicat la ptrat, iar adresa
unde va 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 138.
5.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
nesemnicative 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 oper-
aiei 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
781
- - - - -
2079 renunm la cifra 2 de transfer i avem adresa 079.
5.3. Funcii de cutare hash 245
5.3.2.4 Funcia hash - metoda cifrelor
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.
5.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 de exemplu metoda mpririi,
pentru a genera o adresa nal din tabel.
O funcie hash de acest tip, sumeaz valoarea reprezentrii binare interne a primu-
lui i al ultimului caracter al cheii i a lungimii cheii, translatat la stnga cu patru
poziii binare (sau a multiplicat cu 2
4
= 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.
5.3.2.6 Funcia hash metoda codicrii algebrice
Funcia hash bazat pe metoda codicrii algebrice are la baz teoria de codicare
algebric [Knu, 1976]. O cheie binar de n bii (k
1
k
2
. . . k
n
)
2
este codicat cu ajutorul
unui polinom de gradul n:
K(x) =
n
i=1
k
i
x
i1
(5.8)
Dac spaiul de adresare este n intervalul 0, 2
m
1|, atunci vom construi un polinom
divizor al polinomului K, i anume:
P(x) = x
m
+
m
i=1
p
i
x
i1
. (5.9)
246 5. Tehnici de cutare
mprind polinomul K la polinomul P, folosind operaii n baza 2, vom obine poli-
nomul rest:
R(x) = K(x) mod P(x) =
r
i=1
r
i
x
i1
. (5.10)
Coecienii polinomului rest R(x), (h
1
h
2
. . . h
r
)
2
vor genera adresa cutat.
5.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) = mcx|| + 1 (5.11)
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 cores-
punztor. Alegerea constantei c este dicil.
5.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 armaii
este dependent de mulimile particulare de chei de cutare.
Este nevoie de introducerea unui sistem de referin pentru a compara perfor-
manele 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.
5.3.4 Tehnici de rezoluiune a coliziunilor
5.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 seciunea 5.3.1, 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 la aceeai adres a structurii
de date. n practic, un astfel de fenomen se ntmpl pentru c spaiul cheilor de
5.3. Funcii de cutare hash 247
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 nre-
gistrrilor aate n coliziune la alte adrese ale structurii de date. Dac structura
de date este o tabel, atunci ne propunem s plasm nregistrrile aate 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
aate n coliziune.
Deci, avem nevoie de un mecanism i de algoritmul corespunztor care s exami-
neze 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).
5.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 aat 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, ind
alocat static, are un numr nit de poziii de stocare a nregistrrilor, aceast capaci-
tate neputnd modicat pe parcursul execuiei programului ce implementeaz
algoritmul de manipulare a nregistrrilor. De aceea, pentru a folosi ct mai ecient
248 5. Tehnici de cutare
spaiul de stocare x 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
aat n coliziune prin tehnica adresrii deschise este de mai multe feluri, i anume:
a. Probare liniar
b. Probare aleatoare
a. Probarea liniar
Unul din cele mai simple mecanisme de cutare a unei locaii libere pentru o nregi-
strare avnd o cheie de cutare n coliziune, este de a folosi o secven de cutare
liniar. Presupunnd c avem cheia k K, H(k) = a A, iar la adresa a avem
o coliziune, atunci probarea liniar se bazeaz pe urmtoarea secven de cutare
liniar:
a, a + 1, . . . , m1, m, 1, 2, . . . , a 1 (5.12)
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 : 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.12). Dac am ajuns la locaia de adres a 1, atunci cutarea nu
este cu succes, nregistrarea cutat nu exist n tabel. Altfel, cutarea este
cu succes.
5.3. Funcii de cutare hash 249
Aceast tehnic de rezolvare a coliziunilor se numete probare liniar.
Operaia de inserare este prezentat cu ajutorul unui exemplu. S presupunem c
avem o tabel de dimensiune 11 i cteva nregistrri cu urmtoarele chei de cutare
[Tre, 1986]:
NINA, STOICAN, ANA, ADA, FUNCTIE, B, BRAND i PARAMETRU
Aplicnd o funcie hash H, s presupunem ca avem urmtoarea situaie:
Cheia de cutare Adresa din tabela hash
NINA H(NINA) =1
STOICAN H(STOICAN) = 2
ANA H(ANA)=3
ADA H(ADA) = 3
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 urm-
toarea tabel:
Numrul de probe
Tabel [1] NINA 1
Tabel [2] STOICAN 1
Tabel [3] ANA 1
Tabel [4] ADA 2
Tabel [5] PARAMETRU 8
Tabel [6] Empty
Tabel [7] Empty
Tabel [8] Empty
Tabel [9] FUNCTIE 1
Tabel [10] B 2
Tabel [11] BRAND 3
Figura 5.19: Coninutul tabelei hash dup aplicarea operaiilor de inserare i a cutrii
unei noi poziii libere prin mecanismul de probare liniar
250 5. Tehnici de cutare
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 nal, nregistrarea cu cheia de cutare PARAMETER va plasat prin meca-
nismul probrii liniare n poziia 5 a tabelei, necesitnd 8 operaii de probare, ind n
coliziune cu nregistrrile inserate anterior, ind probate poziiile ocupate 9, 10, 11,
1, 2, 3, 4 i poziia liber 5.
Specicarea 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
5.3. Funcii de cutare hash 251
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;
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.19), dac tergem
252 5. Tehnici de cutare
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 considerat liber i nregistrarea duplicat
va inserat.
Specicarea 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 coliziunilor i calculele pentru determinarea performanelor algoritmului
de cutare n cazul mecanismului de probare liniar. Modelul presupune ca ecare
cheie este echiprobabil pentru cutare. Dac notm cu m capacitatea maxim a
tabelei hash, atunci probabilitatea ca o nregistrare s e cutat este p
i
=
1
m
.
Dac dimensiunea spaiului cheilor de cutare este n, atunci vom avea un numr
de m
n
funcii posibile de la K la A.
Vom nota cu =
n
m
factorul de ncrcare a tabelei hash . Timpul mediu de
cutare va dependent de factorul de ncrcare. n [Knu, 1976] gsim urmtoarea
formul:
ALOS =
_
_
1
2
_
1 +
1
1
_
, pentru cutare cu succes
1
2
_
1 +
1
(1 )
2
_
, pentru cutare cu insucces
(5.13)
Pentru o distribuie uniform a mulimii cheilor 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
5.3. Funcii de cutare hash 253
trebuie s e 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 da-
torat 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 aate n coliziune. De aceea, nregistrrile aate n coli-
ziune 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 ale fenomenului gruprii primare, pot 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
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 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.14)
unde a este adresa iniial generat de funcia hash, c este o constant ntreag,
nenul, aleas astfel nct s e 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.
Specicarea problemei de inserare, avnd ca date de intrare tabela hash numit
tab, dimensiunea maxim a tabelei m, cheia de inserare cheia, este urmtoarea:
254 5. Tehnici de cutare
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). Gru-
parea secundar apare cnd se genereaz aceeai secven de adrese libere pentru
dou chei de cutare aate 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.14),
independent de prima funcie hash. Prin aplicarea acestei metode se anuleaz efectul
negativ al gruprii secundare.
Fie H
1
: K A prima funcie de hash, i k
1
, k
2
K dou chei de cutare distincte
aate n coliziune, adic:
H
1
(K
1
) = H
2
(k
2
) = a A
Fie H
2
: K A a doua funcie de hash, folosit pentru a genera valoarea constan-
tei c din formula de probare aleatoare (5.14). Atunci dac H
2
(k
1
) ,= H
2
(k
2
) putem
5.3. Funcii de cutare hash 255
alege c = H
2
(k
1
). n acest fel, la ecare probare aleatoare se vor genera secvene
diferite de adrese, iar problema gruprii secundare va depit.
Metoda descris mai sus de a folosi dou funcii hash independente se numete
hash dublu.
Exemplu. S considerm urmtoarele funcii hash [Tre, 1984]:
H
1
(k) = k mod m i H
2
(k) = (k mod (m2)) + 1
unde k este valoarea cheii de cutare i m este mrimea tabelei hash. Pentru m = 11
i k
1
= 75 vom avea urmtoarele valori: H
1
(75) = 9 i H
2
(75)= 4.
Aplicnd formula probrii aleatoare (5.14), 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 k
2
= 42, atunci H
1
(42) = 9. Cheile de cutare k
1
i
k
2
sunt n coliziune. Alegnd c = H
2
(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 ) ; {prima funcie hash}
inc := increment( key ) ; {a doua funcie hash}
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:
ALOS =
_
k
1
,
k
2
, . . . ,
k
q
, k
i
, k
j
k
l
, dac H(k
i
) = H(k
2
) = k
i
.
Vom avea n acest fel o tabel hash x, 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 n-
lnuite care stocheaz restul cheilor de cutare aate n coliziune cu cheia reprezen-
tant al clasei de echivalen.
Aceast tehnic de rezoluiune a coliziunilor se numete adresare nlnuit.
Exemplu. n gura de mai jos avem un exemplu de reprezentare a metodei adresrii
nlnuite, pentru m = 11 i n = 9. Presupunem c cheile sunt nserate n ordinea
urmtoare:
NINA , STOICAN , ANA , ADA , FUNCTIE , B , BRAND, PARAMETRU
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 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.
5.3. Funcii de cutare hash 257
Tabel [1] NINA
STOICAN Tabel [2]
ADA ANA Tabel [3]
Tabel [4]
Tabel [5]
Tabel [6]
Tabel [7]
Tabel [8]
Tabel [9]
Tabel [10]
Tabel [11]
B BRAND FUNCTIE PARAMETRU
Figura 5.20: Modelul de rezolvare a coliziunilor prin adresare nlnuit
Specicarea 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
258 5. Tehnici de cutare
Specicarea 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);
@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
cu [Tre, 1984]:
_
_
1 +
2
, pentru cutare cu succes
+e
i=1
(n i) = n(n 1) +
n(n 1)
2
=
n(n 1)
2
.
Atunci performana algoritmului de sortare prin metoda seleciei este O(n
2
). Aceleai
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 alegerea cea mai bun.
6.2.3 Algoritmul de sortare prin inserare
6.2.3.1 Descrierea general a metodei
Este un algoritm aproape la fel de simplu ca algoritmul de sortare prin selecie, dar
poate mai exibil.
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.
6.2. Algoritmi de sortare 271
6.2.3.2 Descrierea algoritmului
Fiind dat o tabel A cu N elemente nesortate, parcurgem tabela si inserm ecare
element n locul potrivit pentru a menine ordinea de sortare aleas ntre celelalte
elemente considerate deja sortate.
Pentru ecare i = 2 . . . N, dac elementele A[1], A[2], . . ., A[i] sunt sortate, vom
insera elementul A[i + 1] ntre lista elementelor sortate: A[1], A[2], . . ., A[i].
Elementele aate n stnga indexului i sunt sortate dar nu sunt nc n poziia lor
nal. Tabela este complet sortat cnd indexul ajunge la captul drept al tabelei.
Putem uura procesul inserrii (ex: cnd cel mai mic element e greu de denit), 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 6.2.3. Sortarea tabelei A din Figura 6.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 6 10 8 9 7 2
Pas 6 1 3 4 5 6 8 10 9 7 2
Pas 7 1 3 4 5 6 8 9 10 7 2
Pas 8 1 3 4 5 6 7 8 9 10 2
Pas 9 1 2 3 4 5 6 7 8 9 10
Figura 6.3: Sortarea unei tabele A cu 10 elemente prin algoritmul de sortare prin
inserare
272 6. Tehnici de sortare
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;
- 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.
6.2.3.3 Implementarea algoritmului
Specicarea 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:
6.2. Algoritmi de sortare 273
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
Implementarea algoritmului de sortare prin metoda inserrii n limbajul Pascal
este:
Procedure inserare ( var A: arraytype; n:integer);
Var i, j: integer;
Begin
A[0] := minus_innit; {minus_innit 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;
6.2.3.4 Complexitatea algoritmului
Algoritmul de sortare prin inserare este un algoritm de sortare liniar: complexitatea
algoritmului este O(N) pentru tabele care conin N elemente sortate sau aproape
274 6. Tehnici de sortare
sortate.
Complexitatea algoritmului de sortare prin inserare depinde de numrul de inserri
i translatri, care este inuenat de ordinea iniial al elementelor. n caz general
sunt necesare
N
2
4
operaii de comparaie i
N
2
8
operaii de interschimbare, deci ordinea
complexitii este O(N
2
) [Tre, 1984].
6.2.4 Algoritmul de sortare Shell
6.2.4.1 Descrierea general a metodei
Sortarea prin micorarea incrementului, numit i sortare Shell, este o extensie sim-
pl a metodei de sortare prin inserare, mbuntind performanele algoritmului prin
interschimbarea elementelor cele mai ndeprtate. Ideea de baz o constituie rearan-
jarea elementelor din tabela A n aa fel nct, lund ecare 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 o proce-
dur pentru ecare 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, e 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 ecare 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 nal, 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 ind n poziia cresctoare dorit.
Algoritmul de sortare Shell , necesit o mulime de incremeni h
t
, h
t1
, . . . , h
1
,
ultimul increment h
1
ind egal cu 1.
O formula des utilizat n practic propune urmtoarele formule pentru secvena
de incremeni [Knu, 1976]:
h
1
= 1; h
i+1
= 3h
i
+ 1 (6.1)
Secvena este 1,4,13, 40, 121, . . . , cu formula general:
h
i
=
3
i
1
2
(6.2)
6.2. Algoritmi de sortare 275
Deci numrul total de incremeni va :
t = log
3
(2n + 1)| (6.3)
6.2.4.2 Descrierea algoritmului
Algoritmul de sortare Shell necesit mai multe operaii dect algoritmul de sortare
prin inserare, dar la ecare pas elementele ce urmeaz a interschimbate efectueaz
salturi lungi spre poziia corect, ceea ce ar trebui s duc la mbuntirea perfor-
manelor algoritmului de sortare.
n general, algoritmul de sortare Shell poate descris astfel [Aho, 1997]:
PENTRU k := t;1 EXECUT
PENTRU d := 0; h
k
1 EXECUT
CHEAM SORTARE_Inserare(@Subtabela d);
Exemplul 6.2.4. Sortarea tabelei A din Figura 6.4 (a) folosind algoritmul de sortare
Shell , n ordine cresctoare:
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 10
Figura 6.4: Sortarea unei tabele A cu 12 elemente prin algoritmul de sortare Shell
276 6. Tehnici de sortare
Pasul 1 Crearea celor h subtabele (Fig. 6.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
Pasul 2 Sortarea celor 5 subtabele (Fig. 6.4 (c))
Pasul 3 Tabela iniial dup pasul de sortare cu incrementul 5 (Fig.6.4(d))
Pasul 3 Tabela iniial dup pasul de sortare cu incrementul 1 (Fig.6.4(d))
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
6.2.4.3 Implementarea algoritmului
Specicarea 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;
6.2. Algoritmi de sortare 277
SFPENTRU
inc := Increment_urmtor(inc, n);
SFALGORITM
Observaie.
Secvena de incrementare este determinat iterativ, folosind funciile Incre-
ment_intial(n) i Increment_urmtor(inc, n). Funcia Increment_intial(n) va
returna cel mai mare increment utilizabil pentru sortarea unei tabele de dimen-
siune 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 h
t
, h
t1
, . . . , h
1
= 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
278 6. Tehnici de sortare
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;
6.2.4.4 Complexitatea algoritmului
Complexitatea algoritmului de sortare Shell este greu de analizat, greu de comparat
cu alte metode, ind 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 .
6.2.5 Algoritmul de sortare rapid (quicksort)
6.2.5.1 Descrierea general a metodei
Algoritmul de sortare, considerat a cel mai rapid, de complexitate O(N log N), este
algoritmul de sortare rapid (quicksort), folosind partiionarea ca idee de baz. Este
mai rapid dect orice metod de sortare simpl, se comport ecient pentru iere
sau tabele mari, dar inecient 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 tabel mare. Algoritmul
este uor de implementat, consum mai puine resurse dect orice alt metod de
sortare.
6.2.5.2 Descrierea algoritmului
Avnd o tabel A cu N elemente, alegem o cheie pivot v n jurul creia rearanjm
elementele. Pivotul poate ales n mai multe moduri. O modalitate simpl ar s
alegem ca pivot primul element.
6.2. Algoritmi de sortare 279
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;
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 6.2.5. Sortarea tabelei A din Figura 6.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 ecare subtabel va conine doar un element.
280 6. Tehnici de sortare
7 5 8 2 3 9 1 6 4
i j
4 5 8 2 3 9 1 6 7
i j
4 5 7 2 3 9 1 6 8
i j
4 5 6 2 3 9 1 7 8
i j
4 5 6 2 3 7 1 9 8
i j
4 5 6 2 3 1 7 9 8
j = i
4 5 6 2 3 1 7 9 8
i j i
j
1 2 3 4 5 6 7 8 9
SCHIMBA(4,1)
STOP
SCHIMBA(7,1)
SCHIMBA(9,7)
SCHIMBA(7,6)
SCHIMBA(8,7)
SCHIMBA(7,4)
Figura 6.5: Sortarea unei tabele A cu 12 elemente prin algoritmul de sortare Shell
6.2.5.3 Implementarea algoritmului
Specicarea 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
@e v := cea mai mare dintre cele dou chei distincte;
@permutm A[i], . . . ., A[j] astfel nct pentru i + 1 k j s avem:
6.2. Algoritmi de sortare 281
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)
SFALGORITM
Implementarea algoritmului de sortare prin metoda rapid n limbajul Pascal
este:
Variabilele left si right reprezint nceputul si sfrsitul tabelei sau subtabelei.
Procedure QUICK(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 sucient i = j}
If left < j-1 then
QUICK (left, j-1);
If i+1 < right then
QUICK (i+1, right);
End;
6.2.5.4 Complexitatea algoritmului
n algoritmului de sortare rapid, ecare element este comparat cu pivotul, adic
avem complexitatea O(N).
282 6. Tehnici de sortare
n continuare, tabela este divizat n dou pri, ecare parte este iari divizat
n dou pari, . . . ., .a.m.d. Dac ecare parte este mprit aproximativ n dou
jumti egale, vom avea log
2
N operaii de mprire.
Deci complexitatea algoritmului de sortare rapid este n caz mediu O(N log
2
N),
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 (6.2). Performanele algoritmului de sortare rapid sunt dependente
de ordinea datelor de intrare. De aceea, nu este o metod de sortare stabil.
6.2.6 Algoritmul de sortare prin interclasare (mergesort)
6.2.6.1 Descrierea general a metodei
Algoritmul de sortare prin interclasare se bazeaz pe urmtoarea idee: pentru a sorta
o tabel cu Nelemente o mprtim n dou tabele pe care le sortm separat i le
interclasm. Este o metod de sortare care foloseste strategia de baz "divide et
impera", conform creia problema se descompune n alte dou subprobleme de acelai
tip i dup rezolvarea lor rezultatele se combin. Algoritmul sorteaz elementele n
ordine cresctoare.
6.2.6.2 Descrierea algoritmului
Fiind dat o tabel A cu N elemente, tiem (sau mprtim) tabela n dou prti,
sortm separat ambele pri i mbinm cele dou jumtti ntr-o tabel auxiliar
temporar. Dac o jumtate are doar un element, o consoderm deja sortat. Tierea
n dou a tabelei nseamn gsirea punctului de mijloc: (prim+ultim)div2.
Pentru a "mbina" jumtile sortate, interclasm ecare subtabel, comparm
succesiv perechile de chei (din ecare parte) i punem valoarea mai mic ntr-o tabela
temporar. Algoritmul 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). Al-
goritmul se termin cnd o subtabel nu mai are nici o nregistrare si mutm nre-
6.2. Algoritmi de sortare 283
gistrrile rmase din cealalt subtabel n tabela temporar. Dup pasul de inter-
clasare putem copia tabela temporar sortat n tabela original.
N = 50
N = 50
[100]
N = 100 A
[1]
[1] [50] [51] [100]
Figura 6.6: "mbinarea" prin interclasare a unei tabele A cu 100 elemente
Pasul 1: Am mijlocul tabelei
- mijloc := (1 + 9) / 2 = 5;
Pasul 2 mprim tabela n dou subtabele fa de elementul de mijloc.
- avem subtabela format din nregistrrile 7, 5, 8, 2;
- avem subtabela format din nregistrrile 3, 9, 1, 6, 4;
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.
6.2.6.3 Implementarea algoritmului
Specicarea problemei de sortare, avnd ca date de intrare tabela A, dimensiunea
maxim a tabelei N, este urmtoarea:
284 6. Tehnici de sortare
Tabela A:
7 5 8 2 3 9 1 6 4
2 5 7 8 1 3 4 6 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
right
first
left
last
left
first
Subtabela 1 Subtabela 2
Temp
right
last
A
Figura 6.7: Sortarea unei tabele A cu 9 elemente prin algoritmul de sortare prin
interclasare
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;
ALTFEL
Temp[Index] := A[Index curent_ drept];
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;
6.2. Algoritmi de sortare 285
SFALGORITM
Implementarea algoritmului de interclasare n limbajul Pascal este:
Variabilele lrst, llast, rrst, rlast indic cele dou capete ale subtabelei din stnga
si ale subtabelei din dreapta. Variabilele curent_left si curent_right reprezint ele-
mentul curent din stnga respectiv din dreapta. Temp este tabela temporar folosit
pentru sortare.
Procedure Interclasare (var A:arraytype; lrst, llast, rrst, rlast: integer);
var
temp: arraytype;
index, curent_left, curent_right: integer;
Begin
curent_left:=lrst;
curent_right:=rrst;
index:=lrst;
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
286 6. Tehnici de sortare
Begin
Temp[index]:=A[curent_right];
curent_right:=curent_right+1;
index:=index+1;
End;
For index:=lrst to rlast do
A[index] := Temp[index]
End;
Implementarea algoritmului de sortare prin interclasare, varianta recursiv, n
limbajul Pascal este:
Procedure SORTARE_Interclasare (var A: arraytype; rst,last:integer);
var
middle: integer;
Begin
If rst < last then
Begin
middle:=(rst+last) div 2;
SORTARE_Interclasare (A, rst, middle);
SORTARE_Interclasare (A, middle +1, last);
Interclasare (A, rst, middle, middle +1, last);
End;
End;
6.2.6.4 Complexitatea algoritmului
Majoritatea operaiilor efectuate de algoritmul de sortare prin interclasare sunt efec-
tuate de operaiile de comparare i de copiere.
n cadrul operaiilor de interclasare, ecare 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 mprit
de cel mult log
2
N ori. La ecare mprire se execut operaia de interclasarere care
este de ordinule O(N).
6.2. Algoritmi de sortare 287
Atunci algoritmul de sortare prin interclasare va avea o complexitate de ordinul
O(N log
2
N) n toate dintre cele trei cazuri [Tom, 1997]. Este o metod stabil. Algo-
ritmul 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.
6.2.7 Algoritmul de sortare prin ansambluri (heapsort)
6.2.7.1 Descrierea general a metodei
Deniia 6.2.1. Un arbore binar posed proprietatea de ansamblu dac orice
nod al su veric proprietatea: cheia de cutare a nodului tat este mai mare sau
egal dect cheia de cutare a nodului u_stnga sau dect cheia de cutare a nodului
u_dreapta.
Deniia 6.2.2. Un ansamblu (heap) este un arbore binar complet ce posed
proprietatea de ansamblu (Deniia 6.2.1).
Caracteristica de baz a acestei structuri de date, numit ansamblu, este c
modicarea valorii cheii de cutare a unui nod se poate face uor pstrnd totui
proprietatea de ansamblu. Presupunnd c cheia de cutare a unui nod_u de-
pete cheia de cutare a nodului_tat, este sucient 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 modicat
a fost ltrat ctre noua poziie [And, 1995].
Dac, dimpotriv, cheia de cutare a nodului_tat scade, devenind mai mic dect
cheia de cutare a unui nod_u, atunci este sucient s schimbm ntre ele nodul_tat
cu nodul_u 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 modicat a fost cernut ctre noua sa poziie [And, 1995].
Metoda de sortare prin ansambluri, se bazeaz pe reprezentarea arborescent a
unei tabele date.
6.2.7.2 Descrierea algoritmului
a. Construirea ansamblului : Descrierea general a algoritmului n Pseudocod
este:
Specicarea problemei de construire a ansamblului , avnd ca date de in-
trare tabela A, dimensiunea maxim a tabelei N, este urmtoarea:
288 6. Tehnici de sortare
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
CHEAM Cernere (A, N, i);
SF-PENTRU
SFALGORITM
ALGORITMUL Cernere (B, M, j) ESTE:
k := j: { Se cerne valoarea din tabela B[j] }
REPET
l := k; { Gsete ul 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 6.8 avem un exemplu de construire a unui ansamblu. Nodurile
reprezentate cu cercuri duble semnic elementele care constituie ansamblul , iar
nodurile reprezentate cu cercuri colorate reprezint noduri care violeaz proprietatea
ansamblului .
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 6.8 (a)
6.2. Algoritmi de sortare 289
1 3 9 1
4 6
9
3 2
8 5
7
4 6
2
8 5
7
1 3
4 2
9 6
8 5
7
b) a) c)
1 8 1
4 2
8
3 5
9 6
7
4 2
3 6
9 5
7
1
3
4 2
7 5
8 6
9
f) ansamblu
e) d)
Figura 6.8: Construirea unui ansamblu A cu 9 elemente
Pozitia 1 2 3 4 5 6 7 8 9
tabela originala 7 5 8 2 3 9 1 6 4
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
290 6. Tehnici de sortare
Pasul 2: Nodul cu cheia 2 violeaz proprietatea de ansamblu (arborele binar
este reprezentat n Figura 6.8 (b))
cernem valoarea nodului cu cheia 2;
interschimbm nodul cu cheia 2 cu nodul cu cheia 6;
arborele binar este reprezentat n Figura 6.8 (c).
Pasul 3: Nodul cu cheia 8 violeaz proprietatea de ansamblu (arborele binar
este reprezentat n Figura 6.8 (c)).
cernem valoarea nodului cu cheia 8;
interschimbm nodul cu cheia 8 cu nodul cu cheia 9;
arborele binar este reprezentat n Figura 6.8 (d).
Pasul 4: Nodul cu cheia 5 violeaz proprietatea de ansamblu (arborele binar
este reprezentat n Figura 6.8 (d))
cernem valoarea nodului cu cheia 5;
interschimbm nodul cu cheia 5 cu nodul cu cheia 6;
arborele binar este reprezentat n Figura 6.8 (e).
Pasul 5: Nodul cu cheia 7 violeaz proprietatea de ansamblu (arborele binar
este reprezentat n Figura 6.8 (e))
cernem valoarea nodului cu cheia 7;
interschimbm nodul cu cheia 7 cu nodul cu cheia 9;
arborele binar este reprezentat n Figura 6.8 (f).
n Figura 6.8 (f) avem reprezentat ansamblul construit din tabela A.
Implementarea algoritmului de creare al ansamblului n limbajul Pascal este:
Procedure Creare_Ansamblu (var A: arraytype, rst, last: integer);
var
r, max: integer;
ok: boolean;
Begin
6.2. Algoritmi de sortare 291
r := rst; 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 i n reprezentarea cu ajutorul tabelei va nregistrarea A[1]. Aceast
nregistrare va interschimbat cu nregistrarea A[N]. Ne vom ocupa n continuare
de primele N1 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 la locul potrivit, adic toate nregistrrile
vor sortate.
6.2.7.3 Implementarea algoritmului
Specicarea 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 }
292 6. Tehnici de sortare
Descrierea general a algoritmului de sortare n Pseudocod este:
ALGORITMUL SORTARE_Ansambluri ESTE:
CITETE A, N;
CHEAM Creare_Ansambluri;
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 ele-
mentele 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_Ansambluri (var A: arraytype; N: integer);
Var i: integer;
Begin
Creare_Ansambluri (A, 1, N);
For i:= N downto 2 do {sortare}
Begin
Swap(A[1],A[i]);
Creare_Ansambluri (A,1,i-1);
End
End;
6.2.7.4 Complexitatea algoritmului
Un arbore binar complet cu N noduri are nevoie de log
2
(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 log
2
N interschimbri,
deci complexitatea sa va O(log
2
N) [Tom, 1997].
Ciclul PENTRU din algoritmul de sortare se va executa de N-1 ori, deci complexi-
tatea algoritmului de sortare este O(N log
2
N).
6.2. Algoritmi de sortare 293
Algoritmul de sortare prin ansambluri are complexitatea O(N log
2
N) n toate
din cele trei cazuri de analizat: cazul general, favorabil i nefavorabil [Knu, 1976].
Pentru tabele mici algoritmul de sortare prin ansambluri este inecient, dar
foarte ecient pentru cele tabele mari. Nu necesit memorie suplimentar. E-
ciena algoritmul de sortare prin ansambluri nu este afectat de ordinea iniial a
elementelor.
6.2.8 Algoritmul de sortare RADIX
6.2.8.1 Descrierea general a metodei
Sortarea RADIX (sau sortarea digital) este o metod de sortare care precede apariia
calculatoarelor electronice, ind inspirat dintr-o metod de sortare mecanic a
cartelelor perforate. Este una din cele mai eciente metode de sortare intern, cu
condiia ca dimensiunea N a numrului de nregistrri de sortat s nu e prea mic,
iar cheile dup care se face ordonarea s nu e prea mici.
Algoritmul de sortare Radix trateaz cheile ca i cum ar numere reprezentate
ntr-o baz M, utiliznd cifrele din reprezentarea individuale a numerelor (de exemplu,
caracterele pot reprezentate n baza 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 semnicativ 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 urm-
torul rang semnicativ, pn cnd, n pasul nal se ordoneaz toate nregistrrile.
6.2.8.2 Descrierea algoritmului
Putem organiza nregistrrile de sortat n buzunare (pocket), ecare buzunar cores-
punznd unei cifre din reprezentarea cheilor de sortat n baza M. Fiecare buzunar
poate reprezentat ca o structur de date de tip coad (list FIFO). La sfritul
ecrui pas al procesului de sortare, cozile pot combinate uor n ordine potrivit.
Dac numrul maxim de cifre ntr-o cheie este M, atunci vor necesari M pai
de sortare, pornind de la cifra cea mai puin semnicativ la cifra cea mai semnica-
tiv. 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 semnicativ a
cheii, interclasm apoi buzunarele. Repetm procesul de la primul pas, sortnd
294 6. Tehnici de sortare
nregistrrile dup cifra urmtoare, interclasm iari buzunarele, .a.m.d.
Exemplu. S considerm urmtoarea secven de numere de sortat n ordine cresc-
toare [Tre, 1986]:
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
61
81 94 87
70 11 42 23 74 65 36 57 99
Buzunar: 0 1 2 3 4 5 6 7 8 9
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
65 74 87 99
11 23 36 42 57 61 70 81 94
Buzunar: 0 1 2 3 4 5 6 7 8 9
Pasul 4: Interclasm buzunarele
obinem secvena de chei: 11, 23, 36, 42, 57, 61, 65, 70, 74, 81, 87, 94, 99
6.2.8.3 Implementarea algoritmului
Specicarea 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:
6.2. Algoritmi de sortare 295
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[i ];
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 cm-
purile cheie (key) i legtur (next). Vectorii head si tail conin adresele primelor
i res-pectiv ultimelor nregistrri din ecare buzunar (coad). Variabila i este in-
dexul 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
= c
1
c
2
c
3
. . . c
M1
c
M
).
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
Else
tail[h].next := r;
tail[h] := r;
296 6. Tehnici de sortare
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;
6.2.8.4 Complexitatea algoritmului
Pentru ca algoritmul de sortare RADIX s e 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 i nu ca o tabel static. Dac folosim
organizarea sub form de list simpli nlnuit, atunci nu va trebui s copiem efectiv
nre-gistrrile din structura iniial n buzunare, ci doar s mutm adresa nregistrrii
dintr-o list n alta. De asemenea, pentru ca interclasarea s e rapid avem nevoie
de pointeri la sfritul ecrei 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
x [Tre, 1984].
Dac avem N nregistrri de sortat cu maximum M cifre necesare pentru
reprezentare, atunci complexitatea algoritmul de sortare RADIX este O(MN).
Bibliograe
[Ata] Atanasiu, A. , R. Pintea [1996]. Culegere de probleme Pascal, Editura
Petrion, Bucureti.
[Aho] Aho, A. V., J. E. Hopcroft, J. D. Ullman [1974]. The Design and Analysis
of Computer Algorithms, Addison-Wesley, Reading, Massachusetts.
[Aho] Aho, A. V., J. E. Hopcroft, J. D. Ullman [1987]. Data Structures and Algo-
rithms, Addison-Wesley, Reading, Massachusetts.
[Alb] Albeanu, G. [1994]. Programare n Pascal i Turbo Pascal. Culegere de prob-
leme, Editura Tehnic, Bucureti.
[And] Andonie, R., I. Grbacea [1995]. Algoritmi fundamentali. O perspectiv
C++, Editura Libris, Cluj-Napoca.
[Baa] Baase, S. [1987]. Computer Algorithms. Introduction to Design and Analysis,
Addison-Wesley, Reading, Massachusetts.
[Bla] Blaga P., G. Coman, S. Groze [1978]. Bazele Informaticii I. Culegere de
probleme, Litograa Universitii Babe-Bolyai, Cluj-Napoca.
[Bh] Bhm, C., T. C. Jacopini [1966]. "Flow Diagrams, Turing Machines and
Languages with only two Formation Rules", Comm. A.C.M. 9:5.
[Boi] Boian F., M. Freniu [1992]. Bazele Informaticii. Limbajul Pascal, ediia a
II-a, Litograa Universitii Babe-Bolyai, Cluj-Napoca.
[Bur] Burdescu, D.D. [1998]. Analiza complexitii algoritmilor, Editura Albastr,
Bucureti.
[Coo] Cook, S. A. [1970]. "The complexity of theorem-proving procedure", 3-rd
ACM Symposium of Computing, pg 151-158.
297
298 Bibliograe
[Cri] Cristea, V., I. Athanasiu, E. Kalisz, A. Pnoiu [1992]. Turbo Pascal 6.0,
Editura Teora, Bucureti.
[Cri] Cristea, V., I. Athanasiu, E. Kalisz, V. Iorga, [1993]. Tehnici de programare,
Editura Teora, Bucureti.
[Dal] Dale N., S. C. Lilly [1988]. Pascal Plus Data Structures, D. C. Heath and
Company, Lexington, Massachusetts.
[For] Fortune, S., C. J. Van Wyk [1993]. "Ecient Exact Arithmetic for Computa-
tional Geometry", Proceedings of the 9th ACM Symposium Computational
Geometry.
[Fre] Freniu M., S. Groze [1986]. Bazele Informaticii, ediia a II-a, Litograa
Universitii Babe-Bolyai, Cluj-Napoca.
[Giu] Giumale, C.A. [2004]. Introducere n analiza algoritmilor. Teorie i aplicaie,
Editura Polirom, Bucureti.
[Hor] Horowitz E., S. Sahni [1978]. Fundamentals of Computer Algorithms, Com-
puter Science Press, Rockville.
[Knut] Knuth D. E, [1976]. Tratat de programarea calculatoarelor. Algoritmi fun-
damentali, Editura Tehnic, Bucureti.
[Knu] Knuth, D. E. [1976]. Tratat de programare a calculatoarelor. Sortare i
cutare, Editura Tehnic, Bucureti.
[Kor] Korsh, J. F., L. J.Garrett [1988]. Data Structures, Algorithms and Program
Style Using C, PWS-Kent Publishing Co., Boston.
[Lev] Lewis, H.R., L. Denenberg [1991]. Data Structures & Their Algorithms,
Harper Collins Publishers, New-York.
[Liv] Livovschi L., [1980]. Scheme logice. Semnicaie, elaborare, vericare,
testare, Editura Tehnic, Bucureti.
[Liv] Livovschi L., H. Georgescu, [1986]. Sinteza i analiza algoritmilor, Editura
Stiinic i Enciclopedic, Bucureti.
[Moc] Mocanu, M., G. Marian, C. Bdic, [1993]. 333 probleme de programare,
Editura Teora, Bucureti.
[Sed] Sedgewitz, R. [1988]. Algorithms, Addison-Wesley, Reading, Massachusetts.
Bibliograe 299
[Sed] Sedgewitz, R. [1990]. Algorithms in C, Addison-Wesley, Reading, Mas-
sachusetts.
[She] Shewchuk, J. R. [1997]. "Floating-point arithmetic and fast robust geometric
predicates", Discrete and Computational Geometry, 18.
[Ski] Skiena, S. [1997]. The Algoritm Design Manual, Editura Springer-Verlag,
New-York.
[Tom] Tomescu, I., [1972]. Introducere n combinatoric, Editura Tehnic, Bu-
cureti.
[Tom] Tomescu, I. [1981]. Probleme de combinatoric i teoria grafurilor, Editura
Didactic i Pedagogic, Bucureti.
[Tom] Tomescu, I., [1997]. Data Structures, Editura Universitii din Bucureti,
Bucureti.
[Tre] Tremblay J. P., P. G. Sorenson [1984]. An Introduction to Data Structures
with Applications, second edition, McGraw-Hill, New-York.
[Tud] Tudor, S. [1993]. Tehnici de programare i structuri de date, vol. II, Editura
Turbo Rabbit, Bucureti.