Sunteți pe pagina 1din 15

Structuri de Date i Algoritmi

Laborator III

Anamaria Rdoi, Ovidiu Grigore

2017

1 Scopul laboratorului
Laboratorul III al materiei Structuri de Date i Algoritmi are ca scop:
1. utilizarea noiunilor de programare generic
2. introducerea structurii de date list simplu nlnuit.
n acest laborator se parcurg urmtoarele puncte:
utilizarea template-urilor (funcii i clase template)
structura de date a unei liste simplu nlnuit
modul de funcionare a unei liste simplu nlnuit
parcurgerea listei simplu nlnuit

adugarea unui element n lista simplu nlnuit


tergerea unui element din lista simplu nlnuit

2 Desfurarea lucrrii
2.1 Programare generic
2.1.1 Functii generice

Exist foarte multe cazuri n care functii (sau clase) sunt nrudite ntre ele. De
exemplu, o funcie care sorteaz un tablou de ntregi va diferi foarte puin fa
de un algoritm de sortare a unui tablou avnd ca elemente numere reale.
Mecanismul abloanelor (templates) creeaz funcii sau clase generice utili-
znd tipurile ca parametri. Un ablon denete o familie de funcii, respectiv
de clase. Aceste tipuri se specic la denire, n mod generic, urmnd apoi
instanierea tipurilor generice cu tipuri concrete. De fapt, un ablon poate 
utilizat pentru un numr nespecicat de entiti concrete, nrudite ntre ele.

1
De exemplu, pentru calculul diferenei n valoare absolut a dou valori
ntregi sau reale, am putea scrie funcii suprancarcate, care ar avea acelai cod,
diferind numai tipul parametrilor.
1 int diferenta_absoluta ( int x, int y){

2 return x > y ? x y : y x;

3 }

4
5 double diferenta_absoluta ( double x, double y){

6 // identic

7 }

Variantele de mai sus pot  comasate ntr-una singur, folosind template-uri.


1 template <t y p e n a m e T>

2 T d i f e r e n t a _ a b s o l u t a (T x, T y){

3 return x > y ? x y : y x;

4 }

In general, denirea unei funcii generice se face astfel:


1 template <p a r 1 , par2 , ... , p a r n>

2 declaratie functie parametrizata ;

Generarea de cod pentru entitatea template are loc la compilare, funcia


generic ind aplicat pentru un tip concret al parametrilor de apel. Parametrii
template-ului pot  tipuri predenite, tipuri denite de utilizator (clase) sau
constante.
Un exemplu complet de program ce folosete noiuni de programare generic
este prezentat mai jos. De remarcat este redenirea operatorului < pentru
numere complexe.
1 #i n c l u d e <i o s t r e a m >

2 #i n c l u d e <math . h>

3
4 using namespace std ;

5
6 // Valoare maxima

7 template <t y p e n a m e T>

8 T maxim (T x, T y)

9 {

10 return x < y ? y : x;

11 }

12
13 class NrComplex

14 {

15 double re , im ;

16 public :

17 NrComplex ( )

18 {

19 re = 0;

20 im = 0;

21 }

22
23 NrComplex ( d o u b l e r , double i )

24 {

25 re = r ;

2
26 im = i ;

27 }

28
29 double modul ( )

30 {

31 return sqrt ( this >r e t h i s >r e + this >im t h i s >im ) ;


32 }

33
34 bool o p e r a t o r <(NrComplex n2 )

35 {

36 return modul ( ) < n2 . modul ( ) ;

37 }

38 friend o s t r e a m& o p e r a t o r << ( o s t r e a m& os , const NrComplex& nc ) ;

39 };

40
41 o s t r e a m& o p e r a t o r << ( o s t r e a m& os , const NrComplex& nc )

42 {

43 os << "( " << nc . r e << " + " << n c . im << " i ) " << endl ;

44 return os ;

45 }

46
47 int main ( )

48 {

49 int a = 3, b = 2;

50
51 cout << " Maximul este : " << maxim ( a , b) << endl ;

52
53 double c = 8.2 , d = 9.4;

54
55 cout << " Maximul este : " << maxim ( c , d) << endl ;

56
57 NrComplex nc1 ( 2 , 5) , nc2 ( 5 , 8) ;

58
59 cout << " Maximul este : " << maxim ( n c 1 , nc2 ) << endl ;

60
61 return 0;

62 }

