Sunteți pe pagina 1din 166

MINISTERUL EDUCAIEI

INSTITUTUL DE FORMARE CONTINU


CATEDRA TEHNOLOGII INFORMAIONALE




Structuri de date
(n baza C++)
SUPORT DE CURS
Ediia 2



Elaborat i adaptat

Sergiu Pereteatcu, conf., dr.
Alexandru Pereteatcu, mag. n inf.








Chiinu - 2014

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
2


Rec oma nda t de c t r e Comi s i a t i i n i f i c o- Met odi c a Uns t i t ut u l u i de For ma r e
Cont i nu , Pr oc es s +ver ba l nr . 1 di n 1 4 i u ni e 2 012



Sergiu Pereteatcu, confereniar unuversitar, doctor
Alexandru Pereteatcu, magistru n informatic



Redactor coordonator
Ion Spinei - confereniar unuversitar, doc

Tehnoredactare computerizat
Ion Stngu




Descrierea CIP a Camerei Naionale a Crii
Pereteatcu, Sergiu
Structuri de date (n baza C++): Suport de curs / Sergiu Pereteatcu, Alexandru Pereteatcu;
Inst. de Formare Continu, Catedra Tehnologii Informaionale. Ch.: Inst. de Formare Continu,
2012. 135 p.
Bibliogr.: p. 134 (15 tit.).
ISBN 978-9975-4404-3-1.
004.6:519.1/6(075.8)
P52
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
3

CUPRINS

1. INTRODUCERE N STRUCTURI DE DATE..................................................................4
1.1. Noiuni generale .............................................................................................................4
1.2. Clase de baz..................................................................................................................5
2. TABELE................................................................................................................................10
2.1. Noiune de tabel............................................................................................................10
2.2. Tabele neordonate ........................................................................................................12
2.3. Tabele neordonate structurate arborescent.....................................................................17
2.4. Tabele ordonate............................................................................................................24
2.5. Tabele cu adresare direct.............................................................................................29
2.6. Tabele de repartizare (repartizarea aleatorie).................................................................29
3. TEHNICI DE SORTARE...................................................................................................40
3.1. Noiuni generale ...........................................................................................................40
3.2. Clase pentru exemple de sortare....................................................................................41
3.3. Sortarea prin interschimbare .........................................................................................44
3.4. Sortarea rapid..............................................................................................................45
3.5. Sortarea prin inserie.....................................................................................................59
3.6. Sortarea prin selecie.....................................................................................................66
3.7. Sortarea arborescent (piramidal, heapsort).................................................................66
3.8. Comparaii practice ai diferiilor algoritmi de sortare....................................................72
4. STRUCTURI DINAMICE DE DATE................................................................................73
4.1. Noiune de structura dinamic de date...........................................................................73
4.2. Arbori binari.................................................................................................................74
4.3. Liste .............................................................................................................................85
4.4. Stive .............................................................................................................................95
4.5. Cozi............................................................................................................................ 118
5. MATRICE ........................................................................................................................... 129
5.1. Noiune de matrice...................................................................................................... 129
5.2. Structura intern de memorie vector......................................................................... 130
5.3. Reprezentarea matricelor n memoria operativ .......................................................... 130
5.4. Reprezentarea matricelor pe linii ............................................................................. 131
5.5. Reprezentarea matricelor pe coloane ....................................................................... 140
5.6. Vectori definitori ........................................................................................................ 147
5.7. Vectori Iliffe............................................................................................................... 153
6. ACTIVITI........................................................................................................................ 161
I Declararea claselor de baz.................................................................................... 161
II Lucrul cu tabele.................................................................................................... 162
III Sortri................................................................................................................. 162
IV Structuri dinamice de date................................................................................... 163
V Matrice ................................................................................................................ 165
BIBLIOGRAFIE........................................................................................................................ 166

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
4

Program = Algoritm + Structuri de date
Niklaus Wirth, 1976
1. INTRODUCERE N STRUCTURI DE DATE
1.1. Noiuni generale

Definiia:
Prin structura de date abstract (SDA), sau pur i simplu structura de date
(SD), vom nelege o totalitate de reguli i restricii ce reflect legturile
existente ntre prile separate de date i prin care prile acestea se unesc
ntr-un singur tot.
Cuvntul abstract n definiia structurii de date subliniaz c structura de date se examineaz fr
cercetarea modului de reprezentare a ei n memoria calculatorului.
Structura nimic nu ne spune despre prile separate de date (mai corect despre coninutul lor).
Coninutul poate fi format n procesul de lucru. Drept vorbind, structura poate s cear ca aceste
prile componente s fie n concordan cu structura. Totui orice informaii ce se conin n
elementele de date nici cum nu depind de nsi structura.
Termenul utilizat element nseamn o parte de structur de date abstract. Elementul poate fi o
valoare de un tip simplu. El poate fi i o alt structur de date, sau o referin la alte structuri de
date, astfel s creeaz structuri de date ierarhice sau secvene de structuri de date.
Vom diviza structuri de date n statice i dinamice.
Definiia:
Exemplu: Matrice cu dimensiunile fixe, Tabeel cu numrul de nregistrri tabelare fix, Vectori cu
numrul de elemente fix.
Definiia:
Prin structura de date dinamic vom nelege aa SD, la care n procesul de
lucru se schimb att informaii ce se conin n elemente de date, ct i
numrul de elemente (componena cantitativ).
Exemplu: Liste nlnuite de diferite tipuri, stive, cozi, arbori binari.
Prin structura de date static vom nelege aa SD, la care n procesul de lucru
se schimb numai informaiile ce se conin n elemente de date i nu se schimb
cantitatea acestor elemente.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
5
1.2. Clase de baz
La demonstrarea metodelor de organizare a structurilor de date vom utiliza clase generice. Orice
astfel de metod va fi realizat printr-o clas generic parametrizat cu o alt clas-parametru ce
reprezint un element al structurii de date respective. n calitate de argumentul la instaniera unei
clase generice vom folosi o clas concret derivat de la clasa abstract elem.
Clasa abstract elem nu va putea fi instaniat. Ea doar descrie cele funcii virtuale pure care
neaprat trebuie redefinite n orice clasa derivat concret, care va fi folosit ulterior pentru
reprezentarea elementelor la construirea structurilor de date. Clasa abstract mai conine
suprancrcrile operatorilor de comparaie bzndu-le pe funcia virtual pur cmp().
Declararea clasei abstracte elem va arta astfel:
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <iostream.h>
#include <math.h>
//
// a b s t r a c t c l a s s "e l e m"
//
class elem
{
public:
virtual int fscanf_el(FILE *f)=0;

virtual void show(const char* opening=NULL,
const char* ending=NULL)=0;

virtual int free() = 0;

virtual int cmp(elem& e2) = 0;

int operator > (elem& e2)
{
return cmp(e2)>0;
}

int operator >= (elem& e2)
{
return cmp(e2)>=0;
}

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
6
int operator < (elem& e2)
{
return cmp(e2)<0;
}

int operator <= (elem& e2)
{
return cmp(e2)<=0;
}

int operator == (elem& e2)
{
return cmp(e2)==0;
}

int operator != (elem& e2)
{
return cmp(e2)!=0;
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};
Concretizm clasa abstract elem cu clasa usual_elem, care mai departe vom utiliza la
demonstrarea organizrii structurilor de date de diferite tipuri. Obiectele clasei usual_elem
(element obinuit, de utilizare curent) vor pstra informaii uzuale despre un om (fie un lucrtor,
sau un student). Aceste informaii vor fi numele (cmpul name), anul de natere (cmpul year) i
salariu (cmpul salary). Declararea clasei usual_elem va arta astfel:
//
// c l a s s "u s u a l _ e l e m"
//
class usual_elem : public elem
{
protected:
char name[16];
int year;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
7
double salary;

public:
usual_elem()
{
name[0]='\0';
year=0;
salary=0.0;
}

usual_elem(char* init_name, int init_year, double init_salary)
{
strcpy(name, init_name);
year=init_year;
salary=init_salary;
}

virtual int fscanf_el(FILE *f)
{
return fscanf(f, "%s %d %lf", name, &year, &salary);
}

virtual void show(const char* opening=NULL,
const char* ending=NULL)
{
if(!opening)
opening="";
if(!ending)
ending="\n";
cout << opening;
if(name[0]) // sau mai bine if(free()==0), sau if(!free())
cout << name << ", " << year << ", " << salary;
cout << ending;
}

virtual int free()
{
return name[0]=='\0';
}

virtual int cmp(elem& e2)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
8
return strcmp(this->name, ((usual_elem&)e2).name);
}
};
Crem un fiier text cu numele, de exemplu, stud.txt, din care mai departe vom introduce
informaii pentru ncrcarea diferitelor structuri de date. Coninutul fiierului stud.txt va arta
astfel:
Green 1987 350.00
Red 1980 450.00
Blue 1981 500.00
Gray 1968 900.00
Orange 1984 550.00
White 1980 600.00
Cyan 1975 800.00
Yellow 1988 300.00
Magenta 1983 600.00
Black 1981 500.00
In fine, declarm clasa abstract SD, care va servi n viitor ca clasa de baz pentru declararea
diferitelor claselor de reprezentare a structurilor de date.
//
// a b s t r a c t c l a s s "S D"
//
class SD
{
protected:
FILE* pf;
long ncomp;

public:

SD()
{
pf=NULL;
ncomp=0;
}

SD(char* file_name)
{
if(!(pf=fopen(file_name, "rt")))
{
char *mes = new char[5+strlen(file_name)+12+1];
error(strcat(strcat(strcpy(mes,"File "),file_name),
" not found!\n"));
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
9
}
ncomp=0;
}

~SD()
{
if(pf)
fclose(pf);
}

virtual void show(const char* opening=NULL,
const char* ending=NULL)=0;

long get_ncomp()
{
return ncomp;
}

void reset_ncomp()
{
ncomp=0;
}

protected:

void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
10
2. TABELE
2.1. Noiune de tabel

Tabel este un set de elemente, fiecare din care are un indicator special numit
cheie cu proprietatea c elementele se adaug n tabel i se caut n tabel dup
cheie. Pe lng cheie, elementul din tabel (se mai numete nc nregistrare
tabelar) de obicei conine date, purttoare de careva informaii.
Exemplul 1.
Tabelul ptratelor numerelor naturale
Cheia
(valoarea
argumentului)
Datele
(valoarea
funciei)
0 0
1 1
2 4
3 9
4 16
5 25
6 36
Cheia n acest tabel este valoarea argumentului, dar valoarea funciei reprezint informaii.
Exemplul 2.
Tabelul de trecere din baza 10 n bazele 2, 8 i 16
Datele Cheia
(valoarea
numrului
n baza 10)
Valoarea
numrului
n baza 2
Valoarea
numrului
n baza 8
Valoarea
numrului
n baza 16
0 0000 00 0
1 0001 01 1
2 0010 02 2
3 0011 03 3
4 0100 04 4
5 0101 05 5
6 0110 06 6
7 0111 07 7
8 1000 10 8
9 1001 11 9
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
11
10 1010 12 A
11 1011 13 B
12 1100 14 C
13 1101 15 D
14 1110 16 E
15 1111 17 F
Cheia n acest tabel este valoarea numrului n baza 10, iar datele poart informaii despre valoarea
numrului n bazele 2, 8 i 16.
Exemplul 3:
Tabelul de nume simbolice
Datele Cheia
Symbol name Type Value
!!DATE Text 09/15/12
??FILENAME Text sumvectr
??TIME Text 11:28:21
A10 Near COD:004E
B10 Near COD:00AD
BINSTR Near COD:01A0
C10 Near COD:0105
N Word DATE:0067
NOMBIN Word DATE:02CF
S10 Near COD:0181
Z Byte DATE:0061
ZMAX Byte DATE:005F
ZT Word DATE01F9
Compilatoare i interpretatoare folosesc tabele de nume. Cheia n astfel de tabel este identificatorul,
dar datele poart informaii despre tipul variabilei, adresa de alocare n memoria calculatorului, etc.
n memoria calculatorului tabele de obicei sunt prezentate sub form de vectori de nregistrri, dar
uneori se folosesc i liste, sau combinri dintre vectori i liste.
Referitor la tabele o problem cea mai important este problema de cutare.

Problema cutrii const n aflarea dup cheia dat adresei (locului) de pstrare
a nregistrrii tabelare cu aa cheie, sau ajungerea la concluzie c o aa
nregistrare nu este n tabel.
Aceast problem se rezolv diferit, n dependen de metoda organizrii a tabelului.
Caracteristica principal a metodei de organizare a tabelului este timpul mediu de cutare a unei
nregistrri tabelare. Acest timp este proporional lungimii medii de cutare.

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
12
Lungimea medie de cutare este numrul mediu de nregistrri parcurse pentru
cutarea nregistrrii necesare.

2.2. Tabele neordonate
n tabele neordonate nregistrrile sunt aranjate una dup alta (pe msura venirii) fr lipsuri. Astfel
de tabele uor se alctuiesc. O nou nregistrare pur i simplu se adaug la sfritul tabelului dup
nregistrarea precedent.
Pentru cutare n aa tabele se aplic parcurgerea secvenial, prin care nregistrrile se parcurg la
rnd una dup alta, ncepnd cu prima.
Lungimea medie de cutare prin parcurgerea secvenial a tabelului cu n nregistrri tabelare se
calculeaz prin formula:

=
=
n
i
i
ip D
1
(2.1)
unde i - este numrul de ordine a nregistrrii, iar p
i
probabilitatea c nregistrarea necesar are
numr i.
Dac nregistrarea cutat se afl n orice loc al tabelului cu probabilitatea egal, atunci
n
p
i
1
= , i
lungimea medie de cutare va fi egal:
) ( ( )
2 2
1 1
1
1
n n n
n n
i
D
n
i
~
+
= =

=
(2.2)
Tabelele neordonate nu sunt economice dup timpul de cutare, de aceea ele nu se folosesc n
calitate de tabele constante n translatoare (compilatoare sau interpretatoare). ns adugarea unei
nregistrri noi n aa tabele necesit timpul minim, deaceea tabelele neordonate uneori se folosesc
n translatoare ca tabele temporare, ncrcndu-se n timpul translaiei. La nceputul vectorului de
reprezentare a acestui tabel, deseori se pstreaz numrul maximal posibil de nregistrri i numrul
primei linii libere din tabel.
Pentru a demonstra lucrul cu tabele neordonate declarm clasa table, ca o clas generic ce
depinde de un tip parametrizat reprezentnd o nregistrare tabelar.
//
// c l a s s "t a b l e"
//
const NMAX=200;
//
template <class el> class table : public SD
{
protected:
int n; // numrul de nregistrri tabelare
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
13
el t[NMAX]; // vector de nregistrri tabelare

public:
table()
{
n=0;
}

table(char* file_name) :
SD(file_name)
{
int repeated;
n=0;
while(!feof(pf))
if(t[n].fscanf_el(pf)>0)
{
if ( (repeated=search(t[n]))>=0 )
{
char message[60];
char repeated_str[10];
message[0]='\0';
strcat(message,
"Key coincides with the key in the position: ");
strcat(message, itoa(repeated+1, repeated_str, 10));
strcat(message, "!\n");
error(message);
}
n++;
}
fclose(pf) , pf=NULL;
}

virtual void show(const char* opening =NULL,
const char* ending=NULL)
{
clrscr();
cout << opening;
if(!opening)
opening="";
if(!ending)
ending="\n";
for(int i=0; i<n; i++)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
14
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
cout << (i+1) << ". "; t[i].show();
}
cout << ending;
cout << "End of Table. Press any key ...\n";
getch();
}

int search(el e)
{
int position = -1;
for(int i=0; (position==-1) && i<n ; i++)
if(ncomp++, e==this->t[i])
position=i;
return position;
}

int get_n()
{
return n;
}
};
n funcia main() demonstrm utilizarea clasei table pentru tipul concret usual_elem.
void main()
{
clrscr();

table<usual_elem> gr("stud.txt");
gr.show("Group:\n","");

char ch='n';
char surname[21];
while(ch!='y')
{
cout << "Enter a name to search: ";
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
15
cin >> surname;
usual_elem e(surname, 2000, 0.0);
gr.reset_ncomp();
int pos=gr.search(e);
if(pos<0)
cout << "No table! "
<< "The number of comparisons: " << gr.get_ncomp() << "\n";
else
cout << "There are in the position " << (pos+1)
<< ". The number of comparisons: " << gr.get_ncomp()<<"\n";
cout << "Done ? (y/n) ";
ch = getch();
cout << endl;
}
}
n funcia main() se creaz un tabel neordonat ncrcat cu nregistrri din fiierul stud.txt".
Apoi dup afisarea tabelului pe ecran, utilizatorului i se d posibilitatea de a cuta n dialog
nregistrrile dup cheia. O variant de afiare poate arta astfel:
Group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of Table. Press any key ...
Enter a name to search: White
There are in the position 6. The number of comparisons: 6
Done ? (y/n)
Enter a name to search: Green
There are in the position 1. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 10. The number of comparisons: 10
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 10
Done ? (y/n)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
16
n urmtorul exemplu al funciei main() se calculeaz lungimea medie de cutare pentru un tabel
simplu neordonat creat n baza fiierului stud.txt.
void main()
{
clrscr();
table<usual_elem> gr("Stud.txt");
gr.show("Group:\n","");

usual_elem sample;
long NCOMP=0;

FILE* pf=fopen("Stud.txt", "rt");
while(!feof(pf))
if(sample.fscanf_el(pf)>0)
{
gr.reset_ncomp();
if(gr.search(sample)>=0)
NCOMP+=gr.get_ncomp();
}
fclose(pf);
cout << "N=" << gr.get_n() << ", NCOMP=" << NCOMP
<< ", ALS=" << ((double)NCOMP/gr.get_n());
getch();
}
De data aceasta afiarea va arta astfel:
Group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of Table. Press any key ...
N=10, NCOMP=55, ALS=5.5
Dup cum se vede lungimea medie de cutare calculat 5.5 coincide cu cea teoretic
(n+1)/2=11/2=5.5.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
17
2.3. Tabele neordonate structurate arborescent
Cteodat n calitate de tabele temporare se aplic tabele neordonate structurate arborescent,
organizate n form de arbore binar. La fiecare nregistrare tabelar n aa tabele se adaug cte doi
pointeri: un pointer spre nregistrarea tabelar cu valoarea mai mic a cheii, iar al doilea pointer
spre nregistrrea tabelar cu valoarea mai mare a cheii.
O nou nregistrare se adaug n tabel la rnd, ca i n tabele neordonate simple. Dup adugarea n
tabel a noii nregistrri valoarea cheii se compar cu valoarea cheii a primei nregistrri a tabelului.
Dup rezultatul comparrii cu ajutorul pointerilor se afl adresa pstrrii urmtoarei nregistrri, cu
cheia crei trebuie de comparat valoarea cheii nregistrrii noi. Acest proces are loc pn atunci,
pn cnd nu va fi gsit nregistrarea tabelar cu pointerul vid n direcia necesar de cutare. n
acest pointer se nscrie adresa pstrrii noii nregistrri tabelare.
De exemplu, n figura 2.1 este artat tabelul neordonat structurat arborescent creat pe baza fiierului
Stud.txt.
Pentru a demonstra lucrul cu tabele neordonate structurate arborescent mai nti de toate crem n
baza clasei usual_elem clasa tree_like la care mai adaugm dou cmpuri cu caracter de
pointeri.
//
// c l a s s "t r e e l i k e" e l e m e n t s
//
class tree_like: public usual_elem
{
protected:
int less;
int greater;

public:
tree_like()
{
less=greater=-1;
}

tree_like(char* init_name, int init_year, double init_salary):
usual_elem(init_name, init_year, init_salary)
{
less=greater=-1;
}

int get_less()
{
return less;
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
18

int set_less(int new_less)
{
return less=new_less;
}

int get_greater()
Fig. 2.1 Tabelul neordonat structurat arborescent
00
01
Red 1980, 450
4 5
02 Blue 1981, 500
9 3
03
04 Orange
05
1984, 550
8 -1
White 1980, 600
-1 7
06 Cyan 1975, 800
-1 -1
07 Yellow 1988, 300
-1 -1
08
09
Magenta 1983, 600
-1 -1
Black 1981, 500
-1 -1
Gray 1968, 900
6 -1
Green 1987, 350
2 1
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
19
{
return greater;
}

int set_greater(int new_greater)
{
return greater=new_greater;
}

virtual void tree_show(const char* opening =NULL,
const char* ending=NULL)
{
if(!opening)
opening="";
if(!ending)
ending="\n";
cout << opening;
usual_elem::show("", "");
cout << " [" << less << ", " << greater << "]";
cout << ending;
}

virtual int fscanf_el(FILE *pf)
{
less=greater=-1;
return usual_elem::fscanf_el(pf);
}
};
Clasa tree_table declarm ca clasa generic derivat de la clasa generic cunoscut table.
//
// c l a s s "t r e e t a b l e"
//
template <class el> class tree_table: public table<el>
{
public:
tree_table()
{
}

tree_table(char* file_name):
table<el>(file_name)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
20
for(int i=1; i<n; i++)
{
int forward=1;
int j=0;
while(forward)
if(t[i]<t[j])
if(t[j].get_less()==-1)
t[j].set_less(i), forward=0;
else
j=t[j].get_less();
else
if(t[i]>t[j])
if(t[j].get_greater()==-1)
t[j].set_greater(i), forward=0;
else
j=t[j].get_greater();
}
}

virtual void tree_show(const char* opening =NULL,
const char* ending=NULL)
{
clrscr();
if(!opening)
opening="";
if(!ending)
ending="\n";
cout << opening;
for(int i=0; i<n; i++)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
cout << (i+1) << ". "; t[i].tree_show();
}
cout << ending;
cout << "End of Table. Press any key ...\n";
getch();
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
21
}

int search(el e)
{
int position = -1;
int forward=1;
int i=0;
int cmp_result;

while(forward)
if( ncomp++, (cmp_result=e.cmp(t[i]))==0 )
position=i, forward=0;
else
{
if(cmp_result<0)
i=t[i].get_less();
else
i=t[i].get_greater();
if(i==-1)
forward=0;
}
return position;
}
};

Cutarea n tabelul arborescent dup cheia dat are loc asemntor cu cutarea locului, n care se
nscrie adresa de pstrare.
Lungimea medie de cutare n tabelul arborescent depinde de ordinea nscrierii nregistrrilor la
ncrcarea tabelului. n cel mai ru caz, cnd nregistrrile veneau n ordine cresctoare (sau
descresctoare) a cheilor, arborele va avea numai o ramur, i lungimea medie de cutare rmne
egal cu n/2, ca i n cazul tabelelor neordonate. n cel mai bun caz, cnd ordinea nscrierii
nregistrrilor este aa, c se primete un arbore binar simetric, lungimea cutrii se micoreaz
pn la D
2
=[log
2
n+2].
n funcia main() demonstrm crearea i utilizarea tabelelor nerdonate structurate arborescent.
void main()
{
clrscr();

tree_table<tree_like> tree_gr("stud.txt");
tree_gr.show("Group:\n", "");
tree_gr.tree_show("Group:\n", "");
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
22

char ch='n';
char surname[21];
while(ch!='y')
{
cout << "Enter a name to search: ";
cin >> surname;
tree_like e(surname, 2000, 0.0);
tree_gr.reset_ncomp();
int pos=tree_gr.search(e);
if(pos<0)
cout << "No table! " << "The number of comparisons: "
<< tree_gr.get_ncomp() << "\n";
else
cout << "There are in the position " << (pos+1)
<< ". The number of comparisons: " << tree_gr.get_ncomp()
<< "\n";
cout << "Done ? (y/n) ";
ch = getch();
cout << endl;
}
}
O variant de afiare poate arta astfel:
Group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of Table. Press any key ...
S-a afiat tabelul simplu neordonat. Dup ce vom apsa orice tast, ecranul va fi ters i va aprea
afiarea urmtoarea:
Group:
1. Green, 1987, 350 [2, 1]
2. Red, 1980, 450 [4, 5]
3. Blue, 1981, 500 [9, 3]
4. Gray, 1968, 900 [6, -1]
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
23
5. Orange, 1984, 550 [8, -1]
6. White, 1980, 600 [-1, 7]
7. Cyan, 1975, 800 [-1, -1]
8. Yellow, 1988, 300 [-1, -1]
9. Magenta, 1983, 600 [-1, -1]
10. Black, 1981, 500 [-1, -1]
End of Table. Press any key ...
Enter a name to search: White
There are in the position 6. The number of comparisons: 3
Done ? (y/n)
Enter a name to search: Green
There are in the position 1. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 10. The number of comparisons: 3
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 3
Done ? (y/n)
Dac vrem s calculm lungimea medie de cutare pentru acest tabel, scriem funcia main() astfel:
void main()
{
clrscr();
tree_table<tree_like> gr("stud.txt");
gr.tree_show("Group:\n","");
tree_like sample;
long NCOMP=0;

FILE* pf=fopen("stud.txt", "rt");
while(!feof(pf))
if(sample.fscanf_el(pf)>0)
{
gr.reset_ncomp();
if(gr.search(sample)>=0)
NCOMP+=gr.get_ncomp();
}
fclose(pf);
cout << "N=" << gr.get_n() << ", NCOMP=" << NCOMP;
cout << ", ALS=" << ((double)NCOMP/gr.get_n());
cout << ", MAX=" << (gr.get_n()/2.0);
cout << ", MIN=" << (log((double)gr.get_n())/log(2.0)+2.0);
getch();
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
24
}
Afiarea va arta:
Group:
1. Green, 1987, 350 [2, 1]
2. Red, 1980, 450 [4, 5]
3. Blue, 1981, 500 [9, 3]
4. Gray, 1968, 900 [6, -1]
5. Orange, 1984, 550 [8, -1]
6. White, 1980, 600 [-1, 7]
7. Cyan, 1975, 800 [-1, -1]
8. Yellow, 1988, 300 [-1, -1]
9. Magenta, 1983, 600 [-1, -1]
10. Black, 1981, 500 [-1, -1]
End of Table. Press any key ...
N=10, NCOMP=29, ALS=2.9, MAX=5, MIN=5.32193
Analiza rezultatelor rmne ca exerciiu.
Neajunsul tabelelor neordonate structurate arborescent cheltuieli mai mari de memorie (pentru
pstrarea pointerilor) i algoritmii de ncrcare tabelului i cutare nregistrrilor puin mai
complicai n comparaie cu cei pentru tabelele neordonate simple.

2.4. Tabele ordonate

Tabele pot fi ordonate cresctor dup codul numeric al cheii, sau dup frecvena apelurilor la
nregistrri. n primul caz pentru cutarea nregistrrii de obicei se folosete cutarea binar, dar n
al doilea parcurgerea secvenial.
Cutarea binar const n mprirea tabelului n dou pri aproape egale i constatarea n care din
cele dou pri se gsete valoarea cheii cutat. Partea ce conine cheia se supune de fiecare dat
mpririi secveniale. Fiindc tabelul este aranjat cresctor dup cheie, pentru a gsi n care parte se
afl valoarea cheii cutate, valoarea cheii n punctul mpririi se compar cu valoarea cheii cutate.
//
// c l a s s "s o r t e d t a b l e"
//
template <class el> class sorted_table: public table<el>
{
public:

sorted_table()
{
}

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
25
sorted_table(char* file_name)
{
el tmp;
pf=fopen(file_name, "rt");
n=0;
while(!feof(pf))
if(tmp.fscanf_el(pf)>0)
{
int i;
for(i=n-1; i>=0 && (tmp<t[i]); i--)
t[i+1]=t[i];
if(n>0 && i>=0 && tmp==t[i])
{
char message[60];
char repeated_str[10];
message[0]='\0';
strcat(message,
"Key coincides with the key in the position: ");
strcat(message, itoa(i+1, repeated_str, 10));
strcat(message, "!\n");
error(message);
}
t[i+1]=tmp, n++;
}
fclose(pf) , pf=NULL;
}

int search(el e)
{
int a=0, b=n-1;
int result;

while(a<b)
{
int i=(a+b)/2;
if(ncomp++, (result=e.cmp(t[i]))>0)
a=i+1;
else
if(result<0)
b=i;
else
a=b=i;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
26
}
return (ncomp++, e==t[a])? a : -1;
}
};
n funcia main() demonstrm utilizarea tabelelor sortate dup cheie.
void main()
{
clrscr();

sorted_table<usual_elem> sorted_gr("stud.txt");
sorted_gr.show("Group:\n","");

char ch='n';
char surname[21];
while(ch!='y')
{
cout << "Enter a name to search: ";
cin >> surname;
usual_elem e(surname, 2000, 0.0);
int pos=sorted_gr.search(e);
int pos=sorted_gr.search(e);
if(pos<0)
cout << "No table! " << "The number of comparisons: "
<< sorted_gr.get_ncomp() << "\n";
else
cout << "There are in the position " << (pos+1)
<< ". The number of comparisons: " << sorted_gr.get_ncomp()
<< "\n";
cout << "Done ? (y/n) ";
ch = getch();
cout << endl;
}
}
Afiarea va arta astfel:

Group:
1. Black, 1981, 500
2. Blue, 1981, 500
3. Cyan, 1975, 800
4. Gray, 1968, 900
5. Green, 1987, 350
6. Magenta, 1983, 600
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
27
7. Orange, 1984, 550
8. Red, 1980, 450
9. White, 1980, 600
10. Yellow, 1988, 300
End of Table. Press any key ...
Enter a name to search: White
There are in the position 9. The number of comparisons: 4
Done ? (y/n)
Enter a name to search: Green
There are in the position 5. The number of comparisons: 2
Done ? (y/n)
Enter a name to search: Black
There are in the position 1. The number of comparisons: 5
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 4
Done ? (y/n)
Lungimea cutrii binare se obine dup formula
| | 2 log
2 2
+ = n D (2.3),
ce pentru n destul de mare aproape c este egal cu limita de jos teoretic pentru metode de cutare,
bazate numai pe compararea cheilor. Teoretic limita de jos este egal cu log
2
(n+1). Cutarea binar
mult mai efectiv dect parcurgerea secvenial. Pentru n=1000, D
1
=500, iar D
2
=11.
Pentru a calcula lungimea medie practic de cutare n tabelul ordonat creat n baza fiierului
"stud.txt" modificm funcia main().
void main()
{
clrscr();
sorted_table<usual_elem> gr("stud.txt");
gr.show("Group:\n","");

usual_elem sample;
long NCOMP=0;

FILE* pf=fopen("Stud.txt", "rt");
while(!feof(pf))
if(sample.fscanf_el(pf)>0)
{
gr.reset_ncomp();
if(gr.search(sample)>=0)
NCOMP+=gr.get_ncomp();
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
28
fclose(pf);
cout << "N=" << gr.get_n() << ", NCOMP=" << NCOMP;
cout << ", ALS=" << ((double)NCOMP/gr.get_n());
cout << ", ALS_TEOR=" << (log((double)gr.get_n())/log(2.0)+2.0);
getch();
}
Afiarea va arta astfel:
Group:
1. Black, 1981, 500
2. Blue, 1981, 500
3. Cyan, 1975, 800
4. Gray, 1968, 900
5. Green, 1987, 350
6. Magenta, 1983, 600
7. Orange, 1984, 550
8. Red, 1980, 450
9. White, 1980, 600
10. Yellow, 1988, 300
End of Table. Press any key ...
N=10, NCOMP=38, ALS=3.8, ALS_TEOR=5.32193
Analiza rezultatelor rmne ca exerciiu.
Lungimea medie a parcurgerii secveniale n tabel, ordonat dup frecven apelrilor la nregistrri,
esenial depinde de repartizarea frecvenilor apelurilor i se obine dup formula general

=
=
n
i
i
p i D
1
. Dac un numr relativ mic de nregistrri se cut foarte des, atunci lungimea medie
de cutare poate fi mult mai mic dect la cutare binar. Aceasta uneori se folosete la crearea
tabelelor ale translatorului, de exemplu tabelul de cuvinte cheie ale limbajului de intrare.
Ordonarea tabelelor cere adugtor cheltuieli de timp al calculatorului. Deaceea tabelele ordonate se
folosesc mai mult ca tabele constante ale translatorului. Dar uneori se ordoneaz i tabele
temporare, cu toate c ordonarea aceasta are anumite greuti. Problema const n aceea c tabelele
temporare ce se alctuiesc n timpul translaiei n multe cazuri tot aici se folosesc i pentru cutare.
Deja completate astfel de tabele au nevoie de verificare: oare nu este inclus nregistrarea dat n
tabel la etapa precedent de lucru al translatorului. De aceea ordonarea tabelelor temporare este
necesar de fcut odat cu ncrcarea lor.
Pentru reducerea cheltuielilor timpului calculatorului la ordonarea tabelelor temporare uneori se
folosete metoda mpririi, la care tabelul se mparte n compartimente, corespunztoare
intervalelor diferite ale valorilor cheii. Compartimentele sunt ordonate, iar nuntru
compartimentelor nregistrrile nu se ordoneaz. Pentru cutarea nregistrrilor se folosete metoda
combinat. De exemplu, compartimentul se gsete prin cutare binar, iar nuntru
compartimentului se folosete parcurgerea secvenial.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
29

2.5. Tabele cu adresare direct
Fie n tabel de m nregistrri, toate nregistrrile au diferite valori ale cheilor k
0
, k
1
, k
2
,..., k
m-1
, i
tabelul este reflectat n vectorul T[0], T[1], , T[n-1], unde mn. Dac este definit funcia f(k),
astfel, ca pentru orice k
i
, i=0, ..., m-1, f(k
i
) are o valoare ntreag ntre 0 i n-1, unde f(k
i
)f(k
j
), ij
atunci nregistrarea tabelar cu cheia K se reflect bireciproc n elementul T[f(K)].
Funcia f(K) se numete funcie de repartizare (dispersare sau Hash funcie). Aceast funcie asigur
calcularea pentru fiecare nregistrare tabelar a numrului corespunztor al elementului vectorului
T. Accesul la nregistrare dup cheia K se efectueaz n acest caz nemijlocit prin calcularea valorii
f(K). Tabelele, pentru care exist i este cunoscut (descris) funcia de repartizare, se numesc
tabele cu adresare direct. Lungimea medie de cutare n astfel de tabele este minimal i egal
D
3
=1.
Alegerea funciei de repartizare, care asigur transformarea bireciproc a cheii nregistrrii n adresa
de pstrare, n caz general este o problem destul de complicat. Practic ea poate fi rezolvat numai
pentru tabelele constante cu setul de valori pentru cheii tiut dinainte. De exemplu: tabelul de
recodificare, tabelul de simboluri ale limbajului de intrare al translatorului.
2.6. Tabele de repartizare (repartizarea aleatorie)
Noiuni generale
Deoarece, practic transformarea bireciproc a cheii n adresa pstrrii nregistrrii, n mod general,
nu poate fi ndeplinit, atunci suntem nevoii s ne refuzm de cerin de reflectare birereciproc.
Aceasta aduce la suprapunerea nregistrrilor sau, altfel zis, la coliziuni. Ca astfel de coliziuni s fie
ct mai puine, funcia de repartizare se alege din condiia de reprezentare aleatorie i cu ct se
poate mai uniform de reflectarea cheilor n adresa de pstrare. Tabele construite dup acest
principiu sunt numite tabele de repartizare.
Repartizarea nu exclude pe deplin posibilitatea de suprapunere a nregistrrilor (coliziuni). De acea
se aplic diferite metode pentru nlturarea coliziunilor. Diferena variantelor de tabele de
repartizare este definit prin metoda folosit de nlturare a coliziunilor.
Tabele de repartizare cu examinarea liniar (adresare deschis)
n metoda de repartizare cu examinarea liniar la reprezentarea tabelelor n vector de lungime n se
folosete urmtorul algoritm al inserrii nregistrrii cu cheia dat K:
1. Calculm i=f(K). Trecem la punctul 2.
2. Dac poziia i este liber, atunci nscriem n aceasta poziie nregistrarea noua. n caz contrar
trecem la punctul 3.
3. Punem i=(i+1) mod n, i trecem la punctul 2:

> +
< + +
=
n i daca
n i daca i
i
1 , 0
1 , 1

La includerea unei noi nregistrri algoritmul rmne determinat pn atunci, cnd vectorul, n care
se reflect tabelul, conine mcar o poziie liber.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
30
Dac aceast condiie nu se ndeplinete este posibil ciclarea, mpotriva creia trebuie de luat
msuri speciale. De exemplu, se poate introduce un contor de poziii verificate, dac acest numr a
devenit mai mare ca n, atunci algoritmul trebuie s fie oprit.
La cutarea nregistrrii cu cheia dat K se folosete urmtorul algoritm:
1. Calculm i=f(K). Trecem la punctul 2
2. Dac poziia i este liber atunci n tabelul dat nu exist nregistrarea cu cheia K. Dac poziia
este ocupat i cheia coincide cu cheia K, atunci cutarea este reuit, n caz contrar trecem la
punctul 3.
3. Punem i=(i+1) mod n, i trecem la punctul 2:

> +
< + +
=
n i daca
n i daca i
i
1 , 0
1 , 1

La cutare algoritmul este determinat dac tabelul conine nregistrarea tabelar cu cheia K, sau
vectorul conine poziii libere. n cazul nendeplinirii acestor condiii trebuie de luat msuri
speciale. De exemplu, se poate introduce un contor de poziii verificate, dac acest numr a devenit
mai mare ca n, atunci algoritmul trebuie s fie oprit.
Declarm n baza clasei usual_elem clasa hashing_elem care va fi dotat cu o funcie de
repartizare.
//
// c l a s s "h a s h i n g _ e l e m"
//
class hashing_elem : public usual_elem
{
public:
hashing_elem()
{
}

hashing_elem(char* init_name, int init_year, double init_salary):
usual_elem(init_name, init_year, init_salary)
{
}

int hf(int n) // hashing function
{
return (name[0]-'A')%n;
}
};
n exemplul acesta valoarea funciei de dispersare este egal cu numrul de ordine al primei litere a
numelui n alfabet. Numrul de ordin se moduleaz dup mrimea vectorului de reprezentare.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
31
n baza clasei generice table declarm clasa hashing_table tot generic, care asigur lucrul cu
tabele de repartizare cu examinarea linear.
//
// c l a s s "h a s h i n g t a b l e"
//
template <class el> class hashing_table: public table<el>
{
protected:
int m;

public:
hashing_table(char* file_name, int n_init)
{
n=n_init, m=0;
el tmp;
int repeated;
pf=fopen(file_name, "rt");
m=0;
while(!feof(pf))
if(tmp.fscanf_el(pf)>0)
{
int i=tmp.hf(n);
repeated=-1;
while((repeated==-1) && !t[i].free())
{
if ( tmp==t[i] )
repeated=i;
else
i=(i+1)%n;
}
if ( repeated!=-1 )
{
char message[60];
char repeated_str[10];
message[0]='\0';
strcat(message,
"Key coincides with the key in the position: ");
strcat(message, itoa(repeated+1, repeated_str, 10));
strcat(message, "!\n");
error(message);
}
t[i]=tmp;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
32
m++;
}
fclose(pf), pf=NULL;
}

int search(el e)
{
int position=-1;
int i=e.hf(n);
while((position==-1) && !t[i].free())
if(ncomp++, e==t[i])
position=i;
else
i=(i+1)%n;
return position;
}

int get_m()
{
return m;
}
};
n funcia main()crem un tabel de repartizare cu examinarea linear, ncrcnd acest tabel din
fiierul text Stud.txt. Apoi afim acest tabel i cutm careva nregistrri dup cheie.
void main()
{
clrscr();
hashing_table<hashing_elem> hashing_gr("stud.txt", 15);
hashing_gr.show("Group:\n","");

char ch='n';
char surname[21];
while(ch!='y')
{
cout << "Enter a name to search: ";
cin >> surname;
hashing_elem e(surname, 2000, 0.0);
hashing_gr.reset_ncomp();
int pos=hashing_gr.search(e);
if(pos<0)
cout << "No table! " << "The number of comparisons: "
<< hashing_gr.get_ncomp() << "\n";
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
33
else
cout << "There are in the position " << (pos+1)
<< ". The number of comparisons: "
<< hashing_gr.get_ncomp() << "\n";
cout << "Done ? (y/n) ";
ch = getch();
cout << endl;
}
}

O variant de afiare poate arta astfel:
Group:
1.
2. Blue, 1981, 500
3. Red, 1980, 450
4. Cyan, 1975, 800
5. Black, 1981, 500
6.
7. Green, 1987, 350
8. Gray, 1968, 900
9. White, 1980, 600
10. Yellow, 1988, 300
11.
12.
13. Magenta, 1983, 600
14.
15. Orange, 1984, 550
End of Table. Press any key ...
Enter a name to search: White
There are in the position 9. The number of comparisons: 2
Done ? (y/n)
Enter a name to search: Green
There are in the position 7. The number of comparisons: 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 5. The number of comparisons: 4
Done ? (y/n)
Enter a name to search: Purple
No table! The number of comparisons: 0
Done ? (y/n)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
34
Pentru exemplul nostru tabelul va arta astfel:
Dup cum se vede poziiile 0, 5, 10, 11, 13 au rmas libere. Pe parcursul completrii tabelului n
poziiile 1, 2, 6, 7 au avut loc coliziuni. Drept vorbind, coliziunea n poziia 7 pentru nregistrarea
tabelar cu cheia White este secundar.
Cercetrile teoretice i experimente pentru cutarea la metoda de repartizare cu examinarea liniar
au artat, c pentru repartizarea aleatorie i uniform a nregistrrilor prin funcia de repartizare n
intervalul [0, n-1], lungimea medie de cutare nu depinde de lungimea tabelului, dar depinde numai
de factorul de ncrcare
n
m
= , unde m - lungimea tabelului, iar n lungimea vectorului de
reprezentare.
Aceast proprietate este foarte important, mai ales pentru tabele mari. Tabele deterministe, att
aranjate ct i cele nearanjate nu posed aceast proprietate. n tabele deterministe lungimea medie
de cutare crete cu creterea lungimii tabelului.
Formula aproximativ

2 2
2
) (

= D , pentru lungimea medie de cutare la metoda de repartizare


cu examinarea liniar ofer coinciden suficient cu experimentul pentru 0,85.
Formula este obinut n presupunerea repartizrii aleatorie i uniform a nregistrrilor pe poziiile
vectorului de reprezentare.
Urmtorul tabel demonstreaz dependena lungimii medie de cutare de factorul de ncrcare .
0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
D() 1.06 1.13 1.21 1.33 1.50 1.75 2.17 3.00 5.5
02 Red, 1980, 450
03 Cyan, 1975, 800
04 Black, 1981, 500
05
07 Gray, 1968, 900
08 White, 1980, 600
09 Yellow, 1988, 300
10
11
13
14 Orange, 1984, 550
00
06 Green, 1987, 350
12 Magenta,1983, 600

01 Blue, 1981, 500
Green
Red
Blue
Gray
Orange
White
Cyan
Yellow
Magenta
Black
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
35
Experimentele arat, c pentru =1 lungimea medie de cutare nu ntrece 20.
Dac distribuirea nregistrrilor pe poziiile vectorului de reflectare nu este uniform, atunci
numerele din tabel cresc n mediu cu 1.5 2 ori. Chiar i cu astfel de corecii repartizarea cu
examinarea linear are lungimea medie de cutare mai mic, ca alte metode. De exemplu, pentru
tabelul din 400 nregistrri i lungimea vectorului de reflectare 512, lungimea medie de cutare
pentru tabelul de repartizare cu examinarea liniar, lund n consideraie distribuirea neuniform a
nregistrrilor, nu depete 4.5 6. n aceleai condiii lungimea medie la cutarea binar este
egal cu 10, iar lungimea medie a parcurgerii secveniale 200.
Neajunsurile: la repartizarea cu examinarea liniar aproape 20% de memorie, rezervat pentru tabel,
nu se folosete.
Pentru a calcula lungimea medie de cutare pentru tabelul cu repartizare linear din exemplul
nostru, cercetm urmtoarea funcia main():
void main()
{
clrscr();
hashing_table<hashing_elem> hashing_gr("stud.txt", 15);
hashing_gr.show("Group:\n","");

hashing_elem sample;
long NCOMP=0;

FILE* pf=fopen("stud.txt", "rt");
while(!feof(pf))
if(sample.fscanf_el(pf)>0)
{
hashing_gr.reset_ncomp();
if(hashing_gr.search(sample)>=0)
NCOMP+=hashing_gr.get_ncomp();
}
fclose(pf);
cout << "M=" << hashing_gr.get_m() << ", NCOMP=" << NCOMP;
cout << ", ALS=" << ((double)NCOMP/hashing_gr.get_m());
double sigma = (double)hashing_gr.get_m()/hashing_gr.get_n();
cout << ", m/n=" << sigma;
cout << ", D(m/n)=" << ((2.-sigma)/(2.-2.*sigma));

getch();
}
Afiarea este urmtoarea:
Group:
1.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
36
2. Blue, 1981, 500
3. Red, 1980, 450
4. Cyan, 1975, 800
5. Black, 1981, 500
6.
7. Green, 1987, 350
8. Gray, 1968, 900
9. White, 1980, 600
10. Yellow, 1988, 300
11.
12.
13. Magenta, 1983, 600
14.
15. Orange, 1984, 550
End of Table. Press any key ...
M=10, NCOMP=16, ALS=1.6, m/n=0.666667, D(m/n)=2
Analiza rezultatelor rmne ca exerciiu.

Tabele de repartizare cu nlnuirea extern (repartizarea deschis, nlnuirea separat)
n metoda examinrii liniare nregistrrile ce produc coliziuni se includ n poziiile libere aceluiai
vector de reflectare. ns pentru aceste nregistrri se poate crea un tabel aparte. n tabelul adugtor
nregistrrile se poate lega n lan, ca n liste, pentru uurarea cutrii.

n tabele de repartizare cu nlnuirea extern lungimea medie de cutare pentru distribuirea
uniform i aleatorie a nregistrrilor se definete dup formula:
( )
n
m
n m D
2
1
1 ,

+ = , n lungimea vectorului de reflectare, m lungimea tabelului.




Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
37


Tabele de repartizare cu nlnuirea intern
ncrcarea poziiilor vectorului de reflectare const din dou etape:
- prima etap se aseamn cu repartizarea cu nlnuirea extern;
- a doua etap se ndeplinete dup terminarea crerii tabelului primar i celui secundar. Ea const
n mutarea lanurilor din tabelul secundarr n poziiile libere ale tabelului primar.
Astfel tabelele din exemplul precedent vor fi transformate n urmtorul tabel:
Prioritatea acestei metode n comparaie cu precedenta economie de memorie, dar neajunsul
flexibilitatea mic i algoritmul de ncrcare a tabelului este mai complicat.
Lungimea medie de cutare aici se definete dup aceiai formula:
n
m
n m D
2
1
1 ) , (

+ = , aceast
metod se folosete pentru tabele permanente, i pentru tabele temporare, care se ncrc la prima
etap, dar se folosesc la alta.
03
04
05
08
10
11
13

00
03

04

05

07

08

09

10

11
13

14

00|Gray, 1968,900

06

12

Primary
Table
Secondary
Table
Gray
06Green, 1987,35000
Green
14Orange,1984,550
Orange
07White, 1980,600
White
Cyan
02Red, 1980,45001
Red
09Yellow,1988,300
Yellow
12Magenta,1983,600

Magenta
01Cyan, 1975,800

02Black, 1981,500|
Black
01Blue, 1981,50002
Blue
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
38
Pentru tabele constante nregistrrile cel mai des folosite se nscriu primele, atunci accesrile
lanurilor interioare sunt rare, ce micoreaz lungimea medie de cutare. Este caracter, c la
folosirea lanurilor interioare toate poziiile ale vectorului de reflectare pot fi ncrcate (adic m=n),
dar lungimea medie de cutare pentru repartizarea uniform i aleatorie a nregistrrilor nu ntrece
1.5.
Tabelele de repartizare aleatorie se ncarc destul de simplu, nu necesit ordonarea nregistrrilor i
asigur o cutare rapid. Deaceea aceste tabele deseori se folosesc n practic.

Funcii de repartizare
Timpul calculrii funciei de repartizare f(k) intr n timpul mediu de cutare, deaceiea trebuie de
inut cont la alegerea algoritmului, realiznd funcia de repartizare.
O funcie bun de repartizare trebuie s asigure repartizarea uniform a nregistrrilor pe poziiile
vectorului de reflectare, fiindc distribuirea neuniform mrete timpul mediu de cutare. ns dac
calcularea valorii funciei de repartizare necesit ndeplinirea unui numr mare de operaii, aceasta
poate distruge toat economia n timpul cutrii. Deci, algoritmul calculrii funciei de repartizare
nu trebuie s fie complicat. S privim cteva metode de calculare a funciei de repartizare:
1. Una din metodele simple se bazeaz pe evidenierea unei pri din codul numeric al cheii. De
exemplu, fie dimensiunea maxim ateptat a tabelului de nume simbolice nu ntrece 256.
Atunci funcia de repartizare poate avea n calitate de valoare 8 bii, fiindc 256=2
8
. Se poate
pur i simplu de a evidenia primii 8 bii din codul binar al identificatorului sau de a lua careva 8
bii din mijlocul codului. Trebuie doar s asigurm cu ct este posibil o distribuire uniform a
nregistrrilor prin funcia f(k) n intervalul [0, 255].
05
08
10
11
13

04Gray, 1968,900
Gray
06Green, 1987,35004
Green
14Orange,1984,550
Orange
07White, 1980,600
White
09Yellow,1988,300
Yellow
12Magenta,1983,600

Magenta
00Black, 1981,500
Black
01Blue, 1981,50000
Blue
03Cyan, 1975,800
Cyan
02Red, 1980,45003
Red
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
39
2. Pentru asigurarea distribuirii uniforme se folosete sumarea codului identificatorului: prima
jumtate a codului se sumeaz cu a doua i din rezultat se evideniaz 8 bii. Se poate de
asemenea de mprit codul cheii n buci cte 8 bii, de sumat bucile i de pus suma pe
modulul 2
8
. Ultima modificare are careva probabilitate teoretic: la presupunerea a statisticei
independente de sumare a bucilor se primete repartizarea aproape de uniform.
3. O alt metod de calculare a funciei de repartizare este mprirea. Pentru vectorul de reflectare
de lungimea n, cheia se privete ca un numr ntreg i se mparte la mrimea n. Experimentele
arat, c restul de la mprire este repartizat aproape uniform n intervalul [0, n-1] i poate fi
folosit ca valoarea funciei de repartizare.
Verificarea experimental a metodelor descrise pentru tabelele de repartizare cu examinarea linear
a artat c evidenierea simpl a bucii din codul identificatorului mrete lungimea medie de
cutare n comparaie cu cea teoretic, definit dup formula:

2 2
2
) (

= D , n 4-5 sau i mai


multe ori. Lungimea medie de cutare pentru metoda de sumare a bucilor dup modulul 2
k

aproape de dou ori mai mare ca teoretic, dar pentru mprirea, lungimea medie de cutare practic
coincide cu teoretic pentru 8.85.

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
40
3. TEHNICI DE SORTARE
3.1. Noiuni generale

Sortarea este operaia de aranjare a elementelor unui vector dup valoarea
cheilor, pentru care este definit relaia de ordine.
Tradiional difer sortarea intern de sortarea extern. Sortarea intern prelucreaz datele pstrate n
memoria operativ a calculatorului, dar sortarea extern, opereaz cu datele care sunt pstrate n
fiiere.
n cazul sortrii interne se tinde la minimizarea numrului de comparaii i permutri ale
elementelor.
n cazul sortrii externe factorul hotrtor este numrul de operaii de intrare i ieire. n acest caz
numrul de comparaii trece pe planul doi, totui i el se i-a n consideraie.
Cazul sortrii interne
Presupunem, c datele supuse sortrii se pstreaz n memoria operativ ntr-un vector t. Fiecare
element t[i] al acetui vector este obiect al clasei parametrizate el n care sunt suprancrcai
operatorii de comparaie. Deci, sunt admise expresii:
t[i]<t[j], t[i]<=t[j], etc.
Presupunem, c funcia swap(i,j) schimb cu locurile elementele t[i] i t[j] a vectorului.
Funcia cmp(i,j) ntoarce un numr ntreg, care este egal cu
-1, dac t[i]<t[j];
0, dac t[i]==t[j];
1, dac t[i]>t[j].

Definiia 1. Perechea de indici (i,j), astfel ca i<j, dar t[i]>t[j] se numete
inversie.

Definiia 2. Vectorul t se numete sortat n ordine cresctoare, dac el nu
conine nici o inversie.

Definiia 3. Vectorul t se numete sortat n ordine descresctoare, dac pentru
orice i, j, i<j rezult c sau (i,j) este inversie, sau t[i]==t[j].
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
41

Definiia 4. Algoritmul sortrii se numete stabil, dac el niciodat nu schimb
ordinea relativ n vector la oricare 2 elemente cu cheile egale. Adic pentru
orice pereche i, j: i<j; t[i]=t[j], i>i', j>j' => i'<j'.
Stabilitatea poate fi o cerin definitoare, de exemplu cnd are loc sortarea dup o anumit cheie a
elementelor deja sortate dup o alt cheie.
Exemplu: lista studenilor care este deja sortat dup numele se cere de aranjat dup anul de studii,
dar pentru fiecare an de studii numele trebuie s rmn n ordinea alfabetic.
Despre complixitatea algoritmilor de sortare
La caracterizarea algoritmilor de sortare se folosete noiunea de mrime (de exemplu numrul de
comparaii de chei) care depinde de un numr natural n (de exemplu numrul de elemente) relativ la
o alt mrime cunoscut care tot depinde de numrul natural acesta. Se spune c mrimea k are
ordinul comparabil cu mrimea m, se noteaz k=O(m), se citete k are ordinul o de m, dac:
const
m
k
n
=

lim

Din formula aceasta rezult c mrimile n-1, n, 2n, n+3 au unul i acelai ordin O(n). Iar mrimea
n
2
are un ordin mai mare.
Algoritmul de sortare a n elementelor bazat pe compararea cheilor are complexitatea minim O(n)
sau mai mare.
Demonstrm prin inducia metematic:
Pentru k = 2 o comparaie. Presupunem c pentru k = n-1 trebuiesc n-2 comparaii. Se adaug nc
un element, deci mai trebuie de fcut cel puin nc o comparaie, obinem n-2+1 = n-1 comparaii.
Deci, complexitatea minim este O(n).
Teoretic este demonstrat [vezi 1] c complexitatea medie a oricrui algoritm de sortare care
opereaz cu comparaiile nu poate fi mai mic de O(nlog
2
n).
Algoritmii triviali de sortare bazai pe compararea cheilor au complexitatea att medie ct i cea
maxim O(n
2
).
Complexitatea medie a oricrui algoritm bun de sortare bazat pe compararea cheilor este O(nlog
2
n),
totodat complexitatea maxim a lui poate fi ori O(nlog
2
n) ori O(n
2
).
3.2. Clase pentru exemple de sortare
Vom folosi clasa abstract elem i clasa concretizat usual_elem.
Declarm clasa generic vector parametrizat cu clasa el.
//
// c l a s s "v e c t o r"
//
template <class el> class vector
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
42
{
protected:
int n; // numrul de elemente ale vectorului
el t[NMAX]; // elemente ale vectorului
long ncomp; // contorul comparaiilor

public:
vector()
{
n=0, ncomp=0;;
}

vector(char* file_name)
{
FILE* pf;
pf=fopen(file_name, "rt");
n=0, ncomp=0;
while(!feof(pf))
if(t[n].fscanf_el(pf)>0)
n++;
fclose(pf);
}

virtual void show(const char* opening, const char* ending)
{
clrscr();
cout << opening;
for(int i=0; i<n; i++)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
cout << (i+1) << ". "; t[i].show("", "\n");
}
cout << ending;
cout << "End of vector. Press any key ...\n";
getch();
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
43

int search(el e)
{
int position = -1;
for(int i=0; (position==-1) && i<n ; i++)
if(ncomp++, e==this->t[i])
position=i;
return position;
}

int get_n()
{
return n;
}

long get_ncomp()
{
return ncomp;
}

void reset_ncomp()
{
ncomp=0;
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}

void swap(int i, int j)
{
el tempor=t[i];
t[i]=t[j];
t[j]=tempor;
}
};

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
44
3.3. Sortarea prin interschimbare
Metoda de sortare prin interschimbare (engl. Exchange sort) const n parcurgerea elementelor ale
vectorului, n aa mod ca fiecare parcurgere micoreaz numrul de inversii, pn atunci cnd nu
rmne nici o inversie. Problema const n cutarea urmtoarei inversiei (i, j).
Schematic:
while (este_inversie (i, j))
swap(i, j);
Sortarea prin interschimbare const n modificri succesive de tip t[i]t[j], pn cnd
elementele vectorului nu vor deveni n ordine cresctoare.
Din aceast categorie fac parte metoda bulelor (bubblesort) unul din cei mai slabi algoritmi de
sortare i sortarea rapid (quicksort) unul din cei mai buni algoritmi de sortare.
Sortarea prin metoda bulelor
Metoda bulelor const n compararea t[i] cu t[i+1], dac ordinea este bun se compar t[i+1]
cu t[i+2], dac ordinea nu este bun se interschimb t[i] cu t[i+1] i apoi se compar t[i+1]
cu t[i+2]. Dup prima parcurgere a vectorului, pe ultima poziie ajunge elementul avnd valoarea
cea mai mare, dup a doua parcurgere ajunge urmtorul element pe penultima poziie, etc.
Algoritmul are complexitatea O(n
2
).

void bubble_sort()
{
BOOLEAN inversion;
do
{
inversion = FALSE;
for(int i=0; i<n-1; i++)
if(ncomp++, t[i]>t[i+1])
{
swap(i,i+1);
inversion = TRUE;
}
}
while (inversion);
}
Complexitatea minim este O(n). Dac vectorul iniial este deja sortat, variabila inversion
niciodat nu va primi valoarea TRUE.
Complexitatea maxim este O((n-1)
2
)=O(n
2
). Dac elementul minimal are indicele iniial n-1,
atunci va fi nevoie de n-1 executri a ciclului exterior, ca s-i dm indicele 0.
Pentru fiecare executare a ciclului exterior cu n-1 comparaii: (n-1)*(n-1)=(n-1)
2
comparaii.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
45
Complexitatea medie de asemenea este egal cu O(n
2
), dac elementul minimal cutat se afl
aleator printre indicii 0, 1,, n-1.
Exerciiu: Este posibil mbuntirea acestui algoritm, ce nu schimb totui esenial complexitatea.
mbuntii algoritmul de mai sus, prescurtnd cu un element parcurgerea de rnd fa de
precedent.
Metoda bulelor este unul din cei mai ri algoritmi de sortare. Neajunsul const n aceea c la fiecare
pas elementul urmtor se compar numai cu vecinul su urmtor.
3.4. Sortarea rapid
Sortarea rapid (quicksort) a fost propus de C.A.R. Hoare i folosete principiile Divide Et
Impera i Echilibru.
Ideea metodei este urmtoarea: se selecteaz un element arbitrar din vector numit principal (sau
pivot) i se rearanjeaz vectorul n doi subvectori, astfel nct cel din stnga are toate elementele
mai mici sau egale dect pivotul, iar cel din dreapta mai mari sau egale ca pivotul. Procedeul se reia
n subvectorul din stnga i apoi n cel din dreapta, etc. Procedeul se termin cnd se ajunge la
subvectori dintr-un singur element.
n baza clasei generice vector declarm clasa derivat vector_quicksort, dotat cu algoritmul de
sortare rapid.
//
// c l a s s " v e c t o r q u i c k s o r t"
//
template <class el> class vector_quicksort: public vector<el>
{
public:
vector_quicksort(char* file_name):
vector<el>(file_name)
{
}

void quicksort(int i=0, int j=-1)
{
if(j>=n || j==-1)
j=n-1;
if(i<0 || i>j)
i=0;
quicksort_intern(i, j);
}

protected:
void quicksort_intern(int i, int j);
int divide(int i, int j);
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
46
};
Presupunem c exist funcia numit divide(), care ntr-un anumit fel alege elementul principal cu
cheia K i rearanjeaz vectorul astfel, ca elementul principal primete un indice imain, iar toate
elementele cu cheile K se aranjeaz de la stnga (adic au indicii < imain), dar toate elementele cu
cheile K se aranjeaz de la dreapta (adic au indicii >imain):
Avem aici un caz tipic recursiv:
- parametrizarea: se precaut pentru subvectorul t[i]t[j]; pentru vectorul iniial i=0, j=n-1;
- cazul trivial: i=j (nu avem ce sorta);
- trecerea de la cazul general la un caz mai simplu, care are loc datorit funciei divide().
Dac exist o astfel de funcie, atunci sortarea rapid imediat se obine n form recursiv:
template <class el>
void vector_quicksort<el>::quicksort_intern(int i, int j)
{
if (j>i)
{
int imain=divide(i,j);
quicksort_intern(i,imain-1);
quicksort_intern(imain+1,j);
}
}
Algoritmul are loc pentru ambele ordine de apeluri recursive.
Schema metodei de divizare n timpul O(n):
12 3 15 10 2 20 4
principal
elementul
+ +

Prelucrm vectorul din stnga i din dreapta pn atunci, pn cnd din stnga nu va fi gsit
elementul cu cheia, ce ntrece cheia elementului principal, dar din dreapta elementul cu cheia mai
mic ca cheia elementului principal. Dup aceasta se poate de schimbat cu locurile aceste dou
elemente, lichidnd prin asta inversia. Apoi astfel de prelucrare dubl, din stnga i din dreapta,
continu cu poziiile deja gsite. Vectorul se socoate mprit, cnd poziiile din stnga i din
dreapta se ntlnesc. Valoarea comun a lor notm prin imain.
imain
0

n-1

imain-1
elementul principal t[imain]
elemente t[imain] elemente t[imain]
imain+1
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
47
Evident, c complexitatea divizrii nu ntrece O(n), sau mai bine spus O(j-i) cnd divizarea se
aplic la subvectorul t[i]t[j].

Sfaturi practice la alegerea elementului principal
Alegerea elementului principal trebuie s fie n aa fel ca s se micoreze probabilitatea cazului
cnd dup divizarea subvectorii (segmentele) s difere mult dup lungime.
Prima strategie: la fiecare divizare alegerea aleatorie (folosind funcia-generator de numere
aleatoare) a valorii indicelui elementului principal dintre i, i+1, , j. Neajunsul acestei metode -
cheltuieli suplimentare de timp necesare pentru aceast operaie.
A dou strategie: n calitate de elementul principal se alege elementul cu valoarea medie dintr-un
set nu mare de elemente. Cel mai simplu i mai uor de examinat setul ce conine trei elemente cu
indicii respectiv i, j i (i+j)/2.
Ambele metode micoreaz probabilitatea cazului catastrofal O(n
2
), doar totui aa situaie nu este
exclus. Sortarea rapid ntotdeauna poate s se degenereze. Paradoxal, c sortarea rapid este unul
din cei mai buni algoritmi de sortare intern, dar suntem nevoii s ne refuzm de ea n probleme
unde limitele superioare de timp (de tip knlog
2
n) necesare pentru sortarea, sunt critice.

Algoritmul divizrii
Exist mai multe variante ale algoritmului de divizare. Toate din ele urmresc cel puin dou
scopuri:
- a accelera ciclurile interioare;
- a prevedea caracterul aleator a vectorului. Adic de a exclude introducerea ntmpltoare a
ordinei n segmentele de divizare din punct de vedere al productivitii generale a algoritmului.
Adic trebuie s ne refuzm de orice ncercare de a sorta n procesul de divizare.
Sedgewick R. E. a propus urmtoarea metod de divizare:
a) punem elementul principal n poziia i (l schimbm dac este necesar cu elementul t[i]).
b) divizm subvectorul t[i+1], t[i+2], t[j], cu ajutorul valoarei elementului principal t[i]
lsnd pe t[i] la locul su. Se primete divizarea cu poziia intermediar imain, de exemplu:
i