La apelul funciei parametrizate, tipul argumentelor din apel determin ce


versiune a template-ului este folosit. De exemplu,
1 maxim ( 1 0 , 25)

va selecta functia
1 int maxim ( i n t , int )

Compilatorul deduce tipul argumentului de apel doar n cazul n care aceast


identicare se poate face n mod unic, fr a efectua vreo conversie implicit. Si-
tuaiile n care exist ambiguitate n determinarea tipului argumentului trebuie
particularizate prin suprancarcare. Redenirea funciei are prioritate asupra
deniiei ablonului. Aceast operaie se numete template specialization.
In cele ce urmeaz, este prezentat cazul particularizrii unui template pentru
un tip specic (char*).
1 #i n c l u d e <i o s t r e a m >

2 #i n c l u d e < s t r i n g . h>

3
3
4 using namespace std ;

5
6 // Valoare maxima

7 template <t y p e n a m e T>

8 T maxim (T x, T y)

9 {

10 return x < y ? y : x;

11 }

12
13 // Template specialization pentru char
14 template <>

15 char maxim<c h a r >( c h a r x, char y)

16 {

17 if ( strcmp ( x , y ) >0)

18 return x;

19 else

20 return y;

21 }

22
23 int main ( )

24 {

25 int a = 3, b = 2;

26
27 cout << " Maximul este : " << maxim ( a , b) << endl ;

28
29 char n1 = " Ionescu " ;

30 char n2 = " Popescu " ;

31
32 cout << " Maximul este : " << maxim ( n1 , n2 ) << endl ;

33
34 return 0;

35 }

Template-urile pot  folosite i pentru denirea unei funcii de cutare a


unui minim ntr-un vector, asa cum se poate vedea n exemplul de mai jos.
1 #i n c l u d e <i o s t r e a m >

2
3 using namespace std ;

4
5 template <t y p e n a m e T>

6 T minim ( c o n s t T x, int n) {

7 T xm = x [ 0 ] ;

8 for ( int i = 1; i <n ; i ++)

9 if ( x [ i ] <xm)

10 xm = x [ i ] ;

11 return xm ;

12 };

13
14
15 int main ( )

16 {

17
18 int ix [ ] = { 3, 8, 1, 5, 13 , 7 };

19 double fx [ ] = { 1.5 , 3.2 , 7.3 , 4.8 };

20 int n = s i z e o f ( ix ) / sizeof ( int ) ;

21 cout << "Minimum din primul vector este " << minim ( i x , n) << endl ;

4
22 n = s i z e o f ( fx ) / s i z e o f ( double ) ;

23 cout << "Minimum din cel de a l doilea vector este " << minim ( f x , n)

<< endl ;

24
25 return 0;

26 }

2.1.2 Clase generice

O clasa generic funcioneaz ca un ablon pentru a deni o familie de clase.


Membrii acestei familii de clase (colecii) difer numai prin tipul elementelor.
Considerm clasa tablou de ntregi. Pentru a deni un tablou de numere reale
sau de numere complexe, am putea copia implementarea clasei, modicnd tipul
datelor i numele clasei. Am avea trei clase pentru ecare din cele trei tipuri de
date: intArray, doubleArray, NrComplexArray.
Familia de clase poate  reprezentat printr-o clasa generica. Instanierea
template-ului se va face prin generarea declarrii unei clase generice, avnd un
argument generic.
1 template <l i s t a _ a r g u m e n t e _ g e n e r i c e > declarare_clasa ;

Utilizarea unei clase generice presupune generarea de ctre compilator a cte


unei clase individuale n funcie de tipurile care instaniaz clasa generic.
1 n u m e _ c l a s a <l i s t a _ a r g u m e n t e _ c o n c r e t e > nume_obiect ;

Ca i n cazul funciilor generice, particularizarea template-ului se face prin