j

i+1
i

j
imain
imain+1 imain-1
elemente t[i] elemente t[i]
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
48
c) schimbm cu locurile elementul t[i] cu elementul t[imain] i dm valoarea imain ca
rezultatul ntors de ctre funcia divide.

template <class el> int vector_quicksort<el>::divide(int i, int j)
{
int imain, jmain, imed;
imed =(i+j)/2;
imain = (ncomp++, t[i] < t[imed]) ?
((ncomp++, t[imed] < t[j]) ?
imed
:
(ncomp++, t[i] < t[j]) ? j : i)
:
((ncomp++, t[imed] > t[j]) ?
imed
:
(ncomp++, t[i] > t[j]) ? j : i);

if(imain > i)
swap(i, imain);
imain = i+1, jmain = j;
while(imain < jmain)
{
while((imain < jmain)&&(ncomp++, t[imain] <= t[i]))
imain++;
while((jmain > imain)&&(ncomp++, t[jmain] >= t[i]))
jmain--;
if(imain < jmain)
swap(imain, jmain);
}
if(ncomp++, t[imain] > t[i])
imain--;
if(imain > i)
swap(i, imain);
i

j
imain
imain+1 imain-1
elemente t[imain] elemente t[imain] elementul
principal
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
49
return imain;
}
Este clar c funcia divide() are complexitatea O(n). Ciclul exterior
while(imain < jmain)
{
}
verific fiecare element al vectorului t[0], t[i], t[n-1] cel mai mult de dou ori, dar restul
operaiilor cere un timp fix.
n funcia main() crem un vector si-il sortatm prin metoda quicksort:
void main()
{
clrscr();

vector_quicksort<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.quicksort();
gr.show("Group sorted by name:\n","");
cout << "n=" << gr.get_n();
cout << ", ncomp=" << gr.get_ncomp();
cout << ", n*log2(n)="
<< (gr.get_n()*log((double)gr.get_n())/log(2.0));
cout << ", n*n=" << ((double)gr.get_n()*gr.get_n());
getch();
}
Afiarea va arta astfel:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by name:
1. Black, 1981, 500
2. Blue, 1981, 500
3. Cyan, 1975, 800
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
50
4. Gray, 1968, 900
5. Green, 1987, 350
6. Magenta, 1983, 600
7. Orange, 1984, 550
8. Red, 1980, 450
9. White, 1980, 600
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=39, n*log2(n)=33.2193, n*n=100
Analiza rezultatelor rmne ca exerciiu.
Dac vrem s sortm dup anul de natere, atunci declarm n baza clasei usual_elem clasa
year_elem la care suprascriem funcia cmp().
//
// c l a s s "y e a r _ e l e m"
//
class year_elem : public usual_elem
{
public:
year_elem()
{
}

year_elem(char* init_name, int init_year, double init_salary):
usual_elem(init_name, init_year, init_salary)
{
}

virtual int cmp(elem& e2)
{
int result;
if(this->year < ((year_elem&)e2).year)
result=-1;
else
if(this->year > ((year_elem&)e2).year)
result=1;
else
result=0;
return result;
}
};
n funcia main() instaniem clasa generic vector_quicksort cu clasa-argument year_elem.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
51
void main()
{
clrscr();

vector_quicksort<year_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.quicksort();
gr.show("Group sorted by year:\n","");
cout << "n=" << gr.get_n();
cout << ", ncomp=" << gr.get_ncomp();
cout << ", n*log2(n)="
<< (gr.get_n()*log((double)gr.get_n())/log(2.0));
cout << ", n*n=" << ((double)gr.get_n()*gr.get_n());
getch();
}
Afiarea va arta astfel:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by year:
1. Gray, 1968, 900
2. Cyan, 1975, 800
3. Red, 1980, 450
4. White, 1980, 600
5. Black, 1981, 500
6. Blue, 1981, 500
7. Magenta, 1983, 600
8. Orange, 1984, 550
9. Green, 1987, 350
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=42, n*log2(n)= 33.2193, n*n=100
Analiza rezultatelor rmne ca exerciiu.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
52
n sfrit declarm n baza clasei usual_elem clasa derivat salary_elem care compar obiecte
dup salariu.
//
// c l a s s "s a l a r y _ e l e m"
//
class salary_elem : public usual_elem
{
public:
salary_elem()
{
}

salary_elem(char* init_name, int init_year, double init_salary):
usual_elem(init_name, init_year, init_salary)
{
}

virtual int cmp(elem& e2)
{
int result;
if(this->salary < ((salary_elem&)e2).salary)
result=-1;
else
if(this->salary > ((salary_elem&)e2).salary)
result=1;
else
result=0;
return result;
}
};
n funcia main() instaniem clasa generic vector_quicksort cu clasa-argument salary_elem.
void main()
{
clrscr();

vector_quicksort<salary_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.quicksort();
gr.show("Group sorted by salary:\n","");
cout << "n=" << gr.get_n();
cout << ", ncomp=" << gr.get_ncomp();
cout << ", n*log2(n)="
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
53
<< (gr.get_n()*log((double)gr.get_n())/log(2.0));
cout << ", n*n=" << ((double)gr.get_n()*gr.get_n());
getch();
}
Afiarea de data aceasta va arta astfel:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by salary:
1. Yellow, 1988, 300
2. Green, 1987, 350
3. Red, 1980, 450
4. Blue, 1981, 500
5. Black, 1981, 500
6. Orange, 1984, 550
7. White, 1980, 600
8. Magenta, 1983, 600
9. Cyan, 1975, 800
10. Gray, 1968, 900
End of vector. Press any key ...
n=10, ncomp=43, n*log2(n)=33.2193, n*n=100
Analiza rezultatelor rmne ca exerciiu.

Construirea sortrii rapide efective
Apelurile recursive neterminate vor fi nscrise n stiv. n cel mai nefavorabil caz divizarea
secvenial poate da sistematic imain=0 (imain=i) sau imain=n-1 (imain=j). n acest caz
divizarea vectorului n doi sub vectori va da permanent unul de lungime 0 iar altul va avea lungimea
n-1 (j-i). Adncimea n apelurile recursive poate atinge valoarea n lungimea vectorului iniial.
Trebuie s prevedem stiva de adncime n (complexitatea spaial O(n), ce nu este accesibil).
Exist o metod simpl: de a ncepe ntotdeauna cu subvectorul de lungime mai mic. Atunci
aceast lungime va fi mai mic dect jumtatea din lungimea subvectorului precedent. Aa c
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
54
numrul maxim P(n) de elemente nscrise simultan n stiv, care este i adncimea maxim a
apelurilor recursive, satisface relaiei
|
|
.
|

\
|
(

+ s
2
1 ) (
n
P n P , adic ) 0 ( 1 ... 1 1 1 ) (
2
log
P n P
n
+ + + + + s
Lund n consideraie, c P(0)=0, obinem c P(n)<log
2
n+1, aa c complexitatea spaial se reduce
la O(log
2
n), (pentru n=10
6
, log
2
10
6
20, trebuie s prevedem stiva de adncimea 20, ce este practic
accesibil). Deci modificm funcia quicksort_intern() ca ea s se arate astfel:
template <class el>
void vector_quicksort<el>::quicksort_intern(int i, int j)
{
if (j>i)
{
int imain=divide(i,j);
if(imain-i > j-imain)
{//ncepem cu intervalul stng
quicksort_intern(i,imain-1);
quicksort_intern(imain+1,j);
}
else
{//ncepem cu intervalul drept
quicksort_intern(imain+1,j);
quicksort_intern(i,imain-1);
}
}
}
Deoarece modificarea introdus nu va schimba afirile obinute prin exemplele de sortare
precedente, nu le mai repetm.
Complexitatea spaial se reduce n aa fel la mrimea P(n) ). (log
2
n O s Apreciem complexitatea
temporal T(n). Fiindc divizarea are complexitatea O(n), avem:
) 1 ( ) 0 ( ) ( ) ( imain n T imain T n O n T + + = . Deci, totul depinde de imain, adic cum vectorul va
fi divizat de ctre funcia divide().
O situaie ideal care ar putea fi obinut prin aplicarea principiului de echilibru, const n
segmentarea vectorului aproximativ n dou pari egale, aa ca
2
n
imain ~ . Atunci
), log ( ) ( ... ) ( ) ( ...
8
2
4
2
2
2 ) (
4
2
2
2 ) (
2
2 ) ( ) (
2
n n O n O n O n O
n
T
n
O
n
O n O
n
T
n
O n O
n
T n O n T
= + + + = =
|
|
.
|

\
|
|
|
.
|

\
|
|
.
|

\
|
+ |
.
|

\
|
+ |
.
|

\
|
+
=
|
|
.
|

\
|
|
.
|

\
|
+ |
.
|

\
|
+ = |
.
|

\
|
+ =

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
55
fiindc T(0)=0. Deci, T(n)=O(nlog
2
n), precum coeficientul la nlog
2
n este acelai ca i coeficientul
pe lng n la complexitatea mpririi.
Aadar, metoda obine O(nlog
2
n) ce este limita de jos pentru complexitatea algoritmilor de sortare
bazai pe compararea cheilor.
Dac divizarea sistematic se obine lng primul sau lng ultimul elemente ale subvectorilor
cercetai (adic permanent imain=i, sau imain=j), atunci fiecare dat rmne de sortat o parte a
subvectorului, n care numrul de elemente este cu o unitate mai mic dect subvectorul precedent, i
rezult c complexitatea va fi ) ( ) 1 ( ... ) 1 ( ) ( ) 1 ( ) 1 ( ) ( ) (
2
n O O n O n O n T O n O n T = + + + = + + = .
n acest caz sortarea rapid are complexitatea teoretic asemntoare cu complexitatea celor mai ri
algoritmi de sortare, de exemplu sortarea prin metoda bulelor. Dar complexitatea practic probabil
va fi i mai mare, din cauza timpului necesar pentru realizarea recursiei dirijate de stiv. Pentru
sortarea rapid este artat teoretic c complexitatea medie apreciat pentru probabilitile egale a
tuturor permutrilor este egal cu O(nlog
2
n) cu aproximativ 2nlog
2
n comparaii a cheilor, de
asemenea este artat c probabilitatea celui mai nefavorabil caz cu complexitatea O(n
2
) este destul
de mic.
Posibilitatea celui mai nefavorabil caz nu este exclus cnd datele sunt deja sortate sau parial
sortate (poate fi i n ordine invers).
Paradoxul sortrii rapide n contrastul cu sortarea prin inserie sau chiar prin metoda bulelor, const
n aceea c sortarea rapid i pierde calitatea la vectori parial ordonai. Faptul acesta este incomod,
fiindc necesitatea de a sorta datele aproape sortate destul de des se ntlnete n practic.

mbuntirea sortrii rapide
Ca sortarea rapid s devin real un algoritm efectiv, ea mai cere nc o mbuntire. Este evident,
c n versiunile precedente recursia i alegerea elementului principal devin destul de grele pentru
subvectori mici. Sortarea rapid nu poate fi aplicat la vectori mici. De aceea recursia trebuie oprit
cnd dimensiunea subvectorului devine mai mic dect careva constant, numit prag. Dup aceasta
se folosete metoda, eficacitatea creia poate s se mbunteasc la datele parial sortate, de
exemplu sortarea prin inserie simpl.
D. Knuth a obinut c valoarea optimal teoretic a pragului este egal cu 9.
n practic rezultatele bune ne dau valorile pragului de la 8 pn la 20, iar valoarea optim se
conine ntre 14 i 16.
//
// c l a s s " v e c t o r o p t i m q u i c k s o r t "
//
template <class el> class vector_optim_quicksort:
public vector_quicksort<el>
{
public:
vector_optim_quicksort(char* file_name, int threshold_init=15):
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
56
vector_quicksort<el>(file_name)
{
threshold=threshold_init;
if(threshold<1)
threshold=1;
}

void quicksort(int i=0, int j=-1)
{
if(j>=n || j==-1)
j=n-1;
if(i<0 || i>j)
i=0;
quicksort_intern(i, j);
}

protected:
int threshold;
void quicksort_intern(int i, int j);
void insertsort(int i, int j);
};

template <class el>
void vector_optim_quicksort<el>::quicksort_intern(int i, int j)
{
if(j-i+1>threshold)
{
int imain=divide(i,j);
if(imain-i > j-imain)
{
quicksort_intern(i,imain-1);
quicksort_intern(imain+1,j);
}
else
{
quicksort_intern(imain+1,j);
quicksort_intern(i,imain-1);
}
}
else
insertsort(i, j);
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
57

template <class el>
void vector_optim_quicksort<el>::insertsort(int i, int j)
{
for(int k = i+1; k<=j; k++)
for(int l=k; (l>i)&&(ncomp++, t[l]<t[l-1]); l--)
swap(l-1, l);
}

Exemple de funcia main() lum din trei exemple precedente, nlocuind n ele denumirea clasei
vector_quicksort cu vector_optim_quicksort i adugnd la parametrii constructorilor
valoarea pentru prag, de exemplu 4. Afirile, analiza crora rmne ca exerciiu, vor arta astfel:
Pentru vectorul concretizat cu clasa usual_elem
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by name:
1. Black, 1981, 500
2. Blue, 1981, 500
3. Cyan, 1975, 800
4. Gray, 1968, 900
5. Green, 1987, 350
6. Magenta, 1983, 600
7. Orange, 1984, 550
8. Red, 1980, 450
9. White, 1980, 600
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=32, n*log2(n)=33.2193, n*n=100
Pentru vectorul concretizat cu clasa year_elem
Unsorted group:
1. Green, 1987, 350
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
58
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by year:
1. Gray, 1968, 900
2. Cyan, 1975, 800
3. Red, 1980, 450
4. White, 1980, 600
5. Blue, 1981, 500
6. Black, 1981, 500
7. Magenta, 1983, 600
8. Orange, 1984, 550
9. Green, 1987, 350
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=37, n*log2(n)=33.2193, n*n=100
Pentru vectorul concretizat cu clasa salary_elem
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by salary:
1. Yellow, 1988, 300
2. Green, 1987, 350
3. Red, 1980, 450
4. Blue, 1981, 500
5. Black, 1981, 500
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
59
6. Orange, 1984, 550
7. White, 1980, 600
8. Magenta, 1983, 600
9. Cyan, 1975, 800
10. Gray, 1968, 900
End of vector. Press any key ...
n=10, ncomp=33, n*log2(n)=33.2193, n*n=100
n urmtorul tabel este prezentat numrul de comparri efectuate la sortarea obiectelor
vector_optim_quicksort create pe baza fiierului stud.txt pentru diferite valori ale pragului
i clase de concretizare.
Cmpul de sortare
Prag
name year salary
0 39 42 43
1 39 42 43
2 37 37 41
3 35 37 38
4 32 37 33
5 29 34 28
6 29 34 28
7 29 34 28
8 29 34 28
9 29 34 28
10 30 28 25
11 30 28 25
Analiza rezultatelor prezentate n acest tabel rmne ca exerciiu.
3.5. Sortarea prin inserie
Inserie simpl
Ideea principal a sortrii prin inserie (engl. Insert sort) este simpl: alegem careva element, sortm
celelalte elemente, inserm elementul ales (adic l includem) la locul potrivit printre altele deja
sortate.
void recursivinsertsort(int i, int j)
{
if(j>i)
{
recursivinsertsort(i, j-1);
for(int l=j; (l>i)&&(ncomp++, t[l]<t[l-1]; l--))
swap(l-1, l);
}
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
60
n forma nerecursiv sortarea prin inserie se scrie astfel:
void insertsort(int i, int j)
{
int k;
for(k=i+1; k<=j; k++) //aici este sortat t[i]t[k-1]
{
for(int l=k; (l>i)&&(ncomp++,t[l]<t[l-1]; l--))
swap(l-1, l);
//aici este sortat t[i]t[k]
}
}
Este evident c aceast metod de sortare este stabil.
Complexitatea medie i maxim a operaiei de inserie este egal O(k-i), dar timpul ndeplinirii se
mbuntete, dac compararea cheilor se combin cu deplasarea elementelor care au chei mai mari
dect cheia elementului t[k].
Este uor de observat, c n procesul inseriei elementul inserat se ncadreaz n toate permutrile
secveniale. i dac interschimbrile sunt mai voluminoase ca semischimburi, se poate puin de
mbuntit eficacitatea acestui proces:
void insertsort(int i, int j)
{
int k;
for(k=i+1; k<=j; k++) //aici este sortat t[i]t[k-1]
{
element tmp=t[k];
int l;
for(l=k-1; (l>=i)&&(ncomp++, t[l]<tmp); l--)
t[l+1]=t[l];
l++;
if(l<k)
t[l]=tmp;
//aici este sortat t[i]t[k]
}
}
Complexitatea maxim i medie a algoritmului de inserare este egal O(n
2
) n prespunere c toate
permutrile au probabiliti egale. Numrul exact de ndeplinire a ciclului este egal
4
) 1 ( n n
pentru
valoarea medie i pentru valoarea maximal
2
) 1 ( n n
(n cazul cnd vectorul iniial este sortat n
ordine invers).
Evideniem totui una din proprietile importante a sortrii prin inserie simpl: spre deosebire de
alte metode ea are cea mai bun eficacitate dac n vectorul iniial este stabilit o oarecare ordine.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
61
Dac vectorul iniial este total sortat, atunci complexitatea este egal O(n). n cazul general
algoritmul folosete orice ordine parial, ce se conine n vector. Dac mai lum n consideraie i
simplitatea algoritmului, ajungem la concluzie c acest algoritm este cel mai bun pentru finisarea
lucrului a metodelor mai pretenioase, cum de exemplu este sortarea rapid. Adic pentru finisarea
lucrului algoritmilor, care destul de repede mpart vectorul n mai multe pri aproape sortate, dar
cer destul de mult timp i se nduesc la sortarea final a subvectorilor mici.

Metoda lui Shell
Neajunsul esenial al sortrii prin inserie simpl const n aceia, c la fiecare pas de mutare
elementul care se mut, se deplaseaz doar cu o poziie. Fiecare din aceste mutri elimin exact o
inversie. n rezultat numrul total de mutri a datelor este egal cu numrul iniial de inversii, care n
probabilitatea medie este:
4
) 1 (
2 * 2
) 1 (
2
2

=
n n n n c
n
.
Donald L. Shell n anul 1959 a propus n loc de inseria sistematic a elementului cu indicele i n
sub vectorul elementelor precedente (modul care contrazice principiului de echilibru), de a include
acest element n sublist, coninnd elemente cu indicii i-h, i-2h, i-3h, , unde h o constant
pozitiv (pas).
Astfel se formeaz vectorul, n care hseria elementelor (elemente care se afl la distana h unul de
la altul) se sorteaz deoparte.

Dup ce au fost sortate deoparte neintersectatele hserii, procesul ncepe cu valori noi h
'
<h. Dar
proprietatea caracteristic sortrii prin inserie uureaz problema n comparaie cu situaia n care
vectorul iniial este arbitrar. Preventiv sortarea prin serii cu distana h grbete sortarea prin serii cu
distana h
'
. Algoritmul Shell esenial folosete aceast proprietate magic, sortnd mai nti seriile
cu distana h
i
, apoi h
i
-1,, apoi h
1
, unde h
i
, h
i-1
,,h
1
sunt aranjate descresctor i h
1
=1. Ultima
schimbare trebuie s furnizeze sortarea total a vectorului, ce reprezint ultimele valori h
i
, h
i-1
,,h
1.
Nu este un rspuns exact la ntrebarea: Care sunt valorile optimale pentru h
i
, h
i-1
,,h
1
?. Secvena
optimal depinde de muli factori i nu n ultimul rnd de n - dimensiunea vectorului sortat.
Pentru vectorii destul de mari rezultatele testelor au artat, c poate fi recomandat secvena pailor
{h
i
}, astfel ca h
i+1
=3h
i
+1, adic secvena care include n ordinea descresctoare: , 364, 121, 40,
13, 4, 1. Procesul ncepe cu h
m-2
, unde m este cel mai mic numr ntreg, aa ca h
m
n, cu alte
cuvinte h
m-2
este primul element al secvenei

egal cu
(

9
n
.
t[0] t[1] t[2]t[0+h] t[1+h] t[2+h]t[0+2*h] t[1+2*h] t[2+2*h]
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
62
Crem n baza clasei generice vector clasa generic vector_Shellsort dotat cu algoritmul de
sortare prin metoda lui Shell:
//
// c l a s s "v e c t o r _ S h e l l s o r t "
//
template <class el> class vector_Shellsort: public vector<el>
{
public:
vector_Shellsort(char* file_name): vector<el>(file_name)
{

}

void Shellsort();
};

template <class el>
void vector_Shellsort<el>::Shellsort()
{
int h;
int i, j, k;
el tmp;
//definirea pasului iniial
h=1;
while(h<n/9)
h=3*h+1;
// aici pasul este egal max(1, hm-2)
do
{
// Sortarea prin serii cu distana h
for(k=0; k<h; k++)
{ // sortarea k serii inserate
for(i=h+k; i<n; i+=h)
{ //includerea lui t[i] la locul su printre precedente
tmp=t[i];
j=i-h;
while((j>=0)&&(ncomp++, t[j]>tmp))
{
t[j+h]=t[j];
j-=h;
}
t[j+h]=tmp;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
63
}
}
//micorarea incrementului
h=h/3;
} while(h>0);
}
Observaii:
1. n locul recalculrii pailor secveniali h se poate de obinut pe ei din calcularea preventiv i
stocarea ntr-un vector adugtor:
2. Se poate de unit buclele dup k i dup i, nlocuind schimburi cu semischimburi;
3. Sortarea prin metoda lui Shell este instabil, i problema aceasta nu poate fi rezolvat uor.
n funcia main() instaniem clasa vector_Shellsort concretizat cu clasa usual_elem, afim
vectorul iniial, l sortm prin metoda lui Shell, afim vectorul sortat i informaii legate de
aprecierea complexitii:
void main()
{
clrscr();

vector_Shellsort<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");

gr.Shellsort();

gr.show("Group sorted by name:\n","");
cout << "n=" << gr.get_n();
cout << ", ncomp=" << gr.get_ncomp();
cout << ", n*log2(n)="
<< (gr.get_n()*log((double)gr.get_n())/log(2.0));
cout << ", n*n=" << ((double)gr.get_n()*gr.get_n());
getch();
}
Afiarea va arta astfel:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
64
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by name:
1. Black, 1981, 500
2. Blue, 1981, 500
3. Cyan, 1975, 800
4. Gray, 1968, 900
5. Green, 1987, 350
6. Magenta, 1983, 600
7. Orange, 1984, 550
8. Red, 1980, 450
9. White, 1980, 600
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=30, n*log2(n)=33.2193, n*n=100
Dup cum se vede numrul de comparri a coincis cu numrul de comparri la inserie simpl.
nlocuim n funcia main() clasa usual_elem cu clasa year_elem, atunci vom obine:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by year:
1. Gray, 1968, 900
2. Cyan, 1975, 800
3. Red, 1980, 450
4. White, 1980, 600
5. Blue, 1981, 500
6. Black, 1981, 500
7. Magenta, 1983, 600
8. Orange, 1984, 550
9. Green, 1987, 350
10. Yellow, 1988, 300
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
65
End of vector. Press any key ...
n=10, ncomp=28, n*log2(n)=33.2193, n*n=100
Analiza rezultatelor rmne ca exerciiu.
Dac vom nlocui n funcia main() clasa year_elem cu clasa salary_elem, vom obine:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by salary:
1. Yellow, 1988, 300
2. Green, 1987, 350
3. Red, 1980, 450
4. Blue, 1981, 500
5. Black, 1981, 500
6. Orange, 1984, 550
7. White, 1980, 600
8. Magenta, 1983, 600
9. Cyan, 1975, 800
10. Gray, 1968, 900
End of vector. Press any key ...
n=10, ncomp=25, n*log2(n)=33.2193, n*n=100
Analiza rezultatelor rmne ca exerciiu.
Metoda lui Shell esenial ntrece inseria simpl pentru n mai mari de 100. Numrul necesar de
comparri n mediu are ordinul 1.66n
1.25
pentru un n destul de mare. Analiznd tabelul urmtor:
n 1.66n
1.25
nlog
2
n
10 29,5
33.2193
100 525 664
1000 9335 9966
10000 166000 132877
10
5
2,95*10
6
1,66*10
6
10
6
5,25*10
7
1,99*10
7
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
66
vedem c metoda lui Shell rezist competiia cu metodele O(nlog
2
n) pn la n=10
5
.
Sortarea Shell ru se adapteaz la sistemele cu memorie virtual (adic care acoper vectorul cu
intervale largi).

3.6. Sortarea prin selecie
Selecie simpl
Ideea acestei metode de sortare (engl. Selection sort) este foarte simpl: se selecteaz elementul
maxim din tablou i i se schimb locul cu ultimul element; n continuare se caut elementul maxim
pn la ultimul i i se schimb cu penultimul elementul. La fiecare parcurgere se examineaz toate
elementele ale vectorului care au rmas neordonate, elementul maxim din care va fi alturat la cele
ordonate.
n form nerecursiv selecie simpl const din n-1 etape. La etapa k se caut elementul cu cheia
maxim dintre elementele care nu sunt ordonate pn la capt i-l leag la poziia n-k.
Exemplu:
void selectsort()
{
int imax, i, j;
for(i=n-1; i>0; i--)
{
imax=i;
for(j=0; j<i; j++)
if(ncomp++, t[j]>t[imax])
imax=j;
swap(i,imax);
// aici sub vectorul ] 1 [ ] [ n t i t este sortat(invarianta buclei)
}
}
Acest algoritm are complexitatea O(n
2
) n toate cazurile. Numrul de ndepliniri a ciclului interior
este egal
2
) 1 ( n n
.

3.7. Sortarea arborescent (piramidal, heapsort)
Sortarea arborescent provine de la selecia simpl. Neajunsul principal al sortrii prin selecie
simpl const n aceea c comparaiile fcute la fiecare etap dau mult mai multe informaii dect
cele care se folosesc efectiv pentru a pune elementul curent la locul potrivit. Pentru a obine o
mbuntire esenial, trebuie de folosit o structur de date mai dezvoltat, permindu-i pe ct se
poate, s pstreze informaia, obinut secvenial la verificare. De exemplu, dac t[i]>=t[k], iar
t[k]>=t[j], atunci t[i]>=t[j].
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
67
Sortarea arborescent folosete un arbore binar concret, din care este uor de extras elemente cu
chei maxime. Acest arbore se numete arbore de maximizare, el posed proprietatea c elementul n
fiecare vrf are cheia mai mare sau egal dect cheile ale fiilor dac aceti fii exist. La aplicarea
arborilor de maximizare apare problema de reorganizare cnd doi subarbori ai rdcinii sunt de
maximizare, iar arborele ntreg nu este de maximizare.
n acest caz pentru reorganizarea arborelui, adic pentru l preface n arbore de maximizare, trebuie
s facem civa pai. ncepnd de la rdcin ne deplasm n direcia maximal interschimbnd
elementele.
Arborele binar plin, adic, la care pn la orice nivel exist toate nodurile cu posibila excepie
pentru cele mai drepte noduri ale ultimului nivel. Astfel de arbore poate fi reprezentat sub form de
vector.
Nodului cu indice i i corespunde nodurile cu indicii 2*i+1 (fiul stng, dac 2*i+1<=n-1) i 2*i+2
(fiul drept, dac 2*i+2<=n-1).
Important de neles c nu crem un arbore aparte, folosind formulele 2*i+1 i 2*i+2, prelucrm
acest vector ca un arbore binar.
Un subarbore binar al arborelui binar care corespunde vectorului t[0]t[n-1] poate fi determinat
printr-o pereche de indici i i j care corespund condiiei (0<=i)&&(i<=j)&&(jn-1), fii
elementului k, unde (i<=k)&&(k<=j), vor avea indicii 2*i+1 i 2*i+2, dac aceste valori nu ntrec
j.
Crem n baza clasei generice vector clasa generic vector_heapsort dotat cu algoritmul de
sortare arborescent:
//
// c l a s s "v e c t o r _ h e a p s o r t "
//
template <class el> class vector_heapsort: public vector<el>
{
public:
vector_heapsort(char* file_name): vector<el>(file_name)
6
8
9
5 6
1
Maximizarea arborelui
3 7 6 5
9
8
7
5 6
1
3 6 6 5
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
68
{

}

void heapsort();

protected:
void reorganization(int i, int j);
void planting();
void maxtreesort();
};
Descriem funcia de reorganizare pentru subarbori.
Fie: i, j o pereche de indici astfel c 0<=i<=j<=n-1 i subarborii t[2*i+1], t[2*i+2], sunt arbori
de maximizare, dac aa subarbori exist, atunci funcia de reorganizare poate fi descris astfel :
template <class el>
void vector_heapsort<el>::reorganization(int i, int j)
{
int pred, next, left, right; // indicii pentru parcurgerea arborelor
next=i ;
do
{
pred=next; // temporar
left=2*pred+1;
if(left<=j) // daca apartine subarborelui
{
if(ncomp++, t[left]>t[next])
next=left;
right=left+1; // 2*pred+2
if((right<=j)&&(ncomp++, t[right]>t[next]))
next=right;
if(next!=pred)
swap(pred,next); // schimbam cu locurile elementele
// t[pred] si t[next]
}
} while(pred!=next);
}
Ca rezultat, n arborele binar ce corespunde vectorului t, subarborele binar t[i], t[2*i+1],
t[2*i+2],, t[j] va fi arbore de maximizare .
Complexitatea reorganizrii este O(h
i,j
), unde h
i,j
- adncimea subarborelui, corespunztor
elementelor t[i], t[2*i+1], t[2*i+2],, t[m*i+1], t[m*i+2]. De aceea h
i,j=
O(log
2
(j-i+1)). n
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
69
aa fel complexitatea reorganizrii este O(log
2
(j-i+1)), mai concret ea se ndeplinete cu 2(log
2
(j-
i+1)) comparaii i log
2
(j-i+2) interschimbri.
Algoritmul de sortare arborescent const din dou etape fiecare din care folosete reorganizarea:
- Plantare (planting) transform vectorul iniial n vectorul cu arbore de maximizare;
- Sortarea arborelui de maximizare (maxtreesort) face sortarea lund n consideraie arborii de
maximizare.
template <class el> void vector_heapsort<el>::heapsort()
{
planting();
maxtreesort();
}
La plantare reorganizarea se aplic la aa indicii i subarborii la care, dac exist, sunt arbori de
maximizare. ncepem de la elementul t[(n-1)/2], fiindc elementul cu indice mai mare nu are
subarbori.
template <class el> void vector_heapsort<el>::planting()
{
for(int i=(n-1)/2; i>=0; i--)
reorganization(i, n-1);
}
Complexitatea plantrii poate fi dedus din complexitatea reorganizrii, adic din subvectorii
cercetai, corespunztori vrfurilor arborelui:
1. adncimea sub vectorului h=[log
2
n]+1 vectorul t[0]t[n-1];
2. adncimea sub vectorului h-1 vectorii t[1]t[n-1], t[2]t[n-1];
3. adncimea sub vectorului h-2 vectorii t[3]t[n-1], t[4]t[n-1], t[5]t[n-1],
t[6]t[n-1];
4.
n aa fel complexitatea poate fi scris n forma: O(1*h*2*(h-1)+...+2
h-2
*2)=O(2
h-1
)=O(n).
Dup plantare t[0] a devenit elementul maximal, el trebuie sa fie interschimbat cu elementul t[n-
1], dup ce rmne de sortat sub vectorul t[0]t[n-2], dar acest sub vector va fi arbore de
maximizare cu unic excepie posibil, privind elementul t[0] (precedentul t[n-1]), de aceea la
acest subvector aplicm reorganizarea, pentru a obine maximul subvectorului n t[0], pe care
interschimbm cu t[n-2], etc.
template <class el> void vector_heapsort<el>::maxtreesort()
{
for (int i=(n-1);i>=1;i--)
{
swap (0, i);
reorganization(0, i-1);
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
70
}
Complexitatea acestei proceduri este ) ( ) (
1
1
, 0

=
=
n
i
i
h O n T , unde h
0,i
- adncimea corespunztoarea
subarborelui t[0]t[i], adic | | 1 log
2 , 0
+ = i h
i
. Deci, obinem c T(n)=O(nlog
2
n). n aa fel
complexitatea algoritmului de sortare arborescenta este O(n+nlog
2
n)=O(nlog
2
n).
Aceasta este complexitatea att maximal ct i cea medie fiindc nimic n-am presupus despre
repartizarea iniial a elementelor. Sortarea arborescent este cel mai sigur algoritm de sortare .

void main()
{
clrscr();
vector_heapsort<usual_elem> gr("Stud.txt");
gr.show("Unsorted group:\n","");
gr.heapsort();
gr.show("Group sorted by name:\n","");
cout << "n=" << gr.get_n();
cout << ", ncomp=" << gr.get_ncomp();
cout << ", n*log2(n)="
<< (gr.get_n()*log((double)gr.get_n())/log(2.0));
cout << ", n*n=" << ((double)gr.get_n()*gr.get_n());
getch();
}
Afiarea pentru clasa usual_elem va fi:
Unsorted group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of vector. Press any key ...
Group sorted by name:
1. Black, 1981, 500
2. Blue, 1981, 500
3. Cyan, 1975, 800
4. Gray, 1968, 900
5. Green, 1987, 350
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
71
6. Magenta, 1983, 600
7. Orange, 1984, 550
8. Red, 1980, 450
9. White, 1980, 600
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=41, n*log2(n)=33.2193, n*n=100

nlocuim n funcia main() clasa usual_elem cu clasa year_elem, atunci vom obine:
Group sorted by year:
1. Gray, 1968, 900
2. Cyan, 1975, 800
3. White, 1980, 600
4. Red, 1980, 450
5. Blue, 1981, 500
6. Black, 1981, 500
7. Magenta, 1983, 600
8. Orange, 1984, 550
9. Green, 1987, 350
10. Yellow, 1988, 300
End of vector. Press any key ...
n=10, ncomp=38, n*log2(n)=33.2193, n*n=100

nlocuim n funcia main() clasa year_elem cu clasa salary_elem, atunci vom obine:
Group sorted by salary:
1. Yellow, 1988, 300
2. Green, 1987, 350
3. Red, 1980, 450
4. Black, 1981, 500
5. Blue, 1981, 500
6. Orange, 1984, 550
7. White, 1980, 600
8. Magenta, 1983, 600
9. Cyan, 1975, 800
10. Gray, 1968, 900
End of vector. Press any key ...
n=10, ncomp=40, n*log2(n)=33.2193, n*n=100
Analiza rezultatelor rmne ca exerciiu.

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
72
3.8. Comparaii practice ai diferiilor algoritmi de sortare
S-au folosit diferite principii de sortare i poate prea greu de ales algoritmul potrivit. El depinde de
muli factori. Dar fiecare din aceti algoritmi se poate uor i repede de reprogramat. De aceea
adresarea la Bubblesort din cauza c este uor de scris, nu poate fi justificat nicicum.
La alegerea algoritmului de sortare pot fi date urmtoarele recomandri:
- pentru n mici (100) i poate mai mari, dac nu ncercm s ctigm cteva microsecunde,
sortarea prin inserie simpl ne d un rezultat destul de bun, n special dac datele sunt deja
parial sortate;
- pentru n de la cteva sute pn la cteva mii, metoda Shell ne d un rezultat excelent. n
sistemele cu memorie virtual ea nu trebuie folosit, dac vectorul se aranjeaz pe un numr
mare de pagini;
- pentru n >100 (de exemplu) quicksort este probabil, cel mai bun algoritm n caz general; dar
el poate s creasc pn la O(n
2
) cu probabilitatea ne nul (probabilitatea totui este destul
de mic, dac este bine scris divizarea);
- pentru n>100 sortarea Heapsort cere aproape de dou ori mai mult timp n mediu, fa de
sortare rapid, dar este garantat comportarea ei cu O(nlogn).
n comparaiile experimentale ale diferitor metode de sortare, a fost folosit un vector real, n care
fiecare element era cheia lui proprie. Vectorul a fost alctuit din elemente aleatorie, ceia ce puin a
favorizat sortarea rapid.
Observaie: Concluziile pot fi diferite n dependen de preul de comparare a cheilor ce se
compar, de modul de interschimbare a elementelor, i de alte operaii:
N

metoda
10 100 1000 10000 25000 50000
Bublesort 0,16 20 2400
Extractsort 0,12 7,3 680
Insertsort 0,12 6,7 610
Shellsort 0,07 2 37 600 1800 4200
Heapsort 0,2 3,5 50 660 1830 3960
Quicksort 0,07 2 28 365 1000 2140

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
73

4. STRUCTURI DINAMICE DE DATE
4.1. Noiune de structura dinamic de date
Definiie:

Structura dinamic de date (SDD) este o aa structur de date numrul de elemente
la care se schimb n procesul de utilizare a ei.
Se adaug elemente noi, se elimin careva elemente din cele existente, precum
adugrile i eliminrile se efectueaz n mod independent unele de altele.
Pentru structuri dinamice de date este de caracter amplasarea elementelor mprtiat prin memorie
n dependen de alocarea locurilor pentru ele n timpul de adugare a lor.
Tipuri de structuri dinamice de date se difer ntre ele prin organizarea legturilor ntre elementele
care ntr n componena SDD, prin ordine de adugare (nscriere) a elementelor noi, prin ordine de
accesare a elementelor, prin ordine de nlturare (tergere) a elementelor existente,
Cele mai rspndite structuri dinamice de date sunt:
- arbori binari;
- liste de diferite tipuri (simplu i dublu nlnuite, nlnuite ciclic);
- stive;
- cozi;
- arbori, etc.




Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
74
4.2. Arbori binari
Definiia arborelui binar este recurent i arat astfel:

Arbore binar reprezint o mulime finit de elemente (noduri), care sau este vid,
sau este compus dintr-un nod special numit rdcin i din doi arbori binari care
nu se intersecteaz ntre ei i se numesc respectiv subarbore stng i subarbore
drept ai arborelui binar dat.

Exemple de arbori binari:
Arbore binar este vid

Arbore binar este compus numai din rdcin (mai exact din rdcin i doi subarbori vizi)
Arbore binar este compus din rdcin i subarbore stng

A
B
A
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
75

Arbore binar este compus din rdcin i subarbore drept
Reinei. Arborii binari din dou exemple precedente sunt diferii. La primul arbore binar
subarbore drept este vid, iar la al doilea arbore binar subarbore stng este vid.

Arbore binar este compus din rdcin, subarbore stng i subarbore drept

Un arbore binar mai complicat


Definiia nodului frunz:
A
B C
A
B C
D E F
A
B
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
76
Nodul la care i subarbore stng i subarbore drept sunt vizi se numete nod frunz
sau terminal
La arborele binar din exemplul precedent nodurile frunz sunt noduri D, E, F.
Nodurile fiecrui arbore binar n mod natural i univoc se repartizeaz pe niveluri astfel:

Arborele binar vid nu are niveluri.
La restul arborelor binari nivelului 1 aparine un singur nod rdcina arborelui.
Nivelului 2 aparin rdcinile existente ale subarborilor stng i cel drept ai
arborelui binar dat.
i aa mai departe, nivelului i+1 aparin rdcinile existente ale subarborilor drepi
i celor stngi ai tuturor nodurilor nivelului i.

Urmrim repartizrea nodurilor unui arbore binar pe niveluri. Fie dat urmtorul arbore binar:





A
B
C
D
E
F
root
right
right
right
left
left
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
77
Atunci acelai arbore binar cu nodurile repartizate pe niveluri va arta astfel:

Arborele binar din n noduri poate avea maxim n niveluri. ntr-adevr, n cazul cnd toate nodurile
au numai un singur subarbore (nu conteaz stng sau drept), n afar de un singur nod care nu va
avea nici un subarbore (acesta va fi nodul de pe ultimul nivel), toate nodurile vor fi repartizate pe
nivelurile separate, i deci numrul total de niveluri va fi n. Mai multe niveluri nu pot exista,
deoarece nu sunt suficiente noduri.

Arborele binar din n noduri poate avea minim | | 1 log
2
+ n niveluri. Numrul minim de niveluri
printre altele se atinge la astfel de arbori binari din n noduri, la care toate nivelurile sunt completate
la maxim cu posibil excepie pentru ultimul nivel, deoarece poate s se ntmple ca pentru
completarea lui nodurile nu vor fi suficiente.
Un alt exemplu de arborele binar cu numrul minim de niveluri :
A
B C
D E F
1
2
3
level
A
B C
D E F
1
2
3
level
4
G H
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
78
Parcurgerea nodurilor arborelui binar este trecerea consecutiv de la un nod la altul prin toate
nodurile cu scopul de prelucrare sau de cutare.

Sunt trei moduri de parcurgere (engl. order traversal):
- preordine (engl. preorder traversal, rus. / ) parcurgere n
lime sau direct;
- inordine (engl. symmetric order traversal / inorder traversal, rus. /
) parcurgere simetric;
- postordine (engl. postorder traversal / endorder traversal, rus. /
) parcurgere n adncime.
Denumirea modului de parcurgere provine din ordine de prelucrare a rdcinii, i din ordine de
parcurge a subarborelui drept i celui stng.
1. Parcurgerea n lime (preordine) const din urmtorii pai:
a) prelucrarea rdcinei;
b) parcurgerea subarborelui stng n preordine, dac el nu este vid;
c) parcurgerea subarborelui drept n preordine, dac el nu este vid.
Poate fi folosit la cutare nodului necesar. Un alt exemplu de parcurgere n lime reprezint
prelucrarea expresiei descrise prin forma direct polonez.

2. Parcurgerea simetric (inordine) const din urmtorii pai:
a) parcurgerea subarborelui stng n nordine, dac el nu este vid;
b) prelucrarea rdcinei;
c) parcurgerea subarborelui drept n nordine, dac el nu este vid.
Dac arborele binar este construit dup principiul tabelului neordonat structurat arborescent, atunci
parcurgerea simetric asigur prelucrarea nodurilor n ordinea cresctoare a cheilor lor.