operaia numit template specialization.
Clasa template tablou este denit i utilizat n programul de mai jos, care
calculeaz suma elementelor introduse n tablouri. Tablourile pot conine ele-
mente de tip int sau numere complexe. In cazul clasei NrComplex, este necesar
s redenim operatorul de adunare +, dar i operatorul de copiere = ntru-
ct ambii operatori sunt folosii n calculul sumei elementelor dintr-un tablou
de numere complexe. Totodat, pentru clasa template Array, sunt denite un
operator de indexare [ ] i o funcie de atribuire folosit pentru a da valori
elementelor din tabloul creat.
1 #i n c l u d e <i o s t r e a m >

2
3 using namespace std ;

4
5 class NrComplex

6 {

7 double re , im ;

8 public :

9 NrComplex ( )

10 {

11 re = 0;

12 im = 0;

13 }

14 NrComplex ( d o u b l e r , double i )

15 {

16 re = r ;

5
17 im = i ;

18 }

19 NrComplex o p e r a t o r +(NrComplex n2 )

20 {

21 NrComplex s ;

22 s . re = this >r e + n2 . r e ;

23 s . im = this >im + n2 . im ;

24 return s ;

25 }

26
27 void o p e r a t o r =(NrComplex n2 )

28 {

29 this >r e = n2 . r e ;

30 this >im = n2 . im ;

31 }

32
33 friend o s t r e a m& o p e r a t o r << ( o s t r e a m& os , const NrComplex& nc ) ;

34 };

35
36 o s t r e a m& o p e r a t o r << ( o s t r e a m& os , const NrComplex& nc )

37 {

38 os << "( " << nc . r e << " + " << n c . im << " i ) " << endl ;

39 return os ;

40
41 }

42
43 template <c l a s s T>

44 class Array {

45 T a ;
46 int d;

47 public :

48 Array ( i n t d){

49 this >a = new T[ d ] ;

50 t h i s >d = d;

51 }

52 ~Array ( ) { delete a; }

53 T operator [ ] ( int i )

54 {

55 return a[ i ];

56 }

57 void setArray ( int pos , T val )

58 {

59 a [ pos ] = val ;

60 }

61 };

62
63 template <c l a s s T>

64 T suma ( A r r a y<T> a , int d)

65 {

66 T s ;

67 s = a [0];

68 for ( int i = 1; i < d; i ++)

69 {

70 s = s + a[ i ];

71 }

72 return s ;

73 }

6
74
75
76 int main ( )

77 {

78 A r r a y<i n t > x ( 3 ) ;

79 A r r a y<NrComplex> z (3) ;

80
81 int val_int ;

82 double complex_re , complex_im ;

83
84 cout << " Citire Array de elemente de tip int : " << endl ;

85 for ( int i = 0; i < 3; i ++)

86 {

87 cout << " Introduceti elementul " << i << ": ";

88 cin >> val_int ;

89 x . setArray ( i , val_int ) ;

90 }

91 cout << "Suma elementelor introduse este : " << suma ( x , 3) << endl

92
93 cout << " Citire Array de numere complexe : " << endl ;

94 for ( int i = 0; i < 3; i ++)

95 {

96 cout << " Introduceti elementul " << i << ": ";

97 cin >> c o m p l e x _ r e >> complex_im ;

98 z . setArray ( i , NrComplex ( c o m p l e x _ r e , complex_im ) ) ;

99 }

100 cout << "Suma elementelor introduse este : " << suma ( z , 3) << endl

<< endl ;

101
102 return 0;

103 }

Tema: Creai un tablou de caractere i aplicai template specialization


pentru a particulariza funcia template suma astfel nct funcia s returneze
caracterele concatenate. De exemplu, daca tabloul este 's', 'd', 'r', funcia tem-
plate suma va avea ca rezultat irul de caractere 'sdr'.

3 Liste simplu nlnuite


Lista liniar este o structur de date omogen, ce conine elemente de acelai
tip. Intre elementele listei, exist o relaie de ordonare n sensul c pentru
ecare element din interiorul listei, exist un element anterior i unul urmtor.
Elementele unei liste se a la adrese de memorie succesive.

info1 info2 info3 info4 NULL

Figura 1: Lista simplu nlnuit

7
In funcie de modul de alocare al memoriei, se disting mai multe tipuri de
liste:
1. liste cu alocare static
2. liste cu alocare mixt
3. liste cu alocare dinamic.
In acest laborator vom studia listele cu alocare static.
Cteva dintre operaiile elementare care se pot efectua asupra listelor sunt:
iniializarea listei