3. Parcurgerea n adncime (postordine) const din urmtorii pai:
a) parcurgerea subarborelui stng n postordine, dac el nu este vid;
b) parcurgerea subarborelui drept n postordine, dac el nu este vid;
c) prelucrarea rdcinei.


Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
79
Poate fi foosit la calcularea expresiei reprezentate sub forma de arbore binar:

Definiia arborelui binar plin:

Arbore binar se numete plin, dac la toate nivelurile toate nodurile sunt prezente,
cu posibil excepie pentru noduri din partea dreapta a ultimului nivel.
Un exemplu de arbore binar plin: Lipsesc dou noduri din partea dreapta a ultimului nivel.
Urmtorul arbore binar nu este plin: Lipsete un nod la ultimul nivel, ns nodul nu este cel mai
drept.
A
B
C
D E
A
B
C
D E
F
+
A

C B
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
80
Arbori binari plini pot fi reprezentai n memoria prin vectori.

Pentru a demonstra lucrul cu arbori binari, construim clasa generic bintree. Pentru concretizarea
clasei bintree poate fi folosit orice clas concret derivat de la clas abstract elem.
//
// c l a s s "b i n t r e e"
//
template <class el> class bintree
{
protected:
bintree *pleft;
bintree *pright;
el *pdata;

public:
bintree()
{
pdata=NULL;
pleft=pright=NULL;
}

bintree(char* file_name)
{
pdata=NULL;
pleft=pright=NULL;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error(File not found!\n);

bintree<el> *pcurrent_nod;
el *pnewel;

while(!feof(pf))
if((pnewel = new el())->fscanf_el(pf)>0)
{
pcurrent_nod=this;
while(pcurrent_nod->pdata!=NULL)
{
if(*pnewel < *(pcurrent_nod->pdata))
{
if(pcurrent_nod->pleft==NULL)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
81
pcurrent_nod->pleft=new bintree<el>();
pcurrent_nod=pcurrent_nod->pleft;
}
else
{
if(pcurrent_nod->pright==NULL)
pcurrent_nod->pright=new bintree<el>();
pcurrent_nod=pcurrent_nod->pright;
}
}
pcurrent_nod->pdata=pnewel;
}
fclose(pf);
}

virtual void show_preorder(const char* opening,
const char* ending)
{
cout << opening;

if(pdata)
pdata->show("", "\n");

if(pleft)
pleft->show_preorder("", "");

if(pright)
pright->show_preorder("", "");

cout << ending;
}

virtual void show_inorder(const char* opening,
const char* ending)
{
cout << opening;

if(pleft)
pleft->show_inorder("", "");

if(pdata)
pdata->show("", "\n");
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
82

if(pright)
pright->show_inorder("", "");

cout << ending;
}

virtual void show_postorder(const char* opening,
const char* ending)
{
cout << opening;

if(pleft)
pleft->show_postorder("", "");

if(pright)
pright->show_postorder("", "");

if(pdata)
pdata->show("", "\n");

cout << ending;
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};
n funcia main() crem un arbore binar ncrcnd-ul din fiierul "Stud.txt" i afim nodurile n
preordine, inordine i postordine:
void main()
{
clrscr();

bintree<usual_elem> btgr("Stud.txt");

btgr.show_preorder("Group in preorder\n","\n");
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
83

btgr.show_inorder("Group in inorder\n","\n");

btgr.show_postorder("Group in postorder\n","\n");

getch();

}
Arborele binar creat va arta astfel:
El corespunde tabelului neordonat structurat arborescent, care a fost creat n capitolul consacrat
tabelelor. Respectiv vom obine afiarea urmtoare:
Group in preorder
Green, 1987, 350
Blue, 1981, 500
Black, 1981, 500
Gray, 1968, 900
Cyan, 1975, 800
Red, 1980, 450
Orange, 1984, 550
Magenta, 1983, 600
White, 1980, 600
Yellow, 1988, 300

Group in inorder
Black, 1981, 500
Blue, 1981, 500
Cyan, 1975, 800
Gray, 1968, 900
Green, 1987, 350
Magenta, 1983, 600
Green
Gray
Red Blue
Orange White
Cyan Yellow Magenta
Black
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
84
Orange, 1984, 550
Red, 1980, 450
White, 1980, 600
Yellow, 1988, 300

Group in postorder
Black, 1981, 500
Cyan, 1975, 800
Gray, 1968, 900
Blue, 1981, 500
Magenta, 1983, 600
Orange, 1984, 550
Yellow, 1988, 300
White, 1980, 600
Red, 1980, 450
Green, 1987, 350

Arbori binari balansai (echilibrai)
AVL-arbore este arbore binar de cutare balansat dup nlime. Adic pentru fiecare nod nlimile
(numrul de niveluri) subarborilor lui se difer nu mai mult de 1.
Denumirea AVL-arbori a fost stabilit dup primele litere ale numelor matematicienilor
G.M.Adelison-Veliskii i E.M.Landis care n 1962 primii au propus utilizarea arborilor binari
balansai.
La arbori binari se aplic operaiile urmtoare:
adugarea unui nod;
nlturarea unui nod;
balansarea dup adugare;
balansarea dup nlturare.
Arborele binar din exemplu precedent s-a primit AVL-arbore.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
85
4.3. Liste

List (engl. list, finite sequence) este o SDD compus dintr-un set de elemente de
una i aceiai structur compus din dou compartimente:
primul compartiment conine informaii legate de acest element. Deobicei
acesta este un pointer la o structur de date extern (ea se numete atom i se
consider indivizibil din punct de vedere a operaiilor asupra listelor), sau un
pointer la o alt list;
al doilea compartiment asigur legturile ntre elementele listei. Coninutul
acestui compartiment depinde de tipul listei.
La list simplu nlnuit (engl. chained list, linked list) compartimentul doi reprezint un pointer la
urmtorul element al listei. La ultimul element acest pointer are valoarea NULL.
n cazul listei nlnuite circular (engl. circular list, ring list), pointer din compartimentul doi la
ultimul element conine adresa primului element al listei.
La liste dublu nlnuite compartimentul doi conine doi pointeri, primul din care indic la
urmtorul element al listei (are valoarea NULL la ultimul element), iar al doilea indic la elementul
precedent al listei (are valoarea NULL la primul element).
La liste dublu nlnuite ciclic compartimentul doi tot conine doi pointeri. Spre deosebire de tipul
precedent primul din aceti doi pointeri n ultimul element conine adresa primului element al listei,
iar al doilea pointer n primul element conine adresa ultimului element al listei.
Operaii cu liste:

NULL
NULL
D
1
D
2
D
n


D
1
D
2
D
n

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
86
crearea listei;
adugarea unui element nou (la nceput, la sfrit, n poziia indicat, dup elementul indicat,
naintea elementului indicat, n locul elementului indicat);
nlturarea unui element (de la nceput, de la sfrit, din poziia indicat, specificat);
cutarea n list;
concatenarea listelor.

Pentru a demonstra lucrul cu liste simplu nlnuite, construim clasa generic list. Pentru
concretizarea clasei list poate fi folosit orice clas concret derivat de la clas abstract elem.
//
// c l a s s "l i s t"
//
template <class el> class list
{
protected:
list<el> *pnext;
el *pdata;

public:
list()
{
pdata=NULL;
pnext=NULL;
}

list(char* file_name)
{
pdata=NULL;
pnext=NULL;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error(File not found!\n);

list<el> *pcurrent_nod;
el *pnewel;

pcurrent_nod=this;
while(!feof(pf))
if((pnewel = new el())->fscanf_el(pf)>0)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
87
{
if(pcurrent_nod->pdata!=NULL)
{
pcurrent_nod->pnext=new list<el>();
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(pf);
}

virtual void list_show(const char* opening, const char* ending)
{
clrscr();
cout << opening;

list *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=1;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
}
}
cout << ending;
cout << "End of List. Press any key ...\n";
getch();
}

int search(el e)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
88
{
int position = -1;

list *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=0;
if(*(pcurrent_nod->pdata)==e)
position=i;
while((position==-1) && (pcurrent_nod=pcurrent_nod->pnext))
{
i++;
if(*(pcurrent_nod->pdata)==e)
position=i;
}
}
return position;
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

n funcia main() crem o list simplu nlnuit ncrcnd-o din fiierul "Stud.txt", afim lista
i artm posibilitatea cutrii, cum am procedat cu tabele:

void main()
{
clrscr();

list<usual_elem> gr("Stud.txt");
gr.list_show("Group:\n","");

char ch='n';
char surname[21];
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
89
while(ch!='y')
{
cout << "Enter a name to search: ";
cin >> surname;
usual_elem e(surname, 2000, 0.0);
int pos=gr.search(e);
if(pos<0)
cout << "No list!\n";
else
cout << "There are in the position " << (pos+1) << endl;
cout << "Done ? (y/n) ";
ch = getch();
cout << endl;
}
}
O versiune de afiare poate arta astfel:
Group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of List. Press any key ...
Enter a name to search: Gray
There are in the position 4
Done ? (y/n)
Enter a name to search: Black
There are in the position 10
Done ? (y/n)
Enter a name to search: Green
There are in the position 1
Done ? (y/n)
Enter a name to search: Magenta
There are in the position 9
Done ? (y/n)
Enter a name to search: Purple
No list!
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
90
Done ? (y/n)

Pentru a demonstra lucrul cu liste dublu nlnuite, construim clasa generic bidirectional_list.
Pentru concretizarea clasei bidirectional_list poate fi folosit orice clas concret derivat de
la clas abstract elem.
//
// c l a s s "b i d i r e c t i o n a l l i s t"
//
template <class el> class bidirectional_list
{
protected:
el *pdata;
bidirectional_list<el> *pnext;
bidirectional_list<el> *ppred;

public:
bidirectional_list()
{
pdata=NULL;
pnext=ppred=NULL;
}

bidirectional_list(char* file_name)
{
pdata=NULL;
pnext=ppred=NULL;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error("File not found!\n");

bidirectional_list<el> *pcurrent_nod;
el *pnewel;

pcurrent_nod=this;
while(!feof(pf))
if((pnewel = new el())->fscanf_el(pf)>0)
{
if(pcurrent_nod->pdata!=NULL)
{
pcurrent_nod->pnext=new bidirectional_list<el>();
pcurrent_nod->pnext->ppred=pcurrent_nod;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
91
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(pf);
}

virtual void list_show(const char* opening, const char* ending)
{
clrscr();
cout << opening;

bidirectional_list<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=1;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
}
}
cout << ending;
cout << "End of List. Press any key ...\n";
getch();
}

virtual void list_invers_show(const char* opening,
const char* ending)
{
clrscr();
cout << opening;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
92

bidirectional_list<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
while(pcurrent_nod->pnext)
pcurrent_nod=pcurrent_nod->pnext;
int i=1;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->ppred)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
}
}
cout << ending;
cout << "End of List. Press any key ...\n";
getch();
}

int search(el e)
{
int position = -1;

bidirectional_list<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=0;
if(*(pcurrent_nod->pdata)==e)
position=i;
while((position==-1) && (pcurrent_nod=pcurrent_nod->pnext))
{
i++;
if(*(pcurrent_nod->pdata)==e)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
93
position=i;
}
}
return position;
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

n funcia main() crem o list dublu nlnuit ncrcnd-o din fiierul "Stud.txt", afim lista
odat n direcia direct i odat n direcia invers, apoi artm posibilitatea cutrii, cum am
procedat cu tabele:
void main()
{
clrscr();

bidirectional_list<usual_elem> gr("Stud.txt");

gr.list_show("Group:\n","\n");

gr.list_invers_show("Group in invers order:\n","");

char ch='n';
char surname[21];
while(ch!='y')
{
cout << "Enter a name to search: ";
cin >> surname;
usual_elem e(surname, 2000, 0.0);
int pos=gr.search(e);
if(pos<0)
cout << "No list!\n";
else
cout << "There are in the position " << (pos+1) << endl;
cout << "Done ? (y/n) ";
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
94
ch = getch();
cout << endl;
}
}
O versiune de afiare poate arta astfel:
Group:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
10. Black, 1981, 500
End of List. Press any key ...
Group in invers order:
1. Black, 1981, 500
2. Magenta, 1983, 600
3. Yellow, 1988, 300
4. Cyan, 1975, 800
5. White, 1980, 600
6. Orange, 1984, 550
7. Gray, 1968, 900
8. Blue, 1981, 500
9. Red, 1980, 450
10. Green, 1987, 350
End of List. Press any key ...
Enter a name to search: Green
There are in the position 1
Done ? (y/n)
Enter a name to search: Black
There are in the position 10
Done ? (y/n)
Enter a name to search: White
There are in the position 6
Done ? (y/n)
Enter a name to search: Purple
No list!
Done ? (y/n)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
95

4.4. Stive
Noiuni generale

Stiv (engl. stack, LIFO list, pushdown stack, pushdown list) este o structur
dinamic de date compus dintr-un set ordonat i finit de elemente de una i
aceiai structur, astfel ca adugarea elementelor noi i accesarea (mai ales
nlturarea) elementelor existente se efectueaz dintr-un capt (numit vrful stivei)
dup principiul ultimul a ntrat primul a ieit (engl. LIFO Last In, First Out ).
La stive se aplic operaiile urmtoare:
inserarea unui element nou n vrful stivei, vrful precedent devine ca urmtorul element
(push);
extragerea unui element din vrful stivei, urmtorul element devine noul vrf (pop);
verificarea dac stiva este vid, adic nu se poate aplica operaia pop (isempty);
verificarea dac stiva este plin, adic nu se poate aplica operaia push (isfull).
Sunt dou metode de realizare a stivelor n memorie operativ:
prin buffer de dimensiune fix;
prin list simpl nlnuit cu adugarea i nlturarea elementelor la nceputul listei.

Realizarea stivelor prin buffer de dimensiune fix
Bufferul reprezint un vector de lungime fix (mrimea, sau adncimea stivei). Tipul elementelor
vectorului depinde de tipul elementelor stivei sau este pointer cu tipul de baz tip elementelor
stivei, cum este artat schematic n figura urmtoare.
Stiva goal de dimensiune n

Cmpul size conine dimensiunea stivei. El se iniializeaz n momentul cnd se creeaz stiva i
mai mult nu se schimb.

0 1 2 3 4 n-2 n-1
size top
0
n
buffer
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
96
Vectorul buffer reprezint spaiul pentru nscriere n stiv. Memoria pentru el se aloc n
momentul cnd se creeaz stiva.
Cmpul top ndic vrful stivei (prima celul disponibil pentru nscriere). El se iniializeaz n
momentul cnd se creeaz stiva i mai departe se actualizeaz la fiecare nscriere (push) i fiecare
extragere (pop).
De exemplu, dup trei nscrieri consecutive (push(A), push(B), push(C)) stiva va arta astfel:
Stiva cu trei elemente

Dac mai departe va urma o extragere (pop), ea va avea rezultatul C, iar stiva va arta astfel:
Stiva dup o extragere

Pentru a demonstra lucrul cu stive n form de buffer de dimensiune fix, crem clasa generic
stackFB care poate fi concretizat cu orice clas concret derivat de la clasa abstract elem:
//
// c l a s s "s t a c k f i x e d b u f f e r"
//
template <class el> class stackFB
{
protected:
el *buffer;
int size, top;

public:
stackFB<el>(int init_size=100)
{
size=init_size;
buffer = new el[size];

0 1 2 3 4 n-2 n-1
size top
3
n
buffer A B C

0 1 2 3 4 n-2 n-1
size top
2
n
buffer A B
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
97
top=0;
}

stackFB<el>(char* file_name, int init_size=100)
{
size=init_size;
buffer = new el[size];
top=0;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error("File not found!\n");

el newel;

while(!feof(pf))
if(newel.fscanf_el(pf)>0)
push(newel);
fclose(pf);
}

~stackFB<el>()
{
delete buffer;
}

int isempty(){return top==0;}

int isfull(){return top==size;}

void push(el newel)
{
if(!isfull())
buffer[top++]=newel;
else
error("Stack is full!\n");
}

el pop()
{
if(top)
return buffer[--top];
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
98
else
error("Stack is empty!\n");
}

virtual void stack_show(const char* opening, const char* ending)
{
clrscr();
cout << opening;

if(!isempty())
{
int i=1;
cout << i << ". ";
int current=top-1;
buffer[current].show("", "\n");
while(--current>=0)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
buffer[current].show("", "\n");
}
}

cout << ending;
cout << "End of Stack. Press any key ...\n";
getch();
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
99
}
};
n funcia main() vom crea o stiv n form de buffer cu adncimea 100 elemente de tip
usual_elem, ncrcnd-o din fiierul "Stud.txt". Apoi vom afia coninutul stivei, vom goli stiva
pe pai, vom pune dou elemente n stiv i ne vom convinge c ele vor fi extrase din stiv n
ordinea invers:
void main()
{
clrscr();

stackFB<usual_elem> gr("Stud.txt", 100);
gr.stack_show("Group in stack:\n","");

cout << "\nExtracting by one:\n";
char ch;
while(!gr.isempty())
{
cout << "Press any key...\n";
ch = getch();
usual_elem extracted_el;
extracted_el = gr.pop();
extracted_el.show("","\n");
}
cout << "Stack is empty! Press any key...\n";
ch = getch();

gr.push(usual_elem("Purple", 1985, 400));
gr.push(usual_elem("Violet", 1984, 500));

cout << endl;
gr.pop().show("","\n");
gr.pop().show("","\n");
cout << "Press any key...\n";

ch = getch();
cout << endl;
}
Afirile vor arta astfel:
Group in stack:
1. Black, 1981, 500
2. Magenta, 1983, 600
3. Yellow, 1988, 300
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
100
4. Cyan, 1975, 800
5. White, 1980, 600
6. Orange, 1984, 550
7. Gray, 1968, 900
8. Blue, 1981, 500
9. Red, 1980, 450
10. Green, 1987, 350
End of Stack. Press any key ...

Extracting by one:
Press any key...
Black, 1981, 500
Press any key...
Magenta, 1983, 600
Press any key...
Yellow, 1988, 300
Press any key...
Cyan, 1975, 800
Press any key...
White, 1980, 600
Press any key...
Orange, 1984, 550
Press any key...
Gray, 1968, 900
Press any key...
Blue, 1981, 500
Press any key...
Red, 1980, 450
Press any key...
Green, 1987, 350
Stack is empty! Press any key...

Violet, 1984, 500
Purple, 1985, 400
Press any key...

Realizarea stivelor prin list
Operaiile de adugare i extragere se efectueaz la nceputul listei care se folosete pentru
reprezentarea stivei n memorie operativ.
Stiva goal n form de list va arta astfel:
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
101
Stiva goal n form de list simplu nlniit

Dup trei nscrieri consecutive (push(A), push(B), push(C)) stiva va arta astfel:
Stiva cu trei elemente

Dac mai departe va urma o extragere (pop), ea va avea rezultatul C, iar stiva va arta astfel:
Stiva dup o extragere