adugarea unor elemente la sfritul / nceputul listei


inserarea unui element pe poziia i in list
tergerea unui element din list

modicarea unui element din list


citirea unui element din list
parcurgerea unei liste
localizarea unui element n list.

Denirea unei liste se face astfel:


1 template <t y p e n a m e DT>

2 class ListaS

3 {

4 DT e l e m [MAX ] ;

5 int p_crt ;

6 int p_sf ;

7 };

n care elem reprezint vectorul cu elementele listei, p_crt indic poziia curent
a cursorului n list, iar p_sf indic poziia ultimului element al listei. MAX este
o variabil global, denit la nceputul programului i indic numrul maxim
de elemente pe care le poate avea lista.
In main(), denirea unui obiect de tip list cu alocare static se face astfel:
1 int main ( ) {

2 L i s t a S <DATA> lst ;

3 . . . .

4 return 0;

5 }

unde DATA reprezint tipul de date folosit (predenit sau clas denit de
utilizator). In continuare, vor  prezentate pe rnd cteva operatii elementare
pentru listele simplu nlnuite.

8
3.1 Iniializarea listei
Iniializarea presupune crearea unei liste vide. Lista vid este acea list pentru
care p_sf este -1.
1 ListaS ()

2 {

3 p_crt = p_sf = 1;
4 }

3.2 Adugarea de elemente la sfritul listei


1 int a d d E l e m S f (DT d )

2 {

3 if ( p _ s f < MAX 1)

4 {

5 p _ s f ++;

6 elem [ p_sf ] = d;

7 return EXIT_SUCCESS ;

8 }

9 else

10 return EXIT_FAILURE ; // daca lista este plina , nu mai pot fi

adaugate elemente noi

11 }

Observaie: In cazul unei clase denite de utilizator, este necesar redenirea


operatorului de atribuire =.
3.3 Operatorul de incrementare sau de avansare a curso-
rului n list cu o poziie
1 int o p e r a t o r ++()

2 {

3 if ( p_crt < p_sf )

4 {

5 p _ c r t ++;

6 return 0;

7 }

8 else

9 return 1; // p_crt este deja la sfarsit

10 }

3.4 Modicarea poziiei cursorului n list


Pentru modicarea poziiei cursorului n lista la o poziie nr, trebuie vericat
dac lista este vid i dac indexul dat ca parametru este valid (mai mare strict
ca 0 i mai mic dect p_sf ce indic nalul listei).
1 int operator () ( int nr )

2 {

3 if ( p_sf != 1 && n r <= p_sf + 1 && n r >0)

4 {

5 p_crt = nr 1;

6 return 0;

7 }

9
8 return 1;

9 }

3.5 Modicarea valorii de pe poziia curent


Inainte de a modica un element al listei, se veric dac lista nu este vid i
daca poziia cursorului este valid. In cazul n care tipul de date al elementelor
din list este o clas denit de utilizator, este necesar denirea operatorului
de atribuire.
1 int S e t C r t D a t a (DT d )

2 {

3 if ( p _ s f <0 || p _ c r t>p _ s f || p _ c r t <0)

4 return 1; // eroare

5 elem [ p_crt ] = d;

6 return 0;

7 }

3.6 Inserarea unui element pe poziia curent


Inainte de a insera un element nou n list pe poziia curent, se veric dac
mai exist loc n list i dac poziia cursorului este valid.
1 int I n s e r t C r t (DT d )

2 {

3 int i ;

4 if ( p _ s f>MAX 2 || p _ c r t>p _ s f || p _ c r t <0)

5 return 1; // e r o a r e

6 d = elem [ p_crt ] ;

7
8 // parcurgere lista de la sfarsit spre pozitia curenta

9 for ( i = p_sf ; i >= p_crt ; i )


10 elem [ i + 1] = elem [ i ] ;

11
12 p _ s f ++; // actualizare index p_sf

13
14 return 0;

15 }

3.7 tergere/eliminarea elementului de la poziia curent


din list
1 int DeleteCrt ()

2 {

3 int i ;

4 if ( p _ s f <0 || p _ c r t>p _ s f || p _ c r t <0)

5 return 1; // e r o a r e

6
7 // mutare elemente cu cate o pozitie la stanga

8 for ( i = p_crt ; i <p _ s f ; i ++)

9 elem [ i ] = elem [ i + 1];

10

10
11 p_sf ; // actualizare index p_sf

12
13 return 0;

14 }

3.8 Lungimea unei liste


1 int Lungime ( )

2 {

3 return p_sf + 1;

4 }

3.9 Cutarea unui element n list


1 int l o o k u p (DT d )

2 {

3 int p = 0;

4 while ( p<p _ s f )

5 {

6 if ( elem [ p ] == d )

7 {

8 p_crt = p + 1;

9 return 1;

10 }

11 p++;

12 }

13 return 0;

14 }

3.10 Programul nal


1 #i n c l u d e <i o s t r e a m >

2 #i n c l u d e < s t d l i b . h>

3
4 using namespace std ;

5
6 #d e f i n e MAX 1 0 0

7
8 class DATA

9 {

10 int a;

11 float b;

12 public :

13 DATA( )

14 {

15 a = b = 0;

16 }

17 DATA( i n t a1 , float b1 )

18 {

19 a = a1 ;

20 b = b1 ;

21 }

22
23 bool o p e r a t o r ==(DATA x 2 )

24 {

25 return ( a == x 2 . a && b == x 2 . b ) ;

26 }

11
27
28 friend o s t r e a m& o p e r a t o r <<( o s t r e a m & , DATA) ;

29
30 };

31
32 o s t r e a m& o p e r a t o r <<( o s t r e a m& os , DATA d )

33 {

34 os << "( " << d . a << " , " << d . b << " )" ;

35 return os ;

36 }

37
38 t e m p l a t e <t y p e n a m e DT>

39 class ListaS ;

40
41 t e m p l a t e <t y p e n a m e DT> // Data Type

42 class ListaS

43 {

44 DT e l e m [MAX ] ;

45 int p_crt ;

46 int p_sf ;

47
48 public :

49 ListaS ()

50 {

51 p_crt = p_sf = 1;
52 }

53 int a d d E l e m S f (DT) ;

54 int o p e r a t o r ++() ;

55 int operator () ( int ) ;

56 int S e t C r t D a t a (DT) ;

57 int I n s e r t C r t (DT) ;

58 int DeleteCrt () ;

59 int getPozCrt ( ) { return p_crt ; }

60 void StergLista () ;

61 int Lungime ( ) ;

62
63 DT& operator [ ] ( int ) ;

64
65 int l o o k u p (DT) ;

66
67 friend o s t r e a m& o p e r a t o r << <DT>( o s t r e a m & , L i s t a S <DT>) ;

68 };

69
70 t e m p l a t e <t y p e n a m e DT>

71 o s t r e a m& o p e r a t o r << ( o s t r e a m& os , L i s t a S <DT> lst )

72 {

73 os << "{ ";

74 for ( int p = 0; p < l s t . p_sf ; p++)

75 os << l s t . elem [ p ] << " ";

76 os << "}" ;

77 return os ;

78 }

79
80 t e m p l a t e <t y p e n a m e DT>

81 int L i s t a S <DT> : : a d d E l e m S f (DT d )

82 {

83 if ( p _ s f<MAX 1)

12
84 {

85 p _ s f ++;

86 elem [ p_sf ] = d;

87 return EXIT_SUCCESS ;

88 }

89 else

90 return EXIT_FAILURE ;

91 }

92
93 t e m p l a t e <t y p e n a m e DT>

94 int L i s t a S <DT> : : o p e r a t o r ++()

95 {

96 if ( p_crt < p_sf )

97 {

98 p _ c r t ++;

99 return 0;

100 }

101 else

102 return 1;

103 }

104
105 t e m p l a t e <t y p e n a m e DT>

106 int L i s t a S <DT> : : o p e r a t o r ( ) ( i n t nr )

107 {

108 if ( p_sf != 1 && n r <= p_sf + 1 && n r >0)

109 {

110 p_crt = nr 1;

111 return 0;

112 }

113 return 1;

114 }

115
116 t e m p l a t e <t y p e n a m e DT>

117 int L i s t a S <DT> : : S e t C r t D a t a (DT d )

118 {

119 if ( p _ s f <0 || p _ c r t>p _ s f || p _ c r t <0)

120 return 1; // eroare

121 elem [ p_crt ] = d;

122 return 0;

123
124 }