Pentru a demonstra lucrul cu stive n form de liste cu adugarea la nceput, crem clasa generic
stackL care poate fi concretizat cu orice clas concret derivat de la clasa abstract elem:
//
// c l a s s "s t a c k l i s t"
//
template <class el> class stackL
{
protected:
el *pdata;
stackL<el> *pnext;

public:
stackL<el>()
NULL
NULL
pdata
pnext





NULL
C A B
pdata
pnext



NULL
B A
pdata
pnext
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
102
{
pdata=NULL;
pnext=NULL;
}

stackL<el>(char* file_name)
{
pdata=NULL;
pnext=NULL;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error("File not found!\n");

el *pnewel;

while(!feof(pf))
if((pnewel=new el())->fscanf_el(pf)>0)
push(*pnewel);
fclose(pf);
}

~stackL<el>()
{

}

int isempty(){return pdata==NULL;}

int isfull(){return 0;}

void push(el &newel)
{
if(!isfull())
{
if(this->pdata)
{
stackL<el> *ptemp=new stackL<el>;
ptemp->pdata=this->pdata;
ptemp->pnext=this->pnext;
this->pnext=ptemp;
}
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
103
this->pdata=&newel;
}
else
error("Stack is full!");
}

el &pop()
{
if(!isempty())
{
el *pret=this->pdata;

if(this->pnext)
{
stackL<el> *ptemp=this->pnext;
this->pnext=ptemp->pnext;
this->pdata=ptemp->pdata;
delete ptemp;
}
else
this->pdata=NULL;

return *pret;
}
else
error("Stack is empty!");
}

virtual void stack_show(const char* opening, const char* ending)
{
clrscr();
cout << opening;

if(!isempty())
{
int i=1;
cout << i << ". ";
stackL<el> *pcurrent=this;
pcurrent->pdata->show("", "\n");
while((pcurrent=pcurrent->pnext)!=NULL)
{
if(i>0 && i%20==0)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
104
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
pcurrent->pdata->show("", "\n");
}
}

cout << ending;
cout << "End of Stack. Press any key ...\n";
getch();
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

n versiunea precedent a funciei main() n loc de stiv n form de buffer crem o stiv n form
de list:
stackL<usual_elem> gr("Stud.txt");
Afiarea fa fi exact aceiai ca i n versiunea precedent.

Utilizarea stivelor la parcurgerea arborilor binari
Mai departe vom demonstra utilizarea stivelor pentru parcurgerea arborilor binari. n capitolul
consacrat arborilor binari toate parcurgerile (preordine, inordine, postordine) au fost realizate prin
funcii recursive. Acum vom folosi stive. Cu acest scop descriem din nou clasele generice stackFB
i stackL simplificndu-le n aa mod, ca ele s poat fi concretizate cu orice clase concrete, ci nu
neaprat cu cele derivate de la clasa elem. Pentru asta eliminm din versiunile precedente ale
claselor stackFB i stackL constructorul care ncarc stiva din fiierul indicat i funcia care
afieaz coninutul stivei. Versiunile simplificate ale claselor stackFB i stackL vor arta astfel:
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
105
//
// c l a s s "s t a c k f i x e d b u f f e r"
//
template <class el> class stackFB
{
protected:
el *buffer;
int size, top;

public:
stackFB<el>(int init_size=100)
{
size=init_size;
buffer = new el[size];
top=0;
}

~stackFB<el>()
{
delete buffer;
}

int isempty(){return top==0;}

int isfull(){return top==size;}

void push(el newel)
{
if(!isfull())
buffer[top++]=newel;
else
error("Stack is full!\n");
}

el pop()
{
if(top)
return buffer[--top];
else
error("Stack is empty!\n");
}

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
106
protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

//
// c l a s s "s t a c k l i s t"
//
template <class el> class stackL
{
protected:
el *pdata;
stackL<el> *pnext;

public:
stackL<el>()
{
pdata=NULL;
pnext=NULL;
}

~stackL<el>()
{

}

int isempty(){return pdata==NULL;}

int isfull(){return 0;}

void push(el &newel)
{
if(!isfull())
{
if(this->pdata)
{
stackL<el> *ptemp=new stackL<el>;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
107
ptemp->pdata=this->pdata;
ptemp->pnext=this->pnext;
this->pnext=ptemp;
}
this->pdata=&newel;
}
else
error("Stack is full!");
}

el &pop()
{
if(!isempty())
{
el *pret=this->pdata;

if(this->pnext)
{
stackL<el> *ptemp=this->pnext;
this->pnext=ptemp->pnext;
this->pdata=ptemp->pdata;
delete ptemp;
}
else
this->pdata=NULL;

return *pret;
}
else
error("Stack is empty!");
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
108
Declarm clasa generic bintree_stack care va putea concretizat cu orice clas concret derivat
de la clasa abstract elem. Clasa bintree_stack va fi asemntoare cu clasa bintree deja
cercetat. Spre deosebire de ultima n clasa bintree_stack parcurgerile vor fi realizate prin
utilizarea stivelor i nu prin funciile recursive. La realizarea parcurgerilor n inordine i postordine,
vom fi nevoii s nscriem n stiv nu numai nodul curent i informaii nsoitoare despre tipul lui
(rdcin sau nod). Cu acest scop va fi declarat nc o clas auxiliar stack_elem pentru a
reprezenta elementul extins al stivei.
//
// c l a s s "b i n t r e e s t a c k"
//
template <class el> class bintree_stack
{
protected:
bintree_stack *pleft;
bintree_stack *pright;
el *pdata;

public:
bintree_stack()
{
pdata=NULL;
pleft=pright=NULL;
}

bintree_stack(char* file_name)
{
pdata=NULL;
pleft=pright=NULL;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error("File not found!\n");

bintree_stack *pcurrent_nod;
el *pnewel;

while(!feof(pf))
if((pnewel = new el())->fscanf_el(pf)>0)
{
pcurrent_nod=this;
while(pcurrent_nod->pdata!=NULL)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
109
if(*pnewel < *(pcurrent_nod->pdata))
{
if(pcurrent_nod->pleft==NULL)
pcurrent_nod->pleft=new bintree_stack();
pcurrent_nod=pcurrent_nod->pleft;
}
else
{
if(pcurrent_nod->pright==NULL)
pcurrent_nod->pright=new bintree_stack();
pcurrent_nod=pcurrent_nod->pright;
}
}
pcurrent_nod->pdata=pnewel;
}
fclose(pf);
}

virtual void show_preorderFB(const char* opening,
const char* ending)
{
stackFB<bintree_stack<el>*> st(100);
st.push(this);

cout << opening;

while(!st.isempty())
{
bintree_stack<el>* pcur=st.pop();
if(pcur->pright)
st.push(pcur->pright);
if(pcur->pleft)
st.push(pcur->pleft);
if(pcur->pdata)
pcur->pdata->show("","\n");
}
cout << ending;
}

virtual void show_inorderFB(const char* opening,
const char* ending)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
110
stackFB<stack_elem<el> > st(100);
stack_elem<el> stel;
stel.p=this;
stel.t='r';

st.push(stel);

cout << opening;

while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pright)
{
stel.p=(current.p)->pright;
stel.t='r';
st.push(stel);
}
if((current.p)->pdata)
{
stel.p=current.p;
stel.t='n';
st.push(stel);
}
if((current.p)->pleft)
{
stel.p=(current.p)->pleft;
stel.t='r';
st.push(stel);
}
}
}
cout << ending;
}

virtual void show_postorderFB(const char* opening,
const char* ending)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
111
stackFB<stack_elem<el> > st(100);
stack_elem<el> stel;
stel.p=this;
stel.t='r';

st.push(stel);

cout << opening;

while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pdata)
{
stel.p=current.p;
stel.t='n';
st.push(stel);
}
if((current.p)->pright)
{
stel.p=(current.p)->pright;
stel.t='r';
st.push(stel);
}
if((current.p)->pleft)
{
stel.p=(current.p)->pleft;
stel.t='r';
st.push(stel);
}
}
}
cout << ending;
}

virtual void show_preorderL(const char* opening,
const char* ending)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
112
stackL<bintree_stack<el>*> st;
st.push(this);

cout << opening;

while(!st.isempty())
{
bintree_stack<el>* pcur=st.pop();
if(pcur->pright)
st.push(pcur->pright);
if(pcur->pleft)
st.push(pcur->pleft);
if(pcur->pdata)
pcur->pdata->show("","\n");
}
cout << ending;
}

virtual void show_inorderL(const char* opening,
const char* ending)
{
stackL<stack_elem<el> > st;
stack_elem<el>* pstel = new stack_elem<el>;
pstel->p=this;
pstel->t='r';

st.push(*pstel);

cout << opening;

while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pright)
{
pstel = new stack_elem<el>;
pstel->p=(current.p)->pright;
pstel->t='r';
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
113
st.push(*pstel);
}
if((current.p)->pdata)
{
pstel = new stack_elem<el>;
pstel->p=current.p;
pstel->t='n';
st.push(*pstel);
}
if((current.p)->pleft)
{
pstel = new stack_elem<el>;
pstel->p=(current.p)->pleft;
pstel->t='r';
st.push(*pstel);
}
}
}
cout << ending;
}

virtual void show_postorderL(const char* opening,
const char* ending)
{
stackL<stack_elem<el> > st;
stack_elem<el>* pstel = new stack_elem<el>;
pstel->p=this;
pstel->t='r';

st.push(*pstel);

cout << opening;

while(!st.isempty())
{
stack_elem<el> current=st.pop();
if(current.t=='n')
(current.p)->pdata->show("","\n");
else
{
if((current.p)->pdata)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
114
pstel = new stack_elem<el>;
pstel->p=current.p;
pstel->t='n';
st.push(*pstel);
}
if((current.p)->pright)
{
pstel = new stack_elem<el>;
pstel->p=(current.p)->pright;
pstel->t='r';
st.push(*pstel);
}
if((current.p)->pleft)
{
pstel = new stack_elem<el>;
pstel->p=(current.p)->pleft;
pstel->t='r';
st.push(*pstel);
}
}
}
cout << ending;
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};
Urmeaz declararea clasei-structurii generice stack_elem cu dou cmpuri. Acestea sunt un pointer
la un nod al arborelui, i un caracter cu valorile posibile 'r' i 'n'.
template <class el> struct stack_elem
{
bintree_stack<el> *p;
char t;
};
n funcia main() crem un arbore binar, ncrcnd-ul din fiierul "Stud.txt", apoi afim
consecutiv nodurile arborelui acesta n preordine, inordine i postordine de dou ori. Odat cu
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
115
ajutorul stivei n form de bufferul de lungime fix, i a doua oar cu ajutorul stivei n form de list
simplu nlnuit.
void main()
{
clrscr();

bintree_stack<usual_elem> btgr("Stud.txt");

btgr.show_preorderFB("Group in preorder with buffer\n","\n");

btgr.show_inorderFB("Group in inorder with buffer\n","\n");

btgr.show_postorderFB("Group in postorder with buffer\n","\n");

btgr.show_preorderL("Group in preorder with list\n","\n");

btgr.show_inorderL("Group in inorder with list\n","\n");

btgr.show_postorderL("Group in postorder with list\n","\n");

getch();
}
Afirile vor coincide cu afirile precedente, i vor arta astfel:
Group in preorder with buffer
Green, 1987, 350
Blue, 1981, 500
Black, 1981, 500
Gray, 1968, 900
Cyan, 1975, 800
Red, 1980, 450
Orange, 1984, 550
Magenta, 1983, 600
White, 1980, 600
Yellow, 1988, 300

Group in inorder with buffer
Black, 1981, 500
Blue, 1981, 500
Cyan, 1975, 800
Gray, 1968, 900
Green, 1987, 350
Magenta, 1983, 600
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
116
Orange, 1984, 550
Red, 1980, 450
White, 1980, 600
Yellow, 1988, 300

Group in postorder with buffer
Black, 1981, 500
Cyan, 1975, 800
Gray, 1968, 900
Blue, 1981, 500
Magenta, 1983, 600
Orange, 1984, 550
Yellow, 1988, 300
White, 1980, 600
Red, 1980, 450
Green, 1987, 350

Group in preorder with list
Green, 1987, 350
Blue, 1981, 500
Black, 1981, 500
Gray, 1968, 900
Cyan, 1975, 800
Red, 1980, 450
Orange, 1984, 550
Magenta, 1983, 600
White, 1980, 600
Yellow, 1988, 300

Group in inorder with list
Black, 1981, 500
Blue, 1981, 500
Cyan, 1975, 800
Gray, 1968, 900
Green, 1987, 350
Magenta, 1983, 600
Orange, 1984, 550
Red, 1980, 450
White, 1980, 600
Yellow, 1988, 300

Group in postorder with list
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
117
Black, 1981, 500
Cyan, 1975, 800
Gray, 1968, 900
Blue, 1981, 500
Magenta, 1983, 600
Orange, 1984, 550
Yellow, 1988, 300
White, 1980, 600
Red, 1980, 450
Green, 1987, 350
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
118

4.5. Cozi
Noiuni generale

Coad (engl. queue, FIFO list, pushup stack, pushup list) este o structur dinamic
de date compus dintr-un set ordonat i finit de elemente de una i aceiai
structur, astfel ca adugarea elementelor noi se efectueaz numai la sfritul
setului, iar accesarea (mai ales extragerea) elementelor existente se efectueaz
numai de la nceputul setului dup principiul primul a ntrat primul a ieit
(engl. FIFO First In, First Out ).
La cozi se aplic operaiile urmtoare:
inserarea unui element nou n coad, ultimul precedent devine ca penultimul (put);
extragerea unui element din coad, urmtorul element devine noul prim (get);
verificarea dac coada este vid (isempty), adic nu se poate aplica operaia get;
verificarea dac coada este plin (isfull), adic nu se poate aplica operaia put.
n dispozitive coada poate fi realizat ca o form special de memorie fr adrese pentru crearea
zonei de tampon de vitez mare pentru schimbul de date ntre fluxul de ntrare sau ieire care se
formeaz n timpul real i unitatea inerioas de memorizare.
Exemple:
zona de tampon (bufferul) tastaturii;
coad de taskuri de deservire de ctre sistemul de operare.
Sunt mai multe metode de realizare a cozilor n memorie operativ:
prin bufferul ciclic de dimensiune fix;
prin list simpl nlnuit dotat cu un pointer cu adresa ultimului element adugat;
prin list simplu nlnuit cu proprietatea c adugarea se face la sfritul listei iar extragerea -
de la nceputul listei.

Realizarea cozilor prin buffer ciclic de dimensiune fix
Bufferul reprezint un vector de lungime fix (mrimea, sau adncimea cozii). Tipul elementelor
vectorului depinde de tipul elementelor cozii sau este pointer cu tipul de baz tip elementelor
cozii, cum este artat schematic n figura urmtoare.


Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
119
Coada goal de dimensiune n

Cmpul size conine dimensiunea cozii. El se iniializeaz n momentul cnd se creeaz coada i
mai mult nu se schimb.
Vectorul buffer reprezint spaiul pentru nscriere n coad. Memoria pentru el se aloc n
momentul cnd se creeaz coada.
Cmpul nextin ndic prima celul disponibil pentru nscriere. El se iniializeaz n momentul
cnd se creeaz coada i mai departe se actualizeaz la fiecare nscriere (put).
Cmpul nextout ndic primul element disponibil pentru extragere. El se iniializeaz n momentul
cnd se creeaz coada i mai departe se actualizeaz la fiecare extragere (pop).
De exemplu, dup trei nscrieri consecutive (put(A), put(B), put(C)) coada va arta astfel:
Coada cu trei elemente

Dac mai departe va urma o extragere (get), ea va avea rezultatul A, iar coada va arta astfel:


0 1 2 3 4 n-2 n-1
size nextin
0
n
buffer
nextout
0
count 0

0 1 2 3 4 n-2 n-1
size nextin
3
n
buffer
nextout
0
count 3
A B C
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
120
Coada dup o extragere

Pentru a demonstra lucrul cu cozi n form de buffer ciclic de dimensiune fix, crem clasa generic
queueCB care poate fi concretizat cu orice clas concret derivat de la clasa abstract elem:
//
// c l a s s "q u e u e c i r c u l a r b u f f e r"
//
template <class el> class queueCB
{
protected:
el *buffer;
int size, nextin, nextout, count;
public:

queueCB(int init_size=100)
{
size=init_size;
buffer = new el[size];
nextin=nextout=count=0;
}

queueCB(char* file_name, int init_size)
{
size=init_size;
buffer = new el[size];
nextin=nextout=count=0;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error("File not found!\n");


0 1 2 3 4 n-2 n-1
size nextin
3
n
buffer
nextout
1
count 2

B C
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
121
el newel;

while(!feof(pf))
if(newel.fscanf_el(pf)>0)
put(newel);
fclose(pf);
}

~queueCB()
{
delete buffer;
}

int isempty(){return count==0;}

int isfull(){return count==size;}

void put(el newel)
{
if(count++ < size)
{
buffer[nextin]=newel;
nextin=++nextin%size;
}
else
error("Queue is full!");
}

el get()
{
if(count-- > 0)
{
int outpos = nextout;
nextout=++nextout%size;
return buffer[outpos];
}
else
error("Queue is empty!");
}

virtual void queue_show(const char* opening, const char* ending)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
122
clrscr();
cout << opening;

if(count>0)
{
int i=1;
cout << i << ". ";
int current=nextout;
buffer[current].show("", "\n");
while((++current%size)!=nextin)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
buffer[current].show("", "\n");
}
}
cout << ending;

cout << "End of Queue. Press any key ...\n";
getch();
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

n funcia main() vom crea o coad n form de buffer ciclic cu adncimea 100 elemente de tip
usual_elem, ncrcnd-o din fiierul "Stud.txt". Apoi vom afia coninutul cozii, vom goli coada
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
123
pe pai, vom pune dou elemente n coad i ne vom convinge c ele vor fi extrase din stiv n
ordinea de nscriere:
void main()
{
clrscr();

queueCB<usual_elem> gr("Stud.txt", 100);
gr.queue_show("Group in queue:\n","");

cout << "\nExtracting by one:\n";
while(!gr.isempty())
{
cout << endl << "Press any key...\n";
getch();
usual_elem extel;
extel = gr.get();
extel.show("","");
}
cout << "\nQueue is empty! Press any key...\n";

gr.put(usual_elem("Purple", 1985, 400));
gr.put(usual_elem("Violet", 1984, 500));

cout << endl;
gr.get().show("","\n");
gr.get().show("","\n");
cout << "Press any key...\n";

getch();
}

Afirile vor arta astfel:
Group in queue:
1. Green, 1987, 350
2. Red, 1980, 450
3. Blue, 1981, 500
4. Gray, 1968, 900
5. Orange, 1984, 550
6. White, 1980, 600
7. Cyan, 1975, 800
8. Yellow, 1988, 300
9. Magenta, 1983, 600
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
124
10. Black, 1981, 500
End of Queue. Press any key ...

Extracting by one:

Press any key...
Green, 1987, 350
Press any key...
Red, 1980, 450
Press any key...
Blue, 1981, 500
Press any key...
Gray, 1968, 900
Press any key...
Orange, 1984, 550
Press any key...
White, 1980, 600
Press any key...
Cyan, 1975, 800
Press any key...
Yellow, 1988, 300
Press any key...
Magenta, 1983, 600
Press any key...
Black, 1981, 500
Queue is empty! Press any key...

Purple, 1985, 400
Violet, 1984, 500
Press any key...

Realizarea cozilor prin list
Operaiile de adugare se efectueaz la nceputul listei iar de extragere la sfritul listei care se
folosete pentru reprezentarea cozii n memorie operativ.
Coada goal n form de list va arta astfel:
Coada goal n form de list simplu nlniit

NULL
NULL
pdata
pnext
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
125
Dup trei nscrieri consecutive (put(A), put(B), put(C)) coada va arta astfel:
Coada cu trei elemente

Dac mai departe va urma o extragere (get), ea va avea rezultatul A, iar coada va arta astfel:
Coada dup o extragere

Pentru a demonstra lucrul cu cozi n form de liste cu extragerea de la nceputul listei i adugarea
la sfritul listei, crem clasa generic queueL care poate fi concretizat cu orice clas concret
derivat de la clasa abstract elem:
//
// c l a s s "q u e u e l i s t"
//
template <class el> class queueL
{
protected:
el *pdata;
queueL<el> *pnext;

public:

queueL()
{
pdata=NULL;
pnext=NULL;
}





NULL
A C B
pdata
pnext



NULL
B C
pdata
pnext
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
126

queueL(char* file_name)
{
pdata=NULL;
pnext=NULL;

FILE* pf=fopen(file_name, "rt");
if(!pf)
error("File not found!\n");

queueL *pcurrent_nod=this;
el *pnewel;

while(!feof(pf))
if((pnewel = new el())->fscanf_el(pf)>0)
{
if(pcurrent_nod->pdata!=NULL)
{
pcurrent_nod->pnext=new queueL<el>();
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
fclose(pf);
}

~queueL()
{

}

int isempty(){return pdata==NULL;}

int isfull(){return 0;}

void put(el newel)
{
if(!isfull())
{
queueL<el> *pcurrent_nod=this;
el *pnewel=new el();
*pnewel=newel;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
127
if(pcurrent_nod->pdata)
{
while(pcurrent_nod->pnext)
pcurrent_nod=pcurrent_nod->pnext;
pcurrent_nod->pnext=new queueL<el>();
pcurrent_nod=pcurrent_nod->pnext;
}
pcurrent_nod->pdata=pnewel;
}
else
error("Queue is full!");
}

el get()
{
if(!isempty())
{
el* pret=pdata;
queueL<el>* pdel=pnext;
if(pdel)
{
pdata=pnext->pdata;
pnext=pnext->pnext;
delete pdel;
}
else
pdata=NULL;
return *pret;
}
else
error("Queue is empty!");
}
virtual void queue_show(const char* opening, const char* ending)
{
clrscr();
cout << opening;

queueL<el> *pcurrent_nod=this;
if(pcurrent_nod->pdata)
{
int i=1;
cout << i << ". ";
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
128
pcurrent_nod->pdata->show("", "\n");
while(pcurrent_nod=pcurrent_nod->pnext)
{
if(i>0 && i%20==0)
{
cout << "Press any key to continue...\n";
getch();
clrscr();
cout << opening;
}
i++;
cout << i << ". ";
pcurrent_nod->pdata->show("", "\n");
}
}
cout << ending;

cout << "End of Queue. Press any key ...\n";
getch();
}

protected:
void error(char* message)
{
cerr << message;
cout << "Press any key to fin...\n";
getch();
exit(1);
}
};

n versiunea precedent a funciei main() n loc de coad n form de buffer ciclic crem o coad n
form de list:
queueL<usual_elem> gr("Stud.txt");
Afiarea fa fi exact aceiai ca i n versiunea precedent.


Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
129

5. MATRICE
5.1. Noiune de matrice
Definiie:
Prin matrice vom nelege structura de date care este compus dintr-un set finit
de elemente de unul i acelai tip, alocate astfel ca poziia fiecrui din elementele
matricei se determin univoc printr-un set aranjat de numere ntregi (indici).
Indicii asigur posibilitatea accesului direct la fiecare element al matricei.
Exemplu. Utiliznd notaia limbajului Pascal, elementul matricei A poate fi notat
A[i1,i2,i3,i4], iar n limbajul C A[i1][i2][i3][i4].
Cantitatea numerelor (indicilor) ce intr n setul aranjat de numere ntregi stabilete dimensiunea
matricei. Dac acest set conine n numere, atunci matricea se numete n-dimensional.
Astfel, numerele i
1
, i
2
,,i
n
, ce intr n setul aranjat se numesc indici. Fiecare indice are domeniul
propriu de valori admisibile, definit printr-o metod sau alta, i care poate fi compus din cteva
subintervale care nu se intersecteaz ntre ele.
O subclas important a matricelor care se folosete att n compilatoare, ct i n limbaje de
programare este clasa de matrice dreptunghiulare. La matricele dreptunghiulare fiecare indice are
intervalul de valori admisibile constant i continue.
Exemplu din Pascal.
Var
A: array[2..4, -3..-1, 0..1] of char;
A fost declarat matricea dreptunghiular, 3-dimensional, cu elementele de tipul char.
Intervalele de valori ale indicilor sunt respectiv:
[2,4] cu trei valori posibile (2, 3, 4) pentru primul indice;
[-3,-1] cu trei valori posibile (-3, -2, -1) pentru al doilea indice;
[0,1] cu dou valori posibile (0, 1) pentru ultimul indice.
Adresarea la un element concret arat astfel: A[4,-2,1].
Exemplu din C.
unsigned char A[3][3][2];
A fost declarat matricea dreptunghiular, 3-dimensional, cu elementele de tipul unsigned char.
Intervalele de valori ale indicilor sunt respectiv:
[0,2] cu trei valori posibile (0, 1, 2) pentru primul indice;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
130
[0,2] cu trei valori posibile (0, 1, 2) pentru al doilea indice;
[0,1] cu dou valori posibile (0, 1) pentru ultimul indice.
Adresarea la un element concret arat astfel: A[2][1][1].

5.2. Structura intern de memorie vector
Definiie:
Vectorul reprezint un set finit de elemente de unul i acelai tip, alocate fizic n
memoria calculatorului, consecutiv unul dup altul fr spaii.
Orice vector este definit prin adresa de baz (coincide cu adresa primului element al vectorului),
dimensiunea unui element i lungimea vectorului (numrul de elemente).
Fiecare element aparte al vectorului poate fi adresat nemijlocit prin indicarea adresei de baz i a
numrului de ordine al elementului n vector.
Practic vectorul corespunde structurii abstracte de date, cum este matricea unidimensional. n
majoritatea cazurilor matricele unidimensionale, n memoria calculatorului, sunt reflectate n
vectori.
n limbajul Pascal vectorul compus din 18 elemente de tipul char poate fi declarat astfel:
Var
V: array[0..18] of char;
cu elementele V[i], i=0,1,2,17.
n limbajul C:
unsigned char V[18];
de asemenea, cu elementele V[i], i=0,1,2,17.

5.3. Reprezentarea matricelor n memoria operativ
n memoria calculatorului matricele, aproape ntotdeauna, sunt reflectate n vectori. n cazul
matricelor rare (matricelor cu numrul redus de elemente nenule) poate fi folosit metoda de
reprezentare prin tabele de nregistrri pentru elemente nenule. ns astfel de cazuri n practic se
ntlnesc rar, de aceea n continuare vom cerceta numai reprezentarea matricelor dreptunghiulare
prin vectori.
Matricea unidimensional B cu intervalul indicelui [l, h], lh, n mod normal se reflect n vector
astfel:
B[i] V[i-l], i=l, l+1, , h,
unde V este adresa de nceput (de alocare) a vectorului n MO, adic V este adresa de baz, iar i-l
este deplasarea spre elementul cu indicele i.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
131
Matricele dreptunghiulare de dimensiuni mai mari de 1, de obicei se reflect n vectori prin una din
urmtoarele dou metode:
1. Mai repede se schimb ultimul indice (aa-numit metod pe linii, denumirea provine de la
matricea de dimensiune 2);
2. Mai repede se schimb primul indice (aa-numit metod pe coloane, denumirea provine de la
matricea de dimensiune 2).

5.4. Reprezentarea matricelor pe linii
Vom ncepe cu un exemplu.
Fie A matricea de dimensiune 3 cu intervalele indicilor:
[2, 4] pentru i
1
;
[-3,-1] pentru i
2
;
[0, 1] pentru i
3
.
n total matricea A va avea 332=18 elemente, care vor fi alocate n memoria operativ ncepnd
de la o adres oarecare V n felul urmtor:
Se vede c ntr-adevr ultimul indice se schimb mai des.
Structura logic a matricei A este urmtoarea:

Adic matricea A reprezint trei matrice bidimensionale 32.
A B C D E F G H I J K L M N O P Q R
V[0] V[1] V[2] V[3] V[4] V[5] V[6] V[7] V[8] V[9] V[10] V[11] V[12] V[13] V[14] V[15] V[16] V[17]
2
-3
0
2
-3
1

2
-2
0
2
-2
1
2
-1
0

2
-1
1

3
-3
0
3
-3
1
3
-2
0

3
-2
1

3
-1
0
3
-1
1
4
-3
0

4
-3
1

4
-2
0
4
-2
1
4
-1
0

4
-1
1
A B
C D
E F
G H
I J
K L
M N
O P
Q R
i
1
=2 i
1
=3 i
1
=4
i
3
i
2

0 1
-3
-2
-1
i
3
i
2

0 1 i
3
i
2

0 1
-3
-2
-1
-3
-2
-1
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
132
n cazul general pentru, o matrice de dimensiune n cu elementele alocate pe linii, cu intervalele
indicilor
[l
1
, h
1
] pentru indicele i
1
,
[l
2
, h
2
] pentru indicele i
2
,

[l
n
, h
n
] pentru indicele i
n
,
elementul A[i
1
, i
2
,, i
n
] se reflect n elementul
V[

=
n
j 1
( i
j
-l
j
) D
j
] al vectorului V, unde D
j
sunt numere care se calculeaz n ordinea invers, dup
urmtoarea formul recurent:
D
n
=1;
D
j
=(h
j+1
-l
j+1
+1)D
j+1
, j=n-1, n-2,,1.
Revenind la exemplul nostru, vom lua i
1
=4, i
2
=-2, i
3
=1.
Amintim c n=3,
l
1
=2, h
1
=4,
l
2
=-3, h
2
=-1,
l
3
=0, h
3
=1,
atunci
D
3
=1,
D
2
=(1-0+1)1=21=2,
D
1
=(-1-(-3)+1)2=32=6,
i
A[i
1
, i
2
,, i
n
] V[(4-2)6+(-2-(-3))2+(1-0)1]= V[26+12+11]=V[12+2+1]=V[15]=P.
n tabelul urmtor este artat cte operaii de tipul + i cte operaii de tipul trebuie de efectuat
accesnd un element al matricei A:
Etapa +
Calcularea D
j
, j=3,2,1 4 2
Calcularea deplasrii 5 3
Total 9 5

Exerciiu. Apreciai cte operaii de tip adunare i cte operaii de tip nmulire se cheltuie la
accesarea unui element al matricei dreptunghiulare de ordinul n.
Pentru a demonstra lucrul cu matricele dreptunghiulare, vom avea nevoie de o clas concret de
reprezentare a elementelor matricelor respective. Declarm n baza clasei abstracte elem clasa
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
133
concret character, una dintre cele mai simple clase de reprezentare a elementelor unei structuri
de date.

//
// c l a s s "c h a r a c t e r"
//
class character : public elem
{
protected:

unsigned char c;

public:

character()
{
c='\0';
}

character(unsigned char init_c)
{
c=init_c;
}

virtual int fscanf_el(FILE *f)
{
return fscanf(f, "%c", &c);
}

virtual void show(const char* opening, const char* ending)
{
printf("%s", opening);
if(c)
printf("%c", c);
printf("%s", ending);
}

virtual int free()
{
return c=='\0';
}

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
134
virtual int cmp(elem& e2)
{
return this->c > ((character&)e2).c ?
1 : this->c < ((character&)e2).c ? -1 : 0;
}
};
n continuare, pentru a demonstra utilizarea matricelor dreptunghiulare de ordinul 3 alocate pe
linii, declarm clasa generic matrix3l:
//
// c l a s s "m a t r i x 3 l"
//
template <class el> class matrix3l
{
protected:

el *V; // pointer to matrix reprezentation vector
int l1, h1;
int l2, h2;
int l3, h3;

unsigned long nopadd, nopmul;

public:

matrix3l(int l1, int h1, int l2, int h2, int l3, int h3)
{
this->l1=l1;
this->h1=h1;
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;

int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];

nopadd=0, nopmul=0;
}

matrix3l(char* file_name, int l1, int h1, int l2, int h2, int l3, int h3)
{
this->l1=l1;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
135
this->h1=h1;
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;

int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];

FILE* pf;
pf=fopen(file_name, "rt");

for(int i=0; i<nel; i++)
V[i].fscanf_el(pf);
fclose(pf);

nopadd=0, nopmul=0;
}

virtual el& elem(int i1, int i2, int i3)
{
int D1, D2, D3;

nopadd+=9, nopmul+=5;

D3=1;
D2=(h3-l3+1)*D3;
D1=(h2-l2+1)*D2;
return V[(i1-l1)*D1+(i2-l2)*D2+(i3-l3)*D3];
}

virtual void show(const char* opening, const char* ending)
{
clrscr();
printf("%s", opening);
int i1, i2, i3;
for(int i1=l1; i1<=h1; i1++)
{
printf("i1=%i\n", i1);
for(i2=l2; i2<=h2; i2++)
{
for(i3=l3; i3<=h3; i3++)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
136
elem(i1, i2, i3).show("", " ");
printf("\n");
}
}
printf("%s", ending);
printf("End of matrix. Press any key ...\n");
getch();
}

virtual void showvect(const char* opening, const char* ending)
{
clrscr();
int nel=(h1-l1+1)*(h2-l2+1)*(h3-l3+1);
printf("%s", opening);
for(int i=0; i<nel; i++)
{
if(i>0 && i%20==0)
{
printf("Press any key to continue...\n");
getch();
clrscr();
printf("%s", opening);
}
printf("%i. ", i); V[i].show("", "\n");
}
printf("%s", ending);
printf("End of vector. Press any key ...\n");
getch();
}

int search(el e)
{
int position = -1;
int nel=(h1-l1+1)*(h2-l2+1)*(h3-l3+1);
for(int i=0; (position==-1) && i<nel ; i++)
if(e==this->V[i])
position=i;
return position;
}

int search(el e, int &i1, int &i2, int &i3)
{
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
137
int found = 0;
for(int i1t=l1; i1t<=h1 && !found; i1t++)
for(int i2t=l2; i2t<=h2 && !found; i2t++)
for(int i3t=l3; i3t<=h3 && !found; i3t++)
if(e==elem(i1t, i2t, i3t))
found=1, i1=i1t, i2=i2t, i3=i3t;
return found;
}

void resetnop()
{
nopadd=0, nopmul=0;
}

long int getnopadd()
{
return nopadd;
}

long int getnopmul()
{
return nopmul;
}

protected:

void error(char* message)
{
printf("%s", message);
printf("Press any key to fin...\n");
getch();
exit(1);
}
};
Clasa generic matrix3l poate fi concretizat cu orice clas real derivat de la clasa abstract
elem.
Pentru ncrcarea matricei, crem un fiier-text cu numele "char.txt" avnd urmtorul coninut:
ABCDEFGHIJKLMNOPQR
n funcia main() crem o matrice dreptunghiular de ordinul 3 cu aranjarea elementelor pe linii,
completndu-le din fiierul "char.txt". Intervalele indicilor s iau aceleai ca i n exemplul
cercetat. n continuare afim elementele matricei n ordinea cum vor fi ele aranjate n memoria
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
138
operativ. Apoi afim matricea, indicnd structura logic, numrul de operaii de tip + i
numrul de operaii de tip efectuate la accesarea elementelor n timpul acestei afiri. Dup
aceasta vom intra n bucla care demonstreaz cutarea elementelor matricei. La sfrit vom
modifica cteva elemente i vom afia matricea modificat.
void main()
{
clrscr();

matrix3l<character> A("char.txt", 2, 4, -3, -1, 0, 1);

A.showvect("Matrix-vector A:\n","\n");

A.show("Matrix A\n","\n");
printf("\nN op. +/- %i, N op. x/: %i\n", A.getnopadd(), A.getnopmul());

char ch='n';
char c;
int i1, i2, i3;

while(ch!='y')
{
printf("Enter a char to search: ");
c=getch();
character mychar(c);
int pos=A.search(c);
if(pos<0)
printf("The character %c no matrix!\n", c);
else
{
A.search(c, i1, i2, i3);
printf("The character %c are in the position %i \nwith indices
[%i,%i,%i]\n",
c, pos, i1, i2, i3);
}

printf("Done ? (y/n) ");
ch = getch();
printf("\n");
}

A.elem(2, -3, 0)='a';
A.elem(2, -2, 1)='d';
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
139
A.elem(3, -3, 0)='g';
A.elem(3, -2, 1)='j';
A.elem(4, -3, 0)='m';
A.elem(4, -2, 1)='p';

A.show("Matrix A after correction:\n","\n");
}
O variant de afiare poate arta astfel:
Matrix-vector A:
0. A
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R

End of vector. Press any key ...
Matrix A
i1=2
A B
C D
E F
i1=3
G H
I J
K L
i1=4
M N
O P
Q R
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
140

End of matrix. Press any key ...

N op. +/- 162, N op. x/: 90
Enter a char to search: The character A are in the position 0
with indices [2,-3,0]
Done ? (y/n)
Enter a char to search: The character R are in the position 17
with indices [4,-1,1]
Done ? (y/n)
Enter a char to search: The character J are in the position 9
with indices [3,-2,1]
Done ? (y/n)
Enter a char to search: The character P are in the position 15
with indices [4,-2,1]
Done ? (y/n)
Enter a char to search: The character p no matrix!
Done ? (y/n)
Matrix A after correction:
i1=2
a B
C d
E F
i1=3
g H
I j
K L
i1=4
m N
O p
Q R

End of matrix. Press any key ...
Exerciiu. Suprancrcai n clasa matrix3l operatorul [].

5.5. Reprezentarea matricelor pe coloane
Cercetm acelai exemplu cu matricea A de dimensiunea 3 cu intervalele indicilor:
[2, 4] pentru i
1
;
[-3,-1] pentru i
2
;
[0, 1] pentru i
3
.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
141
n total, matricea A va avea 332=18 elemente, care vor fi alocate n memoria operativ ncepnd
de la o adres oarecare V, de data aceasta n felul urmtor:

Structura logic a matricei A este urmtoarea:

De data aceasta, matricea A reprezint dou matrice bidimensionale 33.
n cazul general, pentru o matrice de dimensiunea n cu elementele alocate pe coloane, cu
intervalele indicilor
[l
1
, h
1
] pentru indicele i
1
,
[l
2
, h
2
] pentru indicele i
2
,
...
[l
n
, h
n
] pentru indicele i
n
,
elementul A[i
1
, i
2
,, i
n
] se reflect n elementul
V[

=
n
j 1
( i
j
-l
j
) D
j
] al vectorului V, unde D
j
sunt numere care se calculeaz n ordinea direct dup
urmtoarea formul recurent:
D
1
=1;
D
j
=(h
j-1
-l
j-1
+1)D
j-1
, j=2,3,,n.
Revenind la exemplul nostru, s lum iari i
1
=4, i
2
=-2, i
3
=1.
Amintim c n=3,
l
1
=2, h
1
=4,
A B C D E F G H I J K L M N O P Q R
V[0] V[1] V[2] V[3] V[4] V[5] V[6] V[7] V[8] V[9] V[10] V[11] V[12] V[13] V[14] V[15] V[16] V[17]
2
-3
0
3
-3
0
4
-3
0

2
-2
0

3
-2
0
4
-2
0
2
-1
0

3
-1
0

4
-1
0
2
-3
1
3
-3
1

4
-3
1

2
-2
1
3
-2
1
4
-2
1

2
-1
1

3
-1
1
4
-1
1

A D
B E
C F
J M
K N
L O
G P
H Q
I R
i
3
=0 i
3
=1
i
2
i
1

-3 -2
2
3
4
i
2
i
1

-3 -2
2
3
4
-1 -1
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
142
l
2
=-3, h
2
=-1,
l
3
=0, h
3
=1,
atunci
D
1
=1,
D
2
=(4-2+1)1=31=3,
D
3
=(-1-(-3)+1)3=33=9,
i
A[i
1
, i
2
,, i
n
] V[(4-2)1+(-2-(-3))3+(1-0)9]= V[21+13+19]=V[2+3+9]=V[14]=O.
Este evident, cantitatea operaiilor de tipul + i operaiilor de tipul efectuate la accesarea
elementului A[i
1
, i
2
,, i
n
] este aceeai ca i n cazul aranjrii pe linii.
Pentru a demonstra utilizarea tabelelor dreptunghiulare de ordinul 3 alocate pe coloane, declarm
clasa generic matrix3c:
//
// c l a s s "m a t r i x 3 c"
//
template <class el> class matrix3c
{
protected:

el *V; // pointer to matrix reprezentation vector
int l1, h1;
int l2, h2;
int l3, h3;

unsigned long nopadd, nopmul;

public:

matrix3c(int l1, int h1, int l2, int h2, int l3, int h3)
{
this->l1=l1;
this->h1=h1;
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;

int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
143

nopadd=0, nopmul=0;
}

matrix3c(char* file_name, int l1, int h1, int l2, int h2, int l3, int h3)
{
this->l1=l1;
this->h1=h1;
this->l2=l2;
this->h2=h2;
this->l3=l3;
this->h3=h3;

int nel=(this->h1-this->l1+1)*(this->h2-this->l2+1)*(this->h3-this->l3+1);
V = new el[nel];

FILE* pf;
pf=fopen(file_name, "rt");

for(int i=0; i<nel; i++)
V[i].fscanf_el(pf);
fclose(pf);

nopadd=0, nopmul=0;
}

virtual el& elem(int i1, int i2, int i3)
{
int D1, D2, D3;

nopadd+=9, nopmul+=5;

D1=1;
D2=(h1-l1+1)*D1;
D3=(h2-l2+1)*D2;
return V[(i1-l1)*D1+(i2-l2)*D2+(i3-l3)*D3];
}

virtual void show(const char* opening, const char* ending)
{
clrscr();
printf("%s", opening);
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
144
int i1, i2, i3;
for(int i3=l3; i3<=h3; i3++)
{
printf("i3=%i\n", i3);
for(i1=l1; i1<=h1; i1++)
{
for(i2=l2; i2<=h2; i2++)
elem(i1, i2, i3).show("", " ");
printf("\n");
}
}
printf("%s", ending);
printf("End of matrix. Press any key ...\n");
getch();
}

virtual void showvect(const char* opening, const char* ending)
{
clrscr();
int nel=(h1-l1+1)*(h2-l2+1)*(h3-l3+1);
printf("%s", opening);
for(int i=0; i<nel; i++)
{
if(i>0 && i%20==0)
{
printf("Press any key to continue...\n");
getch();
//clrscr();
printf("%s", opening);
}
printf("%i. ", i); V[i].show("", "\n");
}
printf("%s", ending);
printf("End of vector. Press any key ...\n");
getch();
}

int search(el e)
{
int position = -1;
int nel=(h1-l1+1)*(h2-l2+1)*(h3-l3+1);
for(int i=0; (position==-1) && i<nel ; i++)
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
145
if(e==this->V[i])
position=i;
return position;
}

int search(el e, int &i1, int &i2, int &i3)
{
int found = 0;
for(int i1t=l1; i1t<=h1 && !found; i1t++)
for(int i2t=l2; i2t<=h2 && !found; i2t++)
for(int i3t=l3; i3t<=h3 && !found; i3t++)
if(e==elem(i1t, i2t, i3t))
found=1, i1=i1t, i2=i2t, i3=i3t;
return found;
}

void resetnop()
{
nopadd=0, nopmul=0;
}

long int getnopadd()
{
return nopadd;
}

long int getnopmul()
{
return nopmul;
}

protected:

void error(char* message)
{
printf("%s", message);
printf("Press any key to fin...\n");
getch();
exit(1);
}
};
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
146
n funcia main() din exemplul precedent modificm numai declararea matricei, care acum va arta
astfel:
matrix3c<character> A("char.txt", 2, 4, -3, -1, 0, 1);
Afiarea de data aceasta va fi urmtoarea:
Matrix-vector A:
0. A
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R

End of vector. Press any key ...
Matrix A
i3=0
A D G
B E H
C F I
i3=1
J M P
K N Q
L O R

End of matrix. Press any key ...

N op. +/- 162, N op. x/: 90
Enter a char to search: The character A are in the position 0
with indices [2,-3,0]
Done ? (y/n)
Enter a char to search: The character R are in the position 17
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
147
with indices [4,-1,1]
Done ? (y/n)
Enter a char to search: The character J are in the position 9
with indices [2,-3,1]
Done ? (y/n)
Enter a char to search: The character O are in the position 14
with indices [4,-2,1]
Done ? (y/n)
Enter a char to search: The character o no matrix!
Done ? (y/n)
Matrix A after correction:
i3=0
a D G
g E H
m F I
i3=1
J d P
K j Q
L p R

End of matrix. Press any key ...
Exerciiu. Suprancrcai n clasa matrix3c operatorul [].

5.6. Vectori definitori
S examinm metodele de acces pentru fiecare element al matricei n parte. Cea mai simpl soluie
(care a fost folosit i n clasele matrix3l i matrix3c), este aceea c n vectorul de reflectare sunt
alocate numai elementele matricei i, de fiecare dat, cnd este necesar un element oarecare al
matricei, pentru accesarea lui se calculeaz mrimea:
j
n
j
j j
n
j
j j
n
j
j j
D l D i D l i =

= = = 1 1 1
) (

ns, att l
j
, ct i numerele D
j
depind numai de descrierea matricei i nu depind de indicii
elementului la care se face adresarea. De aceea, pentru optimizare, numerele D
j
i mrimea

=
n
j
j j
D l
1
pot fi pstrate n memoria calculatorului, astfel se exclud calculele repetate. Aceste mrimi
se pot pstra mpreun cu elementele matricei, dar cel mai des ele se nscriu ntr-un vector special,
care se numete vector definitor. n aa caz, pentru diferite matrice cu unii i aceiai parametri poate
fi folosit un singur vector definitor.
ntr-un vector definitor se nscriu urmtoarele mrimi:
a) dimensiunea matricei (n);
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
148
b) marginile inferioare i superioare pentru fiecare indice (l
j
, h
j
, j=1,2,...,n);
c) numrul de elemente n matrice;
d) mrimile D
j
pentru j=1,2,...,n;
e) mrimea

=
n
j
j j
D l
1
.
Amintim c numerele D
j
depind de dimensiunea matricei, de intervalele de reprezentare a indicilor
i de metoda de aranjare a elementelor n memoria operativ (pe linii sau pe coloane).
Exemplu. Lum aceeai matrice A de dimensiunea n=3; cu intervalele indicilor i
1
: [2,4], i
2
: [-3,-1],
i
3
: [0,1]; cu elementele de tipul char alocate pe linii. Cu numele matricei A se asociaz doi
pointeri: un pointer la adresa de baz a vectorului de reflectare a elementelor matricei A; i un
pointer la vectorul definitor corespunztor matricei A. Schematic aceasta arat astfel:

Examinm accesul la elementul A[4,-2,1].
A[4,-2,1] V[46+(-2)2+11 - 6] = V[24-4+1-6] = V[16] = P.
n total, am executat 3 operaii de tipul i 3 operaii de tipul +. Amintim c la metoda direct
au fost efectuate 5 operaii de tipul i 9 operaii de tipul +.
ns metoda vectorilor definitori pentru matricea de ordinul n=3 cere suplimentar 1+23+1+3+1=12
celule de memorie de numere ntregi plus un pointer. Dac o celul cu un numr ntreg ocup 2
octei, atunci am folosit suplimentar 24 octei plus un pointer.
Exerciii.
1. Calculai numrul de celule de tipul int necesare pentru vectorul definitor n cazul matricei de
ordinul n.
A

j
3
1 j
j
D l

=

R
Q
C
B
...
...
A
2,-3,0
-3
4
2
3
...
A
...
...
...
...
-1
0
1
18
6
2
6
1
A
2,-3,1
A
2,-2,0
A
4,-1,1
A
4,-1,0
n

l
1
h
1
l
2
h
2
l
3
h
3
N
elem
D
1
D
2
D
3
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
149
2. Apreciai cte operaii de tip adunare i cte operaii de tip nmulire se efectueaz la
accesarea unui element al matricei dreptunghiulare de ordinul n prin utilizarea vectorului
definitor.
n cazul n care sunt mai multe matrice de una i aceeai dimensiune i cu unele i aceleai intervale
de valori ale indicilor, aceste matrice pot folosi unul i acelai vector definitor, dup cum este artat
n figura urmtoare:

Observaie. Elementele matricelor B, C, D pot fi de diferite tipuri, adic pot ocupa n memorie
diferite numere de octei.
Pentru a demonstra utilizarea vectorului definitor la accesarea elementelor matricei dreptunghiulare
de ordinul 3 cu elementele aranjate n memoria operativ pe linii, declarm n baza clasei
generice matrix3l clasa generic matrix3ldv dotat cu vectorul definitor:
//
// c l a s s "m a t r i x 3 l d v"
//
template <class el> class matrix3ldv : public matrix3l<el>
{
protected:

int *d; // poiner to definition vector

public:

matrix3ldv(int l1, int h1, int l2, int h2, int l3, int h3):
A

j j
D l


...
...
... ...
...
...
n

l
1
h
1


Elem.A

B

...
...
C

...
...
...
...
... Elem.B

...
...
... Elem.C

...
...
Vector
definitor

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
150
matrix3l<el>(l1, h1, l2, h2, l3, h3)
{
d = new int[12];
d[0]=3; // dimension
d[1]=l1;
d[2]=h1;
d[3]=l2;
d[4]=h2;
d[5]=l3;
d[6]=h3;
d[7]=(h1-l1+1)*(h2-l2+1)*(h3-l3+1); // number of elements
d[10]=1; // D3
d[9]=(h3-l3+1)*d[10]; // D2
d[8]=(h2-l2+1)*d[9]; // D1
d[11]=l1*d[8]+l2*d[9]+l3*d[10]; // Sum(ljxDj)
}

matrix3ldv(char* file_name, int l1, int h1, int l2, int h2, int l3, int h3):
matrix3l<el>(file_name, l1, h1, l2, h2, l3, h3)
{
d = new int[12];
d[0]=3; // dimension
d[1]=l1;
d[2]=h1;
d[3]=l2;
d[4]=h2;
d[5]=l3;
d[6]=h3;
d[7]=(h1-l1+1)*(h2-l2+1)*(h3-l3+1); // number of elements
d[10]=1; // D3
d[9]=(h3-l3+1)*d[10]; // D2
d[8]=(h2-l2+1)*d[9]; // D1
d[11]=l1*d[8]+l2*d[9]+l3*d[10]; // Sum(ljxDj)
}

virtual el& elem(int i1, int i2, int i3)
{
nopadd+=3, nopmul+=3;
return V[i1*d[8]+i2*d[9]+i3*d[10]-d[11]];
}
};
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
151
n funcia main() din exemplul precedent modificm doar declararea matricei, care de data aceasta
va fi:
matrix3ldv<character> A("char.txt", 2, 4, -3, -1, 0, 1);
Dup lansarea programului, vom obine urmtoarea afiare:
Matrix-vector A:
0. A
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R