125
126 t e m p l a t e <t y p e n a m e DT>

127 int L i s t a S <DT> : : I n s e r t C r t (DT d )

128 {

129 int i ;

130 if ( p _ s f>MAX 2 || p _ c r t>p _ s f || p _ c r t <0)

131 return 1; // e r o a r e

132
133 d = elem [ p_crt ] ;

134 for ( i = p_sf ; i >= p_crt ; i )


135 elem [ i + 1] = elem [ i ] ;

136 p _ s f ++;

137
138 return 0;

139 }

140

13
141 t e m p l a t e <t y p e n a m e DT>

142 int L i s t a S <DT> : : D e l e t e C r t ( )

143 {

144 int i ;

145 if ( p _ s f <0 || p _ c r t>p _ s f || p _ c r t <0)

146 return 1; // e r o a r e

147
148 for ( i = p_crt ; i <p _ s f ; i ++)

149 elem [ i ] = elem [ i + 1 ] ; // t r a n s l a t a r e a ele


150 // m e n t e l o r cu o pozitie

151 p_sf ;
152
153 return 0;

154
155 }

156
157 t e m p l a t e <t y p e n a m e DT>

158 DT& L i s t a S <DT> : : o p e r a t o r [ ] ( i n t p)

159 {

160 return elem [ p ] ;

161 }

162
163 t e m p l a t e <t y p e n a m e DT>

164 void L i s t a S <DT> : : S t e r g L i s t a ( )

165 {

166 p_crt = p_sf = 1;


167 }

168
169 t e m p l a t e <t y p e n a m e DT>

170 int L i s t a S <DT> : : Lungime ( )

171 {

172 return p_sf + 1;

173 }

174
175 t e m p l a t e <t y p e n a m e DT>

176 int L i s t a S <DT> : : l o o k u p (DT d )

177 {

178 int p = 0;

179 while ( p<p _ s f )

180 {

181 if ( elem [ p ] == d )

182 {

183 p_crt = p + 1;

184 return 1;

185 }

186 p++;

187 }

188 return 0;

189 }

190
191
192
193 int main ( )

194 {

195 L i s t a S <DATA> lst ;

196 DATA data ;

197

14
198 cout << lst << endl ;

199
200 cout << " Adaug 2 elemente la s f a r s i t " << endl ;

201 if ( l s t . a d d E l e m S f (DATA( 1 , 2.5) ) == EXIT_FAILURE )

202 exit (1) ;

203 cout << lst << endl ;

204
205 if ( l s t . a d d E l e m S f (DATA( 4 , 2.9) ) == EXIT_FAILURE )

206 exit (1) ;

207 cout << lst << endl ;

208
209 cout << " Avansare pozitie curenta de 2 o r i " << endl ;

210 if (++ l s t )

211 exit (1) ;

212
213 if ( l s t (2) )

214 exit (1) ;

215
216 cout << " Modificare element c u r e n t " << endl ;

217 if ( l s t . S e t C r t D a t a (DATA( 3 , 5.7) ) )

218 exit (1) ;

219 cout << lst << endl ;

220
221 cout << " Inserare element nou " << endl ;

222 if ( l s t . I n s e r t C r t (DATA( 9 , 3.7) ) )

223 exit (1) ;

224 cout << lst << endl ;

225
226 // i f ( l s t . DeleteCrt ( data ) )

227 // exit (1) ;

228 // cout << lst << endl ;

229
230 cout << " Afisare primul e l e m e n t " << endl ;

231 cout << lst [0] << endl ;

232 lst [0] = DATA( 4 , 6.7) ;

233
234 cout << " Modificare primul e l e m e n t " << endl ;

235 cout << lst [0] << endl ;

236 cout << lst << endl ;

237
238 data = DATA( 4 , 6.7) ;

239
240 cout << " Cautarea unui e l e m e n t " << endl ;

241
242 if ( l s t . lookup ( data ) )

243 cout << " Elementul " << d a t a << " a fost gasit in lista pe

pozitia " << l s t . getPozCrt ( ) << endl ;

244
245 else

246 cout << " Elementul " << d a t a << " nu a fost gasit in l i s t a " <<

endl ;

247
248 return 0;

249 }

15

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