End of vector. Press any key ...
Matrix A
i1=2
A B
C D
E F
i1=3
G H
I J
K L
i1=4
M N
O P
Q R

End of matrix. Press any key ...

N op. +/- 54, N op. x/: 54
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
152
Enter a char to search: The character A are in the position 0
with indices [2,-3,0]
Done ? (y/n)
Enter a char to search: The character R are in the position 17
with indices [4,-1,1]
Done ? (y/n)
Enter a char to search: The character J are in the position 9
with indices [3,-2,1]
Done ? (y/n)
Enter a char to search: The character P are in the position 15
with indices [4,-2,1]
Done ? (y/n)
Enter a char to search: The character p no matrix!
Done ? (y/n)
Matrix A after correction:
i1=2
a B
C d
E F
i1=3
g H
I j
K L
i1=4
m N
O p
Q R

End of matrix. Press any key ...
Dup cum s-a observat, numrul total de operaii efectuate la afiarea matricei n forma logic s-a
redus de la 162 pn la 54 pentru + i de la 90 pn la 54 pentru .
Exerciii.
1. Suprancrcai n clasa matrix3ldv operatorul [].
2. Comparai timpul de accesare a elementelor matricei la accesarea direct i la utilizarea
vectorilor definitori.
3. Declarai n baza clasei generice matrix3c clasa generic matrix3cdv dotat cu vectorul
definitor.

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
153
5.7. Vectori Iliffe
Pentru a accesa elementele matricei prin accesul direct sau cu ajutorul vectorului definitor, este
necesar a efectua un ir de adunri i nmuliri, numrul crora este proporional cu dimensiunea
matricei. Informaticianul John K. Iliffe [16] a elaborat metoda care exclude nmulirile i reduce la
minim adunrile la accesarea elementelor matricelor de orice dimensiune n, drept vorbind se
folosete mai mult memorie.
Esena const n aceea c mpreun cu fiecare matrice se pstreaz i o ierarhie de vectori, care au
cptat de denumirea vectori Iliffe.
Cu numele matricei se asociaz un pointer cu adresa primului vector Iliffe deplasat n
corespondena cu valoarea de jos a primului indice n cazul aranjrii pe linii, sau cu valoarea de
jos a ultimului indice n cazul aranjrii pe coloane.
Ierarhia vectorilor Iliffe pentru matricea dreptunghiular A de ordinul 3 din exemplele precedente
cu elementele aranjate pe linii arat astfel:
Cercetm accesul la elementul A[4,-2,1]. Extragem adresa din pointerul A i adugm la ea
deplasarea 4 n conformitate cu valoarea primului indice al elementului necesar. Ajungem la ultimul
element al primului vector Iliffe. Extragem adresa din el i adugm la ea deplasarea -2 n
conformitate cu valoarea indicelui doi al elementului necesar. Nimerim la al doilea element din al
treilea vector Iliffe de pe nivelul doi. Extragem adresa din el i adugm la ea deplasarea 1 n
conformitate cu valoarea indicelui trei al elementului necesar. Obinem adresa acestui element.
Valoarea elementului este P.
Deci, la accesarea elementului A[4,-2,1] nu am efectuat nici o nmulire, ci doar trei adunri de
deplasri la adrese. Adunrile acestea se refer la aritmetica adreselor, adic se efectueaz foarte
rapid. n schimb, am cheltuit suplimentar memoria pentru a aloca 12 pointeri. Ci pointeri va
conine ierarhia vectorilor Iliffe depinde nu numai de dimensiunea matricei, dar i de intervalele
indicilor, i de metoda de alocare a elementelor (pe linii sau pe coloane).
A B C D E F G H I J K L M N O P Q R
2
-3
0
2
-3
1
2
-2
0

2
-2
1

2
-1
0
2
-1
1
3
-3
0

3
-3
1

3
-2
0
3
-2
1
3
-1
0

3
-1
1

4
-3
0
4
-3
1
4
-2
0

4
-2
1

4
-1
0
4
-1
1

A
0
1
2
3
4
-3
-2
-1
0
-3
-2
-1
0
-3
-2
-1
0
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
154
Exerciiu. Calculai numrul de pointeri care va conine ierarhia vectorilor Iliffe pentru o matrice
de ordinul n, cu intervalele indicilor [l
1
,h
1
], [l
2
,h
2
], , [l
n
,h
n
], cu elementele alocate pe linii.
Pentru a demonstra accesarea elementelor matricelor dreptunghiulare de ordinul 3 cu aranjarea
elementelor pe linii utiliznd vectorii Iliffe, crem n baza clasei generice matrix3l clasa
generic matrix3lIl, dotat cu ierarhia respectiv de vectori Iliffe:
//
// c l a s s "m a t r i x 3 l I l"
//
template <class el> class matrix3lIl : public matrix3l<el>
{
protected:

el*** va; // pointer to Iliffes vectors ierarhy

public:

matrix3lIl(int l1, int h1, int l2, int h2, int l3, int h3):
matrix3l<el>(l1, h1, l2, h2, l3, h3)
{
int i1, i2 , d, step;

d=-l3;
step=h3-l3+1;

va = new el**[h1-l1+1] - l1;
for(i1=l1; i1<=h1; i1++)
{
*(va+i1) = new el*[h2-l2+1] - l2;
for(i2=l2; i2<=h2; i2++, d+=step)
*(*(va+i1)+i2)=V+d;
}
}

matrix3lIl(char* file_name, int l1, int h1, int l2, int h2, int l3, int h3):
matrix3l<el>(file_name, l1, h1, l2, h2, l3, h3)
{
int i1, i2 , d, step;

d=-l3;
step=h3-l3+1;

va = new el**[h1-l1+1] - l1;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
155
for(i1=l1; i1<=h1; i1++)
{
*(va+i1) = new el*[h2-l2+1] - l2;
for(i2=l2; i2<=h2; i2++, d+=step)
*(*(va+i1)+i2)=V+d;
}
}

el& elem(int i1, int i2, int i3)
{
nopadd+=3, nopmul+=0;
return *(*(*(va+i1)+i2)+i3);
}
};
n funcia main() din exemplul precedent modificm numai crearea matricei. De data aceasta vom
declara o matrice dreptunghiular de dimensiunea 3, dotat cu ierarhia vectorilor Iliffe:
matrix3lIl<character> A("char.txt", 2, 4, -3, -1, 0, 1);
Rezultatele se vor obine imediat:
Matrix-vector A:
0. A
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R

End of vector. Press any key ...
Matrix A
i1=2
A B
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
156
C D
E F
i1=3
G H
I J
K L
i1=4
M N
O P
Q R

End of matrix. Press any key ...

N op. +/- 54, N op. x/: 0
Enter a char to search: The character A are in the position 0
with indices [2,-3,0]
Done ? (y/n)
Enter a char to search: The character R are in the position 17
with indices [4,-1,1]
Done ? (y/n)
Enter a char to search: The character J are in the position 9
with indices [3,-2,1]
Done ? (y/n)
Enter a char to search: The character P are in the position 15
with indices [4,-2,1]
Done ? (y/n)
Enter a char to search: The character p no matrix!
Done ? (y/n)
Matrix A after correction:
i1=2
a B
C d
E F
i1=3
g H
I j
K L
i1=4
m N
O p
Q R

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
157
End of matrix. Press any key ...
Aici ne intereseaz numai numrul de adunri i numrul de nmuliri efectuate adresndu-ne la
elementele matricei pe parcursul afirii structurii logice (celelalte rezultate au rmas aceleai).
Dup cum se vede, nmulirile au fost excluse, n timp ce numrul de adunri a rmas 54, adic
acelai ca i n cazul vectorului definitor. ns de data aceasta au fost fcute adunrile de adresare,
care se execut mult mai repede dect adunrile obinuite, care au fost efectuate la utilizarea
vectorilor definitori.
Exerciii.
1. Suprancrcai n clasa matrix3lIl operatorul [].
2. Comparai timpul de accesare a elementelor matricei la utilizarea vectorilor definitori cu timpul
de accesare a elementelor matricei la utilizarea vectorilor Iliffe.
Ierarhia vectorilor Iliffe pentru matricea dreptunghiular A de ordinul 3 din exemplele precedente
cu elementele aranjate pe coloane arat astfel:
Cercetm accesul la elementul A[4,-2,1]. Extragem adresa din pointerul A i adugm la ea
deplasarea 1 n conformitate cu valoarea ultimului indice al elementului necesar. Ajungem la
ultimul element al primului vector Iliffe. Extragem adresa din el i adugm la ea deplasarea -2, n
conformitate cu valoarea indicelui doi al elementului necesar. Ajungem la al doilea element din al
treilea vector Iliffe de pe nivelul doi. Extragem adresa din el i adugm la ea deplasarea 4, n
conformitate cu valoarea primului indice al elementului necesar. Obinem adresa elementul necesar.
Valoarea elementului n acest caz este O.
De aceast dat la accesarea elementului A[4,-2,1] am efectuat doar trei adunri de deplasri la
adrese. Suplimentar, am folosit memoria pentru a aloca 8 pointeri. Deci matricea A, din exemplele
cercetate cu utilizarea vectorilor Iliffe, este mai convenabil a fi aranjat pe coloane.
A B C D E F G H I J K L M N O P Q R
2
-3
0
3
-3
0
4
-3
0

2
-2
0

3
-2
0
4
-2
0
2
-1
0

3
-1
0

4
-1
0
2
-3
1
3
-3
1

4
-3
1

2
-2
1
3
-2
1
4
-2
1

2
-1
1

3
-1
1
4
-1
1

A
0
1
-3
-2
-1
0
-3
-2
-1
0

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
158
Exerciiu. Calculai numrul de pointeri care va conine ierarhia vectorilor Iliffe pentru o matrice
de ordinul n, cu intervalele indicilor [l
1
,h
1
], [l
2
,h
2
], , [l
n
,h
n
], cu elementele alocate pe coloane.
Pentru a demonstra accesarea elementelor matricelor dreptunghiulare de ordinul 3 cu aranjarea
elementelor pe coloane i cu utilizarea vectorilor Iliffe, crem n baza clasei generice matrix3c
clasa generic matrix3cIl, dotat cu ierarhia respectiv de vectori Iliffe:
//
// c l a s s "m a t r i x 3 c I l"
//
template <class el> class matrix3cIl : public matrix3c<el>
{
protected:

el*** va; // pointer to Iliffes vectors ierarhy

public:

matrix3cIl(int l1, int h1, int l2, int h2, int l3, int h3):
matrix3c<el>(l1, h1, l2, h2, l3, h3)
{
int i3, i2 , d, step;

d=-l1;
step=h1-l1+1;

va = new el**[h3-l3+1] - l3;
for(i3=l3; i3<=h3; i3++)
{
*(va+i3) = new el*[h2-l2+1] - l2;
for(i2=l2; i2<=h2; i2++, d+=step)
*(*(va+i3)+i2)=V+d;
}
}

matrix3cIl(char* file_name, int l1, int h1, int l2, int h2, int l3, int h3):
matrix3c<el>(file_name, l1, h1, l2, h2, l3, h3)
{
int i3, i2 , d, step;

d=-l1;
step=h1-l1+1;

va = new el**[h3-l3+1] - l3;
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
159
for(i3=l3; i3<=h3; i3++)
{
*(va+i3) = new el*[h2-l2+1] - l2;
for(i2=l2; i2<=h2; i2++, d+=step)
*(*(va+i3)+i2)=V+d;
}
}

el& elem(int i1, int i2, int i3)
{
nopadd+=3, nopmul+=0;
return *(*(*(va+i3)+i2)+i1);
}
};
n funcia main()declarm o matrice dreptunghiular de dimensiunea 3, cu elementele aranjate n
memoria operativ pe coloane, dotat cu ierarhia vectorilor Iliffe:
matrix3cIl<character> A("char.txt", 2, 4, -3, -1, 0, 1);
Dup lansarea programului, obinem urmtoarea afiare:
Matrix-vector A:
0. A
1. B
2. C
3. D
4. E
5. F
6. G
7. H
8. I
9. J
10. K
11. L
12. M
13. N
14. O
15. P
16. Q
17. R

End of vector. Press any key ...
Matrix A
i3=0
A D G
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
160
B E H
C F I
i3=1
J M P
K N Q
L O R

End of matrix. Press any key ...

N op. +/- 54, N op. x/: 0
Enter a char to search: The character A are in the position 0
with indices [2,-3,0]
Done ? (y/n)
Enter a char to search: The character R are in the position 17
with indices [4,-1,1]
Done ? (y/n)
Enter a char to search: The character J are in the position 9
with indices [2,-3,1]
Done ? (y/n)
Enter a char to search: The character O are in the position 14
with indices [4,-2,1]
Done ? (y/n)
Enter a char to search: The character o no matrix!
Done ? (y/n)
Matrix A after correction:
i3=0
a D G
g E H
m F I
i3=1
J d P
K j Q
L p R

End of matrix. Press any key ...
Exerciiu. Suprancrcai n clasa matrix3cIl operatorul [].

Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
161
6. ACTIVITI
I Declararea claselor de baz

Alegei dup preferinele dvs. un domeniu din lista domeniilor propuse, sau propunei un domeniu
propriu.

1. Personal computer______
2. Processor_____________
3. Monitor______________
4. Printer_______________
5. Winchester____________
6. Video card____________
7. Mother board__________
8. Mouse_______________
9. Flush memory_________
10. Mobile phone__________
11. Television_____________
12. Fridge________________
13. Washing machine_______
14. Triangle______________
15. Rectangle_____________
16. Ellipse_______________
17. Circle________________
18. Bezier________________
19. Trapeze_______________
20. Parallelogram__________
21. Polygon______________
22. Star_________________
23. Rhombus_____________
24. City_________________
25. Address______________
26. Book________________
27. Collaborator__________
28. Student______________
29. Film_________________
30. Cinematograph________
31. Pharmacy____________
32. Mark________________
33. Coin_________________
34. Hotel________________
35. Museum______________
36. Shop_________________
37. Baggage______________
38. Apartment____________
39. Patient_______________
40. Car__________________
41. Bicycle______________
42. Flower_______________
43. Mushroom____________
44. Subject_______________
45. Flight________________
46. Dog_________________
47. Cat__________________
48. Parrot________________
49. Cow_________________
50. Bit string_____________
51. Octal________________
52. Hexadecimal__________
53. Rational number________
54. Complex number_______
55. _____________________
56. _____________________
57. _____________________
58. _____________________
59. _____________________
60. _____________________
Pentru domeniul ales creai o clas derivat de la clasa abstract elem (vezi 1.2), care va conine cel
puin 5 cmpuri de diferite tipuri (int, char*, double, etc.), 3 constructori de diferite tipuri,
redefinirea funciei cmp(), suprancrcrile operatorilor de inserie i extragere i altele.
Creai un fiier text cu cel puin 50 de linii informaii pentru crearea obiectelor ale clasei
elaborate. Pe baza acestui fiier vei completa ulterior diferite structuri de date.


Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
162
II Lucrul cu tabele
Tabele neordonate simple
Pe baza clasei abstracte SD (vezi 1.2) declarai clasa derivat generic table pentru a lucra cu tabele
neordonate simple.
Creai un astfel de tabel ncrcnd-ul din fiierul text. Artai cutarea secvenial a nregistrrilor
dup cheie. Calculai lungimea medie de cutare pentru acest tabel i comparai-o cu cea teoretic.

Tabele neordonate structurate arborescent
Declarai pe baza clasei dvs. de reprezentare a nregistrrilor tabelare o clas dotat cu doi pointeri,
unul la nregistrarea tabelar cu cheia mai mic i cel de-al doilea la nregistrarea tabelar cu cheia
mai mare.
Pe baza clasei table declarai clasa derivat generic tree_table pentru a lucra cu tabele
neordonate arborescente. Creai un astfel de tabel ncrcnd-ul din fiierul text. Artai cutarea n
tabelul arborescent a nregistrrilor dup cheie. Calculai lungimea medie de cutare pentru acest
tabel i comparai-o cu cele teoretice (minim i maxim).

Tabele ordonate dup cheie
Pe baza clasei table declarai clasa derivat generic sorted_table pentru a lucra cu tabele
ordonate n ordine cresctoare dup cheie.
Creai un astfel de tabel ncrcnd-ul din fiierul text. Artai cutarea binar a nregistrrilor dup
cheie. Calculai lungimea medie de cutare pentru acest tabel i comparai-o cu cea teoretic.

Tabele de repartizare cu examinarea liniar
Declarai pe baza clasei nregistrrilor tabelare din domeniu dvs. o clas derivat, dotat cu o
funcie de repartizare. Declarai pe baza clasei table clasa derivat generic, care poate fi
concretizat cu clasa nregistrrilor tabelare, dotat cu o funcie de repartizare.
Creai un tabel de repartizare cu examinarea linear ncrcnd-ul din fiierul text. Artai cutarea n
acest tabel a nregistrrilor tabelare dup cheie cu utilizare a funciei de repartizare. Calculai
lungimea medie de cutare pentru acest tabel i comparai-o cu cea teoretic pentru mrimea =m/n
dat. Facei experimente cu diferite valori ale mrimii .

III Sortri
Clasa pentru testarea algoritmilor de sortare
Declarai pe baza clasei abstracte SD clasa generic vector care poate fi utilizat pentru
reprezentarea vectorilor cu elemente obiecte din domeniul dvs. Spre deosebire de tabele, vectorii
pot conine elemente cu chei egale.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
163

Sortarea rapid
Declarai pe baza clasei vector o clas generic dotat cu algoritmul de sortare rapid.
Creai un vector concret pe baza fiierului text. Afiai vectorul nesortat, sortai vectorul dup o
cheie prin sortarea rapid, afiai vectorul sortat, afiai numrul de comparri i numrul de
interschimburi att concrete pentru acest vector i cheia dat ct i cele teoretice. Facei acelai
lucru cu alte chei.

Sortarea rapid cu prag
Declarai pe baza clasei vector o clas generic dotat cu algoritmul de sortare rapid cu prag i cu
inserie simp n calitate de algoritmul de finisare.
Creai un vector concret pe baza fiierului text. Afiai vectorul nesortat, sortai vectorul dup o
cheie prin sortarea rapid cu prag, afiai vectorul sortat, afiai numrul de comparri i numrul de
interschimburi att concrete pentru acest vector i cheia dat ct i cele teoretice. Facei acelai
lucru cu alte chei, cu alte valori de prag, cu ali algoritmi de finisare.

Sortarea piramidal
Declarai pe baza clasei vector o clas generic dotat cu algoritmul de sortare piramidal.
Creai un vector concret pe baza fiierului text. Afiai vectorul nesortat, sortai vectorul dup o
cheie prin sortarea piramidal, afiai vectorul sortat, afiai numrul de comparri i numrul de
interschimburi att concrete pentru acest vector i cheia dat ct i cele teoretice. Facei acelai
lucru cu alte chei.

IV Structuri dinamice de date
Arbori binari
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea arborilor binari
de cutare cu posibilitatea de a parcurge aceti arbori binari n diferite ordini.
Creai pe baza fiierului text un arbore binar de cutare concret i demonstrai cutarea dup cheie
n el. Calculai lungimea medie de cutare pentru acest arbore. Demonstrai parcurgerea acestui
arbore n preordine, n inordine i n postordine.

Liste simplu nlnuite
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea listelor simplu
nlnuite.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
164
Creai pe baza fiierului text o list simplu nlnuit concret i demonstrai cutarea dup cheie n
ea. Calculai lungimea medie de cutare pentru aceast list. Demonstrai metode de adugare
elementelor noi, metode de eliminare, etc.

Liste nlnuite ciclic
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea listelor nlnuite
ciclic.
Creai pe baza fiierului text o list nlnuit ciclic concret i demonstrai cutarea dup cheie n
ea. Calculai lungimea medie de cutare pentru aceast list. Demonstrai metode de adugare
elementelor noi, metode de eliminare, etc.

Liste dublu nlnuite
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea listelor dublu
nlnuite.
Creai pe baza fiierului text o list dublu nlnuit concret i demonstrai cutarea dup cheie n
ea. Calculai lungimea medie de cutare pentru aceast list. Demonstrai metode de adugare
elementelor noi, metode de eliminare, etc.

Stive prin buffer de dimensiune fix
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea stivelor prin
buffer de lungime fix.
Creai pe baza fiierului text o stiv i demonstrai nscrierea n stiv i extragerea din stiv.
Utilizai stiva la parcurgerea arborilor binari.

Stive prin list
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea stivelor prin list
simplu nlnuit cu proprietatea c att nscrierile n list ct si extragerile din list se efectueaz la
nceputul listei.
Creai pe baza fiierului text o stiv i demonstrai nscrierea n stiv i extragerea din stiv.
Utilizai stiva la parcurgerea arborilor binari.

Cozi prin buffer ciclic
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea cozilor prin
buffer ciclic.
Creai pe baza fiierului text o coad i demonstrai punerea la coad i extragerea din coad.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
165

Cozi prin list
Declarai pe baza clasei abstracte SD o clas derivat generic pentru reprezentarea cozilor prin list
simplu nlnuit cu proprietatea c nscrierile n list se efectueaz la un capt al listei iar
extragerile din list se efectueaz la celalalt capt al listei.
Creai pe baza fiierului text o coad i demonstrai punerea la coad i extragerea din coad.

V Matrice
Matrice cu accesare direct
Declarai pe baza clasei abstracte SD clas derivat generic concret matrix4l pentru
reprezentarea matricelor dreptunghiulare de ordinul 4 cu elementele aranjate pe linii. Artai prin
exemple, utilizarea acestei clase declarnd o matrice cu tipul de elemente indicat de ctre profesor.
Declarai pe baza clasei abstracte SD clas derivat generic concret matrix3c pentru
reprezentarea matricelor dreptunghiulare de ordinul 4 cu elementele aranjate pe coloane. Artai
prin exemple, utilizarea acestei clase declarnd o matrice cu tipul de elemente indicat de ctre
profesor.

Matrice cu vectori definitori
Declarai pe baza clasei generice matrix4l clasa generic matrix4ldv pentru reprezentarea
matricelor dreptunghiulare de ordinul 4 cu elementele aranjate pe linii dotat cu vector definitor.
Artai prin exemple, utilizarea acestei clase declarnd o matrice cu tipul de elemente indicat de
ctre profesor.
Declarai pe baza clasei generice matrix4c clasa generic matrix4cdv pentru reprezentarea
matricelor dreptunghiulare de ordinul 4 cu elementele aranjate pe coloane dotat cu vector
definitor. Artai prin exemple, utilizarea acestei clase declarnd o matrice cu tipul de elemente
indicat de ctre profesor.

Matrice cu vectori Iliffe
Declarai pe baza clasei generice matrix4l clasa generic matrix4lIl pentru reprezentarea
matricelor dreptunghiulare de ordinul 4 cu elementele aranjate pe linii dotat cu vectori Iliffe.
Artai prin exemple, utilizarea acestei clase declarnd o matrice cu tipul de elemente indicat de
ctre profesor.
Declarai pe baza clasei generice matrix4c clasa generic matrix4cIl pentru reprezentarea
matricelor dreptunghiulare de ordinul 4 cu elementele aranjate pe coloane dotat cu vectori Iliffe.
Artai prin exemple, utilizarea acestei clase declarnd o matrice cu tipul de elemente indicat de
ctre profesor.
Structuri de date (n baza C++): Suport de curs
S.Pereteatcu, A.Pereteatcu
166
BIBLIOGRAFIE
1. Donald E. KNUTH. Tratat de programarea calculatoarelor. Vol. 1. Algoritmi fundamentali. Vol.
3. Sortarea i cutarea. Bucureti, 1974
2. Julian M. Bucknall. Fundamental Algorithms and Data Strutures in Delphi
3. Schildt H. C++: Manual complet /Trad. din l. engl. Bucureti: Teora, 2000. 644 p.
4. Dorel Lucanu. Bazele proiectrii programelor i algoritmelor. Vol. II. Tehnici de programare.
Vol III. Proiectarea algoritmilor. Editura Universitii Al. I. Cuza, Iai, 1996
5. Tudor Sorin. Tehnici de programare. Bucureti, Editura Teora, 1997
6. Robert E. Sedgewick. Fundamental Algorithms in C/C++. Parts 1-4. Fundamentals. Data
Structures. Sorting. Searching. Part 5. Graph Algorithms
7. . / . . . 1.
. .: , 1976. 736 .
8. . / . . . 3. .
.: , 1978. 748 .
9. Donald E. KNUTH. The art of computer programming. Volume 1. Fundamental Algorithms.
Volume 3. Sorting and Searching.
10. ., . / . . 2-. .: , 1982
11. . Delphi: .
. : , 2003.- 560 .
12. ., ., . :
. . .: , 1989. 568 .
13. . . 1-4. . .
. : . . : , 2003.- 672 .
14. . ++. 5. : .
. : , 2002.- 496 .
15. . JAVA. 1-4. .
. . (3- ): . . : , 2003.- 688 .
16. Iliffe John K., The Use of The Genie System in Numerical Calculations. Annual Review in
Automatic Programming 2: 25, 1961

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