Sunteți pe pagina 1din 318

Vlad Hutanu Tudor Sorin

'

INFORMATIC

(filiera teoretic, profilul real, specializarea


matematic-informatic) i
(filiera vocaional, profil militar MApN, specializarea
matematic-informatic)

Ciclul superior al liceului,


clasa a XI-a

Editura L&S Soft


Bucureti
Copyright 2006 L&S SOFT
Toate drepturile asupra acestei lucrri aparin editurii L&S SOFT.
Reproducerea integral sau parial a textului din aceast carte este posibil
doar cu acordul n scris al editurii L&S SOFT.

Manualul a fost aprobat prin Ordinul ministrului Educaie i i Cercetrii


nr. 4446 din 19.06.2006 in urma evalurii calitative organizate de ctre
Consiliul Naional pentru Evaluarea i Difuzarea Manualelor i este
realizat in conformitate cu programa analitic aprobat prin Ordin al
ministrului Educaiei i Cercetrii nr. 3252 din 13.02.2006.

Refereni tiinifici :

Prof. Dr. Victor Mitrana, Facultatea de Matematic , Universitatea Bucureti


Prof. grad 1Valiana Petrior, Colegiul Naional Bilingv George Cobuc

Tiparul executat la S .C . LUM INATIPO s.r.l.


Str. Luigi Galvani nr. 20 bis, sector 2, Bucureti

Anul tipririi: 2006

Descrierea CIP a Bibliotecii Naionale a Romniei


HUTANU, VLAD
Info rma tic : manual pentru ciclul superior a l liceului : clasa a XI-
a - (filiera teoretic, profilul real, specializarea matematic-informatic)
i (filiera vocaional, profil militar MApN, specializarea matematic
informatic) 1 Vlad Huta nu, Tudor Sorin. - B u cu reti : Editura L & S Soft,
2006
ISBN (10) 973-88037-1-3; ISBN (13) 978-973-88037-1-8

l. Tudor. Sorin

004(075.35)

Editura L&S SOFf: .1:


Adresa: Str. Stnjeneilor nr. 8, bl. 29, se. A, et. 1, apt. 12, Sector 4, Bucureti;
Tei./Fax: 031-l 05.62.84;
Mobil: 0722-530.390; 0722-57.37 .O 1;
E-mail: tsorin@ls-infomat.ro;
Web Site: www.ls-infomat.ro.
Cuprins
Capitolul 1. Tablouri .................................... . .... ... ...................... 7
1.1. Noiunea de tablou ...................... ....................................... ..... ..... ...... 7
1.2. Cum citim i cum afim un tablou bidimensional? ............................. ....... 8
1.3. Aplicaii cu tablouri bidimensionale ....................................... ................. 10
Probleme propuse ...... ....................................... ...................................... 16
Rspunsurile la testele gril .... .. ................................ ................................. 19

Capitolul 2. Subprograme ............... .. ............. ............... ............ 20


2.1. Noiunea de subprogram ....................................... .. .......................... 20
2.2. Subprograme n Pascal. .................................................................................. 22
2.2.1. Un exemplu de utilizare a funciilor..................................................... 22
2.2.2. Un exemplu de utilizare a procedurilor............................................... 24
2.2.3. Structura unui subprogram ................................................................. 25
2.2.3.1. Structura subprogramelor de tip funcie .............................. 25
2.2.3.2. Structura subprogramelor de tip procedur ........................ 26
2.2.4. Definirea i declararea unui subprogram ............................................ 27
2.2.5. Apelul subprogramelor........................................................................ 30
2.2.5.1. Apelul funciilor.................................................................... 30
2.2.5.2. Apelul procedurilor .............................................................. 31
2.2.5.3. Transmiterea parametrilor la apel....................................... 31
2.2.5.4. Cum memoreaz subprogramele parametrii tri mii?.......... 33
2.2.5.5. Transmiterea parametrilor prin valoare ............................... 33
2.2.5.6. Transmiterea parametrilor prin referin.............................. 35
2.2.6. Variabile locale i globale................................................................... 36
2.2.7. Greeli frecvente ................................................................................. 38
2.2.8. Uniti de program ............................................................................... 39
2.3. Subprograme n C++ ....................................................................................... 42
2.3.1. Exemple de utilizare a funciilor .......................................................... 42
2.3.2. Structura unei funcii. .......................................................................... 44
2.3.3. Declararea variabilelor ......... ............................................................... 46
2.3.4. Transmiterea parametrilor.................................................................. 49
2.3.5. Definirea i declararea unui subprogram ............................................ 53
2.4. Aplicaii care folosesc subprograme............... ................................................. 55
Probleme propuse ................ ............................ ......... .......................... .... 62
Rspunsuri. .. ................... ... .................................... .. .. ............................ 72

Capitolul 3. irur i de ca ractere ........... ..... .... ..................... .......... 73


3.1. Gene ral iti......... .... .... ........................ .... ........................... ..... ........ 73
3.2. i ruri de caractere in Pascal. ............. .... ............... ... .. ............ .. ............ 74
3.2.1 . Noiuni introductive ............................................................................. 74
3.2.2. Concatenarea i rurilor..... ................... ................................................ 76
4 Cuprins

3.2.3. Compararea irurilor........................................................................... 77


3.2.4. Lungimea iruri lor de caractere.......................................................... 79
3.2.5. Subiruri. ............................................................................................. 80
3.2.6. Conversii de la iruri la valori numerice i invers ................................ 84
3.2.7. Citirea i scrierea datelor de tip String din i n fiiere text... .............. 88
3.3. iruri de caractere n C++ ................................................................... 89
3.3.1. Generalitti. ....................................................................................... 89
3.3.2. Citirea i scrierea irurilor de caractere .............................................. 89
3.3.3. Tipul char*.......... ... ........................... .. ... .. .. ..... ... .. .. ... .... ...... .... .. .. . 92
3.3.4. Lungimea unui ir de caractere .......................................................... 93
3.3.5. Copierea i concatenarea irurilor de caractere................................. 94
3.3.6. Cutarea unui caracter ntr-un ir....................................................... 95
3.3.7. Compararea irurilor. .......................................................................... 97
3.3.8. Subiruri.. ............................................................................................ 99
3.3.9. Alte funcii utile n prelucrarea irurilor.............................................. 101
3.3.1 O. Conversia irurilor n valori numerice i invers ................................ 104
3.3.11. Citirea i scrierea irurilor de caractere din i n fiiere text... ......... 108
3.3.1 1.1. Operaia de citire ............................................................. 108
3.3.11.2. Operaia de scriere .......................................................... 109
3.3.12. O modalitate de conversie de la ir la alt tip .................................... 109
Probleme propuse ..................................... ..... ........... ............................ 11 O

Capitolul 4. Structuri de date neomogene ................................. 112


4.1. N oi uni introductive ........................................................ .. ................ 112
4.2. Structuri ne omogene n Pascal. ................. ............................ ...... ....... 112
4.2.1 . Tipul Record..... ................................................................................ 112
4.2.2. Accesul simplificat la cmpuri ........................................................... 114
4.2.3. nregistrri imbricate................... ....................................................... 115
4.2.4. Vectori de nreg istrri. ................. ...................................................... 115
4.2.5. nregistrare cu variante...................................................................... 116
4.3. Structuri neomogene n C++ ...... ................................. ................... .... 118
4.3.1. Tipul struct.... .................................................................................... 118
4.3.2. lnregistrri imbricate .......................................................................... 120
4.3.3. nregistrri cu structur variabil ....................................................... 121
Probleme propuse .. .................... ....................................... ... ................. 123

Capitolul 5. Structuri de date ................................................... 124


5.1. Conceptul de structur de date ........ ... ........................ .................. ...... 124
5.2. Structura de tip list liniar .................................................................126
5.2.1. Prezentarea structurii. ....................................................................... 126
5.2.2. liste alocate secvenial... .................................................................. 127
5.2.3. liste alocate nlnuit......................................................................... 128
5.2.4. Implementarea alocrii nlnuite prin utilizarea vectorilor................. 129
5.3. Structura de tip stiv ...... .............................. ..................................... 133
5.4. Structura de tip coad ....... ................... ................... ......... ................. 138
Probleme propuse ...... .......... .. .... .......................................... ................. 138
Rspunsuri ....... ................. ....... ................................................... ......... 140
"'Ual de informatic pentru clasa a Xl-a 5

:Zoitolul 6 . Introducere n recursivitate .... ... ............................. 141


~ Prezentare general ........................................ .. ............... ............... 141
:2 Mod ul n care se realizeaz autoapelul. .............................. ... ............... 141
6.2.1. Realizarea autoapelului n Pascal.. ................................................... 141
6.2.2. Realizarea autoapelului n C++ ......................................................... 142
~ 3 Mecanismul recursivitii. .................................................................. 143
: ~. Cum gndim un algoritm recursiv? ..... .................................................. 147
~ 5. Aplicaii recursive ..... ..... .. .. ................................................. .............. 148
6.5.1. Aplicaii la care se transcrie o formul recursiv ............................... 148
6.5.2. Aplicaii la care nu dispunem de o formul de recuren .................. 153
=~oble me propuse .......................................................... .. ..................... 159
~-aicaii 1 Rezolvri. ............................................................................... 166

cap itolul 7. Metoda Divide et lmpera ............................. ... ...... . 172


- Prezentare general .... ........ ......... ... ..... . .......................................... 172
- 2. Ap licaii .. . ................................................................................. ..... 172
7.2.1 . Valoarea maxim dintr-un vector...................................................... 172
7.2.2. Sortarea prin interclasare................................................................. 174
7.2.3. Sortarea rapid................................................................................. 176
7.2.4. Turnurile din Hanoi. .......................................................................... 179
7.2.5. Problema tieturllor.......................................................................... 180
- .3. Fractali ......................................................................................... 183
7.3.1. Elemente de grafic .......................................................................... 183
7.3.1.1. Generaliti (varianta Pascal) ............................................ 183
7.3.1.2. Generaliti (varianta C++) ............................................... 185
7.3.1.3. Setarea culorilor i procesul de desenare (Pascal i C++)... 186
7.3.2. Curba lui Koch pentru un triunghi echilateral.. .................................. 188
7.3.3. Curba lui Koch pentru un ptrat.. ...................................................... 191
7.3.4. Arborele ............................................................................................. 193
Probleme propuse ........................................................ ......................... 195
Rs punsuri. .. ................ ............ ..... ... ................................................... 196

Capitolul 8. Metoda Backtracking ...... ....................................... 199


8.1. Prezentarea metodei ..... : ............. .................................................... 199
8.1 .1 . Cnd se utilizeaz metoda backtracking?........................................ 199
8.1 .2. Principiul ce st la baza metodei backtracking ................................. 199
8.1.3. O modalitate de implementare a metodei backtracking .................... 201
8.1.4. Problema celor n dame ..................................................................... 204
8.2. Mai puine linii n programul surs ..... ....... .................... ... .................... 207
8.3. Cazul n care se cere o singur soluie. Ex.: problema colorrii hrilor....... 210
8.4. Aplicaii ale metodei backtracking n combinatoric ................................. 212
8.4.1. O generalizare util ........................................................................... 212
8.4.2. Produs cartezian ............................................................................... 213
8.4.3. Generarea tuturor submulimilor unei mulimi. .................................. 215
8.4.4. Generarea combinrilor............................................... ..................... 217
6 Cuprins

8.4.5. Generarea aranjamentelor................................................................ 219


8.4.6. Generarea tuturor partiiilor m~limii {1 ,2, ... , n}................................ 221
8.5. Alte tipuri de probleme care se rezolv prin utilizarea metodei backtracking .... 223
8.5.1 . Generalitti ....................................................................................... 223
8.5.2. Generarea partiiilor unui numr natural. .. ........................................ 224
8.5.3. Plata unei sume cu bancnote de valori date ..................................... 226
8.5.4. Problema labirintului. ........................................................................ 228
8.5.5. Problema bilei. .................................................................................. 231
8.5.6. Sritura calului. ................................................................................. 233
Probleme propuse .......................... ............. .......................... ................ 235
Indicaii. .......................... .......................... .......................... ................ 238

Capitolul 9. Grafuri ........................ ........................ .................. 239


9.1. Grafuri neorientate .................... .......................... ........................... .. 239
9.1.1. Introducere ........................................................................................ 239
9.1.2. Definiia grafului neorientat............................................................... 240
9.1.3. Memorarea grafurilor......................................................................... 242
9.1.4. Graf complet. ..................................................................................... 247
9.1.5. Graf parial , subgraf.. ........................................................................ 248
9.1.6. Parcurgerea grafurilor neorientate.................................................... 250
9.1.6.1. Parcurgerea tn lime (BF- bredth first) ........................... 250
9.1.6.2. Parcurgerea n adncime (OF - depth first) ...................... 253
9.1.6.3. Estimarea timpului necesar parcurgerii grafurilor.............. 255
9.1. 7. Lanuri. ......................................<- ......................... . .............. ............. . 255
9.1 .8. Graf conex ......................................................................................... 259
9.1.9. Componente conexe ......................................................................... 260
9.1.1 O. Cicluri. ............................................................................................. 262
9.1.11. Arbori. .............................................................................................. 264
9.1.11.1. Noiunea de arbore................................ ......................... 264
9.1.11.2. Noiunea de arbore parial. .............................................. 266
9.2. Grafuri orientate ........ .................... ............... ............ : ...................... 267
9.2.1. Noiunea de graf orientat.................................................................. 267
9.2.2. Memorarea grafurilor orientate ......................................................... 270
9.2.3. Graf parial, subgraf... ....................................................................... 272
9.2.4. Parcurgerea grafurilor. Drumuri. Circuite.......................................... 273
9.2.5. Graf tare conex. Componente tare conexe....................................... 275
Probleme propuse .......... .... .......................... .......................... ............... 278
Rspunsuri .......................... .......................... .......................... ............ 286

Anexa 1. Memento ........................ ........................ .................. 289

Anexa 2. Aplicaii practice ale grafurilor ........................ ............ 309

Anexa 3. Codul ASCII ........................ ........................ ............... 316


--- Capitolul 1
Tablouri

1.1. Noiunea de tablou

Anul trecut am studiat tablourile unidimensionale numite uneori, prin analogie


cu matematica, vectori. n acest an studiem tablourile bidimensionale numite, tot
prin analogie cu matematica, matrice .

..~ ..- .."' Definiia 1.1. Un tablou este o structur omogen (format din elemente
~

de acelai fel) cu un numr bine determinat de componente. Tabloul se


- ~:~
' identific printr-un singur nume, iar componentele sale se identific prin
intermediul unui sistem de indici.
Alturat avem reprezentat un tablou. Un
element al acestuia, a 1 .:t, se gsete pe linia i i
coloana j. Este esenial de reinut faptul c toate
elementele tabloului au acelai tip.
A=

am- l,l alll-1,2 alll-l,n

am.l a ",.2 a",~~~

1 . Un magazin ofer spre vnzare n produse. Se dorete s s_e rein


vnzrile lunare, valorice, din fiecare tip de produs. Putem organiza
datele sub form de tablou astfel:
vom numerota cele n produse cu 1 , 2 , .. ., n;
lunile le vom numerota cu 1, 2, ... , 12;
elementul a 1 .:l semnific valoarea incasat din vnzarea produslui i in luna
j a anului - prin urmare, elementele tabloului sunt de tip real.

.$ lntrebri posibile
a) Dac magazinul vinde 5 produse, cte elemente are tabloul?
b) Care sunt indicii de adresare n tablou pentrt.~ a afla vnzrile din produsul
5 n luna septembrie? -
c) Cum se poate calcula suma ncasat n luna mai?
8 Capitolul 1. Tablouri

d) tiind c, din punct de vedere economic, anul este mprit n patru


trimestre i c fiecare trimestru are trei luni, .cum se poate calcula suma
ncasrilor din trimestrul patru al anului?

e) Cum putem determina produsul din vnzarea cruia s-a incasat anual
suma maxim?
f) Care este luna cu cele mai mari ncasri?

2. Tot aa, se poate memora, sub form de tablou, situaia la nvtur a celor m
elevi ai unei clase. Dac numerotm elevii cu 1, 2, ... , m i materiile pe care acetia
le studiaz cu 1, 2, ... , n , atunci a 1 d reprezint media pe care o are elevul i la
materia j.

J~ ntrebri posibile
a) Dac n clas sunt 30 de elevi i acetia studiaz 8 materii, cte elemente
are matricea?
b) Care este materia la care elevii au cele mai bune rezultate?
c) Care este media general a elevului i?
d) Care este media general a elevilor unei clase?
irul exemplelor ar putea continua pentru c sunt foarte multe situaii in care
se utilizeaz tablouri bidimensionale (matrice).

1.2. Cum citim i cum afim un tablou bidimensional?


n clasa a X-a am nvat sa lucrm cu masive unidime.nsionale. Pentru a
adresa un element al unui vector se utilizeaz un singur indice. In cazul matricelor,
vom utiliza doi indici. Mai jos, putei observa cum se declara o matrice cu 1O linii i
9 coloane, cu elemente de tip intreg:

var astablou1
sau direct
var asarray [1 10,1 9) of real;

+ n Pascal, matricea are liniile 1,2,... ,10 i coloanele 1,2, ... ,9 i, de exemplu,
elementul de pe linia a treia i coloana a patra se adreseaz prin a [ 3, 4 l .
+ n C++, matricea are liniile 0,1, ... ,9 i coloanele 0,1, ... ,8 i, de exemplu,
elementul de pe linia a treia i coloana a patra se adreseaz prin a[2] [3] .
Uneori, pentru simplitate, vom folosi liniile i coloanele matricei Tncepand de
la 1 . ln aceste cond iii se pierde o linie i o coloan, fJecare de indice o.
Consideram acest fapt neesenial.
Manual de Informatic pentru clasa a Xl-a 9

De multe ori nu ljtim cte linii i cte coloane va


trebui sa aiba tabloul. In acest caz, tabloul se declara
cu un numar maxim de linii i un numar maxim de
coloane, n aa fel nct acesta sa corespunda oricarui
set de date de intrare. Evident, ntr-un astfel de caz
exista o risip de memorie interna, dar... programul nu
se va termina cu eroare. n figura alturat, avei
reprezentat grafic un tablou cu 8 linii i 8 coloane, din
care, ntr-un anumit caz, utilizam numai primele 41inii i
primele 5 coloane.

Figura 1.1. Exemplu de tablou

Programul care-I utilizeaza va f unciona corect daca avem cel mult a linii i
cel m uit s coloane.

fik::~~n programul urmator se citete i se afieaza un tablou. Iniial se citesc


(L-~ : numarul de linii i de coloane ale tabloului (m i n). Observai modul in
~.~ care am afiat tabloul - de aa natura nct i pe ecran sa arate ca o
matrice, adica fiecare linie s fie scrisa pe un rnd.

var m,n,i,j : integer; #include <iostream.h>


a:array[1 10,1 9] of integer; main()
begin { int m,n,i,],a[10] [9];
write ( 1 m 1 ) ; cout<<m; cin>>m;
readln(m) 1 cout<<"n; cin>>n;
write ( 1 11= 1 )1 for (i=O;i<m;i++)
readln(n); for(]=O;j<n;:J++)
for ! :1 to m o ( cout<< "a[" <<i+1<< 1 , 1

for j:l ton do <<]+1<< "] .. ";


begin cina[i] [] ) ;
write ( 1 A [ 1 , i, 1 , 1 , j, 1. ) ; }
readln(a[i,j]); for (iO;i<m;i++)
and J { for (jO;j<n;j++)
couta[i] [:J]' 1
;
for i:1 to m o cout<<endl;
bagin )
for j:l ton do }
write (a{i,j], 1 1
)1
writaln;
end
and.

+ n memorie, tablourile sunt reinute pe linii. Aceasta inseamna ca la nceput


este memorat prima linie, apoi a doua, .a. m.d.
10 Capitolul 1. Tablouri

1.3. Aplicaii cu tablouri bidimensioAale

O Aplicaia 1.1. lnterschimbare de linii. Se citete un tablou cum linii i n


coloane. Se citesc, de asemenea, i dou numere naturale distincte x i y,
cuprinse ntre 1 i m. Se cere s se interschimbe linia x cu linia y. La nceput vom
afia tabloul iniial, apoi pe cel obinut prin interschlmbarea liniilor x i y.

Exemplu: Considerm tabloul de mai jos, cu m.. 3, n3 i liniile x .. 2, y=3:

(~ !!]
n urma interschimbrii liniilor 2 i 3 se obine:

~ Rezolvare. Dup cum am nvat, pentru a interschimba coninutul a dou


variabile se utilizeaz o a treia, de manevr. De aceast dat , se interschimb dou
lini. Am fi tenta~ ca manevra s fie un vector cun componente. Cu puin atenie ne
dm seama c putem folosi ca man~vr o singur variabil de acelai tip cu cel al
componentelor de baz ale tabloului. In rest, analizai programul de mai jos:

type matrice= array[1 10, #include <iostream.h>


1 101 of byte; main()
var mat: matrice; { int mat [10] [10] ,m,n,i,
m, n, i, j, x, j,x,y, m.an;
y, man : integer; cout<<m"; cin>>m;
begin cout<<"n"; cin>>n;
{-citirea datelor-} for (iO ; i<m;i++)
write ( m= ') 1 readln(m); for ( j =O ; j <n;:l++)
write {'n= '); readln(n); {
for i := 1 tom do cout<<"mat["<<i+1<<','
for j := 1 to n do << j+l<<"l=";
begin cinmat[i] [j];
write ( mat [', i, , ,:!, '] '); };
readln(mat[i,j]); cout<<x";
end; ein>>x;
write('x= '); readln(x); cout<< "y";
write{ 'Y ') 1 readln(y); cin>>y;
{- tiparesc tabloul initial-) cout<<endl;
for i : 1 to m do for {iO;i<m;i++)
begin {
for j := 1 to n do for {jRO;j<n;j++)
write {mat[i,j],' '); cout<<mat[i][j]<<' ;
writeln; cout< <endl;
end; )
Manual de informatic pentru clasa a Xl-a 11

{-interachimbare linii-} for(jOd<n; j++)


for j:=l ton do { man=mat[x-l]~j];
begin mat [x-1] [j] -mat (y-1] [j] ;
man z mat[x,j]; mat[y-1] [j]man;
mat (x, j ] z mat [y, j ]; )
mat[y,j] 1 man; cout<<endl;
end; for (iO;i<m;i++)
writeln; ( for (jO;j<n;:l++)
coutmat [il [j l ' '1
{-tiparesc tabloul inversat-) cout<<endl;
for i :s 1 to m do }
begin }
for j := 1 to n do
write(mat[i,j],' ');
writeln;
end;
end.

O Aplicaia 1.2. Spirala. Se citete un tablou cu n linii i n coloane. Se cere s se


afieze elementele tabloului n ordinea rezultat prin parcurgerea acestuia n
spiral, Tncepnd cu primul element din linia 1, n sensul acelor de ceas.

Exemplu. Fie tabloul:


,

afiate
(CJ]
in ordinea:
Elementele vor fi
1 2 3 6 9 8 7 4 5.

0 Rezolvare. Pentru a putea rezolva problema, privim tabloul ca pe un ansamblu


alctuit din mai multe dreptunghiuri "concentrice":

/-------"'

Tabloul de mai sus este un ansamblu format din trei dreptunghiuri


"concentrice" - ultimul are un singur element i nu a putut fi reprezentat. Dup ce
stabilim numrul de ptrate (cum?), afim elementele aflate pe fiecare latur a
fiecrui ptrat Tn ordinea cerut, avnd grij ca elementele aflate Tn coluri s nu fie
afiate de dou ori.
12 Capitolul 1. Tablouri

type matrice array(l lO, --


#include <iostream .h>
1 10] of integer; main(}
var mat: -trice; ( int mat[l.O] [10),n,i ,j,k;
n, i, j, k: integer; cout<<n "; cin>>n;
begin for(i1;i< =n;i++}
{-citirea datelor-} for (jl;j<=n;j ++)
write ( 1 n 1 } ; readln(n }; ( cout<<"m at[<<i<< ', 1
for i r 1 to n do <<j<<J ;
for j := 1 to n do cin mat[i] [j);
begin }
wri te ( 1 - t ( , i, 1 , 1 , j, 1 l 1 ) ; for(k=l ; k <=n/2+1;k ++}
readln(m at[i,j]}; { for(ik;i<~n-k+l;i++}
end; cout<<ma t[k) [i)<<end l;
{-liatare -) for(i k+l;i<n -k+l. ; i++)
for k := 1 to n div 2 + 1 do cout<<m at[i] [n-k+l]<< endl;
bagin for(in-k ;i>k;i-- }
for i r k to n-k+1 do cout<<ma t[n-k+l] [i] <<endl;
writeln( mat[k,i) }; for(i n-k;i> k+l;i--}
for i := k+l to n-k+1 do cout<<ma t[i] (k]<<end l;
writeln(m at[i,n-k+ 1]}1 )
for i : n-k downto k do }
vriteln(m at[n-k+l ,i)}l
for i r n-k downto k+1 do
writeln(m at[i,k)}
end;
end.

Ll Aplicaia 1.3. Pe o tabl cu n linii i m coloane (n, m numere naturale,


1~n~30 ), sunt plasate pe unele pozi~i jetoane cu litere, conform unui joc corect
de SCRABBLB. tiind c vocalele au eate un punct, iar consoanele eate dou,
stabilii valoarea total a cuvintelor de pe tabl. Valorije n i m i configura
ia tablei
se citesc din fiierul "tabla. txt", conform exemplului (locurile goale de pe tabl
sunt memorate sub forma unor caractere punct).

Exemplu. Pentru datele de intrare:


3 5
D.SAU
ALT:I.
.A.
se afieaz 2 o
(DA3, STAS, ALT:I6, SAtJ4 , AI=2).

0 Rezolvare. Cutarea cuvintelor pe tabl . i cumula rea punctelor lor este, de


obicei, prima soluie la care ne gndim. Algoritmul corespunztor acestei soluii pare
tns destul de complicat. Simpla parcurgere a matricei de caractere i adunarea
valorilor corespunztoare literelor nu este o strategie bun, deoarece se pierde
Manual de Informatic pentru clasa a Xl-a 13

~j ul literelor care apar ntr-un cuvnt pe orizontala i unul pe verticala i care ar


rebui luate de do u ori ln calcul. De aceea, vom analiza ln pi!JS, pentru fiecare litera,
:iaca ea face parte dintr-un singur cuvnt (are litere vecine doar pe orizontal sau
doar pe verticala) i se puncteaza obinuit, sau face parte din doua cuvinte (are litere
.-ecine i pe orizontal i pe vertical) i atunci se puncteaz dublu.

char
n,m,i,j,dir:~e;
int n,m,i,j,dir,p,pt;
p,pt ~integer;
ifstream f(tabla.txt);
f:textl
begin
void main()
aaaign(f, 1 tabla.txt 1 )1 {
reaet(f); f>>n>>m;
readln(f,n,m); for(ilti<nti++)
for i ~l to n do for(:f1I:f <ml:f++)
begin f.a [il [j) 1
for jsl tom do pt=O;
read(f,a[i,:fl)l for(i=1;i< nii++)
readln(f) for(jll:f <-.m;:f++)
endl if (a[i][:fll 1 , ' )
pt ~o,
{
for i ~1 to n do if(a[ill:fl 'A'I 1
for j :,.1 to m do 1
if a[i,j]<>',' then a[i) [j] E' 11
a[i) [:fl 'J:'
begin
a[i) [:fl 1 0' 1
if (a[i,j]c'A') or a[iJ[:fl 'U')
(a[i.j)'E') or p=li
(a[i,:f] 1 l: 1 ) or alsa p:ZI
(a[i, j)= 1 0') or dirQI
(a[i,:f]= 1 U') then P ~1 if (i>l && a[i-1] [:f]l', 1

elae p: :Z; 11 i<n &&


dir~01
a[i+1l [:fl 1 1 )
if (i>1) and (a[i-1,:fl<> 1 , 1
)
dir++;
or if (:f>l &r. a[i) [j-1]1'. 1
(i<n) aud (a[i+1,j)<>' . 1 )
11 :f<m &&
then dir ~ dir+l; a[i) [:f+ll J=l. 1)
if (:f>1) and (a[i,j-1)< > 1 1
)
dir++l
or pt+p*dir;
(j <m) and (a[i,j+1)< > 1 , 1 )
}
then dir:=dir+1; cout<<Pt<<andll
pt ~ -Pt+p*dir )
end1
writeln(pt)
end.

Dac utilizm artificiul de a borda matricea cu caractere punct:

r,pentru i=O,n+l execut

1
a o, i~ 1
1 &n+l, i~ 1
1

~
14 Capitolul 1. Tablouri

atunci testarea vecinilor elementelor de pe margine se realizeaz ntocmai ca i in


cazul celor din interiorul matricei:
.-
dir~dir+l (cel puin un vecin pe direcia vertical)

rdac ai.~-1~' ' sau ai,:l+l:;l!:' '


dir~dir+l (cel puin un vecin pe direcia orizontal)

Se mai poate analiza i cazul in care o liter nu are nici un vecin pe niciuna
dintre d ireciile orizontal sau vertical (caz Tn care litera nu s-ar puncta deloc), ns
problema precizeaz c literele sunt aezate corect conform jocului de scrabble,
deci nu pot fi amplasate litere izolate.

Cl Aplicaia 1.4. Sortarea fr comparaii este o metod de sortare care permite


sortarea an numere naturale, fr a face nici mcar o comparaie intre ele.

Vom prezenta algoritmul pe un exemplu in care se sorteaz cresctor 6


numere naturale: 6 , 36, 41, 25, 40 i 30.

Iniial, irul celor n numere se imparte n 10 clase: prima clas conine


numerele care se termin cu o, a 2-a clas, cele care se termin cu 1, ... a 10
clas, cele care se termin cu 9 .

Pentru memorarea numerelor care aparin fiecrei clase vom utiliza o matrice,
denumit Mat, cu 10 coloane, in care prima linie are indicele o. Elementele din linia o
rein numrul de elemente din ir care se gsesc pe coloana respectiv:

o 1 2 3 4 5 6 7 8 9

11 215
1 :: 1 . 1 o 1 o 1 o 1 1 .:. 1 o 1 o 1 o 1

Obinem din nou irul de numere, aezndu -le n ordinea col<;?anelor i n


ordinea in care le-am pus in fiecare coloan: 40, 30, 41, 25 , 6, 36. lmprim din
nou irul n 10 clase, dup a 2-a cifr a numerelor:
o 1 2 3
'2 5 6 7 8 9

1: 1 o 1
215
1 :~ 1 :: 1 o 1 o 1 o 1 o 1o 1
Manual de informatic pentru clasa a Xl-a 15

Obinem din nou irul de numere, aezndu-le in ordinea coloanelor i n


ordinea n care le-am pus n fiecare coloan: 6, 25, 30__, 36, 40, 41. De
aceast dat, irul este sortat.

~ Observaii
../ Dac k este numrul maxim de cifre a numerelor din ir, operaia de
mprire a numerelor n 10 clase se va relua de k ori.

Algoritmul este "mare consumator" de memorie!

var A:array [1 1001 of #include <iostream. h>


integer; int A(100],Mat(100l [100],n,
Mat:array[0 100,0 100] NrCif,i , :f,k,Cif,Zece;
of integer;
n,HrCif,i,j,k,Cif,Zece: main()
integer; { cout<<"n" ; cin>>n;
begin for (il;i<n; i++)
write('n '); readln(n); { cout<<"A("<<i<<"l";
for i : 1 to n do cinA[i] 1
}
begin
write('A[',i, ' l= '); Zece=1;
readln(A[i]) for(HrCif=1;HrCif<=4;HrCif++)
end; { if (NrCif>1) Zece*10;
Zece : 1; for (i=1;i<n;i++)
for NrCif:=l to 4 do {Cif= {A(i] 1 zece) % 10;
begin Mat(O] [Cif]++;
if HrCif>1 then Mat[Mat[O] [Cif)) [Cif]=A[i];
}
Zece:=Zece*10;
for i:1 to n do //Extrag din mat. in vector
begin k=O;
Cif:=(A[il div Zece) for (iO;i<=9;i++)
mod 10;
if (Mat[O] [i])
Mat[O,Cif] :Mat[O,Cif]+1; for (j=1;j<Mat[0] [i];j++)
Mat[Mat[O,Cif],Cif] : A[i] { k++;
end; A[k]=Mat[j] (i];
}
{Extrag din mat. in vector}
k:=O; for (iO;i<9;i++)
for i:=O to 9 do Mat[O] [i]O;
}
if Mat(O,i]<> O then
for :1:=1 to Mat(O , il do for (i1;i<=n;i++)
begin cout<<A[i]<<endl;
}
k:=k+1;
A[k]: Mat[:f,i]
end;
for i:=O to 9 do
Mat[O,il:=O;
end;
for 1 : =1 to n do
Writeln(A(i]) ,
end .
Capitolul 1. Tablouri
16

Proble.me prop use


de tablou, n
1. Se citete un tablou cun linii i n coloane, numere ntregi. Un astfel
lor, se numet e tablou ptratle .
care numru l liniilor coincide cu numrul coloane

a) Pentru un tablou ptratic A, numim diagonal principal , elemen


tele aflate pe
"linia" care unete A[l, 11 cu A[n,nl .

Exemp lu. Pentru tabloul de mai jos

(~}
elementele sunt: 1 , s i 9.

Se cere:

a1) suma elemen telor aflate pe diagonala principal;


a2) suma elemen telor aflate deasupra diagonalei principale;
a3) suma elemen telor aflate sub diagonala principal.

tele aflate pe
b) Pentru un tablou ptratic A, numim diagonal secundar, elemen
unia" care unete A (n, 11 cu A [l,nl .

Exemp lu. Pentru tabloul

(~}
elementele sunt: 7 , s i 3.

Se cere:

b1) suma elemen telor aflate pe diagonala secundar;


b2) suma elemen telor aflate deasupra diagonalei secundare;
b3) suma elemen telor aflate sub diagonala secundar.

Cerine suplime ntare:

pentru fiecare cedn se va face un program separat;


n nici un program nu se va folosi instruciunea if .

n linia k ,
2. lnterschimbai coloanele unei matrice c1~ m linii i n coloane astfel nct
elementele s fie in ordine cresctoare.
Manual de informatic pentru clasa a Xl-a 17

3. Un teren este dat sub forma unui tablou A cu n linii i m coloane. Elementul
A [i 1 j l reine altitudinea ptrelului de coordonate i i j. S se afieze
coordonatele "ptrelelor vrf" (un ptrel este vrf dac toi vecinii si au o
altitudine strict mai mic).

4. Determinai elementele a ale unei matrice cu n linii i m coloane (elemente


minime pe linie i maxime pe coloan sau maxime pe linie i minime pe coloan) .

../ Indicaie. Atenie! Maximele sau minimele pe linii sau coloane pot s nu fie
unice. Dac vom considera numai o valoare dintre acestea, s-ar putea s pierdem
soluii.

5. Pentru o matrice a, cu .n linii i m coloane citit din fiierul"matl. txt", se cere


s se afieze cel mai mare element din matrice i indicii acestuia. Scriei programul
pseudocod corespunztor.

6. Pentru o matrice de numere reale a, cu 5 linii i 4 coloane, citit de la tastatur,


se cere s se afieze suma elementelor strict pozitive din matrice.

7. Pentru o matrice a , cu n linii i n coloane citit din fiierul"mat3. txt", se cere


s se decid pe care dintre cele dou diagonale, suma elementelor constitutive
este mai mare. Se va afia un mesaj corespu nztor.

8. Pentru 5 cifre n 1 a 1 b 1 c 1 d citite de la tastatur , se cere s se creeze fiierul


"mats. txt" care s conin o matrice cu 2n linii i 2n coloane, format din 4
submatrice disjuncte, fiecare cu n linii i n coloane, una dintre ele fiind format
numai cu componente egale cu a, una numai cu componente egale cu b , una cu c
i una cu d. Este necesa r construirea in prealabil a matricei i n memorie?

9. Fereastra. Fiind dat o matrice cu m linii i n coloane. Se cere s se afieze


toate submatricele cu 3 linii i 3 coloane ale matricei iniiale. Un astfel de procedeu
este utilizat atunci cnd, de exemplu, o imagine este mult prea mare i ea este
afiat cu ajutorul unei ferestre.

Exemplu: m=4 , n=4. Matricea iniial i submatricele sunt prezentate mai jos:

1 2 3 lf
5 G7 8 1 2 3 2 3 lf 5 G7 G7 8
9 H> 11 12 5 G7 G7 8 9 1 o 11 10 11 12
13 1LJ 15 1G 9 1o 11 10 11 12 13 1lf 15 1LJ 15 1G

10. Fiind dat o matrice cum linii i n coloane, se cere s se afieze elementele n
ordinea sugerat n figura de mai jos:

.+
i~
Figura 1.2. Exemplu
18 Capitolul 1. Tablouri

11. Fiind dat o matrice cu m linii i n coloane se cere s se ~ A


afieze elementele n ordinea sugerat n imaginea alturat.

Figura 1.3. Exemplu


4 4
12. Fiind dat o matrice cun linii i n coloane(ptratic) cu numere naturale i fiind
date dou elemente ale matricei de coordonate (xl,yl) i (x2,y2) , care dintre
relaiile de mai jos testeaz dac elementele se gsesc pe o dreapt paralel cu
una dintre diagonalele matricei (principal sau secundar)?

a) if x1-x2 ...y1-y2 a) if (x1-x2==y1-y2)


then writeln('Da') cout<<"Da"l
else writeln('Nu') ; else cout<<"Nu" ;
b) if x1-y1=x2-y2 b) if (x1-yl ..x2-y2)
then writeln('Da') cout<<"Da"
else writeln('Nu'); else cout<<"Nu";
c) i f abs(x1-y1)=abs(x2-y2) c) if (abs(x1-y1)==abs(x2-y2))
then writeln('Da') cout<<"Da" ;
else writeln('Nu')l else cout<<"Nu" l
d) if abs(x1-x2)=abs(yl-y2) d) i f (abs(x1-x2)==abs(yl-y2))
then writeln('Da') cout<<"Da";
else writeln('NU')I el se cout<< "Nu"l

13. Se d un vector v cu m*n componente numere ntregi. Care dintre secvenele


de mai jos copiaz vectqrul v n matricea Mat cu m linii i n coloane? Copierea se
realizeaz completnd mai nti elementele de pe linia 1, apoi elementele de pe
linia 2, ... , iar la sfrit, elementele de pe linia m.

./ Copierea se realizeaz prin utilizarea unui singur ciclu for!

a) for k : =1 to m*n do Mat[1+k a) for <k=1 ; k<=m*n;k+ +)


div n,1+k mod m] : =V[k] ; Mat[l+(k-1)/n] [1+(k-1)% mJ=V[kl ;
b) for k : =1 to m*n do b) for (k=1Jk<=m*n;k++)
Mat[l+(k-1) div m, 1+(k-1) mod Mat[l+(k-1)/m] [1+(k-1)% n] =V[k]I
n] : =V[k] ; c) for (k=1; k<=m*nJk+ +)
c) for k :=1 to m*n do Mat[l+(k-1)/n] [1+(k-1)% n]=V[k];
Mat[1+(k- 1) div n,1+(k-1) mod d) for (k=1;k<=m*n;k++)
n] : =V[k] ; Mat[1+k/n] [1+k%n]=V[k];
d) for k:=1 to m*n do Mat[1+k
div n,l+k mod n]:=V[k];
~u al de informatic pentru clasa a Xl-a 19

~. Se d un vector v cu m*n componente numere ntregi i o matrice Mat cu m


.,.. i n coloane. Care dintre secvenele de mai jos copiaz matricea Mat n
.-:ctorul v? Copierea se realizeaz astfel: mai nti se copiaz linia 1, apoi linia 2,
'ar la sfrit, linia m.

a)
for j:=l tom do
V[j+(i-l)*m):=Mat[i,j]; V[j+(i-l)*m)Mat[i] [j];
!>) for i:l to m do b) for (il;i<-m;i++l
for j:=1 to n do for (j1;j<n;j++)
V[j+(i-l)*n):Mat[i,j]; V[j+(i-l)*nJ=Mat[i] [j];
C} for i:=l tom do c) for (i1;i<m;i++)
for j:=l ton do for (j=l;j<=n;j++)
V[i+(j-l)*n] :~Mat[i,j]; V[i+ (j-1) *nl Mat [i) [j);
d) for i: l to m do d) for (il;i<m;i++l
for j:l ton do for (j1d<=nd++)
V[j+(i-1)*n] :Mat[j,i); V[j+(i-1l*n]=Mat[i,j];

~ spunsurile la testele gril

"2. d); 13. c); 14. b).


Capitolul 2

Subprograme

2.1. Noiunea de subprogram

Definiia 2.1. Prin subprogram vom nelege un ansamblu alctuit din


declarri i instruciuni scrise n vederea unei anumite prelucrri,
ansamblu implementat separat i identificat printr-un nume.

Pn fn prezent am fost doar utilizatori de subprograme. Exemple de astfel


de subprograme folosite sunt:

matematice: sin, cos, abs, exp, trunc (Pascal) 1 floor (C++);


de manipulare a fiierelor: close (Pascal) 1 closo () (C++).

in acest capitol rnvm s lucrm cu subprograme. Pentru a nelege


no.iunea de subprogram, vom porni de la dou exemple.

:h..; 1. Se consider funcia:


'"
~ ~~
~
~ X+ 1
pentru x e [-1,1];

!
1+ x 2 '
f (x) = X + 1,'
pentru x e (- oo ,-1);
6
pentru x e ( 1, oo ).
1+ X

Se citesc dou valori reale a i b. S se scrie un program care afieaz care dintre
valorile f (a> i f (b) este cea mai mare.

Ce observm? C att pentru calculul valorii funciei in punctul a, ct i


pentru calculul valorii funciei n punctul b, aplicm acelai tip de raionament:
ncadrm valoarea respectiv (a sau b) ntr-unul dintre cele trei intervale i aplicm
formula de calcul corespunztoare.

Cum procedm? Prin utilizarea cunotinelor dobndite pn in prezent,


scriem secvena de program care calculeaz valoarea funciei calculat pentru x=a
i se mai scrie o dat (sau se copiaz i se adapteaz) secvena de program care
calculeaz valoarea funciei calculat pentru xb.
if~n ual de informatic pentru clasa a Xl-a 21

Oare nu se poate lucra i altfel? Rspunsul este afirmativ. Se scrie un


:;'"'::>program care calculeaz valoarea funciei ntr-un punct x oarecare i se
:=eleaz subprogramul: o dat pentru x=a i nc o dat pentru x=b. Valorile
:a culate la cele dou apeluri, se compar ntre ele i se afieaz rezultatul cerut.
:;:: 2 Se citete n, un numr natural. Se citesc apoi n numere reale. Se
--X: cere s se afieze cele n numere n ordinea cresctoare a valorilor lor.

Desigur, tim s rezolvm aceast problem n mai multe feluri, pentru c


:;- 11 s memorm un ir de valori (folosind un vector) iam studiat mai multe
-etode prin care se poate obine ordonarea cresctoare a unui ir de valori
:>~os i nd algoritmi de sortare). De aceast dat, vom implementa o metod
:_noscut, cea de sortare, dar vom utiliza subprogramele.

Vom scrie un subprogram care citete un vector, unul care tiprete un


ector i un al treilea care sorteaz vectorul dup una din metodele cunoscute.

n acest caz, programul ar arta astfel:

Pasul 1 - se apeleaz subprogramul care citete vectorul.


Pasul 2 -se apeleaz subprogramul care sorteaz vectorul.
Pasul 3 - se apeleaz subprogramul care tiprete vectorul.

Fa de scrierea clasic, aici problema a fost descompus in trei


probleme mai simple (citire, sortare i tiprire). n general, o problem complex
se rezolv mai uor dac o descompunem in alte subprobleme mai mici. Apoi,
ansele de a grei la scrierea unui subprogram sunt cu mult mai mici dect acelea
::e a grei la scrierea unui program mare.

ln plus, dac ntr-un alt program este necesar sortarea altui vector de
~u mere reale, metoda clasic ne permite s alegem din secvena de instruciuni ce
'ormeaz programul pe cele ce realizeaz sortarea, s le copiem Tn noul program
t s facem eventualele adaptri (numrul de componente i numele vectorului pot
1 altele). Aceste operaii sunt destul de greoaie i necesit mult atenie. Prin
mplementarea modular, cu ajutorul subprogramelor, "preluarea" se realizeaz
mult mai uor.

Putem acum enumera unele dintre avantajele utilizrii subprogramelor:

reutilizarea codului - odat scris, un subprogram poate fi utilizat de ctre


mai m uite programe;
elaborarea algoritmilor prin descompunerea problemei n altele mai
simple - n acest fel, rezolvm cu mult mai uor problema;
reducerea numrului de erori care pot aprea la scrierea programelor;
depistarea cu uurin a erorilor - verificm la nceput subprogramele,
apoi modul n care le-am asamblat {le-am apelat din cadrul programului);
realizarea unor programe uor de urmrit (lizibila) .
22 Capitolul 2. Subprograme

2.2. Subprograme n Pascal

2.2.1. Un exemplu de utilizare a funciilor

O Problema 2.1. Se citete n, numr natural. S se scrie programele care


afieaz valoarea calculat a expresiilor:

Et = 1+.!_ +.!_+ +.!_. E2 =(l +_!_+_!_++_!_)n


2 3 n' 2 3 n

~ Rezolvare. Funcia care calculeaz :e:1 este:


function subp(nainteger)areall
var arealJ
iainteger1
begin
8101
for ir=l to n do SIB+l/i;
subp1s;
end;

Analiza programului anterior

-+ Antetul funciei este "funotion subp(nainteger) :real;".

-+ Funcia se numete "subp".

-+ Ea este recunoscut de compilator prin faptul c antetul este precedat de


cuvntul cheie "function".

-+ Funcia are un parametru numit n. Rolul su este important i anume


precizeaz pentru ce valoare trebuie calculat expresia. Aa cum vom
vedea, exist posibilitatea s avem mai muli parametri, de diferite tipuri.
-+ Funcia are un anumit tip, care precizeaz natura rezultatului. .n exemplu,
tipul este real ntruct expresia calculat este de acest tip.

-+ Funcia are variabile proprii - adic variabile care sunt definite n cadrul el. n
exemplu, ele sunt s i i . Aceste variabile se numesc variabile locale.

-+ Am vzut c funcia ntoarce un anumit rezultat - n exemplu, de tip real.


Observai mecanismul prin care am obinut aceasta. Calculez expresia n
mod obinuit. Rezultatul este reinut de variabila local s. Prin atribuirea
"subp=s 1 ", funcia a primit ca valoare de retur coninutul variabilei s.

n continuare, prez&ntm cele dou programe care utilizeaz funcia:


''anual de informatic pentru clasa a Xl-a 23

var n:integer;
function subp(n:integer)z real;
var szreal;
i:integer;
begin
s:=O;
for i:1 to n do s:s+1/i;
subp:s;
end;
begin
write ('n'); readln(n);
write(subp(n):5: 2);
end.

var n,i:integer;
rez,prodzreal;
function subp(nzinteger)z real;
var szreal;
i:integer;
begin
s:=O;
for izl to n do s:s+l/i;
subp:s;
and;
begin
write ('n'); readln(n);
rez:subp(n);
prod:l;
for izl to n do prodzprod*rez;
write(prodz5:2);
end.

-+ Funcia este apelat ntotdeauna din cadrul unei expresii.


Apelul funciei n primul proaram s-a fcut astfel: "write(subp(n) z5:2) ;",
ar n al doilea, "rez aaubp(n) ". In primul caz expresia este trecut ca parametru
oentru write, iar in al doilea, avem o expresie de atribuire.

n terminologia utilizat n teoria subprogramelor - n particular, n cazul


funciilor- se utilizeaz termenii parametri formali i parametri efectlvl.

Definiia 2.2. Parametrii care se gsesc n antetul funciei se numesc


parametri formali.

Atunci cnd scriem o funcie , nu cunoatem valoarea propriu-zis a


parametrilor. Funcia trebuie s ntoarc rezultatul corect, oricare ar fi valoarea lor.
Din acest punct de vedere ei se numesc formali.

Definiia 2.3. Parametrii care se utilizeaz la apel se numesc parametri


efectivi.

La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare
acetia se numesc parametri efectlvl.
24 Capitolul 2. Subprograme

ntre parametrii formali si parametrii efectivi trebuie s existe o concordan,


care va fi studiat la momentul potrivit.

2.2.2 Un exempl u de utilizare a proced urilor

D Problema 2.2. Se citete n, numr natural. Se citete un vector cu n


componente numere reale. Se cere s se tipreasc vectorul sortat.

0 Rezolvare . Programul este urmtorul:


type vectora rray [1 9) of integer;
var n,i:integ er;
v:vector ;
procedur a citesc;
begin
write('n' ); readln(n );
for i:=l to n do
begin
write('v [,i,']=' ); readln(v [i]);
end;
end;
procedur e tiparesc ;
begin
for i:l ton do writeln( v[i));
end;
procedur a sortez;
var gasit:boo lean;
man:inte ger;
begin
repeat
gasit:=f alse;
for i:=l to n-1 do
if v[i)>v[i +l)
then
begin
gasit:atr ue;
man:v[i ]; v[i):v[ i+lll v[i+l) :man
end
until not gasit;
e nd;
begin
citesc;
sortez;
tiparesc ;
end.

Programul conine trei proceduri: citesc, sortez i tiparesc . Forma


simplificat prin care este descris o procedur este:

procedur a nume;
begin

end;
Vanual de informatic pentru clasa a Xl-a 25
----------------~----------------------------------------

+ Apelul unei proceduri se face prin utilizarea numelui ei, sub forma nume 1
Mai precis, apelul unei proceduri este instruciun~, numit instruciunea
de apel.
-+ La apel, controlul programului este transferat la prima instruciune a
procedurii - dup cum se ntmpl i la funcii. Dup executarea procedurii,
se revine in programul principal/a prima instruciune care urmeaz celei de
apel- n cazul de fa se ntlnete o alt instruciune de apel.
~ Ca i funciile, procedurile se pot plasa n cadrul programului intre
declaraiile de variabile i instruciunea compusfJ.

-+ Orice variabilfJ a programului principal este i variabii(J a procedurii (invers nu


este adev~rat).

l

n acest exemplu, procedurile sunt apelate fr utilizarea parametrilor. n
realitate, procedurile pot avea parametri ntocmai ca i funciile.

2.2.3. Structura unui subprogram

n esen, un subprogram este alctuit din:

Antet - conine mai multe informaii important~ necesare compilatorului,


numele subprogramului, lista parametrilor formali. In cazul subprogramelor de
tip funcie, conine i tipul rezultatului (valoarea ntoars de funcie).

Bloc - cuprinde definiiile tipurilor de variabile, ale variabilelor, ale


subprogramelor i o instruciune compus. Structura sa este identic cu cea a
programului principal, indiferent dac este bloc de procedur sau de funcie.

~ Programul principal conine un antet (program nume) i un bloc.

Pentru prezentarea structurii subprogramelor de tip funcie vom utiliza


diagramele de sintax.

2.2.3.1. Structura subprogramelor de tip funcie

n figura urmtoare este prezentat structura antetului:

LISTA
ANTET DE
--FUNCIE PARAMETRI
FORMALI

IDENTIFICATOR
DE TIP

Figura 2.1. Structura antetului unui subprogram de tip funcie


26 Capitolul 2. Subprograme

Exemplu:
function suma(x,y:int eger):real;
begin
sum.a:=x+y;
end

- antetul este "function suma (x, y a integer) a real:";

- identificatorul (numele) funciei este suma. Lista parametrilor formali este:


"x, y: integer". Funcia este de tip real (identificatorul de tip);

-blocul este (n acest caz lipsesc variabilele locale):

begin
suma:x+y;
end

Important: identificatorul de tip (tipul valorii ntoarse de funcie) poate fi: de


r~~i' orice tip ordinal, de orice tip real, de orice tip pointer sau de tipul string
(acest tip va fi studiat n acest manual).

2.2.3 .2. Structura subprogramelor de tip procedur

n figura urmtoare este prezentat antetul de procedur:

LIST.J.
ANTET IDENTIFICATO R PARAMETRI
PROCEOURE
-PROCEDUR FORMALI

Figura 2.2. Structura antetului unui subprogram de tip procedura

Exemplu:
procedura suma(var szreal; x,yzreal);
begin
SI"'X+y;
end;

-antetul este: "procedura suma(var sareal1 x,y:real) 1"

- identificatorul (numele procedurii) este suma;

-lista parametrilor formali este: "var s :real1 x,yareal;";

- blocul este:
begin
SIX+y;
end;
v,a.,ual de informatic pentru clasa a Xl-a 27

: .2.4. Definirea i declararea unui subprogr:.am

Dei aparent asemntoare, cele dou noiun i difer . Buna nelegere a lor
-e aj ut s evitm anumite erori. Mai mult, aceste noiuni sunt utilizate de orice
,...baj de programare, nu numai de Pascal.

Definiia 2.4. A defini un subprogram,. nseamn a-1 scrie efectiv,


dup structura anterior prezentat. O problem important este locul
unde se definete subprogramul.

Pascal, subprogramele se definesc n trei locuri:

n blocul programului care-I utilizeaz numit i program principal ntre


declaratia variabilelor i instruciunea compus:
program exemplul!
var x:integer;
procedura t ;
begin
writeln(x)
end;
begin
XJ 3!
t
end .

2. n cadrul unitilor de program vor fi studiate ulterior.

3. n blocul unul alt subprogram. Aceast form este proprie limbajului


Pascal. n exemplu, procedura t, are ca subprogram procedura z. Iniial
programul va atribui variabi.lei x valoarea 3. Apoi va apela procedura t . Ea
tiprete coninutul lui x (3), apoi apeleaz procedura z. La rndul ei,
aceasta afieaz un mesaj: eu sunt z .
program exemplul ;
var x:integer1
procedura t;
procedura z;
begin
writeln(eu sunt z') ;
end;
begin
writeln(X)I z;
end;

begin
x:=3;
t
end.
28 Capitolul 2. Subprowame

Definitia 2.5. A declara un subprogram, nseamn a~l anuna. Un


subprogram nedeclarat nu poate fi folosit. ~

1. n cazul in care subprogramul este definit in blocul programului principal


sau in blocul subprogramului, se consider c a fost i declarat pentru
acesta, deci poate fi folosit. n acest caz, declaraia coincide cu definiia.

Exemple

n programul exemplul, procedura t este definit n blocul programului


principal. Ea poate fi apelat din programul principal.

n programul exemplu2, procedura t este definit n blocul programului


principal, deci poate fi apelat de acesta. Procedura z este definit n blocul
procedurii t. Ea poate fi apelat din t. n schimb, nu poate fi apelat din
programul principal.

2. n blocul programului principal sau n blocul unui subprogram se definesc, n


ordine, subprogramele s 1 , s 2 , ... , sk. n acest caz, automat s 1 este
declarat pentru s 2, s 3, ... , sk, apoi s 2 este declarat pentru 6 3, ... , sk, iar sk-1
este declarat pentru sk.

Exemple

Procedurile al i s2 pot fi apelate din programul principal. Procedura sl


poate fi apelat din procedura s2, dar s2 nu poate fi apelat, n absena altei
clauze, din sl:

procedura sl;
begin
writeln( 'sl')
end;
procedura s2;
begin
sl;
writeln ( s2');
end;
begin
sl,;
s2;
end.

Procedura test conine definiia a dou proceduri sl i s2. Nici una din
aceste proceduri nu se consider declarat pentru programul principal.
Amndou sunt declarate pentru procedura test. Pentru procedura s2, sl
este declarat, dar pentru sl procedura s2 nu este declarat.
\1anual de informatic pentru clasa a Xl-a
29

proced ura test;


proced ura sl;
begin
writel n( 'sl')
end;
proced ura s2;
begin
Sll
writel n( 's2 ') 1
end1
begin
Sll

end1

begin
test1
end.

3. n situaia prezentat n cazul 2, se poate totui ca orice subpro


gram definit
la nivelul unui bloc s fie declarat pentru toate subprogramel
e definite la
nivelul aceluiai bloc, ca in exemplul urmtor.

Declaraia se fac.e prin antet, urmat de cuvntul cheie "forw ard".

f Observai c, n acest caz, definiia nu coincide cu declaraia.


proced ura b1 forwar d1

proced ura &1


begin
writel n('Eu sunt a')l
bl
end1

proced ura b;
begin
writel n( 'Eu sunt b')
Glldl

begin
&1
end.

4. n cazul in care subprogramul a fost definit n cadrul unei uniti


de program,
declaraia unitii,clauza "uses", are efect de declaraie pentru toate
subpro grame le definit e in cadrul el (unitile de program vor fi
studiate n
cadrul acestui capitol).
30 Capitolul 2. Subprograme

2.2.5. Apelul subprogramelor

Definiia 2.6. A apela un subprogram, nseamn a-1 lansa n


executare. Pentru a putea fi apelat din cadrul unui bloc, un subprogram
trebuie declarat la nivelul blocului respectiv.

2.2.5.1. Apelul funciilor

n programul de mai jos este apelat o funcie care calculeaz produsul.a


dou numere ntregi. Programul tiprete suma ntre 1 i produsul calculat. In
exemplu, valoarea gsit este 7:

var p,x,yainteger;

function prod(x , y z i~teger)ainteger;


begin
prodax*y;
end1

begin
x:=2;
y:-3;
pa l+prod(x,y);
writeln(p)
end .

-+ Apelul unei funcii se realizeaz din interiorul unei expresii. n exemplu,


expresia este: "l+prod(x,y)". Rezultatul ar fi fost obinut mai simplu dac
scriam "writeln(l+prod(x, y)) ; ".

~b Observaii
-/ n cadrul expresiei, apelul este un operand. El Intr n calcul cu valoarea
returnat de funcie.

-/ Dup apelul funciei, se continu evaluarea expresiei.

Mai jos este prezentat operandul care reprezint apelul funciei.

LIST
APEL IDENTIFICATOR PARAMETRI
FUNCIE FUNCIE
EFECTIV!

Figura 2.3. Structura operandulul care reprezintA apelul funciei


\1anual de informatic pent ru clasa a Xl-a
31

2.2. 5.2. Apelul proc edu rilor _

Cele cteva exemple date pn acum fac inutil prezentarea unui alt
exemplu. Trebuie s tim c:

1. Apelul unei proceduri se face print


r-o instruciune, numit Instruciune
procedural.Sintaxa acestei instruciuni este prezentat
mai jos:

INST RUC TIUN E LIST


-PROCEDURAL 1DEN TI FI CA TOR PAR AME TRI
IEFEC TIVI

Figura 2.4. Structura instruciunii procedurale

2. Dup apel, se va executa instruciunea care urmeaz instruciunii procedurale.

2.2. 5.3. Transmiterea para met rilor la ape


l
n ce privete mecanismul de transmite
re a parametrilor nu exist nici o
diferen ntre proceduri i funcii. Din acest motiv,
~rata
transmiterea parametrilor se va
unitar.

Para metr ii form ali sunt cei trecui n ante


tul subprogramului.
Para metr ii efec tlvl sunt cei trecui la apel
ul subprogramului.

? Aa cum am vzut, subprogra


mele pot lucra cu variabilele globale ale
blocului care conine defin iia lor. Atunci
care este motivul pentru care sunt
necesari parametrii?

Cunotinele dobndite pn in
acest moment nu permit o justificare
comp let. Putem spune numai c
utilizarea parametrilor permite ca subprogra
s fie scris independent de programu mul
l principal. S lum un exemplu: ni se cere
scriem un subprogram care calculeaz s
suma a dou valori reale. Ce adunm?
Pentru un program ar trebui s adunm x cu y, iar pentru altul, m cu n.
var x,y, sum :inte ger;
proc edur a sum a(a, b:in tege r; var
s:in tege r);
begi n
s:a +b;
end;
begi n
x:3 ; Yl=4 ;
sum a(x, y,su m); writ eln( sum );
suma(~,3,sum); writ eln(
sum );
end.
32 Capitolul 2. Subprograme

n programul anterior, procedura suma calculeaz suma a dou numere


ntregi. Ea este apelat de dou ori din cadrul programul~i principal.

- parametrii formali sunt: "a, b: integer; var s: integer; ";


- pentru primul apel, parametrii efectivi sunt: x, y, sum;
- pentru al doilea apel, parametrii efectivi sunt: 2, 3, sum.

lat cteva reguli care trebuie respectate la apel:

lO> Numrul parametrilor formali trebuie s coincid cu numrul


parametrilor efectivi. n exemplu, acest numr este 3.

);> Tipul parametrilor formali trebuie s coincid cu tipul parametrilor


efectivi sau tipul parametrilor efectivi s poat fi convertit implicit ctre
tipul parametrilor formali, la fel ca n cazul atribuirii.

De exemplu, dac parametrii formali a i b sunt de tipul integer, nu este


permis ca parametrii efectiv! s fie de alt tip (de exemplu, de tipul real).

fJ Nu este obligatoriu ca numele parametrilor formali s coincid cu numele


parametrilor efectivi.

lO> Nu este permis s definim tipul parametrilor n cadrul antetului subpro-


gramului. Tipul trebuie s fie predefinit sau s fie declarat n prealabil.

Exemple
type vector=array [1 9] of integer;

procedura test(n:integrer, v:vector) ; {corect}


procedura test(n:integrer, v:array[1 .. 9] of integrer); (incorect}

Parametrii formali sunt de dou feluri: transmii prin valoare i transmii


prin referin. n cazul in care acetia sunt precedai de cuvntul cheie var, se
consider c sunt transmii prin referin, contrar, prin valoare.

Tratarea transmiterii prin valoare i prin referin se va face n paragrafele


u rmtoare. Pentru moment, prezentm sintaxa parametrilor formali i a
parametrilor efectivi:
LIST
-PARAME TRI IDE NTI F I CA TOR T I P
FORMAU

LIST
PARAM ETRI
EFECTI V!
EXPRESI E

Figura 2.5.
Sintaxa parametrilor trimii
ranual de informatic pentru clasa a Xl-a 33

2.2 .5.4. Cum memoreaz subprogramele parametrii transmii?

n acest paragraf vom analiza modul prin care sunt memorai parametrii
""al1 smii n momentul lan srii n executare a subprogramului.

~ Pentru memorarea parametrilor, subprogramele folosesc o zon de memorie


numit stiv (mai exact, aceast zon se numete segment de stiv).

~ Memorarea parametrilor transmii se face n ordinea n care acetia


figureaz n antet: de la stnga la dreapta.

-+ Pentru parametrii transmii prin valoare, se memorem valoarea transmis,


iar pentru cei transmii prin referin, se memoreaz adresa variabilei
transmis ca parametru.

~ n cadrul subprogramului, parametrii transmii i memorai n stiv sunt


variabile. Numele lor este cel din lista parametrilor formali.
'
Relum exemplul anterior:
antetul este: "procedura suma(a,b:integer1 var s:integer) ;";
la prtmul apel, parametrii sunt: x, y, sum, unde x reine "3" i y "4".

n stiv sunt memorate variabilele subprogramului. n figur, sunt prezentate


I valorile memorate:

stiva~~~--3------4--~---a-d-re_s_a_v_a_ri_a_bi-le_i_s_um____~l
a b s
~a al doilea apel, parametrii sunt: 2, 3, sum.

stiva ~1 2 1 1 3 adresa variabilei sum


1
a b s
f: Observaii

./ La revenirea n blocul apelant, coninutul variabilelor memorate n stiv se va
pierde.
./ Memorarea n stiv are i alte consecine, dar acestea vor fi tratate la
momentul potrivit (vezi recursivitatea!).

2.2.5.5. Transmiterea parametrilor prin valoare

Transmiterea prin valoare se utilizeaz atunci cnd suntem interesai ca


subprogramul s lucreze cu acea valoare, dar n prelucrare, nu ne intereseaz ca
parametrul efectiv (cel din blocul apelant) s rein valoarea modificat n subprogram.
'
34 Capitolul 2. Subprograme

Astfel, se pot transmite prin valoare:

);> valorile reinute de variabile - n acest caz, parametrii efectiv! trebuie s fie
numele variabilelor.

Exemplu:
var n:integer;
prooedure test(n:integer);
begin
n:=n+l;
writeln(n)
end;
begin
n:l;
test (n);
writeln(n);
end.

-parametrul n este transmis prin valoare.

-+ n programul principal, avem declarat variabila n, care este iniializat cu 1.

-+ Apelm procedura. La apel, se rezerv spaiu n stiv, spaiu care are


numele parametrului (deci tot n) i este Iniializat cu valoarea memorat de
variabila n a programului principal. n acest moment avem dou variabile n i
ambele rein valoarea 1.

-+ n procedur, variabila n este incrementat (adic la vechiul coninut se


adaug 1). Evident, este vorba de variabila memorat n stiv.

+ Aflm coninutul variabilei n (cea din stiv), deci se tiprete 2.


+ La Ieirea din procedur, variabila n (din stiv) se pierde - adic nu mal are
spaiu alocat. Prin urmare, valoarea 2 este pierdut.

+ n programul principal se tiprete coninutul variabilei n, adic 1.

);> parametrii efectiv! sunt valori sau expresii, care mai nti se evalueaz.

Exemplu:
prooedure test(n:integer);
begin
writeln(n)
end;

begin
test(3);
test(3+4*5);
end.
anual de informatic pentru clasa a Xl- a 35

n procedur se creeaz o variabil n segmentul de stiv, numit n, care la


: ""mul apel reine valoarea 3 i la al doilea, valoarea 23. La ieirea din procedur
;oninutul variabilei se pierde.

Aa cum am vzut, n cazul transmiterii prin valoare, se pot folosi ca


:arametri efectiv! expresii. De asemenea, expresiile pot avea ca operanzi funcii.
_""n torul program citete dou valori x i y i calculeaz expresia (x-y) * (x+y).

Exemplu:
program test_param;
var x,y:integer;
function suma (a,b:integer):int eger;
begin
suma:=a+b;
end;
function dif (a,b:integer):int eger;
begin
dif:=a-b;
end;
function prod(a,b:integer ):integer;
begin
prod:=a*b;
end;
begin
write('xa'); readln(x);
write('y='l; readln(y);
writeln(prod(dif (x,y),suma(x,y)) );
end.

2.2.5.6. Transmiterea parametrilor prin referin

Parametrii sunt transmii prin referin atunci cnd ne intereseaz ca, la


revenirea din subprogram, variabila transmis s rein valoarea stabilit n timpul
executrii subprogram ului.

+ n cazul transmiterii prin referin, parametrii efectiv! trebuie s fie variabile.


+ n cazul subprogramelor de tip procedur, transmiterea prin referin este
mecanismul clasic prin care acestea ntorc valori ctre blocul apelant.
+ Pentru ca un parametru s fie transmis prin referin este necesar ca
parametrul formal s fie precedat de cuvntul cheie "var".

+ n cazul transmiterii prin referin, subprogramul reine n stiv adresa variabilei.

? n acest caz, ne putem ntreba care este mecanismul prin care, dei pentru o
variabil transmis se reine adresa sa, n subprogram putem adresa
variabila normal (nu indirect)? La compilare, orice referin la variabila
respectiv, este "tradus" ca adresare indirect.
36 Capitolul 2. Subprograme

Exemplu. Programul urmtor utilizeaz o procedur care interschimb valorile


reinute de dou variabile. Acestea sunt transmise prin referin.

var x,y:integer;
procedura interschimb(var x,y:integer)l
var man:integer1
begin
man:x; XIYI Yl~l
end;
begin
x:21 yz.,3;
intarschimb(x,y);
writa(x, ,y);
end.

2.2.6. Variabile locale i globale

~'
]l.B
Definiia 2.7. Variabilele globale sunt variabilele programului principal.
Ele sunt rezervate ntr-o zon special de date, numit segment de date.
n versiunea 7 . o a limbajului Pascal, variabilele numerice sunt
iniializate cu o.

Definiia 2.8. Variabilele locale sunt variabile declarate n interiorul


subprogramelor. Aceste variabile sunt memorate n segmentul de stiv,
dup variabilele generate de parametri. Este sarcina programatorului s
asigure iniializarea lor cu valorile dorite. La ieirea din subprogram
coninutul variabilelor locale se pierde.

Un termen des folosit n practica limbajelor de programare este acela de


vizibilitate. A preciza vizibilitatea unei :tariabile inseamn a spune care sunt
blocurile de unde se poate adresa (ca s-i atribuim o valoare, de exemplu).

+ Variabilele globale sunt viz.ibile la nivelul programului principal i la nivelul


subprogramelor.
var x:integar1 Programul alturat tiprete de trei ori
procedura a; 2, coninutul variabilei globale x.
procedura b1
begin
writaln(x)
end;
begin
Xl2;
b;
writeln(x)
end;
begin
a;
xz2;
writeln(x) 1
end.
.lanual de informatic pentru clasa a Xl-a 37

-+ Variabilele locale sunt vizibile doar la nivelul subprogramului n care au fost


declarate i la nivelul subprogramelor definite n acesta. .~
procedure a; Programul alturat tiprete de doua ori 2,
var x:integer; coninutul variabilei locale x. Dac am fi
procedure b;
ncercat s tiprim x din cadrul programului
begin
writeln(x) principal, programul ar fi dat eroare de
end; compilare.
begin
x:=2;
b;
writeln(x)
end;
begin

,
a;
end.

Atenie! Exist situaii n care o variabil global nu poate fi adresat din


cadrul subprogramului, adie~ atunci cnd acesta conine declaraia unei alte
' variabile, cu acelai nume. In acest caz, prin nume, se adreseaz variabila
locala. Regula este urmtoarea: n cazul rn care dou variabile au acelai
nume, dar vizibiliti diferite, se adreseam i'ntotdeauna variabila cu
vizibilitatea mai redus . Evident, n cazul existenei a dou variabile cu
aceeai vizibilitate i acelai nume, compilatorul va da eroare de sintax.

Programul de mai jos tiprete 2, nu 3:


var x 1 integer;
procedura a;
begin
x:=2;
writeln(x)
end;
begin
x:=J;
a;
end.

Alt termen des utilizat n practica programrii este durata de via a unei
-ariabile. El se refer la perioada de timp n care variabila este alocata n memorie.
!.stfel, avem:

durat static - variabila are alocat spaiu pe tot timpul executrii programului.
durata local - variabila are alocat spaiu doar n timpul ct se execut un
anumit bloc.
durat dinamic - alocarea spaiului de memorie se face n timpul executarii prin
subprograme speciale sau operatori (n Pascal avem subprograme speciale).
Variabilele cu aceast durat de via se numesc dinamice i nu se trateaz n
acest manual.
38 Capitolul 2. Subprograme

Din acest punct de vedere putem spune c variabilele globale au dura~ de


via static,iar variabilele locale au durata de via local.
Un ultim termen este dat de clasa de memorare a unei variabile. Se refer
la locul unde variabila este memorat. Astfel, o variabil poate fi memorat n
segmentul de date, n segmentul de stiv sau n heap.

Astfel, pe lng tip, o variabil se caracterizeaz prin: clas de memorare,


vizibilitate i durat de via.

2.2.7. Greeli frecvente

1. Greeli care apar la transmiterea tipurilor nestandard

Reamintim faptul c un tip este standard dac este cunoscut de limbaj (de
exemplu, integer). n caz contrar tipul este nestandard (de exemplu, tipul care
descrie un vector cu componente de tip real) . lat o procedur scris greit:
procedura er (var Vlarray[1 99) of real);
begin

end;

Eroarea este dat de faptul c tipul nestandard al variabilei v este descris n


lista parametrilor. Programul va da eroare de sintax.
Pentru a proceda corect, tipul este descris separat, n cadrul programului
principal, prin type.
type vect=array[1 99] of real;
var v1vect;
procedura er (var Vlvect)t
begin

endt

2. Greeli care apar la atribuirea valorii de retur a unei funcii (valoarea pe


care funcia o intoarce)

lat o funcie, scris eronat, care ntoarce o valoare ntreag a (o sum).

function suma( n,i:integer):inte gert


var s1integer;
begin
calculez s;

swna(n,i):=st
end;

Eroarea const n faptul c in atribuirea "suma(n, i ; ::s;" au fost trecui


parametri. Corect este "suma: =s; ".
'.~anual de informatic pentru clasa a Xl-a - 39

2. 2.8. Uniti de program

n activitatea practic se fac aplicaii cu un numr mare de programe care de


-,uite ori sunt de mari dimensiuni. O preocupare constant a informaticienilor este
:re a pune la dispoziia programatorilor instrumente eficiente de programare. n
acest sens, limbajul Pascal ofer posibilitatea lucrului C\J uniti de program
unit-uri).

Definiia 2.9. Prin unitate de program nelegem un ansamblu de date,


proceduri i funcii, plasate i compilate mpreun, care pot fi uor
utilizate n scrierea altor programe, fr a se cunoate amnunte
necesare realizrii lor.

Forma general a unei uniti de program este urmtoarea:

UNIT <nume unitate>;


J:NTERFACE
[USES <numele altor uniti de program pe care le utilizeaz>;]
[tipuri de date i variabile globale n programul care utilizeaz
unitatea]
antete de proceduri i funcii

IMPLEMEN'l'ATION
[tipuri de date i variabile locale (valabile numai pentru unitatea de
program)]
procedurile i funciile utilizate de unitatea de program
(BEGJ:N
.. .. ... o eventual secven de program care se execut
....... n momentul declarrl unitii de program n
....... programul care o utilizeaz.
END.]

_. Prima parte, obligatorie, este precedat de clauza "INTERFACE". Aici se


gsesc definiiile tipurilor de date, variabilelor, i sunt enumerate procedurile
i funciile ce pot fi utilizate din programul principal. Pentru orice tip de
variabil declarat aici, se pot declara variabile de acest tip att n cadrul
unitii ct i n cadrul programului care folosete unitatea. Se observ c o
unitate de program are n mod obligatoriu dou pri, opional, o a treia.
Toate procedurile i funciile care aici sunt numai enumerate pot fi folosite de
orice program care folosete unitatea.

_. A doua parte, obligatorie, se gsete plasat sub clauza ":IMPLEMEN'l'ATION''.


Aici se pot declara tipurile i variabilele vizibile numai pentru unitatea dat.
Tot aici se scriu clar toate procedurile i funciile care n parte au fost numai
declarate, precum i altele ce pot fi folosite numai n cadrul unitii.

_. Partea opional a fost prezentat n cadrul formei generale a unitii.


40 Capitolul 2. Subprogramc

;j;, "" n continuare, vom da un exemplu pur didactic de unitate de program


Q~: numit OPERA'l'J:J:. Aceasta conine patru~ proceduri: de adunare
~ scdere, nmulire i mprire de variabile reale. Variabilele a i b sur:
globale pentru programul care utilizeaz aceast unitate, iar variabila c poate f
utilizat numai n cadrul unitii. n secvena de iniializare se citesc valorile
variabilelor a i b.

Unitatea de program este prezentat in continuare:


unit operatii;
intorfaco
var a,brroal;
procedura adun(a,b:roal);
procedura scad(a,b:roal);
procedura produs(a,brroal);
procedura impart(a,b:raal);
implomaDtation
var caraal;
procedura adun(a,brraal);
begin
cra+b;
writaln(calr2);
ond;

procedura scad(a,brreal)t
begin
cra-b;
writoln(crls2);
end;
procedura produs(a,baroal);
bagin
caa*b;
writoln(cal:2);
end
procedura impart(a,brREAL);
begin
if b~ o thon writaln('~rtiroa nu se poate face ')
olso
begin
cra/b;
writoln(ca3a2);
endt
and;
begin
writo( 1 a 1 ) 1
roadln(a) ;
wri taln ( 1 b= 1 ) 1
roadln(b);
end.
~"'u al de informatic pentru clasa a Xl-a 43

..;; Funcia are un anumit tip, care precizeaz natura rezultatului. n exemplu,
tipul este doub:Le ntruct expresia calculat este de acest t\p.
-+ Funcia are variabile proprii - adica variabile care sunt definite n cadrul ei. n
exemplu, s i i. Aceste variabile se numesc variabile locale.
-+ Am vazut ntoarce un anumit rezultat - n exemplu, de tip double.
c funcia
Observai mecanismul prin care am obinut aceasta. Calculez expresia n
mod obinuit. Rezultatul este reinut de variabila local s. Prin instruciunea
"return s;", funcia a primit ca valoare de retur coninutul variabilei s.

n terminologia utilizata n teoria subprogramelor - n particular, n cazul


.:-ciil or- se utilizeaz termenii parametri formali i parametri efectiv/.

Definiia 2.1 O. Parametrii care se gasesc n antetul funciei se numesc


parametri formali.

Atunci cnd scriem o funcie nu cunoatem valoarea propriu-zis a


:.:.rametrilor. Funcia trebuie sa intoarca rezultatul corect, oricare ar fi valoarea lor.
: 11 acest punct de vedere ei se numesc formali.

Definiia 2.11. Parametrii care se utilizeaz la apel se numesc parametri


efectiv!.

La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare,
acetia se numesc parametri efectivi.

=entru apelul "rez=subp (n) 1 ", parametrul efectiv este n.

:J Problema 2.4. Se citete n, numar natural. Se citete un vector cu n


:omponente numere reale. Se cere sa se tipareasca vectorul sortat.

#include <iostream.h>
void citeac(int vt[lO],int n)
{ int i1
for(i-=O;i<n;i++)
{ cout<<"v["<<i+l<<"l"l
cin>>vt[i];
}
}

void sortez(int vt[lO],int n)


{ int gasit,i,man1
do
( gasitO;
for (i=O;i<n-lli++)
if (vt(i]>vt(i+l])
{ man=vt[il;
vt[i]=vt[i+l]l
vt[i+l]=manl
ga,sitl; }
} while (gasit);
}
44 Capitolul 2. Subprograme

void scriu(int vt[lO],int n)


{ int i;
for(i=O;i< n;i++)
cout<<vt[i )<<endl;
}

main()
{ int v[lO),n;
cout<<n= ;
cin>>n;
citesc(v,n );
sortez(v,n );
scriu(v,n) 1
}

Programul conine trei funcii: citesc, sortez i tiparesc.

:> La apel, controlul programului este transferat la prima instruciune a funciei.


Du,m executarea funciei, se revine in programul principal la prima
instruciune care urmem celei de apel - in cazul de falJ se ntlnete o alt~
instruciune de apel.

:> Cele trei funcii au tipul vo:l.d, adic nu au valoare de retur. Ele returneam
rezultatul prin intermediul parametrilor.

2.3.2. Structura unei funcii

n esen, o funcie este alctuit din:

+ Antet - acesta conine mai multe informaii importante necesare


compilatorului: numele funciei, lista parametrilor formali, tipul rezultatului.

Structura antetului este:

tip nume(list a parametr ilor formali)

Lista parametrilor formali este de forma:


parametru 1 , parametru2 , , parametru n

Exista i posibilitatea ca lista parametrilor formali sa fie vid. Fiecare


parametru are forma:

tip nume.

+ O instruciune compus - aceasta cuprinde declaraiile variabilelor locale,


i instruciunile propriu-zise.

Poate fi tip al unei funcii orice tip de data cu excepia masivelor.


-~al de informatic pentru clasa a Xl-a 45

E:xemple de antete:

- .int suma(int a, int b) - funcia se numete suma, returneaz un


ezultat de tip int i are doi parametri formali de tip int, numii a i b.
- ?Oid t (int n, float v[20l) - funcia se numete t, este de tip void
nu returneaz rezultat prin nume), are doi parametri formali, primul numit n, de
p int, al doilea num'it v, de tip float * (un tip care reine adrese de vectori
cu elemente de tipul float).

O funcie returneaz rezultatul la ntlnirea instruciunii return, care are


forma:
return expresiei

Trebuie ca tipul expresiei s coincida cu tipul funciei.

La ntlnirea instruciunii return, dup atribuirea valorii, execuia funciei se


r.: ,eie i se revine la funcia care a apelat-o. n absena instruciunii return,
l!.t ecuia funciei se ncheie dup execuia ultimei instruciuni. n acest caz nu se
r-:xll'ce nici o valoare.

-+ O funcie poate fi apelata de sine stattor (prin nume i lista parametrilor


efectivi), dar poate fi inclus i n cadrul expresiilor, caz n care, la evaluarea
expresiei este apelat. Aceast ultim form de apel nu este valabila n cazul
funciilor de tip void.

include <iostream.h> n programul alturat este apelat o


funcie care calculeaz produsul a
int prod (int x, int y) dou numere ntregi.
{ return x*y 1 )
main() Programul tiprete suma ntre 1 i
{ int xl,:y-31 produsul calculat. n exemplu, 7.
cout<<l+prod(x,y )l
)

Apelul funciei s-a realizat din interiorul expresiei: "l+prod(x,y) ".

1
,
Observaii

. n cadrul expresiei, apelul este un operand. El intr in calcul cu valoarea


returnat de funcie.
\

Dup apelul funciei se continu evaluarea expresiei.

La apel, ordinea de evaluare a parametrilor nu este definit. De exemplu,


dac apelm funcia test astfel:

test(2-3,2+3),

nu tim dac nainte se efectueaz scderea sau adunarea.


46 Capitolul 2. Subprograme

2.3.3. Declararea variabilelo r

Pn n prezent am declarat variabile doar n corpul funciilor - inclusiv n cel


al funciei main ( ) . Variabilele declarate astfel se numesc locale.

+ Fiecrui program i se aloc trei zone distincte n memoria intern n care se


gsesc memorate variabilele programului:

Figura 2.5. Cele trei zone in memoria internA

De asemenea, exist posibilitatea ca variabilele s fie memorate ntr-un


anumit registru al microprocesorului. n acest caz timpul de acces la astfel de
variabile este foarte mic, deci se pot obine programe optimizate.

+ n general, o variabil se caracterizeaz prin 4 atribute. Acestea sunt:

clasa de memorare;
vizibilitate;
durata de via;
tipul variabilei, singurul pe care l-am studiat pn n prezent.

1. Clasa de memorare - precizeaz locul unde este memorat variabila


respectiv. O variabil poate fi memorat n segmentul de date, n cel de
stiv, n heap sau ntr-un registru al microprocesorului.

2. VIzibilitatea - precizeaz liniile textului surs din care variabila respectiv


poate fi accesat.

Astfel avem:

a. VIzibilitate la nivel de bloc (instruciune compus).

b. Vizibilitate la nivel de fiier n cazul n care programul ocup un


singur fiier surs, singurul caz pe care l tratm acum.

c. Vizibilitate la nivel de clas este n legtur cu programarea pe


obiecte, pe care o vei studia individual.
a,ual de informatic pentru clasa a Xl-a 47

Durata de via reprezint timpul in care variabila respectiv are alocat


spaiuin memoria intern. Astfel avem:

a. Durat static variabila are alocat spaiu in tot timpul execuiei


programului.
b. Durat local - variabila are alocat spaiu in timpul in care se execut
instruciunile blocului respectiv.
c. Durat dinamic alocarea i dezalocarea spaiului necesar variabilei
respective se face de ctre programator prin operatori sau funcii
speciale.

n C++ variabilele pot fi mprite n trei mari categorii: globale, locale i


: namice. Noi studiem numai primele dou categorii, variabilele globale i locale .

.& Variabile globale

Acestea se declar in afara corpului oricrei funcii, ca mai jos:


#include <iostream.h>
int a ;
int t()
( a a 3;
cout<<a;
}

int b;
main()
{ b 4;
cout<<a<<endl;
t(}J
}

Variabilele a i b sunt globale. n astfel de cazuri, variabilele respective pot


utilizate de toate funciile care urmea~ n textul surs~ declaraiei variabilei
espective. Din acest motiv, astfel de variabile se numesc globale.

l La declarare, variabilele globale sunt iniializate cu o.



.\tributele variabilelor globale sunt:

1. Clasa de memorare - segmentul de date.

2. Vizibilitatea - n cazul n care declaraiile acestora sunt naintea tuturor


'u nci i lor , acestea sunt vizibile la nivelul ntregului program (fi ier) . Dac anumite
'u ncii se afl plasate naintea declarai ilor acestor variabile, atunci ele sunt vizibile
doar pentru funciile care sunt plasate dup aceste declaraii. In exemplul anterior,
variabila a poate fi accesat din corpul oricrei funcii, dar variabila b poate fi
accesat doar din funcia main ( ) .
48 Capitolul 2. Subprograme

3. Durata de via a variabilelor globale este static. Ele au spaiu rezervat n tot
timpul execuiei programului.

B} Variabile locale

Acestea sunt declarate n corpul funciilor. Mai precis, pot fi declarate n orice
bloc (instruciune compus) al acestora.

~ Variabilele declarate n corpul funciei main () sunt tot locale. n programul


~~ urmtor, variabilele a i bsunt locale.

Variabila a este declarat n corpul funciei t ( ) , iar variabila b este declarat


n corpul funciei main ( ) .

Exemplu:
void t()
{ int a3;
}

main()
{ int b4;
}

1. Clasa de memorare a variabilelor locale este implicit segmentul de stiv .


Exist posibilitatea ca acestea s fie alocate n registrele microprocesorului, caz n
care declaraia lor trebuie precedat de cuvntul cheie "register".

Exemplu:
register int b41

Variabilele locale nu sunt iniializate implicit cu o. n ipoteza n care acestea


nu sunt iniializate explicit de programator, rein o valoare oarecare, numit
valoare rezidual. '

2. VIzibilitatea variabilelor locale este la nivelul blocului in care au fost declarate.

n funcia urmtoare am declarat dou variabile de tip int, numite b i c .


Variabila b este vizibil la nivelul funciei, dar variabila c este vizibil doar la nivelul
blocului n care a fost declarat.

Exemplu:
void t()
{ int b4t
{ int c 3;
cout<<b<< " "<<c;
}
}
'Aanual de informatic pentru clasa a Xl-a 49

(? .. n programul urmtor am declarat trei variabile, toate numite a . Una este


CX: global, iar dou sunt locale, dar declarate n blocuri diferite:
#include <iostream.h>
int a;
void t ()
{ int a=4;
{ int a=3;
cout<<a<<endl;
}
cout<<a<<endl;
}

main()
{ a=S;
t();
cout<<a;
}

in program, se afieaz coninutul tuturor acestor variabile (3, 4, s).

f , Observaii

./ n cazul n care, ntr-un anumit bloc sunt vizibile (se pot accesa) mai multe
variabile, toate cu acelai nume, dar au domenii de vizibilitate diferite, se
acceseaz variabila cu vizibilitatea cea mai mic. De exemplu, dac n
programul anterior se tiprete variabila a din cadrul subblocului funciei, se
tiprete 3, pentru c acesta este coninutul variabilei cu cea mai mic
vizibilitate (cea declarat n subblocul respectiv).

./ _!=xist posibilitatea ca, un ciclu for s conin~ declaraia unei variabile locale.
In secvena urmtoare se calculeaz suma primelor 4 numere naturale.
Variabila i este declarat (i n consecin vizibil) doar n blocul for:

int n=4, s=O;


for (int i=l;i<=n;i++ ) s+=i;
cout <<s;

3. Durata de via a variabilelor locale este att timp ct dureaz execuia blocului
respectiv.

2.3.4. Transmiterea parametrilor

Aa cum am artat, parametrii care se gsesc n antetul funciei se numesc


parametri formali, iar cei care se gsesc n instruciunea de apel se numesc
parametri efectivi.

<dz::. Privii programul urmtor. Acesta conine o funcie care calculeaz suma
~~ a dou numere naturale.
50 Capitolul 2. Subprograme

#include <iostream.h> Parametrii formali sunt a i b.


int suma(int a , int b) Funeia este apelat de mai
{ return a+b; multe ori. Parametrii efectivi sunt,
} pe rnd:
main() 7 2, 3;
{ int c=4,d=3; 7 2+7, 3-1*2;
cout<<suma(2,3)<<endl;
cout<<suma(2+7,3-1*2)<<e nd1; 7 c, d;
cout<<suma(c,d)<<end1; 7 1. 9, 3. 3.
cout<<suma(1.9,3.3)<<end l;
}

Dup fiecare apel al funciei se tiprete suma obinut. ntre parametrii


formali i cei efectivi trebuie s existe o anumit concordan, care este descris
prin regulile t:rmtoare:

Numrul parametrilor formali trebuie s coincid cu numrul


parametrilor efectivi. La aceast regul. exist o excepie care va fi
prezentat ntr-un paragraf separat. In exemplul dat, numrul
parametrilor formali este 2, iar cel al parametrilor efectivi este tot 2
(pentru un apel).
Tipul parametrilor formali trebuie s coincid cu tipul parametrilor
efectiv! sau tipul parametrilor efectiv! s poat fi convertit implicit
ctre tipul parametrilor formali, la fel ca n cazul atribuirii.

suma< 2, 3 > - parametrii formali sunt expresii constante de tip ntreg;

swna(2+7, 3-1*2) - parametrii formali sunt expresii constante de tip ntreg;


n acest caz, nainte de apel se evalueaz expresiile de mai sus;

suma(c,d) - parametrii formali sunt expresii de tip ntreg (dat de tipul


variabilelor);

suma< 1. 9, 3 . 3 > - parametrii formali sunt expresii constante de tip real. n


acest caz, ele sunt convertite ctre int la fel ca n cazul atribuirii (se
trunchiaz zecimala). Prin urmare, suma calculat este 4=1+3.

~ Nu este obligatoriu ca numele parametrilor formali s coincid cu numele


1 parametrilor efectivi.

Vom analiza modul n care sunt memorai parametrii transmii n momentul


lansriin execuie a funciei.

-+ Pentru memorarea parametrilor subprogramele folosesc segmentul de


stiv,ntocmai ca pentru variabilele locale.

-+ Memorarea parametrilor transmii se face n ordinea n care acetia


figureaza n antet: de la stnga fa dreapta.
Manual de informatic pentru clasa a Xl-a 51

-+ n cadrul subprogramului, parametrii transmii i memorai n stiv sunt


variabil.e. Numele lor este cel din lista parametrilor formali.

-+ Variabilele obinute n urma memorrii parametrilor transmii sunt variabile


locale.

lat, de exemplu, cum sunt memorai n stiv parametrii n cazul primului apel:

stiva ---+1 2 1 3

a b

L Observaii

/ la revenirea n blocul apelant, coninutul variabilelor memorate n stiv se


pierde- dupa cum tim, durata de viaa a variabilelor locale este local.

/ Memorarea n stiv are i alte consecine, dar acestea vor fi tratate la


momentul potrivit.

Exist dou mecanisme de transmitere a parametrilor, transmiterea prin


valoare i transmiterea prin referin. Acestea vor fi tratate n continuare.

A. Transmiterea prin valoare se utilizeaz atunci cnd suntem interesai ca


subprogramul sa lucreze cu acea valoare, dar n prelucrare, nu ne
intereseaz ca parametrul efectiv (cel din blocul apelant) s rein valoarea
modificat n subprogram.

Se pot transmite prin valoare:

1. Valorile relnute de variabile;


2. Expresii (acestea pot conine i funcii).

1. Valorile relnute de variabile. n acest caz, parametrii efectivi trebuie s fie


numele variabilelor care se trimit prin valoare.

Exemplu:
#include <iostream.h>
void test (int n)
{ n+=l;
cout<<n<<endll
}

main()
{ int nl1
test (n);
cout<<n<<endl;
}

Parametrul n este transmis prin valoare.


52 Capitolul 2. Subprograme

~ in main ( ) , avem declarat variabila n, care este iniializat cu 1.

~ Apelm funcia. La apel, se rezerv spaiu n stiv, spaiu care are numele
parametrului (deci tot n) i este initializat cu valoarea memorat de variabila
n a programului principal. in acest 'moment avem dou variabile n i ambele
rein valoarea 1.

~ in funcie, variabila n este incrementat (adic la vechiul coninut se adaug 1).


Evident, este vorba de variabila rezervat n cadrul ei.

~ Tiprim coninutul variabilei n (cea din stiv), deci se tiprete 2.

~ La ieirea din funcie, variabila n (din stiv) se pierde - adic nu mai are
spaiu alocat. Prin urmare, valoarea 2 este pierdut.

~ in main ( ) se tiprete coninutul variabilei n, adic 1.

2. Parametrii efectlvl sunt expresii care mal nti se evalueaz.


Exemplu:
#include <iostream.h>
void test (int n)
{ cout<<n<<endl;
}

main()
{ test(3);
test(3+4*5);
}

~ Transmiterea prin valoare a masivelor permite ca funqiile ~ intoar~ noile


valori ale acestora (care au fost atribuite in funqii). De ce? Numele masivului
este un pointer ctre componentele lui. Prin valoare se transmite acest
nume. Cu ajutorul acestuia accesm componentele masivului.

~; :i;,. in programul urmtor funcia vector iniializeaz vectorul transmis ca


~~ : parametru, iar n main( > se afieaz rezultatul:
#include <iostream.h>
void vector (int x(lOJ)
{ for (int iO;i<lO;i++) x[i) i;
}

main()
{ int a[lO];
vector(a)J
for (int iO;i<lOJi++) cout<<a(i)<<" "1
}
"'anual de informatic pentru clasa a Xl-a 53

; . Transmiterea prin referin. Parametrii sunt transmii prin referin atunci


:.nd ne intereseaz ca la revenirea din subprogram, variabila transmis s rein
aloarea stabilit n timpul execuiei subprogramului.

~ in cazul transmiterii prin referin, parametrii efectivi trebuie s fie referine la


variabile.

~ n cazul transmiterii prin referin, subprogramul reine n stiv adresa


variabilei.

;::: Programul urmtor utilizeaz o funcie care interschimb valorile reinute


-X. de dou variabile. Acestea sunt transmise prin referin .

#include <iostream.h>
void intersc(int &a,int &b)
{ int man=a;
a=b;
b=man;
}

main()
{ int x=2,:y=3;
intersc(x,y) 1
cout<<x<<" "<<y;
}

2. 3.5. Definirea i declararea unui subprogram

Dei aparent asem ntoare, cele dou noiuni difer . Buna nelegere a lor
-e ajut s evitm anumite erori. Mai mult, aceste noiuni sunt utilizate de orice
"'lbaj de programare, nu numai n C++.

Definiia 2.12. A defini un subprogram, inseamn~ a-/ scrie efectiv, dup


structura anterior prezentat. O problem important este locul unde se
definete subprogramul.

Definiia 2.13. A declara un subprogram, inseamn~ a-1 anuna. Un


subprogram nedeclarat nu poate fi folosit.

Definiia unui subprogram ine loc i de declaraie!

Programul urmtor conine dou funcii: sl i s2. Definiiile ambelor


Ex: funciise gsesc naintea funciei main (). Din acest motiv ele pot fi
apelate din main ( ) . Definiia funciei sl este naintea definiiei lui s2,
deci funcia sl poate fi apelat din s2. n schimb, din sl nu poate fi
apelat funcia s2, pentru c definiia lui s2 este dup cea a lui sl.
54 Capitolul 2. Subprograme

#include <iostream . h>


void sl()
{ cout<<"Eu sunt sl"<<endl;
}

void s2()
{ s1 (); cout<<"Eu sunt s2"<<endl;
}

main()
{ s1 () 1
s2();

n situaia prezentat, totui se poate ca sl s apeleze pe s2, chiar dac


sunt definite n aceeai ordine.

n astfel de cazuri se folosete prototipul funciei (antetul urmat de "; ").


Prototipul are rolul de a declara o funcie. El nu conine definiia acesteia.

#include <iostream.h>
void s2();
void sl()
{ s2 () 1 cout<<"Eu sunt sl"<<endl;
}

void s2()
{ cout<<"Eu sunt s2<<endl;
}

main()
{ sl ();
}

f
, (, l
Programatorii n C++ obinuiesc s scrie mai nti prototipurile tuturor
funciilorutilizate de program - fr main () - iar dup funcia ma in ( > s le
defineasc. n acest fel, orice funcie - mai puin ma in ( ) - poate fi apelat
din oricare alta:
#include <iostream.h>
void sl(); // prototip sl
void s2(); // prototip s2
main()
{ sl();
}

void al()
{ s2 (); cout<<"Eu sunt sl" <<endl;
}

void s2 ()
{ sl (); cout<<"Eu sunt s2"<<endl;
}
~an ual de informatic pentru clasa a Xl- a ss

2 .4. Aplicaii care folosesc subprograme

::1 Aplicaia 2.1. Revenim la exemplul de funcie dat n paragraful 2.1. Acesta va fi
:-ezentat n totalitate. Se consider funcia:

x+ 1 , pentru xe [-1,1];
2
f(x)= ~-\, pentru xe(-oo,-1};

1 - -,
1 +X
pentru x e ( l , oo ).

Se citesc doua valori reale a i b. sa se scrie un program care afieaza care


: 1tre valorile f (a) i f (b) este cea mal mare.

;::1 Rezolvare. Programul este prezentat n continuare:


"" ., .
! :, Varianta Pasc,~~ . r,.
var a,b,va,vbsreal; # include <iostream.h>
function f(xsreal)sreal; float f ( float x)
var y:real; ( float Y1
begin yx+11
y:=x+l1 if{x<-1) return y;
if x<-1 then fs y else if{x>l) return 6/y1
else if x>l then f:s6/y else return y/(l+x*x);
else f:y/(l+x*x)
end;
void main()
begin ( float a,b,va,vb;
write(a~'l; readln(a)1 cout<<"a"1 cin>>a;
write('b='); readln(b); cout<<"b"; cin>>b;
vasf(a)1 vaf (a) 1
vb:f {b) 1 vb f.(b) 1
if va>vb if (va>vb) cout<<va<<endl1
then writeln(va) elae cout<<vb<<endl1
alse writeln(vb) }
end.

J Aplicaia 2.2. Se citesc dou numere intregi m i n . Se cere s se tipareasc


:el mai mare divizor comun i cel mai mic multiplu comun al lor.

~ Rezolvare. Cunoatei deja modul in care se calculeaza cel mai mare divizor
:omun pentru dou numere naturale date. Cel mai mic multiplu comun a dou
"Umere se poate determina imprind produsul lor la cel mal mare divizor comun al
or. Prin urmare, scriem o funcie cmmdc cu doi parametri formali m i n , care
.,toarce o valoare intreag- cel mai mare divizor comun al lor.
56 Capitolul 2. Subprograme

var m, n:integer; #include <iostream.h>


function cmmdc(m,n:integer) int cmmdc(int m, int n)
:integer; { while (ml n)
begin if (m>n) m-=n;
while m<>n do else n-=m;
if m>n then m:-m-n return m;
else n::n-m; }
cnundc:=m;
void main()
end;
{ int cm,m,n;
begin cout<<"m"; cin>>m;
write ( ' m='); readln(m)l cout<<"n" ; cin>>n;
write ('n='); readln(n) ; cm=cmmdc (m,n) 1
writeln(cmmdc(m,n)); cout<<cm<<" "<<m*n/cm;
writeln(m*n div cmmdc(m,n)); }
end .

~Exerciii
1. Gs ii dou motive pentru care parametrii funciei cmmdc trebuie s fie transmii
prin valoare i nu prin referin.

2. Scriei
un subprogram cmmmo care s returneze cel mai mic multiplu comun a
dou numere naturale. Stabilii locul unde trebuie integrat acesta in programul dat
i modificai programul principal astfel fnct s se utilizeze subprogramul cerut.

3. Cte expresii diferite care au ca rezultat cel mai mare divizor comun al
numerelor naturale nenule a, b i o exist? ln orice expresie se utilizeaz numai
apeluri ale funciei ollDl\do i variabilele a, b i c. De exemplu, trei expresii sunt:
cmmdo(ommdc(a,b),c),
ommdc ( cmmdc (b, a), o) i
cmmdc(o,cmmdc(a,b) ).

O Aplicaia 2.3. Se citete un vector cu n componente numere intregi. Se cere s


se tipreasc cel mai mare divizor comun al valorilor reinute de vector.

~ Rezolvare. Dispunem deja de o funcie care calculeaz cel mai mare divizor
comun a dou numere i am testat-o n programul anterior. Pentru varietate, de
data aceasta implementm o funcie cu algoritmul lui Euclid pentru calculul celui
mai mare divizor comun, algoritm prin mpriri, nu prin scderi repetate. Cu
ajutorul ei calculm cel mai mare divizor comun pentru valorile reinute de primele
dou componente i memorm aceast valoare n variabila o. Apoi, pentru fiecare
dintre componentele urmtoare, se calculeaz cel mai mare divizor comun intre
valoare.a curent memorat in o i cea reinut de componenta curent a
vectorului. Cel mai mare divizor comun va fi reinut din nou de c.
Manual de informatic pentru clasa a Xl-a 57

var v:array(1 . 20]of integer; #include d :ostream. h>


n,i,csint eger; int v[21),n;
function emmdc(m ,n:integer ) int cmmdc(in t m, int n)
sinteger1 { int r;
var r:intege r; do { r=m%n;
begin m-n;
repeat n=-r;
r:m mod n; ) while (ri=O)
msn; n:r return m1
until rO; }

end; void main()


{ int i , c,
begin cout<<"n "; cin> >n;
write ('n='); readln(n ); cout<<"Co mponente vector:" ;
write( compone nte vect.or: ); for(il ;i<=n ; i++)
for i:1 ton do read(v[i ]); cinv[i ];
c:cmmd c(v[1],v[ 2])1 ccmmdc (v[l],v[:ll ]);
for i: 3 ton do for (i=3;i<n ;i++)
c:cmmd c(c,v[i]) ; ccmmdc (c,v[i])l
writeln( c) cout<<c;
end. }

~Exerciiu
In locul secvenei
c ~ cmmdc(v[ l) ,v[:ll))
pentru i =3, n execut
c ~ cmmdc(c ,v[i))
sfrtit pentru
dorim s utilizm, mal compact, secvena:

pentru i=l,n execut


c ~ cmmdc(c ,v[il)
sfrit pentru

Care este valoarea pe care trebuie s o aib variabila c inaintea acestei secven~:?

0 Aplicaia 2.4. Triunghi special. Se citesc dou numere naturale m i n mal .


mici dect 10. Se cere ca programul dvs. s afieze un triunghi, dup regulile pe
care le deducei din exemplele urmtoare :

1. m6 n1 2. m7 n9

1 9
2 3 l :Il
4 5 6 3 4 5
7 8 9 1 6 7 8 9
2 3 4 5 6 1 2 3 4 5
7 8 9 1 2 3 6 7 8 9 1 :Il
3 4 5 6 7 8 9 Junior Division
58 Capitolul 2. Subprograme

0 Rezolvare. Se observ c dac n=S trebuie s obinem irul s 1 61 7 1 a1


9, 1. , 2, 3, Problema este de a putea num.ra ncepnd de la n, iar cnd
s-a depit valoarea 9, de a relua numrarea de la 1. Vom utiliza o funcie (succ)
care primete ca parametru de intrare un numr k i returneaz valoarea
urmtoare, n logica prezentat mai sus.

Alt aspect al problemei este realizarea tipririi acestor valori pe m linii, linia 1
avnd o singur valoare, linia a doua dou valori etc. Algoritmul este implementat
n procedura tipar, care are ca parametri formali pe m i n, transmii prin valoare.
Valorile lor sunt citite n programul principal.

var m,n:integer; #include <iostream.h>


function suc(k:integer):integer; int suc(int k)
begin { if {k==9) return 11
if k=9 then succ:=l else return k+l;
else succzsk+l }
end;
void tipar(int m,int n)
procedura tipar(m,n:integer); ( int i,j;
var i,j : integer; for(i=1;i<=m;i++)
begin ( for (j=l;j<i;j++)
for i : =1 to m do begin { cout<<n;
for j: l t o i do begin nsuc(n);
write (n); }
n : =suc(n) cout<<endl;
end; }
writeln }
end
end; void main()
( int m,n;
begin
cout<<"m="; cin>>m;
write('m='); readln(m); cout<<"n"; cin>>n;
write('n'); readln(n); tipar(m,n);
tipar(m,n) }
end .

~ Exerciii
1. Dup apelul tipar(mln) din programul principal, dac se adaug o instruc-
iune care afieaz valoarea lui n, ce valoare estimai c se va tipri?
2. Cum trebuie s arate definiia subprogramului suc, dac n subprogramul
tipar, n loc de n~suc (n), se utilizeaz instruciunea suc (n)?
3. Cum putem defini subprogramul suc astfel nct secvena de afiare din
subprogramul tipar s fie:
pentru i=l,m execut
pentru j=1,i execut
scrie suc(n)
sfrit pentru
scrie EOLN
sfrit pentru
V anual de informatic pentru clasa a Xl-a 59

:J Aplicaia 2.5. Se citesc dou numere naturale m<n. Se cere s' se tipreasc
~te
numerele palindrom aflate ntre m i n. Un numr este paling;om dac, citit de
r- stnga la dreapta
i citit de la dreapta ctre stnga, rezultatul este acelai. De
~em plu, numrull2l este palindrom.

~ Rezolvare. S analizm problema. Este necesar s fie testate toate numerele


-tre m i n, pentru ca apoi s fie tiprite numai cele care ndeplinesc condiia cerut .

.Pentru fiecare numr, avem subproblema verificrii proprietii de numr


::;alindromic. Pentru aceasta, vom scrie o funcie numit palin care are rolul de a
:=sta dac un numr este sau nu palindrom. Analiza proprietii de numr
=alindromic o efectum construind rsturnatul (inversul) acelui numr i verificm
:ac cele dou valori (numrul i rsturnatul su) sunt egale.

Construirea "inversului" (nu n sens matematic) unui numr natural este i ea


: su bproblem a problemei verificrii proprietii de palindrom. Vom scrie o funcie
::..nvers, care va returna inversul unui numr natural transmis ca parametru .

Urmrind apelurile, vom constata c programul principal apeleaz funcia


~.alin, iar funcia palin apeleaz la rndul ej funcia invers. Programul apelant
3 fu nciei palin este programul principal, n timp ce programul apelant al funciei
::..Dvers este subprogramul palin.

Care este avantajul scrierii fiecrei funcii? Acesta este dat de faptul c,
s:unci cnd scriem funcia, ne concentrm exclusiv asupra ei, deci posibilitatea de
s g rei este mai mic . Dac dispunem de funcie, algoritmul in continuare devine
1ult mai simplu. n plus, este posibil ca oricare dintre funcii s poat fi folosit i n
3 te cazuri, la rezolvarea altor probleme.

f Observaii

"' Ordinea definirii celor dou subprograme devine important, deoarece funcia
in~ers, de care are nevoie funcia palin, trebuie declarat anterior acesteia.

../ Faptul c numrul al crui invers se calculeaz este transmis subprogramului


prin valoare este iari un avantaj. Cu toate c algoritmul ce construiete
inversul lui n distruge de fapt valoarea acestuia, acest lucru nu este resimit de
programul apelant.

function invers(n:1ongint):longint; #include <iostream.h>


var r:longint;
begin long invers(long n)
r:=O; { long r=O;
while n<>O do begin while(ni=O) {
r:=r*10+n mod 10; r=r*10+n%10;
n:=n div 10 n/=10;
}
end;
invers:=r return r;
}
end;
60 Capitolul 2. Subprograme

function palin(n:longint):boolean; int palin(long n)


begin { return invers(n)==n;
palin:=invers(n)=n; }
end;
void main()
var m,n,i:integer; { .:l.nt m,n,i;
begin cout<<"m="; cin>>m;
write('m='); readln(m); cout<<"n="; cin>>n;
write('n='); readln(n); for(i=m;i<=n;i++)
for i:~m to n do if (palin(i))
if palin(i) then writeln(i) ; cout<<i<<endl;
end. }

/ Exerciii
1. Modificai antetul funciei invers, transformnd parametrul n n parametru
transmis prin referin i urmrii efectele modificrii efectuate.

2. Modificai antetul funciei invers, transformnd parametrul n n parametru


tr-ansmis prin referin i testai proprietatea de palindrom folosind compararea
n=invers (n) n loc de invers (n) =n. Explicai de ce aceast modificare nu
reprezint o corecie a erorii aprute la cerina 1?

3. Un numr natural este superpallndrom dac este palindrom att el ct i


ptratul su. Scriei, pe baza programului dat, un program care listeaz toate
numerele cu aceast proprietate aflate ntre doi ntregi a i b (a<b<32000).

O Aplicaia 2.6. Suma cuburilor cifrelor. Se citete un numr natural


n~9999999. Se calculeaz suma cuburilor cifrelor sale. Exemplu: dac se citete
25, se calculeaz 2 3 +5 3 =133. Cu numrul obin ut procedm la fel: 1 3 +3 3 +3 3 =55 .
Repetm procedeul: 5 3 +5 3 =250 . i iar: 2 3 +5 3 +0 3 =133 . Repetm procedeul pn
ce obinem un numr care este deja prezent n seria generat . Se cere s se
afieze irul de valori calculate prin acest procedeu.

Exemplu: pentru n=25, se afieaz seria

25 133 55 250 133.

.Junior Divlslon

0 Rezolvare. Suma cuburilor cifrelor unui numr natural este calculat de funcia
swna. Numrul n (citit) va ri memorat de prima compon ent a vectorului seria.
Apoi, suma cuburilor sale, de componenta a doua, suma cuburilor numrului reinut
de a doua component va fi reinut de a treia component, .a.m.d. Dup ce este
memorat o valoare, ea este comparat, pe rnd, cu cele obinute anterior. Dac
este regsit, se tiprete numrul de termeni ai seriei i seria propriu-zis
Funcia swna calculeaz suma cuburilor cifrelor unui numr. Funcia este verific
dac valoarea n exist deja n irul s format din ls componente.
l.lanual de informatic pentru clasa a Xl-a 61

type vecarray[1 . .100] of longint; #include <iostream. h>


var nzlongint; seria:vee;
ind,i:inte ger; long n;
int seria[100 ],ind,i;
function suma(nzlon gint):longi nt;
var s,i,c:inte ger; int suma(int n)
begin { int sO,c;
s:O; while (n) {
while n<>O do cn%10;
begin s+cc*c;
c:n mod 10; n/=10;
s:s+c*c*c ; }
n:=n div 10 return s;
end; }
suma:s int este(long n,int s[100],
end; int ls)
function este(n:lon gint;var s:vec; { int i;
ls:integer) :boolean; for(iO;i< ls;i++)
var i:integer; if(s[iln ) return O;
begin return O;
este:true ; }
for i:1 to ls do void main()
if s[i)n then este:fals e { cout<<"n ; cin>>n;
end; ind.. O;
begin seria[ind) n;
write('n '); readln(n); do {
seria[l): n; nsuma(se ria[ind-1]) ;
ind:al; seria[++in d]n;
repeat ) while(l este(n,ser ia,
n: suma(seria [ind-1)); ind-1));
ind:ind+1 ; for (i1;i<ind ;i++)
seria(ind] :n; cout<<seri a[i)<<endl ;
until este(n,ser ia,ind-1); }
for i:l to ind do
writeln(s eria[i]);
end.

0 Aplicaia 2.7. S se scrie o procedur care citete o matrice cu elemente


1umere tntregi din fiierul text MAT. orxor. Pe prima linie a fiierului sunt dou valori:
m (numrul de linii ale matricei) i n (numrul de coloane ale matricei). Urmtoarele m
nii ale fiierului conin, rn ordine, elementele aflate pe fiecare linie a matricei.
Verificai subprogramul definit, integrndu-1 ntr-un program de testare.

Exemplu: fiierul f in conine:

3 4
3 1 7 g
1 2 3 4
9 1 3 8
62 Capitolul 2. Subprograme

0 Rezolvare. Pentru a putea fi folosit pentru citirea oricrei matrice de numere


intregi, procedura va trebui s utilizeze ca parametri .de ieire matricea, numrul de
linii i numrul de coloane ale matricei. '

Tn programul urmtor se testeaz procedura, prin listarea matricei:

type mataarray[1 100,1 100] #include <fstream.h>


of integer;
void citesc(int mat[100] [100],
var m:mat;
int&: m, int&: n)
linii,coloane,i,j:intege r;
{ fstream f("fis.txt,ios::in);
procedura citesc(var t:mat; f>>m>>n;
var m,n:integer); for (int i=1;i<=m;i++)
var i,j:integer; for (int j1;j<=n;j++)
f:text; fmat [il [j];
begin f .close() 1
assign(f, 1 mat.txt 1 )J }
reset(f);
void main()
readln(f,m,n) 1
{ int m,n, mat[100) [100];
for i:=1 to m do
citmat(m,n,mat);
for j:1 ton do
for (int i l ; i<-.m;i++)
read(f,t[i,j]);
close(f) { for (int :i l;j<n;j++)
cout<<mat [il [j] << ";
end;
cout<<endl;
begin
citesc(m,linii,coloane); }
for i :."' 1 to linii do
bagin
for j:l to coloane do
write(m[i,j], 1 1 ) 1
writeln
end
end.

Probleme propuse

1. Scriei un program care calculeaz i afieaz valoarea fiecreia dintre expresiile


de mai jos, pentru x citit de la tastatur:

a) G(x) =sin(x)+cos(x)cos(2x);
b) H(x) = 10{x} (am notat prin {x} partea fracionar a lui x).
'anual de informatic pentru clasa a Xl-a 63

2. Coifurile NFL. Exist 28 de echipe de fotbal n NFL (Liga Naional


:e Fotbal n SUA). Unele magazine au aparate care ofer _ coifuri n
""'niatur ale echipelor contra o. 25$. Cnd pui moneda n aparat, nu
:;i ce coif vei obine, oricare din cele 28 de coifuri diferite i poate veni
: n aparat (sunt oferite aleator). Scriei un program care simuleaz punerea
-onezii ntr-un astfel de aparat pn cnd se obin toate cele 28 de coifuri.
:>rogramul trebuie s tipreasc i totalul cheltuielilor efectuate pentru obinerea
:elor 28 de coifuri.
Junior Divislon

~ Indicaie. Utilizai subprogramele predefinite Random i Randomize.

3. Scriei o funcie care primete ca parametru lungimea laturii unui ptrat i


eturneaz aria sa.
~. Scriei un subprogram care primete ca parametru lungimea laturii unui ptrat i
eturneaz att lungimea diagonalei, ct i perimetrul ptratului.
5. Scriei o funcie care primete ca parametri de intrare lungimile celor dou catete
ale unui triunghi dreptunghic i returneaz lungimea ipotenuzei.
6. Scriei o funcie care primete 3 parametri de tip real, cu semn ificaia de lungimi
oentru 3 segmente. Funcia va returna 1 dac cele trei segmente pot forma un
triunghi i o, in caz contrar.

7.Scriei o funcie care returneaz prima cifr a unui .,numr natural. De exemplu,
dac parametrul efectiv este 127, funcia va returna 1.

8. "Numai ultima cifr". Se citesc n (numr natural, n<100) i n numere naturale


nenule x1 x2 x3 xn. numere mai mici ca 30000. Se cere:

ultima cifr a numrulu i x 1 + x 2 +....+x ,.;


ultima cifr a numrul ui x(1.r3 ...r.

8 pentru c ultima cifr a sumei 11+4+3 este 8;


1 pentru c ultima cifra a lui 1112 este 1.

Concursul Naional al Elevilor, Sinaia

9. S se citeasc dou matrice i s se efectueze suma lor. Programul se va


realiza astfel:

se scrie un subprogram de citire a unei matrice cu m linii i n coloane;


se scrie un subprogram de tipri re a unei matrice cu m linii i n coloane;
se scrie un subprogram care adun dou matrice;
" prv gramul principal rezult din apelul acestor subprograme.
64 Capitolul 2. Subprograme

10. S se calculeze coeficienii polinomului P(x) = (x+a)n, n dou variante.

a) Programul utilizeaz un subprogram care fnmulete un polinom oarecare


de grad k (coeficienii se gsesc ntr-un vector, transmis prin referin)
cu polinomul x+a.

b} Programul utilizeaz un subprogram care calculeaz coeficienii, aa cum


rezult din formula (binomul lui Newton):

11

cx+a)" =Ic,~ak x"- k.


k =O

11. S se tipreasc toate numerele prime aflate ntre doi ntregi citii. Programul
va folosi o funcie care testeaz dac un numr este prim sau nu.

12. Scriei un program care tiprete numerele ntregi gsite ntre dou valori citite,
numere. care se divid cu suma cifrelor lor. Programul va utiliza o funcie care
returneaz suma cifrelor unui numr ntreg primit ca parametr.u .

13. S se scrie o procedur care permut dou linii date ale unei matrice ptratice.

14. Scrie! o procedur care interclaseaz doi vectori sortai tiind c acetia sunt
ordonai descresctor.

15. Se citesc dou polinoame de grade m i n (coeficienii fiecrui polinom se citesc


ntr-un vector). S se afieze coeficienii polinomului sum i cei ai polinomului
produs. Jn ambele cazuri se vor utiliza proceduri de citire, adunare, nmulire.

16. Se citesc 3 valori a, b, n (a i b reale, n ntreg). Se cere s se calculeze valorile


unei funcii F, definit pe intervalul [a, b] n n+l puncte rezultate din mprirea
Intervalului [a,b] n n pri egale i s se afieze cea mai mare dintre aceste
valori. Funcia F va fi dat sub forma unui subprogram de tip funcie.

17. Un numr raional


este reinut prin utilizarea unui vector cu dou componente.
Scriei subprogramele care adun, scad, nmu lesc i mpart dou numere
raionale . Subprogramele trebuie s returneze numrul simplificat.

18. Design triunghiular. Triunghiul de mai jos este generat de un algoritm.


Descoperii acest algoritm i folosii-! pentru a scrie un program care citete
numrul n de linii i genereaz triunghiul cu n linii corespunztor.

1
232
34543
4567654
567898765
67890109876
7890123210987

Junior Division
_-_a. de informatic pentru clasa a Xl-a 65

... :a afieaz programul urmtor?


, Var_iantaPasca.! ,. ,
T3..: z:integer; #include <iostream. h>
;=ocedure test(a:int eger); void test(int a)
~in { a++;
a:=a+l; write{a); cout<<a;
c.d; }

=egin void main()


z: =S; { int z=S;
t est(z); test(z);
write(z) cout<<z;
end . }

~ 6 6; b) 5 6; c) 6 6; d) 6 s.
:~ . Ce afi eaz programul urmtor?
o!j'! '., ' ' 1"
.~ Varianta Pascal ' Varianta C++'
function f(x:intege r):integer ; #include <iostream. h>
begin int f(int x)
f:=x+l { return x+1;
and; }
procedura t(a:intege r); void t(int a)
begin { a++; cout<<a;
a:=a+l; writeln(a) ; }
and;
void main()
begin { t(f(f(f(1) )));
t(f(f(f(l) ))) }
end.

a) 3; b) 4; d) eroare de sintax.

21. Ce afieaz programul urmtor:


1
Varianta P.ascal
IJ'i';J,,I li,,. .11,.
V~rianta C# ~~!; 1J!I!'I!:I~" '.
'
var a:integer; #include <iostream. h>
int a;
function f:integer;
var a:integer; int f()
begin { int a 3;
a:=3; cout<<a;
write(a); return a;
f:=a; }
end; void main()
begin { a2;
a:=2; cout<<a;
wri t eln(a,f); cout<<f();
end. }

a) 233; b) 23; c) 32; d) 232.


66 Capitolul 2. Subprograme

22. tiind c valorile citite ale variabilelor a i b sunt numere naturale nenule, care
dintre secvene utilizeaz subprogramul increment...pentru a obine produsul celor
dou numere?

var a,b,i,j,t:integer; #include <iostream.h>


procedura increment(var x:integer); int a,b,i,j,t;
begin void increment(int& x)
x:=x+1 { X++; }
end; void main()
begin { cin>>a;
readln(a); readln(b); cin>>b;
ts=a; t=a;

writeln(t) cout<<t;
end. }

a) for i:=l to a do for(i=1;i<=a;i++)


for j:=1 tob do for(jal;j<=b;j++)
increment(t); increment(t);
b) for itl to a do for(i=1;i<=a;i++)
for j:=1 to b-1 do for(jal;j<b;j++)
increment(t); increment(t);
c) for i:=l to b do for(i=l;i<=b;i++)
for j : =l t o t do for(j=l;j<=t;j++)
increment(t); increment(t);
d) for i:=l to a do for(i=l;i<=b;i++)
increment(t); increment(t);

23. Pentru varianta de limbaj preferat, stabilii care dintre urmtoarele antete de
subprogram sunt corecte:
a) procedura p(n:integer; var void p(int n, int& v[10))
v: array[l. .101 of integer);
b) function p(n:integer;var p(int n, float& v)
v:real);
c) procedura p(n:integer;v:real); void p(int n, float v)
d) functio~ p(n):integer; int p(int& n; float v)

24. Pentru funciile definite mai jos, care dintre afirmaii este fals?

function f(xsreal):real; float f(float x)


begin { if (x<3) return 3*x-1;
if x<3 then f:=3*x+l else return x-1;
else f t=x-1 }
end;
function g(x:real):real; float g(float x)
begin { if (x<lO) return 4*x;
if x<10 then g:=4*x else return x-1;
}
else g:=x-1
end;
, - i.Jal de informatic pentru clasa a Xl-a 67

a> Expresia f ( g ( 3) ) produce valoarea 11;


b) Expresia g ( f ( 3 ) ) produce valoarea a;
c > Expresia f ( g ( f ( 3 ) ) > produce valoarea 7;
d) Expresia (f+g) (3) produce valoarea 14.

~ Fiind dat funcia urmtoare, care dintre afirmaii sunt adevrate?

varianta Pascal
~ction Cat(n1,n2:in teger): long Cat(int n1,int n2)
longint; { int inv=O;
Tar inv:integer; while (n21a0)
~gin { inv=inv*10+n2 %10;
inv:=O; n2=n2/10;
while n2<>0 do begin }
inv:inv*10+ n2 mod 10; while (invi=O)
n2:=n2 div 10 { nl=nl*lO+inv% 10;
end; inv=inv/10;
while inv<>O do begin
n1:=n1*10+in v mod 10; return nl;
inv:inv div 10
end;
Cat:=nl
end;

a) cat(12,10) returneaz 1210;


b) Cat(10,12) returneaz1012;
c) cat< o, 12) returneaz 12;
d) Cat (12, O) returneaz 120.

26. Fiind dat funcia urmtoare, care dintre afirmaii este fals?

long Cat(int nl,int n2)


{ int n2s;
var n2s:integer; n2s=n2;
begin while (n210)
n2s:=n2; { n2/=10;
while n2 <>0 do begin n1*=10;
n2:=n2 div 10; }
n1:n1*10 return n1+n2s;
end; }
Cat:=n1+n2s
end;

a) Cat(-12,13) returneaz -1213;


b) cat ( 12, o> returneaz 12;
c> Cat (o, 12) returneaz 12;
d) Cat (13, 12) returneaz 1312.
68 Capitolul 2. Subprograme

27. Se consider declarrile urmtoare:

1'',__. ;.,:
;, ,,
' "':\ Varianta Pa9cal
.
type vect=array [1 40] of byte; void Concat(int A[20], int 1
8(20], int m, int n, int C[40],
procedura Concat(A,B :vect; int&. p)
m,n:b.yte;v ar C1vect;var p:byte);
void Reun(int A[20], int 8[20],
procedura Reun(A,B:v ect; int m, int n, int C[40], int&
m,n:b.yte;v ar C:vect;var p:b.yte); p)

procedura rnters(A,B :vect; void rnters(int A[20], int


m,n:b.yte;v ar C1vect;var p1b.yte); B[20],int m, int n, int C[40],
int&. p)
procedura Dif(A,B:ve ct;m,n:byte ; void Dif(int A[20J, int B[20],
var C1vect;var p:byte); int m, int n , int C[40], int&
p)
procedura Elimin(var A1vect;
var nu byte) ; void Elimin (int A[20],int& m)

n care:

- Conoat are rolul de a returna vectorul c cu p componente, vector obinut din


concatenarea componentelor vectorului A de m elemente cu ale vectorului B cu n
elemente. De exemplu, din Aa(1,2,3 , 7), m=4, B=(2,5,3) , n=3, se obine
C=(1,2,3 ,7,2,5,3), pa7,
- Reun are rolul de a returna vectorul c cu p componente , vector obinut dir
reuniunea mulimilor de numere naturale din vectorii A cu m elemente i B cu n
elemente (presupunand c A conine valori distincte i B conine valori distincte)
De exemplu, din A(1,2,3, 7), m=4, B=(2,5,3) , n=3, se obine
c- c1 , 2 , 3 , 1 , s >, p s.

- :rnters are rolul de a returna vectorul c cu p componente, vector obinut dir


intersecia mulimilorde numere naturale din vectorii A cu m elemente i B cu n
elemente (in aceleai condiii ca i in cazul reuniunii). De exemplu, <iir
A= (1, 2, 3, 7), m4, B= (2, 5, 3), na3, se obine C (2, 3), p=2.
- c cu p componente, vector obinut din
Dif are rolul de a returna vectorul
diferena mulimilor
de numere naturale din vectorii A cu m elemente i B cu n
elemente (in aceleai condiii ca i fn cazul reuniunii). De exemplu, dir
A(1,2,3, 7), m=4,B(2 ,5,3), n=3 , seobineC=(1,7), p2.
- Elimin are rolul de a returna vectorul care conine toate elementele distincte
ale vectorului iniial cu m componente, prin eliminarea valorilor multiple. De
exemplu, pentru A= ( 1, 1, 2, 3, 2), m=S, se returneaz A= ( 1, 2, 3) , m=3 .

A. Se citesc doi vectori x cu a numere naturale i Y cu b numere naturale


Elementele din fiecare vector nu sunt neaprat distincte. Care dintre secvenele de
mai jos nu calculeaz reuniunea mulimilor numerelor naturale reinute de cei do
vectori? Rezultatul se va gsi in vectorul z.
2..- Jal de informatic pentru clasa a Xl-a 69

Concat(X,Y,a,b, Z , p);
Elimin(Z,p);
Elimin(X,a); Elimin(Y,b);
Concat(X,Y,a,b,Z,p);
Elimin(Concat(X,Y,a,b ,Z,p),p);
Elimin(X,a); Elimin(Y,b);
Reun(X,Y,a,b,Z,p);

Se citesc doi vectori x cu a numere naturale i Y cu b numere naturale.


=::e11entele din fiecare vector sunt distincte. Care dintre secvenele de mai jos
::=.culeaz intersecia mulimilor numerelor naturale reinute de cei doi vectori?
::-::zultatul se va gsi in vectorul z.
Dif(X,Y,a,b,Z,p);
Dif(X,Z,a,p,Z,p);
; Dif(X,a,Y,b,Z,p);
Dif(Y,Z,b,p,Z,p);
: Intersect(X,a,Y,b,Z,p)
~ Intersect(X,Y,a,b,Z,p) ;

"' Se citesc doi vectori x cu a numere naturale i Y cu b numere naturale.


=ementele din fiecare vector sunt distincte. Care dintre secvenele de mai jos nu
::c:>cu leaz nici x - Y, nici Y-x? Rezultatul se va gsi in vectorul z.

Inters (X,Y,a,b,Z,p)l
Dif(X, Z,a,p,Z,p);
= Inters( X,Y,a,b,Z,p);
Dif(Y,Z,b,p,Z,p)l
: Inters(Y, X,a,b,Z,p);
Dif(X,Z,a,b,Z,p);
~ Dif(X,Y,a,b,Z,p);

28. Se conside r subprogramul urmtor:

procedura Afis (n:integer); void Afis (int n)


var i,j,k:integer; { int i,j,k;
begin k2*n-1J i =l;
kl2*n-1;i:=1; while Ci<an)
while i<n do {for(j=l;]<(k-2*i+1)/2Jj+ +l
begin caut<<' ';
for j:=l to (k-2*i+l)div 2 do for(j 1;]<=2*i-1J]++)
write (' '); caut<<'*';
fo.r j: =l to 2*i-l do i++;
write ('*'); caut<<endl;
i:=i+l; }
wr:i.te:n }
end
end;
70 Capitolul 2. Subprograme

A. Dac n=8, cte caractere"*" se afieaz pe ultimul rnd tiprit?

a) 8; b) 16; c) 15; d) 17.

B. Dac n4, cte caractere"*" se afieaz in total (pe toate randurile)?

a) 8; b) 16; C) 12; d) 20.

C. Dac n20, eate spaii se scriu naintea primului caracter"*", pe penultimul rnd?

a) 10; b) 20; c) 19; d) 1.

29. Se consider subprogramul urmtor:

type vectarray[l lO] of byte; void xx (i nt V[lO] )


{ int A[4) (4],i,j , ZI
procedure xx(var Vrvect);
for (i=O;i<4;i++)
var A:array[1 . 4,1 . 4] of byte;
for (j=3;j >=O;j--)
i,j,z:byte;
begin
{ A[i] [j]=V[i]%2;
V[i]/=2;
for irl to 4 do
}
for j:=4 dow.nto 1 do
for (i=O;i<4;i++)
begin
{ z=A [O] [ i) 1
A[i,j]rV[i) mod 2;
for (j=llj<4;j++)
V[i] :=V[i] div 21
end;
z=z*2+A[j] [i) 1
V[i]=z;
for i : l to 4 do
}
begi.n
}
z r=A[l,i];
for j:=2 to 4 do
zrz*2+A [j , i] ;
v[i] rz;
end;
end1

A. Care este coninutul lui v dup apel, dac inainte este V=< 1, 2, 3, 4)?
a) V=(1 1 2,3 1 4); b) V=(4,3,2 1 1);
c) V=(0,1,6,10 ) ; d) V=(0,4 , 5 1 9) .

B. Care trebuie s fie iniial coni nutul lui v, dac dup apel este V= ( 1 1 6 1 10, o)?
a) V=(2,4,6,8); b) V=(1,6,10,0) ;
c) V=(0,10,6,1); d) V=(1,9,3,2) .

C. Pentru care dintre exemplele u rmtoare de configu raii ale lui v la intrarea n
subprogram, coni n utu l acestuia la i eire coincide cu cel de la intrare?
a) V=(13,10,5, 1 1); b) V=(2,3 1 9 1 13);
c) V=(0,1,2,12); d) v .. (1,4,9,15 .
'.1anual de informatic pentru clasa a Xl- a 71

30. Se consider subprogramul urmtor:

typevect=array[1 , . 101 of integer; int Cmp(int m, int n,


int A[10], int 8[10])
function Cmp(m,n:integer; { int i=O;
A,B:vect):byte; while (i<=m && i<=n &&
var i:integer; A[il==B[i]) i++;
begin if(i>n && i>m) return O;
i:=l; else if(i>n) return 1;
while (i<=m) and (i<=n) else if(i>m) return -1;
and (A[i]=B[i]) do i:=i+l;
else if(A(i]<B[i])
if (i>n) and (i>m) return -1;
then Clllp:=O el se
else if i>n then Cmp:=1 return 1;
else if i>m then cmp:=-1 }
else if A[i]<B[i]
then Cm;p:=-1
else Cmp:=1;
end;

A. Ce valoare returneaz funcia apelat pentru fiecare dintre cazurile urmtoare?

a) m=3, n=3, A= ( 1, 2, 3), B= ( 1, 2, 3);


b) m=2, n=3, A=(l,2), B= ( 1, 2, 3);
c) m=2, n=3, A=(l,3), B= ( l, 2, 3);
d) m=l, n=l, A= (1), B= ( 1).

B. Pentru m=S, n=3, A=(1,2 , 5 , 7 , 2), B=(1 , 2 , 0), stabiliicevaloarepoatefi


a treia component a vectorului B astfel nct funcia s returneze valoarea o.

a) 3; b) s;
c) nu exist o astfel de valoare; d) 2 .

C. Pentru X=< 1, O. O,
s , 7), Y= c1, 2, 7), stabilii ce valori pot fi scrise n casete
astfel nct apelul CJl\P ( 4, 4, x, Y) s returneze aceeai valoare ca i apelul
cmp ( 4 , 4 , Y, X) .

a) 2 i respectiv 3; b) 2 i respectiv s;
c) nu exist astfel de valori; d) 3 i respectiv 6.

O. Pentru care ir de vectori, funcia Cmp, apelat pentru oricare doi vectori
consecutivi n ir, returneaz aceeai valoare?

a) A= ( 1, 2, 3) , B= ( 1, 2, 3), C ( 1, 2, 2);
b) A=(1,2), B=(1,2), C=(1,3);
c) A=(1,3), B=(l,2), C=(1,3);
d) Ac ( 2), B= ( 1), c= (O).
72 Capitolul 2. Subprograme

31. Scriei subprograme pentru:

A. Calculul valorilor ce caracterizeaz o sfer (arie i volum) pe baza valorii razei


sale r.
B. Calculul valorilor caracteristice ale unui con (raza bazei, generatoarea i fnlimea)
pe baza valorii volumului conului i a ariei sale laterale.
C. Obinerea descompunerii fn factori primi a unui numr natural n.
D. Ordonarea componentelor pozitive ale unui ir de valori, valorile negative
rmnnd pe poziiile lor iniiale.
E. Determinarea unei subsecvene palindromice a unui ir de numere naturale de
cel mult dou cifre.
F. Verificarea respectrii limitei de vitez pe un sector de drum pentru un vehicul
care fi parcurge i care este inregistrat la diferite momente de timp de o camer
video. Se transmit: viteza maxim admis v, numrul de camere video n, distanele
fa de punctul de inceput al sectorului de drum unde sunt amplasate camerele:
d 1 ,d2 , ... ,d,. i momentele la care s-a inregistrat trecerea mobilului prin dreptul
fiecrei camere t1,t21- .. ,to.

Rspunsuri

19. d); 20. c); 21. a); 22. b); 23. c); 24. d); 25. b),c); 26.a) ;

27. A. b), c); B. a), d); C. c);

28. A. c); B. b); C. d).

29. Indicaie: fiecare numr este scris in binar pe o linie a matricei. Se afieaz
numerele zecimale obinute din numerele iri binar de pe fiecare coloan a matricei.
A. c) , B. a) , C. a) .

30. Indicaie: funcia realizeaz compararea lexicografic a doi vectori care rein
numere naturale. A. a) o; b) -1; c) 1; d) o; B. c); C. b); O. d).
Capitolul 3
iruri de caractere

. 1. Generaliti

Programele nu lucreaz numai cu numere. Ele utilizeaz din plin irurile de


ca.-actere. In absena lor ar fi foarte greu ca, de exemplu, un program s poat citi
SL afia numele unei persoane sau numele unei localiti. Ne putem imagina un
~ :1e caractere ca un vector n care fiecare component reine un caracter. Dup
e...., se tie, fiecare caracter este memorat prin utilizarea codului ASC:U. irurile de
c:.:actere pot fi citite, afiate i prelucrate cu ajutorul unor subprograme puse la
-=:.poziie de limbaj.

irurile de caractere au aplicaii uriae n viaa real. S vedem cteva dintre


~stea:

-t Cine n-a folosit un editor de texte? Chiar acum, cnd scriem programele
Pascal sau C++ utilizm un editor de texte. Luai codul surs al unui program
(fiiere cu extensii .pas sau cpp). Observai c sursa este un fiier text n
care fiecare linie a ei, este o linie a fiierului text. Prin urmare, fiecare linie a
fiierului text conine un ir de caractere. Ce operaii putem face cu
editoarele? De exemplu, putem modifica o linie. O astfel de operaie const
n includerea sau tergerea unui subir (caractere consecutive din Interiorul
unul ir). Astfel de operaii se fac, i vom vedea cum, prin prelucrarea
irurilor de caractere. Alte operaii: a) Find- este o operaie de Identificare
a unui subir n cadrul unui ir de caractere; b) Replace este o operaie de
nlocuire a unui subir cu un altul; c) cut este o operaie prin care, din cadrul
unul ir se extrage un subir al su i acesta este memorat n Clipboard.
Prin Paste se insereaz un ir de caractere n cadrul altui ir de caractere.
irul exemplelor ar putea continua. Putei gsi altele?

-t Ai nvat, la "Tehnologia Informaiei i a Comunicailor", cum, de exemplu,


putem crea tabele (Excel, Word sau Access). Am vzut c liniile tabelului,
pot conine valori numerice, dar i alfabetlce, care sunt iruri de caractere.
Putem sorta liniile unui tabel dup o anumit coloan (de exemplu, dup
numele persoanelor, n ordine alfabetic). De aici, rezult c ntre irurile qe
caractere exist o relaie de ordine, corezpunztoare ordonrii alfabetica. In
informatic, o astfel de relaie se numete ordine lexicografic. Cum se
ordoneaz alfabetic (lexicografic) mai multe iruri de caractere? Care sunt
principiile care stau la baza acestei ordonri? Despre toate acestea vom
nva n acest capitol.

+ Limbajele actuale permit numai introducerea datelor sub form de iruri de


caractere. Luai, de exemplu, o component de tip edit, component studiat
la 'Tehnologia Informaiei i a Comunicaiilor". Chiar dac vrei, de exemplu,
74 Capitolul 3 -iruri de caractere

s introducei numrul 12, vei introduce de fapt irul de caractere 12 .


Programul va converti i rul de caractere ' l l ' n numru l ntreg 12. Nu
ntotdeauna o astfel de operaie reuete, pentru c este posibil ca persoana
care introduce data respectiv s greeasc. De exemplu, n loc de irul'12' ,
s introduc irul '1Gl'. Aceasta nseamn c n timpul operaiei de conversie,
se efectueaz i o anumit validare. n cazul de fa, trebuie efectuat o
validare numeric. Componentele studiate la Tehnologia Informaiei afieaz
iruri de caractere. Prin urmare, dac realizm un astfel de program, este
necesar s convertim valorile numerice n iruri i invers. Cum efectum astfel
de conversii? Conversiile sunt prezentate n acest capitol.
ntruct exist diferene semnificative ntre modul n care sunt reinute i
prelucrate irurile de caractere n cele dou limbaje (Pascal i C++), prezentarea
acestora se va face separat.

3.2. iruri de caractere n Pascal

3.2.1. Noiuni introductive

Poate ai observat c pn n acest moment, nu am memorat cuvinte.


Acestea au fost doar afiate. In Pascal se poate lucra cu uurin cu ele, datorit
faptului c limbajul este nzestrat cu un tip de date special, numit string.

Definiia 3.1. O succesiune de caractere cuprinse ntre dou caractere


apostrof se numete ir de caractere.

Exemple: un sir'; 'toamna se nwnara bobocii'.

O ntrebare: ntre caracterele care alctuiesc irul se poate gsi i


apostroful? De exemplu, irul Alt sir este scris corect?

Rspunsul comport o anumit nuanare. Pentru a include apostroful, se


folosete un artificiu: acesta este trecut de dou~ ori. Prin urmare, irul Alt
sir este incorect, corect este Alt sir . Atenie! n memorie, irul Alt
sir este reinut ca Alt sir , deci cu un singur apostrof. De ce este
nevoie s se procedeze astfel? Motivul este dat de faptul c, dac am proceda
altfel, compilatorul nu ar putea decide unde se termin irul, cu alte cuvinte, care
este apostroful final.
n Pascal, pentru a putea lucra cu irurile de caractere se folosesc variabilele
de tip string. Tipul string este predefinit, adic este cunoscut, nu avem nevoie
s-I declarm cu type.

var ta string; Programul alturat are decl arat o


begin variabil t, de tip string. Ea este
t 1 'Iepuras;
iniializat cu irul 'Iepuras , apoi este
writeln(t);
end. afiat.
.anual de informatic pentru clasa a Xl-a 75

Pentru nceput, s analizm modul n care o variabil de tip string


emoreatil un ir de caractere. Pentru aceasta, pornim de la exemplul dat n
::'ogramul anterior:

t[S]
1-----l
- ...- . . - -..- t[255]
t[O] t[l] t[2] t[3] t[4] t[S] t[6] t[7]

Ce observm? Pentru o variabila de tip string se rezeNa automat un vector


~u 256 deoctei, numerotai de la o la 255. Primul dintre ei are rolul de a reine
1umarul de octei ocupai de ir.

n exemplul dat, irul 'I epuras este alctuit din apte caractere. Octeii de
a 11a 7 memoreatil caracterele din care este alctuit iru l. Restul octeilor, de la a
a 255 au un coninut neprecizat. De altfel, nici nu ne intereseaz coninutul lor.
faptul c afiarea s-a realizat, n ansamblu, prin precizarea numelui.
Observai

ntruct o variabil de tip string memoreaz cuvintele sub form de vector


de caractere, exisM posibilitatea s accesm direct coninutul unui octet, aa cum
suntem obinuii. Astfel, t [1] reine codul caracterului I , t [2] reine codul
caracterului e, .a.m.d . Programul care urmeaz afieaz acelai cuvnt, pe litere:
var t: string;
i: integer;
begin
t r= ':Iepuras'J
for i := 1 ton do write(t[i ]);
end.

Mai mult, putem modifica coninutul unui singur octet, aa cum rezult din
programul urmtor.
var t: string;
begin
t 1 ':Iepuras;
t[6] 1'11 ' i ' l
write(t)J
end.

in loc de 'a', t [6) reine i . Prin urmare, programul afieaz 'Iepuris'.


n cazul variabilelor de tip string exist posibilitatea ca atribuirea sa se faca
direct, nu pe litere, aa cum rezult din programul urmtor:
var t, z: stringi
begin
t 1 :Iepuras ' 1
% : = t;
write(z);
end.

in urma atribuirii, variabila z reine cuvntu l" ~epuras" i acesta este afiat.
76 Capitolul 3 - iruri de caractere

Am vzut c pentru o variabil de tip string se rein automat 256 de octei,


din care primul reine lungimea. n multe cazuri, acest numr este prea mare - se
consum memorie inutil. Din acest motiv exist~ posibilitatea ca o variabil~ de tip
string s fie declarat in aa fel inct s ocupe un numr mai mic de octei.

Exemplu: v ar t: string[4];
Variabila t, ocup 5 oc:tei. Primul, cel de indice o, are rolul de a reine
lungimea cuvntului memorat. In acest caz, variabila poate reine cuvinte ce au cel
mult 4 caractere. Programul afieaz 'mama'.
var tt string[4 ] ;
begin
t z 'mama';
write(t);
end.

Ce facem n cazul n care cuvntul care va fi memorat, are un numr mai


mare de litere dect numrul de octei ai variabilei care l memoreaz?

Exemplu:
var tz string[4];

t:= 'DANSATOR';

n astfel de cazuri se rein numai primele caractere, attea cte pot fi


memorate. n exemplu, variabila t reine cuvntul 'DANS'.

Dup cum am nvat, caracterul blank se memoreaz ca oricare altul, prin


codul su. Prin urmare, o variabil de tip string poate reine mai multe cuvinte,
separate prin unul sau mai multe blank-uri.

Exemplu:
var numet string;

numez 'Ion Zaharia;

n concluzie, prin utilizarea variabilelor de tip string avem avantajul c


putem adresa irul de caractere att n ansamblu, prin utilizarea numelui variabilei,
ct i pe caractere, prin utilizarea parantezelor drepte.

Acesta nu este singurul avantaj. Limbajul este nzestrat cu proceduri i funci i


care uureaz mult lucrul cu irurile de caractere.

3.2.2. Concatenarea irurilor

Pentru a concatena dou iru ri de caractere se folosete operatorul '+ '.


Operatorul '+ este binar (adic are doi operanzi) i poate aciona asupra datelor
de tip string. Ce ne legem prin concatenare?
Jal de informatic pentru clasa a Xl-a 77

Definiia 3.2. Concatenarea este operaia prin care din dou iruri de
caractere se obine un al treilea, format astfel: p~imul ir (cel aflat n
stnga operatorului), urmat de al doilea ir (cel aflat in dreapta
operatorului).

:.amplu:
program st6;
var t, z: string;
begin
t := acest';
z := ' exemplu';
t : t+z;
writeln(t);
end.

- programul st6 se concateneaz dou iruri de caractere (t: =t+z; ):

variabila t reine irul 1 acest 1 ;


variabila z reine irul 1 exemplu 1 ;
prin operaia (t+z;) se obine irul 1 acest exemplu';
irul obinut este atribuit variabilei t.

J Observaii

1. Dac am fi scris t :mz+t; programul ar fi afiat exempluacest 1 De


aci tragem concluzia c operaia de concatenare nu este comutativ (conteaz
:;dlnea n care sunt trecui cel doi operanzi).
2. Observm ct este de important s inem cont de poziia blank-ului (al
::oilea ir este precedat de blank). Observai c dac am fcut concatenarea z+t,
am obinut irul 1 exempluacest 1 , care este precedat de blank.

3. Trgbuie s avem n vedere c irul obinut n urma concatenrii s poat fi


-,emorat n ntregime - variabila creia i se atribuie s fie declarat cu un numr de
octei care s permit memorarea sa, altfel irul va fi memorat trunchiat - adic vor
' memorate numai primele caractere, attea cte ncap.

3.2.3. Compararea irurilor

Orict ar prea de curios, irurile de caractere pot fi comparate. Astfel, dou


iruri de caractere (notate a i b), se pot gsi n una din relaiile:

aab - cele dou iruri sunt egale;


a>b - irul a este mai mare dect irul b;
a<b - irul a este mai mic dect irul b.
78 Capitolul 3 -iruri de caractere

Dar cum se pot compara dou iruri? S nu uitm c i dou caractere se


pot compara dup codul lor. Am vzut modul n car~. au fost codificate caracterele,
dup o anumit logic: da~ un caracter urmeazA altuia, n ordine alfabeti~, atunci
el are drept cod un numr mai mare dect al caracterului cruia i urmeam.
Exemplu: codul caracterului d este mai mare cu o unitate dect codul caracterului c.

irurile sunt succesiuni de caractere. Prin urmare, compararea se face pe


caractere. n continuare prezentm algoritmul de comparare a dou iruri.

Fie dou iruri de caractere, notate cu a (cu m caractere) i b (cu n


caractere).

~ Se compar codurile primelor dou caractere (aflate n stnga irurilor, de


indice 1). Avem 3 posibiliti:

dac codul primului caracter al irului a este mai mare dect codul
primului caracter al irului b , atunci a>b.

dac codul primului caracter al irului b este mai mare dect codul
primului caracter al irului a, atunci a<b (b>a ).

n caz de egalitate se compar codurile caracterelor de indice 2.

~ Dac m<n , i n urma comparrii primelor m caractere a rezultat egalitate, atunci


a<b (bare mai multe caractere).

~ Dac m>n, i n urma comparrii primelor n caractere a rezultat egalitate,


atunci a>b (a are mai multe caractere).

~ Dac mn i n urma comparrii tuturor caracterelor a rezultat egalitate, atunci


cele dou iruri sunt egale (a=b).

Exemple:
a=' abc' , b= 'bactr . Atunci a<b, pentru c a [ 11 este a i are codul mai
mic dect b [ 1 1 care este b .

a= 1 abc 1 , b= aba 1 Atunci a>b, codul lui a [1] este egal cu codul lui b [1] ,
codul lui a [ 2 J este egal cu codul lui b [ 21 iar codul lui a [ 3 1 este mai mare
1

dect codul lui b [ 31 .

a abc' 1 b= 1 abea . Aici m=3, n=4. Atunci a<b, codul lui a [1] este egal cu
codul lui b [11. codul lui a [2 1 este egal cu codul lui b [2], codul lui a [3 ]
este egal cu codul lui b[3] i n>m (irul bare mai multe caractere).

Compararea irurilor de caractere este extrem de util n sortarea alfabetic


a cuvintelor (ca n dicionar). Ordinea astfel imp us se mai numete i ordine
lexicografic.
'.~anual de informatic pentru clasa a Xl-a 79

n programul urmtor se sorteaz alfabetic mai multe iruri de caractere


;:....;..
_.,/\;. (cuvinte). Pentru aceasta, se declar un vector n care fiecare
component este de tip string.

Algoritmul de sortare este unul studiat (care?), motiv pentru care nu revenim
asupra lui. Programul este prezentat n continuare:

type cuvinte= array[1 10] of string;


var v: cuvinte;
man: string;
n, i: byte;
inv: boolean;
begin
write( 'n= );
readln(n);
for i := 1 to n do
readln(v[i]);
repeat
inv := false;
for i := 1 to n-1 do
if v[i] > v[i+1] then
begin
man ,. v[i];
v[i] ;a v[i+1] 1
v[i+ll := man;
inv : true;
end
until not inv;
for i := 1 to n do
writeln(v[i]);
end.

3.2.4. Lungimea irurilor de caractere

Definiia 3.3. Prin lungimea unui ir de caractere nelegem numrul de


caractere pe care acesta le conine.

Exemple:
iru l mama are lungimea 4;

irul mama are lungimea s (i blank-ul este caracter).

:::>entru aflarea lungimii unui ir avem dou posibiliti:

1. Prin utilizarea funciei length, care are forma general:

function length(S: String): Integer;

' ntoarce lungimea irului s - numr Tntreg.


80 Capitolul 3 - iruri de caraC"'

4 Exemple de utilizare

a) var a: string;
c: integer;

a := un test ' ;
c := length(a);

n urma atribuirii, variabila c reine 7.

b) n condiiile de mai sus, writeln(length( a)) afieaz 7.

2. Dup
cum am nvat, octetul de indice o reine lungimea irului. Pentru c
obinefolosim funcia ord astfel: ord(a [01 >. De ce aa? Atunci cnd scne-
a[OJ ne referim la un caracter. Folosind aceast expresie obinem caracterul ca
are codul dat de numr (n binar). Deci, pentru a obine codul su, utiliz~
funcia ord.

CJ n programul urmtor se afieaz lungimea unui ir citit. Tiprirea Si


(4,-X: face n cele dou moduri prezentate:

var a: string;
begin
write('a= '); readln(a);
writeln('lungime a sirului a este ' length(a))t
writeln('lungime a sirului a este ord(a[O)));
end.

Un caz aparte de ir este irul vid. Prin ir vid nelegem un ir f/!1r nici ...
caracter. Evident, irul vid are lungimea o.

Exemplu: a:= . Am iniializat variabila a, de tip string, cu irul vid.

3.2 .5. Subiruri

Definiia 3.4. Fiind dat un ir de caractere, prin subir al su se nelege


un ir de caractere consecutive care se regsesc n irul iniial.

Exemple:

irul harnic are ca subir irul mi . Acesta ncepe n poziia a treia din
irul iniial (3 caractere);

irulmama are ca subir irul ma . Observm faptul c subirul apare de


dou ori - ncepnd cu poziiile 1 i 3. Prin urmare, n cadrul unui ir, un subir
poate aprea de mai m uite ori.

irul harnic nu are ca subir irul rnit , chiar dac primele trei
caractere (mi) se regsesc n irul iniial.
'Mual de informatic pentru clasa a Xl-a 81

=Jn cii ce ac i oneaz asupra iruri lo r de caractere


.-
Exist mai multe proceduri i funcii care acioneaz asupra iruri lor de
:aractere. Acestea sunt prezent~te n continuare.

,. Funcia copy are rolul de a extrage un subir din cadrul unui ir dat:

function copy(s:string;inceput,lungime:integer):string;

variabila s (de tip string)- conine irul din care se face extragerea;
inceput - reine poziia de nceput a subi rului care se extrage;
lungime - rei ne numrul de caractere care se extrag.

f; n cazul n care prin parametrul lungime specificm mal multe caractere


dect are irul, se extrag caracterele pn la sfritul irului.

=ie programul urmtor:

var a, b: string;
i, j: byte;
begin
write('a= ') ; readln(a);
write('i= '); readln(i);
write('j= '); readln(j);
b := copy(a, i, j);
writeln(b);
end.

Dac se citete irul 'un text , 4 pentru i i 3 pentru j, variabla b va reine


su birul 1
tex 1

)- Funcia pos are rolul de a verifica dac un ir este subir pentru altul:
function pos(subsir,sir:string):byte;

Se scriu, n ordine, urmtori parametri:

subsir - subirul cutat;


sir - irul n care se face cutarea.

F uncia returneaz:

o, dac nu a fost gsit subirul cerut;


poziia de nceput a subirului, n cazul n care acesta a fost gsit.

Exemple: 1. Fie irul abcde 1 Se caut subirul 1 bcd 1 Acesta este gsit, iar
1

f uncia returneaz 2 (poziia de nceput a subirului). Dac se caut sub irul 1 cz 1 ,


f uncia returneaz o ( 1 cz 1 nu este subir al irului 1 abcde 1 ).
82 Capitolul 3 - iruri de caractere

2. Programul urmtor citete dou iruri a i b i verific dac b este subir al lui
a. n ambele cazuri se dau mesaje. Dac b nu a fost identificat ca subir al lui a,
sau, n caz contrar, se afieaz poziia de nceput a sa.
var a, b: string;
n: integer1
begin
write('a= '); readln(a);
write('b ')1 readln(b)J
n := poa(b,a);
if n O then writeln('b nu este subsir al lui a')
else writeln('b este subsir al lui a si incepe in
pozitia ,n) 1
end.

)o> Procedura insert are rolul de a insera un ir de caractere ncepnd cu o


anumit poziie, n alt ir. Pentru aceasta, ea primete ca parametri
urmtoarele:

procedura insert (sir de ins: string; var ir_unde_ins:


stringi poz: integer);
unde:

sir_de_ins - irul care urmeaz a fi inserat;


sir_unde_ ins - irul n care se face inserarea;
poz - poziia din care se face inserarea.

Exemplu:
var a, b: string;
begin
write(a '); raadln(a)t
write('b '); readln(b)t
insert(b, a, 3);
writeln(a);
and .

n programul anterior am citit dou variabile de tip string, a i b. irul reinut


de variabila b este inserat n irul reinut de variabila a ncepnd cu poziia 3 .

Exemplu: dac a reine irul 1


abcd 1 i b reine irul 1
123 1 , programul afieaz
1
ab123cd 1

)o> Procedura delete are rolul de a terge un subir din cadrul unui ir dat.
Pentru aceasta, ea are ca parametri, n ordine:
procedure delete(var sir: string; indice, nr_car: integer);

unde:

Sir - variabila care conine irul din care se face tergerea;


Indice - indicele primului caracter al sub irului care se terge;
nr_car - numrul de caractere pe care l are subirul.
..,.,ual de informatic pentru clasa a Xl-a 83

::Xemplu:
Programul urmtor citete un ir de caractere ntr-o varibil de tip string,
- -it a. irului cititi se terge subirul care ncepe n poziia 3 i are lungimea 2
::ou caractere). De exemplu, dac variabila a reine irul abcde', se afieaz
.aba'.

var a:string1
begin
write('a= ' ); readln(a)J
delete(a,3,2);
writel n(a);
end.

:J Aplicaia 3.1. n programul urmtor se listeaz indicii tuturor apariiilor


:aracterulul citit n ir:
var sir: string;
ch: string [l l ;
pozn, pozv: byte1
begin
writeln(introduceti sirul'); readln(sir)1
writeln(introduceti caracterul ')1 readln(ch)J
pozn : pos(ch, sir)1
pozv : O;
while pozn <> O do
begin
POZV := POZV+POZDI
writeln(pozv)J
sir : copy(sir, pozn+l, 255)1
pozn := pos(ch, sir);
end
end.

O Aplicaia 3.2. tergerea tuturor apariiilor unui subir din cadrul unui ir:
var sir., subsir: stringi
poz, lung: byte1
begin
writeln(introduceti sirul')l readln(sir);
writeln('introduceti subsirul '); readln(subsir)J
lung:~ length(subsir);
poz : pos(subsir, sir);
while poz <> O do
begin
delete(sir, poz, lung);
poz := pos(subsir, sir);
end;
writeln(sir)J
end.
84 Capitolul 3 - iruri de caractere

O Aplicaia 3.3. nlocuirea tuturor apariiilor unui subir cu alt subir. Analizai
programul urmtor pentru a descoperi modul n care se realizeaz aceasta:
var sir, sir_ sters, sir_adaugat: string;
poz, lungt byte;
begin
writeln( 1 introduceti sirul 1 ) ; readln(sir);
writeln( 1 introduceti sirul care se sterge);
readln(sir_sters);
writeln( 1 introduceti sirul care se adauga)/
readln(sir_ adaugat)J
lung := length(sir_sters);
poz : pos(sir_sters, sir);
while poz <> O do
begin
delete(sir,poz,lung);
insert(sir_adaugat, sir, poz);
poz t= pos(sir_ sters, sir);
end1
writeln(sir};
end.

3.2.6. Conversia de la iruri la valori numerice i invers


Fie irul 1 l.23 1 Evident, acesta este diferit de numrul123. Dup cum tim ,
irul ocup 4 octei (nu uitai, primul octet reine lungimea). Numrul 123, dac
este memorat de o variabil de tip integer, ocup doi octei i este reinut n cod
complementar. limbajul dispune de dou proceduri care realizeaz conversia de la
valori numerice la iruri i invers.
~ Procedura str are rolul de a transforma o valoare numeric n ir.

procedura Str(X [: Lg [: Zec )]1 var S:string)l

Pentru aceasta i se transmit, n ordine, doi parametri:


x-variabila (valoarea) numeric- poate fi ntreag sau real;

s - variabila de tip string care reine irul convertit.

Exemplu:
var a: string1
n: integer;
begin
write ( 1 n '); readln(n);
str(n, a);
writeln(a)
end.

n programul de mai sus se citete o valoare ntreag (n). Valoarea este


convertit ctre
tipul string - variabila a are acest tip. Rezultatul este afiat. De
exemplu, dac se citete 123 se afieaz 123. Pn aici nimic spectaculos. Dac
~ ual de informatic pentru clasa a Xl-a 85

::'1 fi afiat coninutul variabilei n, am avea acelai rezultat. Atunci la ce folosesc


::stfel de conversii? Pentru a putea da rspunsul trebuie .s mai nvm ceva
:aspre modul n care putem apela procedura str. Am fi putut s scriem apelul i
=a: str(n:4,a) ;. Observai faptul c, dup numele variabilei care se afieaz
::l.) au fost puse caracterul ':' i numrul 4 . Aceasta i'nseamn c am cerut ca
::zultatul (de tip string) s ocupe s octei - unde primul reine lungimea, deci 4
xtei pentru memorare.

S analizm acum modul de efectuare a conversiei.

=> Dac variabila n reine numrul 1.234, variabila a va reine irul


1
1234 1

=> Dac variabila n reine numrull.23, atunci a va re ine irul 1


123 1
Rezult c iru l , fr octetul de lungime, ocup 4 octei. n astfel de
cazuri, iru l este completat n stnga cu numrul de blank-uri necesar.

=> Dac variabila n reine num rul12345 atunci irul va fi '12345 Cu 1


alte cuvinte nu se respect cerina noastr, pentru c dac ar fi fost


respectat, rezultatul ar fi fost eronat.

Acum putem rspunde la ntrebarea: la ce folosesc astfel de conversii?


=>rogramatorul va avea grij ca ntotdeauna numrul d~ octei ai i rul ui s fie mai
mare sau egal cu numrul de octei ai valorii convertite. In acest fel, la afiare, vom
ti care este spaiul ocupat de ir i putem s afim rezultatele aliniate (tabele). In
continuare, ne ocu pm de conversia valorilor reale ctre iruri de caractere.
Exemplu:
var a: string;
x: real;
begin
X :;:: -67.789;
str(x: 10: 2, a);
writeln(a)
end.

n programul de mai sus se convertete numrul -67.789 ctre un ir.


Cerina este ca iru l efectiv s ocupe 1.0 caractere, dintre care ultimele do'u s fie
zecimale. Evident, dou caractere vor fi semnul - i punctul zecimal. n' exemplu,
se obine irul -67 . 79 . Ce observm?

./ ntotdeauna numrul zecimalelor solicitat de programator este respectat. n


cazul n care numrul efectiv de zecimale este mai mare dect numrul
solicitat pentru conversie, naintea conversiei n um ru l este rotunjit: Dac
numru l solicitat de zecimale ar fi fost o, s-ar fi afiat -67 (deci punctul
zecimal nu ar fi afiat) .
./ n cazul n care numrul total de cifre al prii ntregi + numrul total de
zecimale + 2 (caracterele de semn i punctul zecimal) ocup mai mult
dect numrul total de octei solicitai pentru afiare, acesta din urm nu este
86 Capitolul 3 -iruri de caractere

respectat. Cu alte cuvinte, se trunchiaz numai zecimalele nu i partea


ntreag a valorii reale. De exemplu, dac am fi scris x: 1: 2, irul obinut ar
fi fost o -67.79 o

./ n cazul Tn care numrul care se convertete este pozitiv, semnul 0


+ 0 nu
este trecut.

Acum studiem conversia invers de la tipul string ctre valori numerice


(ntregi sau reale). De exemplu, irul '123 se poate converti ctre valoarea de tip
integer: 123.

De la nceput precizm c nu ntotdeauna conversia reuete. De exemplu.


dac ncercm s convertim irul 0 1a2 o ctre o valoare de tip integer, conversia
nu reuete, pentru c irul conine caracterul 1 a 1

};> Pentru realizarea conversiei utilizm procedura val. Ea are trei parametri i
anume:
proc:edu.re val (a: atring1 var variabila...JNIIIB%'ica; var cod._er: integer) ;

unde:
a - conine irul ce urmeaz a fi convertit;

variabila_numerica - variabila de tip ntreg sau real care va


reine rezultatul conversiei (valoarea numeric).

eod_er - variabil de tip ntreg. Dup conversie, aceasta va reine o


dacconversia a reuit sau o valoare diferit de o, n caz contrar.

S analizm programul urmtor:

var as stringi
x, ers integer;
begin
write('Sirul este ')1 readln( a)l
val(a, x, er)1
if er O then writeln(' conversia a reusit , x)
el se
begin
writeln ('conversia nu a reusit')/
writeln(x)
end
end.

Programul citete un ir de caractere care este reinut n variabila de tip


atring a. Se ncearc conversia irului ctre o variabil de tip -integer. n cazU'
n care tentativa a reuit, se afieaz mesajul corespunztor i coninutul variabilei,
altfel se afieaz numai un mesaj prin care se anun faptul c tentativa a euat.
...:- ~ al de informatic pentru clasa a Xl-a 87

Observaii

Dac irul de caractere cifre este precedat de un numr de blank-uri,
conversia reuete.

Exemplu: irul 1
123 1 se poate converti ctre valoarea 123.

Dac irul de caractere cifre este urmat de un numr de blank-uri, conversia


nu reuete.

Exemplu: irul 123 nu poate fi convertit ctre o valoare numeric.

Dac irul conine un singur caracter liter, el nu poate fi convertit ctre o


valoare numeric. De exemplu, irul l2i nu poate fi convertit. Excepie
fac irurile de caractere care respect sintaxa unei constante reale n form
tiinific (de exemplu, 'l.E-3')

Dac variabila care reine rezultatul este de tip ntreg, iar irul conine punctul
zecimal, conversia nu reuete.

Exemplu: irul 1. 23 nu poate fi convertit ctre o variabil de tip ntreg,


dar poate fi convertit ctre o variabil de tip real .

..~ Dac n urma conversiei se obine o valoare numeric care nu poate fi


memorat de variabila respectiv, programul se termin anormal, prin eroare
de executare.

:J Aplicaia 3.4. Programul urmtor testeaz dac o valoare introdus este


1u meric i dac este cuprins n intervalul [ 10, 2 o]:
var sira stringi
eroarea integer1
valoarea real1
begin
writeln( introdu ceti sirul ')1
readln(s ir) 1
~al(sir, valoare, eroare)l
if eroare<>O
then
writeln( val. introdus a este eronata )
el se
if (valoare < 10) or (valoare > ~O) then
writeln( val. nu este in interval ul dorit ')
el se
writeln( okl')
end.
88 Capitolul 3 -iruri de caractere

3.2. 7. Citirea i scrierea datelor de tip String din i


n fiiere text
"l
A} Citirea datelor de tip String

Aceste variabile se citesc ncepnd din poziia curent a cursorului pn este


citit numrul de caractere necesar tipului sau pn s-a ajuns la sfritul de linie.

Programul de mai jos demonstreaz acest fapt (dac linia 1 a fiierului are 3
caractere, se vor afia dou pe un rnd i unul pe al doilea rnd). Dup citirea unei
astfel de variabile, pointerul se afl sau pe caracterul ce urmeaz dup ultimul
caracter citit sau pe CR. n situaia n care pointerul se afl pe CR i se foreaz o
nou citire de tip String, se returneaz irul vid.

var f: text;
a: string[2];
b: string;
begin
assign(f, 'fl.dat');
reset(f);
read(f, a);
writeln(a);
read(f,b);
writeln(b);
close(f);
end.

B) Scrierea datelor de tip String

n general, coninutul unei date de tip string se scrie n fiier n totalitate.


Opional, numele variabilei poate fi urmat de ' :' i de un parametru, m. Pentru
datele de acest tip, se iau n considerare lungimea efectiv a irului i valoarea
parametrului m ce specific numrul de poziii pe care se face scrierea. n cazul n
care valoarea lui m este mai mic dect lungimea efectiv a irului, aceasta se
ignor, irul va fi scris n ntregime. Dac valoarea lui m este mai mare dect
lungimea efectiv a irului, acesta este scris pe m poziii aliniat dreapta, iar n fa
se pun blank-uri.
Exemplu: se scrie irul Marian'.
var f:text;
sir:string[6] ;
begin
assign(f,'Fl.txt');
rewrite (f);
sir:= 'Marian';
write(f,sir:10);
close(f);
end .
\~anual de informatic pentru clasa a Xl-a 89

3.3. iruri de caractere n C++

3.3.1. Generaliti

Am nvat faptul c o constant de tip ir de caractere se declar intre dou~


caractere ", de exemplu: "calculator". Dar cum se reine in memoria intern?
Aceasta este reinut sub forma unui vector de caractere. Primul element, cel de
"ldice o, reine codul ASCXI al caracterului 'c', al doilea reine codul ASC:U al
caracterului 'a', ... , .a.m.d. Convenia este ca ultimul octet s rein o (codul
caracterului nul). Prin urmare, pentru a reine irul "calculator" trebuie s fie
--ezervate cel puin 11 elemente de tip char (10 litere plus caracterul nul) -adic
11 octei. Menionm c pentru fiecare caracter este reinut codul Asc:n.

1 c 1 a 1 1 1 c 1u , ........................................................................................, J
O

a[OJ a[l] a[2J a[lO]

Vectorii de caractere pot fi iniializai la declarare, caracterul nul fiind


'Tiemorat automat.

Exemple:
char vect(ll]="calculator".
char vect {] "calculator". n acest caz, compilatorul face calculul
numrului de octei necesari.
char vect [100]a"calculator". Am rezervat mai muli octei dect era
necesar.

3. 3.2. Citirea i scrierea irurilor de caractere

Se propune urmtoarea problem : s se citeasc i s se afieze cuv~ntul


calculator". Pentru aceasta, ar trebui s procedm astfel:

reinem un vector cu cel puin 11 componente de tip char - n exemplu 20;


citim cuvntul, caracter cu caracter;
il afim .
orogramul urmtor realizeaz toate acestea:
#include <iostream.h>
main()
{ char a[lOJ;
int i;
for(i~O;i<lO ii ++) cin>>a [i] ;
a[10]0;
for(i O;i<lO;i++) cout<<a[i];
}
90 Capitolul 3 -iruri de caractere

S recunoatem c o astfel de modalitate de lucru este deosebit de greoaie.


Dar dac citim un cuvnt cu patru litere? S-ar putea- scrie o secven care s
citeasc cuvntul pn la ntlnirea caracterului EN'l'ER, ns i aceast modalitate
este greoaie.

Limbajul C++ permite ca lucrul cu iruri de caractere s fie cu mult mai


simplu. Refacem programul anterior:

#include <iostream.h>
main()
{
char a[20];
cin>>a;
cout<<a;
}

J~ Observaii
./ Caracterul nul este adugat automat.

./ Procednd ca mai sus, putem citi orice cuvnt cu un numr de pn la 19


caractere - excluznd caracterul nul.
./ Putem s rezervm, n limita memoriei pe care o are la dispoziie programul ,
un numr mai mare de octei.

Exemplu: char a[1000] .

./ Un vector poate fi adresat pe componente.

Exemplu: a [O]= 1 c 1
, a [1) =a 1
, .a.m.d.

Din pcate, prin metoda de mai sus nu poate fi citit un ir care conine mai
multe cuvinte separate prin spaii. De exemplu, dac la rularea programului anterior
tastm irul" un om", se va afia "un". Aceasta nseamn c citirea se face astfel:

Se sar toate caracterele albe. n exemplu, s-au srit blank-urile.

Se citete irul care ncepe cu primul caracter care nu este alb i se


sfrete la ntlnirea primului caracter alb (n exemplu, blank).

Din acest motiv, pentru citirea irurilor de caractere vom utiliza o funcie de
un tip special, pe care o prezentm n continuare.

)> Funcia:

cin . get(vector_de_caractere, int nr, char='\n')


citete un ir de caractere pn cnd este ndeplinit una dintre condiiile de mai jos:

au fost citite nr-1 caractere;

a fost ntlnit caracterul transmis ca ultim parametru (implicit, "\n").


clasa a Xl-a 91
de informatic

Observaii

Sunt citite i caracterele albe.


!:ste inserat caracterul nul.
ir.
Caracterul transmis ca ultim parametru nu este inserat in
Al treilea parametru este trecut n mod facultativ. Dac nu este trecut, se
-=-u une c este 1 \n .

Privii urmtoarele exemple:

Se citete un ir de maximum 2 caractere:


char a[10) ;
cin.ge t(a,3);
cout<< a;
va fi afiat.
:.: exemplu, dac tastm 1 mama i Enter se citete irul "ma", care
1

sau cnd
2.. _a fel ca mai sus, dar citirea se ntrerupe la ntlnirea caracterului
1
1 g

a.. fost citite 9 caractere ale irului.


char a[10);
cin.ge t(a,10 ,'g')l
cout<<a 1

n C++ pot exista mal multe funcii cu acelai nume, dar care difer
prin
::.arametrii primii. Astfel, exist i funcia:

ain.ge t()

~r parametri. Ea are rolul de a citi un caracter (fie c este alb, fie c nu).

f Observaie. ln cazul utilizrii repetate a funciei


problem . Analizai programul
ain.ge t ()
urmtor :
cu trei
parametri, apare o
linclud e <iostre am.h>
linclud e <string .h>
main()
{ char sir1[10 00], sir2[25 ]1
cout<< sir 1 1
cin.ge t(sir1, 1000);
cin.ge t{) 1
cout<< sir 2 1
cin.ge t(sir2 ,25)1
}

Dac dup prima citire nu am fi folosit funcia cin.ge t () fr parametri, a


a fost
doua citire nu nr mai fi fost efectuat. De ce? Sfritul primului ir introdus
fcut ca in memori e (buffer ) s fie pstrat
marcat prin tastarea Enter. Aceasta a
funciei
caracterul '\n 1 La a doua citire, noul ir va ncepe cu acesta. Prin logica
92 Capitolul 3 - iruri de caractere

cu trei parametri, citirea se face pn la Tntlnirea lui. Tn concluzie, se citete irul


vid. Utilizatorul nu mai apuc s i tasteze textul. - Prin utilizarea funciei fr
parametri, acel caracter se citete i noua citire se poate efectua fr probleme.

3.3.3. Tipul char*


Vectorii de caractere au o proprietate deosebit. Privii programul urmtor:

#include <iostream.h>
main()
{
char a[]a"masa";
cout<<a+l<<" "<<a+2<<" "<<a+3;

Tn urma executrii, se tiprete: "asa sa a".

'a De ce? Limbajul C++ permite ca un vector de caractere s fie adresat


"' ncepnd de la un anumit octet al su:
~ cnd scriem a, adresm vectorul - n ansamblul lui - ncepnd cu
primul su octet (cel care reine primul caracter al irului de caractere);
echivalent, puteam scrie a+O;
~ cnd scriem a+l, adresm vectorul Tncepnd cu al doilea octet;
~ cnd scriem a+2, adresm vectorul incepnd cu al treilea octet;

Din acest motiv, programul ti prete pentru a+l irul "asa" , pentru a+2
irul "sa", .a . m . d . Mai mult, vectorii astfel adresai pot fi accesa i aa cum
suntem deja obinuii. Astfel, pentru exemplul anterior, (a+l) [OJ reine caracterul
'a' , (a+l) [1] reinecaracterul s ,etc.

Dup cum observai, a+l, a+2, ... sunt expresii. Orice expresie are un
anumit tip. Care este tipul lor? Tipul acestor expresii este char*. Ce semnificaie
are? Semnificaia este cea de adres.

Definiia 3.5. Numrul de ordine al unui octet in memoria intern se


~
::J:_) numete adresa octetului respectiv.

Definiia 3.6. Adresa unui vector de caractere este adresa primului


su octet.

! O variabil de tipul char* poate reine adresa unui vector de caractere.

! n C++, numele unui vector de caractere este o adres constant de vector


i poate fi atribuit unei variabile de tip char*.
~ _aJ de informatic pentru clasa a Xl- a 93

~: Considerm urmtorul exemplu:

#include <iostream.h>
main()
( char a[]"Exemplu", *p;
paa; cout<<p<<endl;
p++; cout<<p<<endl;
p++l cout<<p<<endl;
cout<<p[ll<<endl;
cout<<p-a;
}

Am declarat un vector de caractere numit a, pe care l-am iniializat cu un ir.


:-:asemenea, am declarat i o variabil de tip char* numit p . Tn aceste condiii,
:_em afirma c:
pa; este o atribuire corect . Variabila p va reine adresa vectorului de
caractere a, adic adresa primului su octet. ln schimb, atribuirea a=p este
incorect, pentru c a este o constant ce reprezint o adres .

dupatribuire, putem utiliza variabila p in aceleai condiii ca variabila v. De


exemplu, putem afia irul reinut prin "coutpendl; " .
dac la coninutul variabilei p se adaug 1 , aceasta va reine adresa
vectorului al crui prim octet coincide cu al doilea octet al vectorului v. De
exemplu , dac tipresc vectorul se va afia "xemplu". Noul vector se poate
adresa i pe octei. Exemplu: p[ll.
se pot face i scderi ntre adrese. ln acest caz, rezultatul este ntreg. De
exer:nplu, prin p-a se obine indicele n v, al primului octet al vectorului
reinut dep. Testai programul!

3.3 .4. Lungimea unui ir de caractere

Pentru a putea fi folosite funciile de prelucrare a irurilor de caractere,


trebuie s fie inclus fiierul antet "string.h", tot aa cum includem fiierul
"iostream.h":
#include <iostream.h>

~ Funcia strlen are rolul de a returna lungimea efectiv a unui ir (n calculul


lungimii nu intr caracterul nul). Forma general este:
size_ t strlen(char*);
unde:
size_ t este un tip ntreg, utilizat n adresarea memoriei, definit n "string.h"
(l putem privi ca pe tipul unsigned int);
argumentul este de tip char* (adic o adres ctre un ir).
94 Capitolul 3- iruri de caractere

Programul de mai jos citete un ir i afieaz numrul de caractere pe care


le are irul
citit (exclusiv caracterul nul):

#include <iostream.h>
#include <string.h>
main()
{ char a[lOOJ;
cin . get(a,lOO) ;
cout<<"Sirul citit are "<<strlen (a)<<" caractere";
}

Aa cum tim din lucrul cu tablouri, atribuirile de forma ab, unde a i b sunt
vectori de caractere, nu sunt permise. Tot aa, o atribuire de forma a:::"un sir"
nu este permis. Astfel de operaii ca i multe altele se fac cu anumite funcii, puse
la dispoziie de limbaj. Pentru ca acestea s poat fi folosite, trebuie s fie inclus
fiierul antet "string. h", tot aa cum includem fiierul "iostream. h". Ordinea
de includere nu are importan. fn continuare, vom prezenta cele mai uzuale funcii
i modul fn care acestea se folosesc.

3.3 .5. Copierea i concatenarea irurilor de caractere

);> Funcia strcpy are forma general:

char *strcpy(char* dest, char* sursa);

iare rolul de a copia irul de adres sursa la adresa dest. Copierea se termin
dup ce a fost copiat caracterul nul. Se returneaz adresa dest. Analizai
codul urmtor:
#include <iostream.h>
#include <string . h>
main()
{ char a[lOO]="un sir", b[lOO]"alt sir"t
strcpy (a,b);
cout<<at
}

Tn programul de mai sus se copiaz n vectorul de caractere a irul de


caractere reinut de b. Programul va afia "alt sir". Aceast copiere simuleaz
atribuirea: a=b.

);> Funcia standard strcat are forma general:

char~ strcat(char* dest, char* sursa);

i rolul de a aduga irului de adres dest irul de adres sursa. irul de adres
sursa rmne nemodificat. Aceast operaie se numete concatenare i nu este
comutativ. Rezultatul este adresa irului sursa, iar irul va avea ca lungime,
suma lungimilor celor dou iruri care au fost concatenate.
.,... Jal de informatic pentru clasa a Xl-a 95

Programul urmtor tiprete "mama merge":


#include <iostream. h>
#include <string.h>
main()
{
char a[20) mama", b(100]=" marge";
strcat (a,b);
cout<<a;
}

, Funcia strncat are forma general:

char *strncat(char *dest , const char *sursa, size_t nr);

r ace)al
ro) ca strcat cu deosebirea c adaug lru)u'l destma'le prlm'll nr octei al
s rului surs. Adugarea caracterelor se face Tnaintea caracterului nul. Funcia
-etu rneaz adresa de nceput a irului destinaie.

3. 3.6. Cutarea unui caracter ntr-un ir

;. Funcia strchr are forma general:

char* strchr(char *s, int c);

i rolul de a cuta caracterul c in irul s. Cutarea se face de la stnga la


dreapta. ln cazul in care caracterul este gsit, funcia ntoarce adresa subirului
care ncepe cu prima apariie a caracterului citit i se termin cu caracterul nul al
irului n care se face cutarea. Altfel, ntoarce o expresie de tip char* cu valoarea
o (adic o adres vid de ir) . Exemplele care urmeaz ne vor lmuri.

ln programul urmtor se caut in irul a caracterul t 1 Acesta este gsit, iar


programul tiprete irul "ta este". Evident, acesta este subirul care incepe cu
caracterul t . 1

#include <iostream.h>
#include <string . h>
main()
{
char a[20]"Acesta este"1
cout<<strchr (a,'t 1 )1
}

D Aplicaia 3.5. in unele cazuri ne intereseaz indicele n cadrul vectorului al


caracterului cutat. Acesta se obine ca diferen ntre dou valori de tipul char* .
Desczutul este adresa returnat de funcie, iar scztorul este adresa vectorului n
care se face cutarea.
96 Capitolul 3 -iruri de caractere

Programul de mai jos tiprete indicele primei apariii a caracterului 't', i anume 4:
#include <iostream.h>
#include <string.h>
main()
{
char a[201="Acesta este";
cout<<strchr (a, t)-a;;
}

O Aplic.aia 3.6. n programul urmtor se citete un ir i un caracter. Dac


acesta este gsit n i r, se tiprete indicele primei apariii a caracterului n irul
solicitat, altfel programul semnaleaz faptul c acest caracter nu exist n ir.
#include <string.h>
main()
{
char a[100], *t,c;
cout<< "introduceti sirul "; cin.get(a,100);
cout<< "caracterul cutat "; cin>>c;
t=strchr(a,c);
if (t) cout<<"Indicele este "<<t-a;
else cout<< " sirul nu contine acest caracter ";
}

,Jw Observaii
../ Variabila t este de tipul char* .

../ Testul de apartenen a caracterului la ir s-a fcut prin a vedea dac


variabila t reine sau nu o (adic o adres nul de ir).

O Aplicaia 3.7. In programul urmtor se listeaz indicii tuturor apariiilor


caracterului citit n ir:

#include <iostream.h>
#include <string.h>
main()
{
char a[lOO], *t,c;
cout<< "introduceti sirul "; cin.get(a, lOO);
cout<< "caracterul cutat "; cin>>c;
t=a-1;
do
(
t++;
t=strchr(t,c); .
if (t) cout<<"Indicele este "<<t-a<<endl;
} while (t);
}

Fiecare adres de subir, care are ca prim caracter cel reinut de c, intr n
calculul indicelui acelui caracter - din ea se scade adresa de nceput.
97

=_'1Cia strrchr are forma general:


char *strrchr(const char *s, int' c);

::ela i rol cu strchr, deosebirea fiind c ntoarce adresa ultimei apariii a


::J~'"""=C~erului (cutarea se face de la dreapta ctre stnga). Ea este uti l izat n
~ .=za n care se caut ultima apariie a caracterului Tn cadrul iru l u i.

- 3. 7. Compararea irurilor

.... =uncia strcmp are forma general:

int strcmp(const char *sl, const char*s2);

-o ul de a compara dou iruri de caractere Valoarea returnat este:

<0, dac sl<s2;

=O, dac sl=s2;

>0, dac sl>s2.

? Dar care este mecanismul prin care se compar dou iruri de caractere?

Fie m numrul de caractere al irului sl i n numrul de caractere al irului s2.
5 presupunem c primele i caractere ale lui sl coincid cu primele i ale lui s2.

:J n cazul n care codul caracterului i+l al iru l ui sl este mai mare dect codul
caracterului corespunztor irului s2, avem sl>s2.

:l n cazul' n care codul caracterului i+l al irului sl este mai mic dect codul
caracterului corespunztor irului s2, avem sl<s2. ln cazul in care i la
aceast comparaie avem egalitate, avem patru posibiliti:

ambele iruri au un numr strict mai mare de caractere dect i+l, caz n
care se compar ca nainte caracterele de pe poziia i+2;

. sl are i+l caractere, iar s2 are un numr de caractere mai mare dect
i+l, n acest caz sl<s2;

s2 are i+l caractere, iar sl are un numr de caractere mai mare decat
i+l, n acest caz sl>s2;

att sl ct i s2 au i+l caractere, caz n care sl=s2.

Pe scurt, un ir sl este mai mic ca altul s2, dac Tn dicionar sl ar figura


naintea lui s2.

Exemple: "soare">s;
"tata">mama;
98 Capitolul 3 -iruri de caractere

Probai relaiade ordine dintre dou cuvinte (iruri care nu conin


caractere albe) prin utilizarea programului urmtor:
#include <iostream.h>
#include <string.h>
main()
(
char a[100],b[100];
int semnal;
cout<< introduceti sirul a "; cin>>a;
cout<< "introduceti sirul b "; cin>>b;
semnal=strcmp(a,b);
if (semnal<O) cout<<"a<b";
el se
if (semnal>O) cout<<"a>b";
else cout<<"a b";
}

(;, Funcia strcmp face distincie ntre literele mari i miel ale a/fabetului.

> Funcia stricmp are forma general:


int stricmp(char *s1,char *s2);

i acelai rol ca strcmp. Diferena este c nu face distincie ntre literele mari i
miel.
Vectori de cuvinte. Exist aplicaii in care este necesar s se lucreze cu n
cuvinte - fnelegnd prin cuvnt o succesiune de caractere care nu sunt albe. n
acest caz avem posibilitatea s declarm vectori de cuvinte. Acestea sunt, de fapt,
matrice cu elemente de baz de tip char.

Exemplu: char a [10] [25] 1

Fiecare linie din cele 10 ale matricei poate reine un ir de caractere. Acesta poate
avea cel mult 25 de caractere (inclusiv caracterul nul). Cuvintele pot fi adresate prin
a [O] (primul cuvnt), a [1) cuvntul al doilea, . a . m . d.

D Aplicaia 3.8. Tn programul urmtor se citesc n cuvinte. Acestea sunt sortate


alfabetic:
#include <iostream.h>
#include <string.h>
main()
(
char cuvinte[lO] [25] , man[25];
int i,n,gasit ;
cout<<"n=";
cin>>n;
for (i=O;i<n;i++)
( cout<<"cuvant ";
cin>>cuvinte[i];
}
-<:.. de informatic pentru clasa a Xl-a 99

do
{ gasit=O;
f or (i=O;i<n-l;i++)
if {strcmp(cuvinte[ i],cuvinte[i+l])>O )
{ strcpy(man,cuvin te[i]);
strcpy(cuvinte[i ],cuvinte(i+l]);
strcpy(cuvinte[i+ l],man);
gasit=l;
}
}
while (gasit);
for (i=O;i<n;i++) cout<<cuvinte[i ] <<endl;

Dac pot compara dou cuvinte, atunci pot s le sortez. Am folosit sortarea
nterschimbare. lat c, algoritmii, cu precdere cei fundamentali, pot fi folosii
"'tr-un context diferit de cel n care au fost prezentai.

3.8. Subiruri

" Funcia strstr are forma general :

char *etrstr(const char *el, conet char *s2)1

are rolul de a identifica dac irul s2 este subi r (caractere succesive) al i ru lu i


Jl Dac acesta este identificat, funcia returneaz adresa de inceput in cadrul
: rului sl, altfel returneaz adresa nul {O). Cutarea se face de la stnga la
:eapta. n cazul n care s2 apare de mal multe ori n cadrul lui el, se returneaz
:dresa de nceput a primei apariii.

Exemplu: fie char sl[l="xyzt", s2[]="yz", atunci strstr(el,s2)1


~eturneaz sl+l (adresa caracterului y n sl).

:J Aplicaia 3.9. Tn programul urmtor se citesc dou iruri de caractere i se


esteaz dac al doilea este subir al primului. In caz afirmativ, programul afieaz
11dicele caracterului de inceput al subirului.

#include <iostream.h>
#incl ude <string.h>
m.ain()
{
char sir(l000],subsir[ 25], *t;
cout<<"introduce ti textul ";
cin.get(sir,lOOO );
cin.get();
cout<<"introduce ti subsirul cautat ";
cin.get(subsir,2 5);
t=strstr(sir,sub sir);
if (t) cout<<"este subsir si are indicele "<<t-sir;
else cout<<"nu este subsir";
}
100 Capitolul 3- iruri de caracterE

O Aplicaia 3.10. tergerea tuturor apariiilor unui subir din cadrul unui ir
Imediat ce am identificat adresa de inceput a subiruloi, restul irului (fr subir)
este copiat pe poziia de inceput a subirului.
#include <iostream.h>
.# include <string . h>
main()
{ char sir[1000],subsir[ 25],*p;
int lung_subsir;
cout<<"introduce ti textul ";
cin.get(sir,1000 );
cin.get();
cout<<"introduce ti subsirul ";
cin.aetlBUbB~r,~~)i
lung_ subsir=strlen(su bsir);
pstrstr(sir,sub sir);
while (p)
{ strcpy(p,p+lung_ subsir);
p strstr(p,subsir) ;
)
cout<<sir;
)

O Aplicaia 3.11. fnlocuirea tuturor apariiilor unui subir cu alt subir. V las pe
dvs. s descoperii modul in care programul urmtor realizeaz aceasta:
#include <iostream.h>
#include <string.h>
main()
( char sir[100], man[100], sterg[25], ada ug[25], *p;
int lung_ sterg, lung_ adaug;
cout<<"introduce ti textul ";
cin.get(sir,lOO) ;
cin.get();
cout<<"inlocuim subsirul ";
cin.get(sterg,25 );
cin . get();
cout<<"cu subsirul "1
cin.get(ad&ug,25 );
lung_ sterg strlen(sterg);
lung_ adaugstrlen(ada ug);
pstrstr(sir,ste rg);
while (p)
(
man[O] O;//subsir vid;
strncat(man,sir, p-sir);
strcat(man,adaug );
strcat(man,p+lun g_ sterg);
atrcpy(sir,man);
pstrstr(p+lung_ adaug,sterg);
)
cout<<sir;
. )
a.~ual de Informatic pentru clasa a Xl-a 101

- = ~ l te funcii utile n prelucrarea irurilor


_-,::,a strtok are forma general:
char *strtok(char *sl,.const char *s2)1

-c: ul de executare este urmtorul:


1rulsl este considerat ca fiind alctuit din o, 1 , .. ., n entiti separate prin
unul sau mai multe caractere cu rol de separator, iar irul s2 ca fiind alctuit
din unul sau mai multe caractere cu rol de separator;

Exemplu: irul sl. este " mama, tata si bunicul". irul s2 este:
" , ". ntruct caracterele separatoare sunt blank-ul i virgula, rezult c
entitile sunt: ":mama", "tata" "si" "bunicul".

la prima apelare care trebuie s fie de forma strtok ( sl, s2) 1, funcia
intoarce adresa primului caracter al primei entiti (n exemplu "mama"). in
plus, dup prima entitate separatorul este nlocuit automat prin caracterul
nul (cod O);

urmtoarele apeluri ale funciei sunt de forma strtok (NULL, s2);, iar
funcia intoarce de fiecare dat adresa primului caracter al urmtoarei entiti
i , dup ea, este adugat caracterul nul - aceasta permite ca entitatea s
poat fi extras cu uurin.

n momentul n care i rul rmas nu mai conine entiti , funcia Tntoarce


adresa nul .

:J Aplicaia 3.12. In programul urmtor se citete un ir de caractere. Entitile se


:onsider a fi cuvinte - iruri de caractere care nu sunt albe - separate prin blank-uri
.lsau virgule. Programullisteaz entitile depistate, fiecare pe un rand.
#incl.ude <iostream.h>
#include <string.h>
main()
{ char sir[lOOOJ,separator[]=" ,
" 1 *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout< <p< <endl;
p =strtok(NULL, separator);
}
}

Variabila p rei ne adresa de nceput a entitii. Dac entitatea este gsit, p


va o valoare d ife rit de o, caz n care entitatea este afiat i se va cuta
reine
u rmtoarea entitate.
102 Capitolul 3- iruri de caractere

LI Aplicatia 3.13. Programul urmtor citete un ir de caractere i tiprete irul


obinut pri~ eliminarea blank-urilor. n fapt, se separ entitile, care sunt afiate
una dup alta.
#include <iostream.h>
#include <string.h>
main()
{ char sir [1000] , separator[]=" , 11 , '*p;
cin.get(sir,lOOO) ;
p=strtok(sir,separator);
while (p)
< cout<<p;
p=strtok(NULL, separator); }

)> Funcia strcspn are forma general:


size_t strcspn(const char *sl, const char *s2);
iare rolul de a returna numrul de caractere al irului sl - caractere consecutive
care ncep obligatoriu cu primul caracter- care nu se gsesc in irul s2.

)> Funcia standard strspn are forma general:

size_t strspn(char *al, char *s2);


i are rolul de a returna numrul de caractere al irului al - caractere consecutive
care ncep obligatoriu cu primul caracter- care se gsesc in irul s2.
Exemple
1. Fie char* sl="AB2def"; *s2="123";. Atunci: strcspn(sl , s2)
returneaz 2 (pentru c primele dou caractere A' i 'B ' din sl nu se gsesc in
s2 ), iar strspn ( sl, s2) returneaz o (primUl caracter din sl nu se gsete in s2 ).
2. Fie char* sl="AB2def"; *s2="16A32BF";. Atunci: strospn(sl,s2)
returneazo (pentru c primul caracter A' din al se gsete in s2), iar
atrspn (al, a2) returneaz 3 (caracterele A , 'B', '2' din sl se gsesc in sa).

LI Aplicaia 3.14. Se citete un ir de caractere care nu conine caractere albe.


S se verifice dac irul este alctuit exclusiv din caractere numerice.
Vom reine un vector numit cifre. Componentele lui rein toate caracterele
numerice 0-9. irul de caractere citit are toate caracterele numerice dac toate
caracterele sale - numrul lor este dat de strlen - se regsesc printre
caracterele vectorului cifre.
#include <iostream.h>
#include <string.h>
main()
{ char c::uvant[lOO], cifre[]="0123456789";
cout<<"Introduceti cuvantul "; c::in>>cuvant;
if (strspn(c::uvant,cifre)==strlen(cuvant)) cout<<"numeric";
else cout<<"nenumeric";
}
clasa a Xl-a 103

c;ra 3.15. Se citete un de caractere care nu conine caractere albe.


ir
,.."...~ ::iac irul e alctuit exclusiv din caractere nenumerlce .
:r- ::ne un vector numit cifre. Componentele lui rein toate caracterele
lm!ll!:!U::E: :-9. Cuvntul citit are toate caracterele nenumerice dac toate
.ectorului cifre - numrul lor este 10 - nu se regsesc printre

k~ude <iostream. h>


t~:ude <string.h>
-.::..= \)
:.:.ar cuvant[lOO ], cifre[]="O l23456789 ";
cout<<"Int roduceti cuvantul "; cin>>cuvan t;
1f (strcspn(ci fre,cuvant )==lO) cout<<"co rect ";
else cout<<"inc orect";

=.'"cia strlwr are forma general:


char *strlwr(c har *s);

.:::---. ertete toate literele mari ( 1 A 1 z ) n litere mici ( 1 a



1
,
1
z ).
s:_ ~racterelor rmn neschimbate. Funcia ntoarce adresa s .

=-~cia strupr are forma general :


char *strupr(c har *s);

-: _, de a converti toate lterele mici ( 1 a 1


1
z 1 ) n litere mari ( 1 A z 1 ).
rs-- caracterelor rmn neschimbate. Funcia intoarce adresa s. n programul
-a:or se citete un cuvnt. Cuvntul citit se tiprete cu litere mari.
#include <iostream. h>
#include <string.h>
main()
{ char a[20];
cout<<" J:ntroduce ti cuvantul "; cin>>a;
oout<<stru pr(a);
}

Funcia atrpbrk are forma general :

char *atrpbrk( char *sl, char *s2);

s acioneaz n felul urmtor:

Caut primul caracter al irului al n s2. Dac este gsit, returneaza adresa
sa din cadrul iru lui sl i execuia se termin, altfel trece la pasul urmtor.
Caut al doilea caracter al irului sl n s2. Dac este gsit, returneaz adresa
sa din cadrul irului sl i execuia se termin, altfel trece la pasul urmtor.

dac nici un caracter al irului al m:. aparine irului s2, funcia returneaz
adresa nul.
104 Capitolul 3 - iruri de caractef"!

Exemplu: fie char *sl="abcdefghi jklmnopqrstuvwxyz", *s2 "<::12" ;


Atunci strpbrk(sl, s2) returneaz adresa sl+2 (adresa caracterului c, pentr.
c acesta este primul caracter din sl gsit in s2).

CJ Aplicaia 3.16. Se citesc dou cuvinte. Se cere s se afieze toate caracterele


primului cuvant care se regsesc in al doilea.
#include <iostream.h>
#include <string.h>
main()
{<::har cuvant1[10], cuvant2[10],*p;
cout<<"Xntroduceti primul cuvant ; cin>>cuvantl;
cout<<"Xntroduceti al doilea cuvant ; cin>>cuvant2;
pastrpbrk(cuvantl,cuvant 2);
while(p)
{ cout<<p[O]<<endl;
p++;
p=strpbrk(p,cuvant2);
}
}

Caracterele primului cuvant, Tncepand de la primul, sunt cutate in al doilea


cuvant. Orice caracter gsit se tiprete. Aceasta se face pornind de la adresa
irului, returnat de strpbrk. Apoi, variabila care conine aceast adres se
incrementeaz. Aceasta pentru ca, la urmtoarea cutare, s nu fie returnat
aceeai adres de ir.

3.3.1 O. Conversia irurilor n valori numerice i invers

Urmtoarele au prototipul Tn "stdlib. h"


funcii i folosesc pentru
conversia valorilor numerice Tn ir i invers.
~ Funcia atof un ir ctre tipul double. Dac conversia eueaz
convertete
(se intalnete un caracter nenumeric) valoarea Tntoars este O. Dac primele
caractere ale irului sunt albe, acestea sunt ignorate.
double atof(const char *s);

Observaiile sunt valabile i pentru urmtoarele 3 funcii:


~ Funcia _atold convertete un ir ctre tipullong double:
long double _atold(const char *s);

~ Funcia atoi convertete un ir ctre tipul int:


int atoi(const char *s);

~ Funcia a tol convertete un ir ctre tipullong:


long atol(const char *s);
tru clasa a Xl-a 1os

Se citete un text alctuit din mai multe cuvinte. Se cere s se


:J.;J:::C:..:oorilor numerice ntlnite in text. Se presupune c valorile
u;.;~... r:-oouse corect.

E ~r n entiti. Dac o entitate este alctuit exclusiv din + ,


~. atunci ea este convertit n double i adunat la o variabil s,

~~ <iostream.h>
~:de <string.h>
~~e <stdlib.h>
IIIC..:::.
:.:.ar sir[lOOO],separator[]=" ",cifre[]="0123456789.+-", *p;
!.cx!b~ e s=O;
~ .get(sir,lOOO);
~st rtok(sir,separator);
~le (p)
i f (strspn(p,cifre)==strlen(p)) s+=atof(p);
p=strtok(NOLL, separator);

oout<<"suma numerelor intalnite in sir este "<<s ;

:::_... :":'<3 ecvt are rolul de a converti o valoare de tip double ctre un ir.
:..~e rul nul este adugat automat irului obinut. Forma general este:
~ ecvt(double valoare, int poz, int* zec, int* semn);

valoare - valoarea de convertit;


poz - numrul de poziii pe care trebuie s le ocupe irul obinut n urma
con versiei;
zec -adresa unei variabile, de tip int, care reine, dup apel, numrul
zecimalelor pe care le are numrul;
semn - adresa unei variabile, de tip int, care are rolul de a memora,
dup apel, 1, dac numrul este negativ, sau o, n caz contrar.

Pn n prezent nu am studiat modul in care putem obine adresa unei


ahile. Reinei c dac a este o variabil, &:a este adresa ei. Funcia utilizeaz
.-:est mecanism de transmitere a parametrilor pentru ca s poat returna anumite
"F_:::ultate pe care le gsim n variabilele respective. in cazul ei, variabila zec va
~,.,e dup apel numrul intregilor, iar variabila semn semnul rezultatului.

Funcia nu insereaz n ir nici punctul zecimal, nici semnul numrului. irul


:oi nut
ncepe cu cifra cea mai semnificativ a numrului. Pentru ca irul obinut s
re corect, este necesar s fie prelucrat, fn continuare, de ctre programator. Dac
- Jmru l poziiilor ocupate de ir (poz) este mai mare dect ocup data, irul este
completat n stnga cu un numr de o necesar. in cazul n care numrul poziiilor
~ste mai mic dect cel ocupat de numr, rezultatul este rotunjit.

Exemple: ecvt (val, 3, &:zec, &:semn) ;


106 Capitolul 3 - iruri de caractere

dac val reine 1234, atunci se returneaz irul "123", zec reine 4 i
semn reine o.
dac val reine 1239, atunci se returneaz irul "124", zec reine 4 i
semn reine o.

dac val reine 1, atunci se returneaz irul "100" , zec reine 1 i semn
reine o.
dac val reine -0.001, atunci se returneaz irul "100", zec reine -3
i semn reine 1.

Pentru a v convinge, rulai programul urmtor:


#include <iostream.h>
#include <stdlib.h>
#include <string.h>
main()
{ double numar;
int zec,semn;
char numar_sir[20]="", numar_prel[20]="";
cout<<"n="; cin>>numar;
//convertesc numarul si tiparesc rezultatul
11 asa cum este furnizat de functie
strcpy(numar_sir,ecvt(numar,19,&zec , &semn)) ;
cout<<"Sirul este "<<numar_ sir<<" "<<zec<< " "<<semn<<endl;
11 prelucrez sirul pentru a tipari rezultatul asa cum
11 este asteptat de utilizator.
if (semn) strcat(numar_prel,"-");
strncat(numar_prel,numar_ sir,zec);
strcat(numar_prel,".");
strncat(numar_prel,numar_ sir+zec,3);
cout<<numar_prel;
}

)> Funcia itoa are rolul de a converti o valoare de tip int ntr-un ir, a crui
adres este memorat in variabila sir. Valoarea baza reine baza de numeraie
ctre care s se fac conversia (de obicei baza este 10). fn cazul bazei 10, irul
obinut reine i, eventual, semnul"-". Funcia ntoarce adresa irului obinut.

char* itoa(int valoare, char *sir, int baza);

)> Funcia 1 toa are acelai efect ca i toa, deosebirea fiind dat de faptul c se
convertete ctre ir o valoare de tip long int.

char* ltoa(long value , char *sir., int baza);

)> Funcia ultoa are acelai efect ca itoa, deosebirea fiind dat de faptul c
se convertete ctre ir o valoare de tip unsigned long.

char* ultoa(unsigned long value, char *sir, int baza);

Pentru conversii, se mai pot utiliza urmtoarele funcii:


vanual de informatic pentru clasa a Xl-a
107

Funcia

long strto l(co nst char *s, char **en


dptr, int baza );
::.re rolul de a converti un ir ctre long . Tn afara
irului care trebuie convertit,
:.J'lcia primete ca parametru de intrare adresa unei variabile de
tip char *. Dup
::pel, aceast vari abil va reine poziia primului
caracter din ir care nu poate fi
:oovertit. De exemplu, dac irul este "12m 21 ",
dup apel, variabila a crei adres
; fost transmis ca parametru reine adresa carac
terului 1 m 1 Dar care este rostul
:xistenei acestei informaii? Cu ajuto
rul ei se pot depista eventualele erori aprute
~tunel cnd se introduc datele. Privii
irul dat anterior ca exemplu: e clar
~"'Lllizatorul a dorit s introduc un numr c
, dar in locul unei cifre a tastat m
1 1

:J Aplicaia 3.18. Programul urmtor testeaz dac o


valoare introdus este
- u meric i dac este cuprins n intervalul [10, 20]. Testul propr
a:unci cand comparm numrul caracterelor iu-zis se face
convertite cu lungimea irului.
::galitatea are semnificaia c intreg irul este nume
ric. Variabila radi x trebuie s
:onin s , 10 sau 16, adic baza in care
este considerat nu mru l sub form de ir.
#inc lude <iost ream .h>
#inc lude <std lib . h>
#inc lude <stri ng.h >
main (void )
{ char numa r[20] , *adr esa;
long v;
cin> >num ar 1
v=st rtol( num ar,& adre sa,lO );
if(ad resa- num arls trlen (num ar))
cout< <"Da ta cont ine cara ctere nenu meri
ce";
el se
if (v<lO 11 v>20 ) cout "da ta nume rica
in afar a limi tei ";
else cout <<v< <end l;
}

, Funcia

doub le strto d(co nst char *s, char


**en dptr )l
:onvertete un ir ctre doub le.

, Funcia

long doub le _ strto ld(c onst char *(s)


, char **en dptr );
~nvertete un ir ctre long doub le.
:;. Funcia

unsi gned long strto ul(c onst char *s,c


har **en dptr ,int baza )1
convertete un ir ctre unsi gned long
.
Jn caz de depire - adic numrul nu poate fi
memorat deoarece este n
afara tipului - ultimele patru funcii returneaz
cea mai mare sau cea mai mic
1aloare care poate fi memorat de tipul n
care se face conversia, dup
cum valoarea este pozitiv sau negativ .
108 Capitolul 3 - iruri de caractere

3 .3.11. Citirea i scrierea irurilor de c;.aractere din i n


fiiere text

3.3.11.1. Operaia de citire

Pentru a citi o linie a unui fiier text, se poate folosi funcia urmtoare:

getline(char* Adresa_sir, int Nr_car, char='\n').

Funcia citete un ir de caractere, pn cnd una dintre condiiile urmtoare


este ndeplinit:

a) au fost citite Nr_car-1 caractere;


b) a fost detectat sfritul de linie: \n'.

Evident, n acest fel, la o citire pot fi aduse n memorie cel mult 32766
caractere (vezi limitele tipului int).

l~ Observaii

../ Caracterul care marcheaz sfritul liniei ' \n' nu este inserat n ir, n
schimb este inserat caracterul nul (march eaz sfritul iru lui) .
../ Este suficient s apelm funcia cu primii doi parametri, ultimul fiind implicit.
../ Dac se dorete, ultimul parametru poate fi apelat explicit cu o valoare
convenabil, caz Tn care citirea se face pn la intlnirea ei sau pn cnd
au fost citite Nr_car-1 caractere.

..11. Programulurmtor citete linie cu linie un fiier text ale crui linii nu au
~. mai mult de soo de caractere i afieaz liniile pe monitor. Nu se
cunoate lungimea fiecrei linii.
#include <fstream.h>
main()
{ fstream f("f.dat",iosz:in );
char Linie_citita[501 );
while (f.getline(Linie_ ci tita,501))
cout<<Linie_citit a<<endl;
}

Observaie foarte
(;. efectueaz
important! Prin fLinie_citito. , citirea se
astfel:
a) ncepnd cu poziia curent a pointerului se sar toate caracterele albe;
b) se citesc toate caracterele pn la ntlnirea unui caracter alb.
De exemplu, dac o linie a fiierului conine irul " Afara ploua", se
citete irul"Afara". Testa.i!
iX~ ~al de informatic pentru clasa a Xl-a 1os

3.3.11.2 . Operaia de scriere

Scrierea se face prin comanda f sir;. Prin aceast instruciune se


:-e intreg irul, ncepnd cu poziia curent a pointerului, inclusiv caracterele albe.
~ -a.;zai exemplul urmtor:

#include <fstream.h>
main()
{ fstream f("f.dat",ios::out);
f<<" Afara este"<<endl;
f<<"primavaral";
f . close() 1
}

~ 3. 12. O modalitate de conversie de la ir la alt tip

Exist ialte posibiliti de conversie de iruri la alte tipuri de date. Un tip


:::-ecial, numit istrstream, permite chiar declararea stream~urilor (fluxurilor) de
::i ruri ctre variabile. "Citirea" se efectueaz cu ajutorul operatorului "" la fel ca
:. - fiier.

Un ir x
reine "1 2 3 4 5". O funcie special ( numit constructor)
.i:aeaz irului x , un stream (flux), numit ins. Ea are doi parametri: irul x i
.-gimea lui: istrstream ins (X, strlen (X)) 1.

"Citirea" se efectueaz cu conversie ctre tipul respectiv. Programul va afia


- ...merele 1,2,3,4,5 cte unul pe liniei
#include <iostream.h>
#include <strstrea.h>
#include <string.h>
main()
( ohar X[1"1 2 3 4 5"1
istrstream ins(X, strlen(X));
int nr1
while (ins>>nr) oout<<nr<<endll
}

f. Observai ct de simplu se detecteaz sfritul irului.



Tot aa, se pot "citi" mai multe cuvinte dintr-un ir. Programul urmtor citete
cuvintele i le afieaz. De aceast dat se consider c este ir valid i cel de
ungime o, fapt care conduce la o nou citire i deci la ciclare. Pentru aceasta,
de fiecare dat, se testeaz ca lungimea irului citit s fie nevid.
11 o Capitolul 3 -iruri de caractere

Programul este prezentat n continuare:

#include <iostream.h>
#include <strstrea.h>
#include <string.h>
main()
{
char X[)="l mama tata 4 bunica";
char cuvant [20);
istrstream ins{X, strlen{X));
while (ins>>cuvant && strlen(cuvant))
cout<<cuvant<<en dl;
}

Probleme propuse
1. Se de la tastatur un text. Cuvintele se
citete consider separate prin virgul
spaiu sau punct. eate cuvinte are textul citit?

2. Se citete de la tastatur un text i o succesiune de caractere. De cte on


ntalnim aceast succesiune in cadrul textului?

3. Se citete un text. Dou cuvinte pot fi separate printr-unul sau mai multe spai i
Se cere s se elimine spaiile inutile.
4. Se un fiier text care conine o singur propoziie, pe o linie. Programul
citete
rea ranjeaz literele n fiecare propoziie, in ordine alfabetic, pstrand locul
cuvintelor. Numai literele de la 'A' la 'Z' sunt afectate. Celelalte caractere rmn
neschimbate. Ieirea va fi tot un fiier text. Numele fiierelor este ales de dvs.

Exemple:

THE PRrCE OF BREAD rs $1.25 PER POUND.


ABC DDEEE EF HrrXNO OP $1.25 PPR RRSTU.
THE LrCENSE PLATE READ G76-ZA3.
AAA CDEEEEE GHrLL NPRS T76- TZ3 .
Junior Divlslon

5. Cretere automat. Scriei un program care s mreasc toate numerele care


apar ntr-un document (citit dintr-un fiier text) dup un procent citit de la tastatur.
De exemplu, dac se introduce 12, procentul este: 12%. Toate numerele trebuie
afiate cu dou zecimale. Testai programul dvs. pe fraza:

"Batranul Mc Donald's avea 7 vaci care dadeau 120 de litri de


lapte pe zi. Ele veneau acasa la 4 P.M"

Junior Divislon
1
::.,ual de informatic pentru clasa a Xl- a

ea micorat a cuv
ntului "MISSISSIPPI",
ve rsi un
:.. Eli mi na re. "MSSSS
PP " es te micorat i ea :
uro r lite rel or "1". O fraz poate fi
:~n ut prin elimi
na rea tut RSR C FAT", prin
RA TE " are ve rsiunea micorat ''TRV
~AVERSAREA CA
II FE ne literele dintr-o
"E" . Se ce re ca programul dvs. s elimi se
= 11inarea literelor "A ", "1", linie. Literele care
t np ut . tx t" i scris pe o singur
ul "i
-az citit din fiier
tex t .tx t" .
este n fiierul "o ut pu
:m in se citesc de
la tastatur, iar ieirea
Ju nio r Di vls ion

z lim ba jul
co lec tiv - nu ma i pe ntr u ele vii care studia
n
- Problem de luc ru
l. ir uri ge ne ral iza te.
:~asca re
um ii de faptul c,
in Pascal, irurile cu ca
sun te i mul
Presupunem c nu
caractere.
~e poate lucra po t
avea cel mult 25 5 de
caractere.
luc rm cu iruri care
au cel mu lt 30 00 de
De exemplu , do rim s
iar sfritul unui ir
re inu t ca un ve cto r de 30 00 de caractere,
Jn astfel de ir va fi
valorii o (in binar).
:a fi marcat prin memorarea
subprogramele urmtoare:
Scriei
ir ;
in lungimea unui
subprogram care determ
iruri ;
ite concatenarea a dou
subprogram ca re perm
ir pentru altul;
ir este sau nu sub
bp rog ram ca re identific dac un
su
tete un ir ctre
un int reg;
subprogram care conver
re un ir;
tete un intreg ct
subprogram care conver
tete un ir ctre
un numr rea l;
subprogram care conver
tete un real ctre
un ir;
subprogram care conver
anumit poziie a
altui ir ;
rog ram ca re ins ereaz un ir pe o
subp
ate poziia
re terge un subir
al unui i r da t (se cuno
su bp rog ram ca
;
de inc ep ut a subirului)
intr-un fiier tex t;
su bp rog ram ca re permite sc rierea unui ir

n fiier text.
ite citirea unui ir dintr-u
subprogram care perm
Capitolul 4
Structuri de date neomogene

4.1. Noiuni introductive

La "Tehnologia Informaiei i a Comunicaiilor" am nvat s lucrm cu


tabele (Excel sau Access}. S considerm o linie a unui tabel. De exemplu, ea
conine numele unei persoane (30 caractere alfabetice), vrsta (un ntreg} i
salariul brut (un numr real}. Liniile, n totalitatea lor, alctuiesc tabelul. Fcnd
abstracie de faptul c la "Tehnologia Informaiei i a Comunicaiilor" se folosesc
programe gata fcute, specializate, destinate unor utilizatori crora nu li se pretinde
s fie experi n informatic, se pot pune mai multe ntrebri, cum ar fi:

!' cum se poate reine n memorie o linie a unui tabel?


!' cum se poate reine un tabel pe suport extern?

Rspunsul la prima ntrebare este dat de existena unor variabile speciale,


care au o structur neomogen. O astfel de variabil este mprit, la rndul ei, n
mal multe subvariabile numite, uneori, cmpurl. Pentru exemplul considerat, o
variabil, s-o numim Pers, va conine o subvar\abil num\\ Nume, care es\e un ir
de caractere; o alta, numit varsta, pentru care se alege un tip ntreg i o alta
numit Salariu, de un tip real. Astfel, observm c variabila Pers es:f
neomogen din punct de vedere al structurii, spre deosebire, de exemplu, de ~~
vector care are toate componentele de acelai tip. Cum se declar i cum ~
utifizeaztJ o astfel de varfabiftJ vom nvtJa n acest capitol.

n ceea ce privete rspunsul la a doua ntrebare, o posibilitate de a rei ne ...-


tabel este dat de crearea unui fiier cu tip.
fr Crearea i exploatarea fiierelor cu tip nu face parte din programa dvs., c.?'
~ .: este recomandabil s le studiai n mod individual.

4.2. Structuri neomogene n Pascal

4.2.1. Tipul Record


n practic, apar situaii n care toate tipurile de date nvate pn n pre:::r'
nu ne sunt de mare folos. S anal izm un exemplu.

~.'! Presupunem c dorim s prelucrm anumite date referitoare la mai -:JII


q.~ : elevi. Pentru fiecare elev, cunoatem:
Vanual de informatic pentru clasa a Xl-a 113

1. Numele i prenumele- se reine n string[20J;


2. Nota la matematic- variabil de tip rea'l;
3. Nota la fizic - variabil de tip real;
4. Vrsta variabil de tip byte;
5. Dac este biat sau fat - o variabil de tip char reine B sau 1 F 1

Observai faptul c informaiile referitoare 1~ un elev sunt eterogene (de la


1umele de tip string, pn vrsta de tip byte). In Pascal, exist posibilitatea ca
ioate aceste informaii s se regseasc ntr-un singur tip de nregistrare,
1Umit RECORD.
n programul urmtor, observm cum se declar (n acest caz, elev), cum
se citete i cum se afieaz o variabil (numit e) de acest tip:
type elev = record
nume: string[20 ];
n_mat, n _ fiz1 real;
varsta : byte;
sex : char;
end;
var e: elev;
begin
write('nume elev ' ); readln(e.nume);
write('nota matematica '); readln(e.n~t)l
write(nota fizica ')1 readln (e.n_ fiz};
write(varsta '); readln(e.varsta);
write ('sexul ') ; readln(e,sex);
writeln(nume , e . nume);
writeln(nota matematica , e.n_mat);
writeln('nota fizica , e.n_ fiz) ;
writeln(varsta 1 , e.varsta);
writeln('sexul , e.sex);
end.

f Observaii

v" Pentru a adresa un anumit cmp al variabilei de tip RECORD, se folosete


numele ei, urmat de '.', apoi de numele cmpului.

Exemplu: e.nwne reprezint cmpul nwne al variabilei e.


v" n cazul n care avem mai multe cmpuri adiacente (care urmeaz unul dup
altul) i de acelai tip, le putem declara deodat, separndu-le prin virgul.

Exemplu: cmpurile: "Nota la matematic" i "Nota la fizic" sunt adiacente


ide tip real, deci declaraia este:
n _mat, n _fiz: real;
114 Capitolul 4. Structuri de date neomogene \4anual de Informatic~

+ lat cum arat n memorie o nregistrare de acest tip- ocup 35 de octei :


4.2.3. nregistr ri
2 1 octeti 6 octeti 6 octeti 1 octet f octet
'----v------' '----v------' '---v---' .....__"_...., '----y---J
nume tr.mlll n. fiz virsta .re.t n general, cmp
"ltrebare: dar RECORD? 1
Cmpurile unei variabile de acest tip pot fi citite sau afiate individual. De
asemenea, li se pot atribui valori, pot intra n calcule, tot individual. program r3;
type elev = rac
Dac a i b sunt dou variabile de acelai tip RECORD se pot face fr DUJI

probleme atribuiri de genul a: b;. da~

4.2.2 . Acces ul simplificat la cmp uri n_:


v a.:
S e:J
Aa cum a fost prezentat, modul de acces la cmpurile unei variabile de tip e.n(
RECORD este deosebit de greoi - ntotdeauna punem numele variabilei n fa. n var e1 elev1
realitate, accesul la cmpurile unei astfel de variabile se poate face mult mai uor, begin
prin utilizarea instruciunii w:t:TH, cu forma general : with e do
begin
with var 1 , var 2 , , varn do instruciune write( n x
with da ta
i are rolul ca, n cadrul instruciunii subordonate, adresarea s se fac simplificat, begil
adic prin utilizarea exclusiv a numelui cmpului. wri t
writ
Rel um programul anterior, dar de aceast dat am utilizat instruciunea with: writ
end1
type elev = record end
n ume1 string[~011 end.
n_mat, n_ fizl real ;
varsta1 byte1 Pentru un elev, s
sex1 char1 tipul RECORD (include 2
end1 cmpurilor care o alctL
var e1 elev; fi putut face i aa: e
astfel de adresare este 1
begin
with e do Putem avea arie<
begin RECORD, care inc
wri te('nume elev ')1 readln(nume)l
write( ' nota matematica ')1 readln(~t)l
write( nota fizica '); readln(n_fiz)l 4.2.4. Vectori de
write(varsta ')1 readln(varsta)1
write ('sexul ')1 readln(sex)l Aa cum s-a ar~
writeln( nume ',nume) 1
de tip RECORD.
writeln('nota matematica ,n~t)1
writeln('nota fizica ,n_fiz)1 Adresarea cmp1
writeln('varsta ,varsta)l paranteze drepte ntn
writeln('sexul ,sex)l propri u-zis se face ac
end
end. Dac veste '
82
a-~:
'
urmtor) ,atur
prin v[i] . nu

.- "
~ual de informatic pentru clasa a Xl-a
115

.2.3. nregistrri imbr icate

n general, cmpurile care alcatuiesc un tip RECORD pot


avea orice tip. O
trebare: dar RECOR D? Raspunsul este afirmativ. Analizai progra
mul urmator:
progra m r3;
type elev = recor d
numes string [20J;
data_ n: recor d
zi, lunaa byte;
an: integ er;
end;
n_mat , n_fiza real;
varst aa byte;
sexa char;
end1
var ea elev;
bagin
with e do
begin
write( num e elev '); readln (nume );
with data_ n do
bagin
write (ziu a naste rii '); readl n(zi) ;
write ('luna naste rii '); readl n(lun a);
write (anu l naste rii ); readl n(an) ;
end;
end
end.

Pentru un elev, se citesc numele i data naterii. Aceasta


din urma este de
lUI RECORD (Include ziua, luna i anul naterii). Pentru adresa
rea simplificata a
m purilor care o alcatuiesc s-a folosit, din nou, instruciune
a WITH. Adresarea s-ar
putut face i aa: e.da ta_n .zi, e.dat a_n.l una, e.da
ta_n. an. Evident, o
ltfel de adresare este greoaie i nerecomandata ...
Putem avea oricte niveluri de imbricare (un tip RECORD
include un alt tip
RECORD, care include un altul, .a.m .d.).

2.4. Vectori de nregistrri

Aa cum s-a artat, elementele unui vector pot fi de orice tip, deci inclusiv
tip RECORD.
Adresarea cmpurilor se face prin numele vectorului, urmat
de perechea de
ranteze drepte ntre care este trecut indicele compo
nentei, apoi selecia
~ ri u-zis se face aa cum am nvat.

Daca veste vectorul, iar nregistrarea este de tip elev (ca


;:i: ur~tor}, atunci numele se selecteaz prin v[il
n programul
.nume, iar ziua nater i i
pnn v [il .nume . zi.
116 Capitolul 4. Structuri de date neomogene

i de aceast dat, pentru selecia simplificat, se poate utiliza cu succes


instruciunea WITH, aa cum rezult din programul urm.tor, unde se citete un
vector cu n nregistrri de tip elev:

type elev = record


nume: string[20 ] ;
data_n: record
zi, luna:byte;
an:integer;
end;
end;
vector_inregistrari array[1 9] of elev;
var v: vector_ inregistrari;
n, i: integer;
begin
write('n='); readln(n);
for i := l to n do
with v[i] do
begin
write(nume elev '); readln(nume);
with data_ n do
begin
write('ziua nasterii '); readln(zi);
write('luna nasterii '); readln(luna);
write(anul nasterii '); readln(an);
end;
end
end.

4.2.5. nregistrare cu variante


Nu toate nregistrrile au o structur fix (acelai numr de cmpuri) aa
cum au fost cele prezentate. Sunt cazuri cnd un tip inregistrare are o parte fix
urmat de o parte variabil.

S presupunem c ne Intereseaz o situaie referitoare la studiile unei


persoane. O astfel de nregistrare are o parte fix dat de cmpurile care rein
numele, vrsta i tipul de studii. O persoan poate s nu aib studii, caz n care nu
mai este necesar s avem alte informaii, poate s fi fcut cteva clase de coal
general (ne-ar putea interesa cte clase), s fi terminat liceul (caz n care dorim
s tim anul terminrii i oraul) sau s aib studii superioare (i atunci ne
intereseaz ~ numele facultii i numrul de ani de studiu n cadrul facultii
respective). In concluzie, n funcie de tipul de studii, nregistrarea arat altfel.

1 Limbajul permite ca
realizeaz aceasta?
nregistrrile s aib o structur variabil. Cum se

n primul rnd, trebuie reinut c partea variabil este plasat in cadrul


inreglstrrll dup partea fix. O parte variabil se dezvolt in cadrul
inreglstrrii dup valorile pe care
le la un cmp situat in cadrul prii fixe.
..{anual de informatic pentru clasa a Xl-a 117

n programul care urmeaz, se exemplific descrierea unui tip de nregistrare


-ariabil, selecia prii
variabile fcndu-se n funcie de yalorile pe care le ia
:mpul studii. Pentru selectare, se folosete o clauz special numit CASE.
::mpul dup care se face selecia apare descris n aceast clauz.
Cmpul selector trebuie s fie de tip ordinar cu un numr finit de
elemente. n funcie de _valorile pe care le poate lua cmpul selector, se va
:ezvolta partea variabil. In esent, se scriu pe rnd valorile posibile ale cmpului
~lector. n dreptul fiecrei valori se trece partea pe care trebuie s o conin
71registrarea n acest caz. Aceasta se ncadreaz ntre paranteze rotunde i poate
- chiar vid. Cmpurile prezente ntre paranteze se scriu separate prin ; .
!."lalizai programul urmtor (care citete o singur nregistrare):
type persoana = record
nume: string[JO];
varsta: byte;
case studii: char of
f 1
1 ( ) ;
(nr_ cl: integer);
g:
'1': (an_t: integer;
oras: string);
s: (fac: record
nume_f: string[20];
an_s: byte
end)
end;
var p: persoana;
begin
write( 'nume '); readln(p.nume);
write(varsta '); readln(p.varsta);
write(studii '); readln{p.studii);
case p . studii of
'g': begin
wri te ( 'numar clase ); readln(p.nr_ cl)J
end;
'1': begin
write(anul terminarii liceului ')J readln(p.an_ t);
write('orasul '); readln(p.oras);
end;
's': begin
write('numele facultatii '); readln(p.fac.nume_ f);
writeln(' ani de studii facultate ');
readln{p.fac.an_ s);
end
end {case}
end.

f Observaii

/ Pentru fiecare inregistrare de acest tip compilatorul rezerv numrul de


octeinecesari celei mai lungi variante.
/ Este preferabil ca citirea unei variabile de tip nregistrare cu variante s se
facprin utilizarea instruciunii CASE.
118 Capitolul 4. Structuri de date neomogene

4.3. Structuri neomogene n C++

4.3.1. Tipul struct

n practic, apar situaii n care toate tipurile de date nvate pn n prezent


nu ne sunt de mare folos. Pentru a nelege aceasta, vom porni de la un exemplu .

..... ;~ Presupunem c dorim s prelucrm date referitoare la mai muli elevi.


...~
~.
Astfel, pentru fiecare elev cunoatem:
' ..,,

1. Numele- char [20) ;


2. Prenumele- char (20] ; ;
2. Nota matematic - float;
3. Nota informatic - float;
4. Vrsta - int;
Observai faptul c informaiile referitoare la un elev sunt eterogene: iruri de
caractere, numere reale sau ntregi. Cum am putea rezolva problema prin utilizarea
cunotinelor de care dispunem? Ar fi necesari s vectori, cte unul pentru fiecare
Informaie. Astfel am avea doi vectori cu elemente de baz iruri de caractere
pentru nume i prenume, doi vectori cu elemente de baz de tip float pentru note
i unul cu elemente de baz de tip int pentru vrst. Fiecrui elevi , i corespund
componentele i ale fiecrui vector. O astfel de abordare este greoaie, nenatural.
Ar fi cu mult mai bine dac limbajul ar dispune de un mecanism prin care fiecrui
elev s-i corespund o singur nregistrare.

n C++ exist un tip de date, numit atruot, care ne permite acest lucru.
Forma general este (ce este trecut ntre paranteze drepte este considerat facultativ):
struct [nume structura]
{
[<tip> <nume variabila[, nume variabila, ]>]
[<tip> <nume variabila[, nume variabila, ]>] 1

} [lista de variabile] 1

Pentru exemplul dat, structura este:


struct elev
{
char nume[20], prenume[20];
float nota~te,nota_info;
int varsta1
};

i se numete elev.
IJan ual de informatic pentru clasa a Xl-a
119
Exi st dou posibiliti de dec lara re a vari abil elor care _alc
tuiesc structura.
1. Aa cum rezult din form a general, scriind la sfrit numele variabilelor:
stru ct ele v
{ cha r num e[20 ], pren ume [20]
;
floa t nota _ma te,n ota_ info ;
int var sta1
}in r1,i nr2 ;

Aici, inr l i inr 2 sunt dou variabile de tipul ele v.


2. Clasic, declarnd variabilele aa
cum suntem obinuii:
ele v inr 1, inr2 1

Definiia structurii poate fi~ura


att n cadrul funciei mai n c) ct i
dup includerile de fiiere ante n faa ei,
t. In ce ne privete , vom prefera a dou
a variant .
Se pune urmtoarea ntrebare: fiind
dat o variabil de un tip stru
este modalitatea de acces la cmpuri ct, care
le ei? Pentru aceasta, se folosete
de selecie direct, notat cu ' .', ope operatorul
rator cu prioritate maxim .
Fie inr o variabil de tipul elev . Atunci:
inr . num e - reprezint irul num
e al variabilei inr ;
inr. num e [O] - reprezint prim
ul caracter al irului nume;
inr. not a_m ate - reprezint cm
pul not a_m ate al variabilei inr .
n programul urmtor, se citete i
se tiprete o variabil de tipul ele v:
#in clude <io stre am. h>
stru ot ele v
{ cha r num e[20 ], pren ume [20]
1
floa t nota~te,nota_infol
int var sta1
}1

mai n()
{ ele v inr1
cout <<"N Ume "1 cin> >inr .num
e;
cou t<< Pren ume "1 cin> >inr .pre
num e1
oou t<< "No ta mat ema tica ";
cin>>inr.nota~te;
cou t<< No ta info rma tica "1
cin> >in r.no ta_i nfo ;
oou t<< "Va rsta "1
cin> >in r.va rsta 1
cout <<" Am oit it t << end l
<<in r.nu me< <" "<< inr. pren ume
<<e ndl
<<inr.nota~te~<endl
<<i nr.n ota_ info <<e ndl
<<i nr . var sta;
}
120 Capitolul 4. Structuri de date neomogene

ntre dou variabile de acelai tip struct se poate folosi atribuirea. Astfel,
dac inrl, inr2 sunt dou variabile de tip elev, prin atribuirea inrl:::inr2,
variabila inrl ia aceeai valoare ca variabila inr2. n C++, o astfel de atribuire se
mai numete copiere bit cu bit.

4.3.2. nregistrri imbricate


Exist situaii cnd un tip structurat conine in interiorul su un alt tip
structurat. Privii tipul urmtor:

struct elev
( char nume(20], prenume[20];
struct
( int clasa;
float note(20] ;
}situatie;
int varsta;
} ;

Structura de baz este elev. n interiorul su se gsete o alt structur, de


aceast dat fr nume, dar pentru care exist declarat "o variabil" numit
situatie. n realitate nu este vorba de o variabil, ci de un nume prin intermediul
cruia poate fi accesat un element al structurii. Am vzut c, in general, elementele
structurii se acceseaz prin numele variabilei de tipul structurii respective.

l't .,. Fie inr o inregistrare de tipul elev. n aceste condiii, accesarea
Q %: 1
elementelor situate n interiorul substructurll se face ca mai jos:

inr. situatie.clasa - se acceseaz cmpul clasa al


substructuril;
inr. situatie. note [o J - se acceseaz prima not a
vectorului inclus in substructur.

Exemplul urmtor prezint o alt posibilitate de declarare a structurilor:

struct elevl
( char nume[20], prenume[20);
struct
( int clasa;
float note[20);
}situatie_ l, situatie_2;
int varsta;
};

Tipul structurat elevl, subordoneaz, pe lng alte tipuri, dou structuri


situatie_ l i situatie_2 . Forma este echivalent cu cea n care cele dou
structuri sunt descrise una dup alta.

n practic, se folosete termenul "imbricate" pentru una sau mai multe


structuri incluse una in alta, ca mai sus.
\4anual de informatic pentru clasa a Xl- a 121

4.3.3. nregistrri cu structur variabil


Pentru nceput, vom studia un tip aparte de dat structurat, numit union.
Analizaiprogramul urmtor:
#include <iostream.h>
union test
{
int a;
char b[lOlt
double CI
};
main()
{
test var;int i;
cin>>var.c; cout<<var.c<<ond lt
c i n>>var.bt cout<<var.bt
}

Variabila var este de tipul union. Ea conine un ntreg, un vector de


caractere i o variabil real. Cele trei cmpuri subordonate ocup respectiv 2
octei, 10 octei i e octei. n realitate, pentru toate variabilele s-au reinut 10 octei
- adic octeii necesari pentru a memora cmpul cel ma/lung. Aceasta nseamn
c, la un moment dat, se poate memora doar un singur cmp dintre cele
subordonate. n exemplu, am utilizat la nceput variabila ntreag, apoi irul
de caractere.
lat forma general a unei uniuni:
union [<numele uniunii>]
(
<tip> <nume variabila> 1

} [lista de variabile] ;

Cu excepia faptului c numai un cmp poate fi ocupat la un moment dat,


toate celelalte reguli sunt identice cu cele de la structuri. Bine, vei intreba, dar la
ce folosesc "uniunile"? Sunt situaii n care nregistrrile nu au format fix, ci ve ~;<lbil.
Ca s fiu clar, voi da un exemplu.
S~ presupunem clj ne intereseaztl o situaie referitoare la studiile unei
persoane. O astfel de nregistrare are o parte fix dat de cmpurile care rein
numele, vrsta i tipul de studii. O persoan poate s nu aib studii, caz n care nu
mai este necesar s avem alte informaii, poate s fi fcut cteva clase de coal
general (ne-ar putea interesa cte clase), s fi terminat liceul (caz n care dorim
s tim anul terminrii i oraul) sau s aib studii superioare (i atiJnci ne
intereseaz numele facultii i numrul de ani de studiu n cadrul facultii
respective). In concluzie, n funcie de tipul de studii, nregistrarea arat altfel.

? Limbajul perm ite ca


realizeaz aceasta?
nregistrrile s aib o structur variabil . Cum se
122 Capitolul 4. Structuri de date neomogene

Uniunile pot fi incluse n structuri. La rndul lor, structurile. pot fi incluse n


uniuni. Pentru exemplul nostru, nregistrarea are o parte fix care este alctuit din
numele persoanei respective i o variabil de tip char, numit studii, care reine
tipul studiilor pe care le are persoana respectiv. Astfel, dac persoana respectiv
nu are studii, reine f , dac are cteva clase de general, reine 1 g , dac are
liceul, reine 1 1 , iar dac are studii superioare, 1 s 1

Apoi urmeaz partea variabil care este o uniune. Aceasta conine o


variabil nr_clase - pentru cazul n care studii reine 1 g 1 , o structur pentru
cazul n care studii, reine 1 , .a.m.d. n rest, citirea i afiarea nregistrrii se
face, de fiecare dat, sub swi tch, n funcie de datele citite sau coninute. n
concluzie, nregistrarea are structura variabilfJ, dar ocup un numr fix de octei.

Uniunea poate figura oriunde n interiorul structurii - nu este obligatoriu ca


aceasta s fie scris la sfritul structurii. Analizai programul:
#include <iostream.h>
struct persoana
{ char nume[30], studii;
un ion
{
int nr_clase;
struct
{int an_t;
char oras(20];
}liceu;
struct
{char nume_f[30);
int nr_ani;
}facultate;
}std;
};

main()
{ persoana pers;
cout<<"Nume persoana " ;cin.get(pers . nume,30);
cout<<"Studii f-fara g-generala,l-liceu;s-superioare) ";
cin>>pers.studii;
switch (pers.studii)
{
case g : cout<<" numar clase" ;
cin>>pers.std . nr_clase;
break;
case '1': cout<<"anul terminarii liceului" ;
cin>>pers.std . liceu.an_t;
cout<<"orasul ";
cin>>pers.std.liceu.oras;
break;
case s: cout <<"nwnele facultatii ";cin.get();
cin.get(pers.std.facultate.nume_f,30);
cout<<"nr ani de studiu ";
cin>>pers.std . facultate.nr_ani;
}
~ anual de informatic pentru clasa a Xl-a 123

//afisez inregistrarea
cout<<pers.nume<<endl;
switch (pers . studii)
{
case 'f': cout<<n-are saracu studii"; break;
case 'g': cout<<" numar clase "<<pers.std.nr_clase; break;
case '1': cout<<"a terminat liceul in"
<<pers.std.liceu.an_t
<<" in orasul "<<pers . std.liceu.oras; break;
case s: cout<<"numele facultatii"
<<pers.std.facultate.nume_f
<<" nr ani de studiu "
<< pers.std.facultate.nr_ani;
}
}

Probleme propuse
1. Citii o variabil cu urmtoarea structur:

nwne_elev: 30 caractere;
data_nasterii:
zi : intreg;
luna : intreg;
an : intreg;
nota matematica - real;
nota informatica - real;
nota engleza - real;
media - real;

(media se calculeaz, nu se citete).

Testai dac datele au fost introduse corect. Citirea se va verifica prin afiarea
rezultatului.
2. Citii n nregistrri de tipul celei de mai sus i afiai-le n ordinea alfabetic a
numelui.

3. Aceeai problem ca cea anterioar, numai c afiarea se va face n ordinea


descresctoare a mediilor.

4. Presupunnd c nregistrrile se refer la un examen de admitere dat, s se


afieze n ordine descresctoare a mediilor, n limita unui numr de locuri sau pn
cnd se epuizeaz toate nregistrrile elevilor cu medii mai mari sau egale cu s. n
cazul n care pe ultimul loc avem mai muli elevi cu aceeai medie, toi acetia sunt
considerai admii. Programul va afia numrul de locuri n plus.
Capitolul 5
Structuri de date

5.1. Conceptul de structur de date

Orice algoritm primete date de intrare, le prelucreaz i obine date de


ieire . Yn fiecare caz, datele de intrare, datele intermediare - cele create n timpul
prelucrrii - i datele de ie ire sunt structurate (organizate) ntr-un anumit fel care
corespunde Intrrii, necesitilor de prelucrare sau a celor de utilizare ulterioar.

Pentru a veni n sprijinul programatorilor, limbajele de programare evoluate


(de exemplu, C++ sau Pascal) pun la dispoziia acestora posibilitatea organizrii
datelor n anumite "abloane" , numite tipuri de date. Mal precis, prin tip de date
se nelege:

o mulime de valori;
o regul de codificare a acestora; 1
o mulime de operaii definite pe mulimea datelor.

La rndullor, tipurile de date pot fi:

simple - descriu date care aparin unor mulimi care nu sunt


rezultate ca produs cartezian al altor mu limi. Exemplu: int .

structurate - descriu date care aparin unor mulimi rezultate ca


produs cartezian al altor mulimi.

~~: 1. Privii declaraia de mai jos:


. ,. '; :j
1W''il'ii..,, 1;rii~!':Jy~rlanta r Vari~ha C!t-+ :r',...S'. ,.: ',
~ ~
1 '1 .11.- 1
~( .
1.,111. 1 ,,, ' ' ' 'P ilsca't .:,-,' . " ' ,,11 t ' ,,

type rational..record struct r a tional


p,q:integer; { int p,q;
end };

Prin tipul de mai sus se descrie structura unei variabile capabil s rein
numere raionale. Fie A 1 mulimea valorilor care pot fi memorate prin utilizarea
tipului ntreg. Fie A2 =A1 {0}. Atunci, o variabil de tip ratio nal poate memora
valori care aparin mulimii A 1 XA2 Evident, este sarcina programatorului ca valoarea
reinut de variabila corespunztoare lui q s fie diferit de o.

n unele lucrri vei ntlni definiii ale tipului de date care exclud regula de codificare. Aici
1

se pornete de la ideea c nu ntotdeauna este necesar, pentru a lucra cu tipul respectiv,


s cunoatem regula de codificare.
Manual de informatic pentru clasa a Xl-a 125

2. Mai jos, este prezentat un alt exemplu:

type vector=arr~ [1 100] of real; double a[lOO];


var a:vector;

Fie B mu limea valorilor care pot fi reinute de tipul real. Atunci, variabila a
poate reine la un moment dat un element al mulimii :

BxBx ... x B.
~
de 11 an'

Practica impune utilizarea unor structuri ale datelor de o mare varietate, care
nu se suprapun ntotdeauna peste tipurile care pot fi descrise prin limbaj .

.~ ,. Definiia 5.1. Prin structur de date vom nelege un ansamblu de date


J,~~,,...' caracterizat prin relaiile existente ntre ele i prin operaiile care pot fi
efectuate cu datele respective.

Vom numi nod, o variabil de un tip oarecare. De obicei, acest tip este
structurat. Dup caz, termenul nod poate fi nlocuit cu articol, nregistrare sau
entitate.

fn cele mai multe cazuri, "ansamblul de date" care formeaz structura este
alctuit dintr-o mu lime cu un numr variabil de noduri.

Relaiile existente Tntre noduri i operaiile care pot fi efectuate cu ele vor fi
prezentate prin exemple.

IH: De reinut!
fJ

./ Tipul variabilei care alctuiete nodul nu caracterizeaz structura de date .

./ Structura de date este un concept abstract. Mai precis, conceptul n sine nu


precizeaz locul unde structura respectiv va fi memorat (clasa de
memorare) i nici detaliile de implementare (cele care in de limbajul folosit) .

./ Tn facultile de profil (calculatoare, informatic) se studiaz disciplina numit


"Structuri de date". Ea este una dintre disciplinele care se includ n cadrul
mai larg al informaticii, tot aa cum, de exemplu, algebra se studiaz ca
disciplin aparte a matematicii.

./ ln practic s-au impus anumite structuri. Acest lucru este datorat faptului c
exist muli algoritmi care le utilizeaz. Ele vor fi tratate, pe scurt, n
paragrafele urmtoare.
126 Capitolul 5. Structuri de date

5.2. Structura de tip list liniar

5.2.1. Prezentarea structurii

Definiia 5.2. O list liniar este o colecie de n~O noduri, x1, xl, ... , Xn
aflate ntr-o relaie de ordine. Astfel, X 1 este primul nod al listei, X 2
este al doilea nod al listei, ..., Xn este ultimul nod.

Operaiile permise sunt:

accesul la oricare nod al listei n scopul citirii sau modificrii informaiei


coninute de acesta;

adugarea unui nod, indiferent de poziia pe care o ocup in list;

tergerea unui nod, indiferent de poziia pe care o ocup in list.

schimbarea poziiei unui nod n cadrul listei.

Faptul c structura este liniar nseamn c fiecare nod, cu excepia


ultimului, are un singur nod succesor (care ii urmeaz in list) i, cu excepia
primului nod, are un singur predecesor (care se afl imediat naintea lui
in list).

Dac vorbim la modul general de o structur de date, nu ne intereseazli,


pentru moment, modul n care aceasta va fi implementatli (adic unde este
memorat i cum se efectueaz operaiile permise asupra ei). Pur i simplu, ne
imaginm lista ca mai jos, unde fiecare nod i memoreaz informaia inf 1 :

in:E 1 ~~ in:E 2 1 +! in:E .a


noda nod,.

Exemple de aplicaii care utilizeaz liste liniare:

a) Evidena situaiei colare a elevilor unei clase. Fie n numrul elevilor. Aici, un
nod reine numele unui elev i notele la diversele materii. Vom avea deci, n noduri.
Nodurile vor fi memorate in ordinea alfabetic a numelor elevilor. n clasa
respectiv pot fi transferai elevi din alte clase, caz in care se adaug noduri. Din
clas, unii elevi pot pleca n alte clase, caz in care se terg noduri.

b) Se dorete s se rein un ir de numere naturale, n ordinea in care au fost


citite de la tastatur. Aici, un nod reine un numr natural.

Nu toate aplicaiile utilizeaz liste liniare. Exemple de structuri care nu sunt


liste liniare:
se dau n orae i oselele care unesc unele dintre aceste orae;
arborele genealogie al unei persoane.
\Aanual de informatic pentru clasa a Xl-a 127

5.2.2. Liste alocate secvenial

Din acest moment ne punem problema s vedem modul in care se poate


implementa o list liniar.

O prim form de alocare este cea secvenial. in cazul acestei alocri,


nodurile listei ocup poziii succesive in memorie. Acest tip de alocare se ntlnete
des, de eate ori utilizm vectorii. Altfel spus, primul nod al listei va fi reinut de
primul element al vectorului, al doilea nod al listei de al doilea element al vectorului,
. a . m.d.

n continuare, urmrim modul in care putem efectua operaiile permise cu o


list liniar .

a) Accesul la oricare nod al listei se poate face cu mare uurin . Dac dorim s
adresm nodul k, atunci scriem v [kl (presupunand c vectorul care reine nodul
se numete v).

b) tergerea unui nod, Indiferent de poziia pe care o ocup in list

Fie lista alocat secvenial:

Eliminm al doilea nod - coninut 3 (tergem coninutul nodului 2):

1 71 1 1 12 1 8 1 9 15 1 8 13 12 1 6 +. . . . .f...........
f...........l.......... I........... +. . . . . +. . . J
J......... I..........

Pentru a pstra structura i pentru a nu pierde informaii, este obligatoriu ca


i nformaiile reinute de nodurile care urmeaz nodului ters s fie deplasate ctre
stnga:

~ Practic, de aceast dat, nodul 2 (elementul de indice 2 al vectorului) va


.~ reine informaia celui de-al treilea nod; nodul 3, va reine informaia celui
de-al patrulea nod; . a . m . d . ln multe aplicai i , aceast modificare nu prezint
importan.

c) Adugarea unui nod, indiferent de poziia pe care o ocup in list

Fie lista alocat secvenial:

1 71 3 1 1 1 2 1 8 19 1 5 18 1 3 1 2 1 6 1
128 Capitolul 5. Structuri de date

Nodul 2 va conine 5 (practic, adugm un nod). ncepnd cu nodul 2,


deplasm toate info rmaiile asociate nodurilor ctre dreapta:

111 13 11 12 la 19 15 la 13 12 16 1
Acum se completeaz valoarea reinut de nodul 2:

171 5 1 3 11 12 1a 19 15 18 13 12 16 1
Observaii

i de aceast dat, nodurile vor reine informaii diferite. De exemplu, nodul


3 va reine ce anterior reinea nodul 2, .a . m.d.

ln concluzie, la alocarea secvenial, accesul la nod este foarte rapid, dar


adugarea sau tergerea unui nod se fac cu efort de calcul, pentru c
necesit deplasri ale coninuturilor nodurilor.

5.2.3. Liste alocate nlnuit

Exist dou feluri de alocare nlnuit: alocare simplu nlntuit i alocare


dublu nlnuit. n acest paragraf prezentm principiile alocrii inln(uite, urm~md ca
n paragraful urmtor s artm modul in care implementm listele alocate nlnuit.

1. O list lin iar simplu nlnuit este o structur de forma:

adr1
.J.I..:..ad.::.:.r:...dt---~11!
Ll..:.in:.:..
1
adr2
1 in2 1adrd .. nil

Semnificaia notaiilor folosite este urmtoarea :

adr1, adr2, adr3, ... , adrn reprezint adresele ce1or n inregistrri;

in1, in:l, ... , inn reprezint informaiile coninute de noduri, de alt natur
dect cele de adres.

nil - are semnificaia "nici o adres" - elementul este ultimul in list.

Dup cum observm, fiecare nod, cu excepia ultimului, reine adresa


nodului urmtor.

2. Alocarea dublu nlnuit. Alocarea simp~u nlnuit permite parcurgerea listei


ntr-un singur sens (de la stnga la dreapta). In cazul n care se dorete ca lista s
poat fi parcurs n ambele sensuri, se utilizeaz alocarea dublu nlnuit. Aici,
Aanual de informatic pentru clasa a Xl-a 129

"ecare nod reine adresele predecesorului i succesorului su, aa cum se vede i n


"gura urmtoare:

1 nil 1in 1 1 adr2 1 1 adr1 1 in2 1 adr3 C: ::::J adrn11 inn 1 nil
adG ad~ adrn

5.2.4. Implementarea alocrii nlnuite prin utilizarea


vectorilor

Aa cum am invat, lista liniar este alctuit din mai multe noduri intre care
exist o relaie de ordine. Tn cazul alocrii Tnlnuite, informaia memorat de
ecare nod va cuprinde i un cmp de adres -in cazul alocrii simplu inlnuit
sau dou cmpuri de adres -in cazul alocrii dublu Tn lnuit. in acest paragraf
vom studia implementarea alocrii simplu in lnuit.
lat cum se descrie informaia dintr-un nod, n cazul listelor alocate simplu
nlnuit, atunci cnd acesta reine un nu[llr intreg.

1 info 1 adresa nodului urmtor 1


"' Varianta Pascal ' Varlanta ' C~+
type Adresa=Intoger; typedef int adresa;
nod= record struct nod
info:integor; { int info;
adr_urm:AdreQa; adresa adr_ urm;
end; ) 1

Pentru memorarea listei folosim un vector care are componentele de tip Nod,
descris mai jos:

Varianta C++
Lista=array[l lOOO) of Nod; nod L[1000];
var L:lista~

Din descriere rezult c lista poate avea cel mult 1000 de noduri. Acesta
este spaiul disponibil.

Privii exemplul de mai jos:

L ~~~-7~-3--~--~--_.-5~~4--~~--5--~4~--o--~~~~
1 2 3 4 5 6
130 Capitolul 5. Structuri de date

Dac facem abstracie de implementare, lista este:

1~~.~ J I o
.~rJ. Ce observm?

a) Fiecare nod trebuie s rein i adresa nodului urmtor. Adresa este, de fapt,
indicele componentei din vector care reine informaia asociat nodului urmtor.
Prin urmare, necesarul de memorie este mai mare.

b) Nodurile nu ocup adrese succesive n memorie. De exemplu, dei primul nod


al listei este reinut de prima component a vectorului (de indice 1), al doilea nod al
listei este reinut de componenta de indice 3 a vectorului. Din acest motiv, vom face
distincie ntre numr.ul unui nod (acesta este n cadrul listei) i indicele vectorului
unde este memorat. In exemplul de mai sus, nodul 2 reine 5, iar el este memorat
de componenta de indice 3 a vectorului.

Pentru realizarea practic a implementrii apar o serie de probleme. Acestea


vor fi rezolvate n cele ce urmeaz .

IRl Problema 1. Gestiunea memoriei. Conceptul de list nu precizeaz numrul


de noduri pe care ea le poate avea. n practic, numrul de noduri este limitat.
Aceasta nseamn c, la un moment dat, numrul de noduri poate fi depit. Prin
urmare, programul care lucreaz cu o astfel de list trebuie s gestioneze
spaiul disponibil.

n aceste condiii, vectorul care reine nodurile, va fi dublat de un altul, ale


crui componente rein 1 sau o, dup cum componenta de acelai indice a
vectorului L reine sau nu un nod . Eventual, se poate utiliza o variabil care
memoreaz numrul de componente ale vectorului care reine nodurile.

L ----.1 3 15 1 11
4 1 5 14
1 2 3 4 5 6

ocupat-.! o o
1 2 3 4 5 6

!Rl Problema 2. Accesul la un nod al listei. Spre deosebire de alocarea


secvenial, unde accesul este imediat, la alocarea nlnuit accesul se face
ncepnd cu primul nod al listei. Dac nu acesta este nodul cutat, se trece la nodul
urmtor (orice nod conine adresa nodului urmtor, . a.m.d.) .

!Rl Problema 3. Adugarea unui nod. S presupunem c n lista de mai jos


dorim s adugm, dup al treilea nod, un nod cu informaia 9 .
"'anual de informatic pentru clasa a Xl-a 131

L ... 1 7 13 15 14 11 15 4 1o
1 2 3 4 5 6

ocupat---.1 o o
1 2 3 4 5 6

Prin testarea vectorului ocupat, se observ c primul element liber al


.. ectorului L este cel de indice 2.

a) Marcm nodul ca ocupat (ocupat [2] va reine 1).

b) Memorm informaia: 9.

L~1713 Q 15 14 11 5 14 1 o
1 2 3 4 5 6

ocupat---.1 o
1 2 3 4 5 6

c) Noul nod va reine ca adres urmtoare, adresa urmtoare reinut de al


treilea nod (pentru c introducerea noului nod se face dup acesta):

L ... 1 7 1 3 Q !1 5 14 1 1 15 14 1 o
1 2 3 4 5 6

ocupat---.1 o
1 2 3 4 5 6

d) Al treilea nod va reine ca adres urmtoare, adresa nodului nou introdus,


pentru c acesta s-a introdus dup el:

L ... 1 7 1 3 Q fi 1 5 14 1 1 12 14 1o
1 2 3 4 5 6

ocupat---.1 o
1 2 3 4 5 6

Dup aceast modificare, lista va fi:

17 13 ;J 15 14~ 11 l~l 19 15~ 14 1 o


1 ~3 '-44 5 ~5
132 Capitolul 5. Structuri de date

[8] Problema 4. tergerea unui nod. sa presupunem c in lista de mai jos dorim
s tergem al doilea nod.

L ---+1 1 7 3 15 14 11 1 5 14 1o
1 2 3 4 5 6

ocupat--+-1 o o
1 2 3 4 5 6

Al doilea nod se gsete in elementul de indice 3. Prin urmare, ocupat [3]


va reine o. n continuare, primul nod va reine ca adres urmtoare adresa nodului
3 (pentru c acesta urmeaz nodului 2). Aceast adres se ia din cmpul de
adres urmtoare a nodului care urmeaz s fie ters.

L 1 7 14 15 1 4 11 1 5 14 1o
1 2 3 4 5 6

ocupat--+-1 o o o
1 2 3 4 5 G

l Observai faptul c, dei nu am ters informaia asociat nodului, acesta


rf devine inaccesibil prin parcurgerea listei ncepnd cu primul nod.

Lista va deveni:

-+ Dezavantajele alocrii nlnuite sunt:

1. Accesul la un nod al listei se face prin parcurgerea nodurilor care l


preced. Aceasta necesit un efort de calcul.

2. Informaiile de adres , prezente n cadrul fiecrui nod ocup memorie.

-+ Avantajele alocrii nlnuite sunt date de faptul c operaiile de adugare


sau eliminare a unui nod se fac rapid.

Exemplele sunt date pentru lista liniar simplu nlnuit, dar bine nelese,
ne permit s deducem singuri modul de efectuare a operaiilor respective pentru
liste dublu nlnuite .
"'an ual de informatic pentru clasa a Xl-a 133

5.3. Structura de tip stiv

Definiia 5.3. Stiva este o list pentru care singurele operaii permise
sunt:

adugarea unui element n stiv;

eliminarea, consultarea, sau modificarea ultimului element introdus


in stiv.

Stiva funcioneaz pe principiul LIFO (Last In First Out) - Hultimul


ntrat primul ieit".

Pentru a nelege modul de lucru cu stiva, ne imagin m un numr n de


farfurii identice, aezate una peste alta (o "stiv" de farfurii). Adugarea sau
scoaterea unei farfurii se face, cu uurin, numai n vrful stivei. Dup ce am scos
toate farfuriile din stiv, spunem c aceasta este vid. Orict ar prea de simplu
principiul stivei, el are consecine uriae n programare.

-+ Stivele se pot aloca secvenial (ca vectorii). Fie ST [il un vector. ST (11,
ST (2 1, ..., ST (n) pot reine numai litere sau numai cifre. O variabil k indic
in permanen vrful stivei, adic ultimul element Introdus.

Exemplificm, n continuare, modul de lucru cu stiva:

G ln stiva iniial vid se Introduce litera A, vrful stivei va fi la nivelul 1 (k=l).

0AB Introducem in stiv litera B, deci k va lua valoarea 2.

0
D Scoatem din stiv pe B (A nu poate fi scos deocamdat); k=l.

0
D Scoatem din stiv pe A; stiva rmne vid k=O.

~ Observaii

./ ln mod practic, la scoaterea unei variabile din stiv, valoarea variabilei ce


indic vrful stivei scade cu 1, iar atunci cnd scriem ceva n stiv, o
eventual valoare rezidual se pierde.
134 Capitolul 5. Structuri de date

./ Pe un anumit nivel se reine, de regul, o singur informaie {liter sau cifr) ,


Tns este posibil s avem mai multe informaii.

./ n cazul stivei, alocarea secvenial nu prezint mari dezavantaje, ca n cazul


mai general al listelor, pentru c nu se fac operaii de inserare sau tergere
n interiorul stivei, ci numai n vrful ei.
Singurul dezavantaj, in comparaie cu alocarea dinamic nlnu it este dat
de faptul c numrul de noduri care pot fi memorate la un moment dat este
mai mic - depinde de gradul de ocupare al segmentului de date.,

./ in literatura de specialitate vei ntlni termenul PUSH pentru operaia de


adugare n stiv a unei nregistrri i POP, pentru extragere.

'
./ Este posibil s v ntrebai : de ce nu putem accesa un element al stivei, chiar
dac nu este ultimul introdus? Nimeni nu ne oprete~ doar c, n acest caz,
nu respectm pri'ncipiul stivei.

a
C'X: Exemple

1. Funcia Manna-Pnuen. Se citete xez. Se cere programul pentru calculul


funciei:

x-1, x~12
F(x) = {
F(F(x + 2)),x < 1.2

Vom incepe prin a studia modul de calcul al funciei pentru x=lS i x=S:

f(15)=14;
f (8 )=f(f(10))=f(f(f(12))) =f(f(ll ))=f(f(f(13)))=f(f(12)) =f(11)
af(f( 1 3))=f(12)=11.

Algoritmul va folosi o stiv ST i o varibil numit k, ce indic n


permanen vrful stivei.

Algoritmul se bazeaz pe urmtoarel e considerente:

la o nou autoapelare a funciei f, se urc n stiv {k se incrementeaz


cu 1) i se pune noua valoare;

in situaia in care, pentru valoarea aflat pe nivelul k, se poate calcula


funcia, se coboar Tn stiv, punndu-se pe acest nivel noua valoare;

algoritmul se ncheie cnd se ajunge Tn stiv la nivelul o..


~ ual de inform ati c pentru clasa a Xl-a 135

Pentru exemplul dat, prezentm schematic funcionarea sa:

12 13

10 10 11 11
8 '1 8 8 8 8

12 13

8 11 11 12
f=11

Programul este prezentat n continuare:

var st:array [1 100] of iinclude <iostream.h>


integer; int st{100],n, k;
n,k : integer; main()
begin { cout<<"n=" ;
write('n='); readln(n); cin>>n;
k:=1t st [ 1]:=nt k=1;
while k>O do st[l]=n;
if st [k ] <12 then begin while (k>O)
k:k+1 ; if (st[k]<12)
st[k]:=st[k-1]+2 { k++ ;
end st[k]=st(k-1]+2;
else begin }
k:=k-1; el se
if k>O { k- - J
then st [k]:=st[k+1]-1 if (k>O) st[k]=st[k+1l-1 t
end; }
writeln('f=,st[1]-1) cout<<"n="<<st[l]-1 ;
end. }

~ Se poate demonstra uor c pentru valori mai mici decat 12, funcia ia
i -' valoarea 11. Observaia simplific mult programul, dar exemplul a fost dat n
alt scop.

2. Fu ncia lui Ackermann. Se d funcia de mai jos, defin it pe produsul cartezian


NXN. Se citesc m i n . S se calculeze Ack (m, n >.

l
n+1, m=0
Ack(m,n)= Ack(m-1 ,1 ), n= O
Ack(m - 1,Ack(m,n -1)),altfel
136 Capitolul 5. Structuri de date

Pentru a elabora algoritmul, studiem un exemplu numeric:


ack(2, 1) ack(l,ack(2,0))=ack(l,ac k(1,1))=ack(1,ack(O,ack( 1,0)))=
ack( l ,ack(O,ack(O,l)))ack(l,a ck(0,2))=ack(l,3)=ack(O ,ack(l,2)) =
aack(O,ack(O,ack(l,l)))~ack(O,ack(O,ack(O,ack(l,O))))=
ack(O,ack(O,ack(O,ack(O,l))))~ack(O,ack(O,ack(0,2)))=

ack(O,,ack(0,3))=ack(0,4 )5.

Pentru calculul acestei funcii, folosim o stiv dubl , ST. Iniial, valorile m i n
se rein la nivetul 1. Pe nivelul k al stivei se rein valorile curente m i n . ln funcie de
valorile acestora se procedeaz astfel:

pentru a i n diferite de o, este necesar un nou calcul de funcie, caz in care


se urc in stiv i pe noul nivel se pun argumentele m i n-1;

pentru cazul n=O, se rmne pe acelai nivel in stiv, punnd in locul lui m
valoaream-1, iar n locul lui n, valoarea 1;

in situaia in care mO , funcia se poate calcula; se coboar in stiv i se


inlocu iete valoarea lui m cu m-1, valoarea lui n cu valoarea calculat
anterior.

ln continuare, prezentm grafic modul de funcionare a algoritmului pentru


exemplul ack ( 2, 1):

1 o o1
2 o 1 1 1 1 1 1
2 1 2 1 2 1 2 1 2 1

1 o
1 1 1 1
o2 1 3 1 2 1 2
g1 1 3 1 2 1 3 1 3

o1
1 1 o2
1 2 1 2 o3
1 3 1 3 1 3 o4 ack(2,1 )=5.
137
lll.anual de Informatic pent ru clasa a Xl-a

Var ianta C++

t ype stiva =arr ay [1 1000 0,1 2] int st[10 000 l [2lr


of inte ger; main ()
{ int m, n,k;
var st:s tiva ;
cout < <" m; cin>> m;
m,n, k : inte ger;
cout << "n=" ; cin> >n;
begi n k=1;
writ e( 'm=' ); st[k ) [O]=m ;
read ln(m ) ; st(k ] [1]= n;
writ e( n:: ); whil e (k>O )
read ln(n ) ; if (st[k ] [0] && st[k ] [1])
k:=l ; { k++;
st[k ,1] :=m; st(k ] (O] st[k -1)[ 0);
st[k ,2):= n; st(k ] [1]= st[k- 1] (1]- 1;
whil e k>O do }
if (st[k ,1l< >0) and el se
(st[k ,21< >0) if ( 1 st [k] [1])
then { st [k) [O) at [k) [0) -1;
begi n st(k ] (1]= 1;
k:=k +l; }
at[k ,1]l= Bt[k -1,1 ]; el se
st[k ,2l:= st[k -1,2 )-1 { k--;
end if (k>O )
el se { at[k ] (O] st[k ] [0]- 1;
if at[k ,2l= O t [kl [1] =st [k+1 l [1] +1;
then }
begi n }
st(k ,1] :st[ k,1] - 1; cout <<"a c("< <m< <', '<<
st [k, 2]:= 1 n<<" )"< <st[1 ] [1)+ 1;
end }
else
begi n
kl=k -1;
if k>O
then
begi n
st(k ,l]: st[k ,l]-1 ;
st[k ,2] Jast( k+1, 2)+1
end
end;
writ eln( ac( ,m, , ,n, )=',
st[1 ,2]+ 1)
end.

u valori mici ale lui m i


Funcia lui Acke rman n ia valori extrem de mari pentr
( 4, 4) . lncercai ...
n. De exemplu, nu vei reui s calculai Ack
138 Capitolul 5. Structuri de date

5.4. Structura de tip coad

Definiia 5.4. O coad este o list pentru care toate inserrile sunt fcute
la unul din capete, toate tergerile (consultrile, modificrile) la cellalt
capt.

Coada funcioneaz pe principiul FI:FO (First :rn First OUt)


"primul intrat primul ieit".

Este cu totul nerecomandabil alocarea secvenial a cozii, deoarece in


aceast situaie , are loc un fenomen de migraie a datelor ctre ultimele
componente ale vectorului (cele de indice mare).

: .. S presupunem c simulm o coad cu ajutorul unui vector cu zece


/:!~: componente, care rein numere intregi. Introducem in coad~. pe rand,
! numerele :1, 2, 3, 4.

1 2 3 4

Dac scoatem din coad pe 1 i introducem in coad pe 5, coada va arta


in felul urmtor:

2 3 4 5

Scoatem din coad pe 2 i introducem pe 6:

3 4 5 6

l, Se observ acest fenomen de "migraie".

Probleme propuse
1. Care dintre structurile de mai jos nu este liniar?

a) b) C) d)

2. Un vector reine pe poziiile de la 1 la k nodurile unei liste liniare. Fiecare element


al vectorului (nod) reine un num r natural. Se cere s se scrie un subprog ram care
insereaz in list, pe poziia p , un numr natural citit de la tastatur.
anual de informatic pentru clasa a Xl-a 139

cemplu: k=3; V= ( 1, 2, 3); p=2. Numrul citit este 5. Dup rulare trebuie s
rem:
:4;V=(l,S,2 ,3).

Un vector reine pe poziiile de la 1 la k nodurile unei liste liniare. Fiecare


:!ment al vectorului (nod) reine un numr natural. Se cere s se scrie un
oprogram care terge din list nodul aflat pe poziia p, l~pS"k..

cemplu: k=3; V= ( 1, 2, 3); p=2. Dup rulare trebuie s avem: k=2; V== ( 1, 3).

Pentru problema anterioar, care dintre afirmaiile de mai jos este fals?

Pentru a terge un nod aflat pe poziia p sunt necesare k-p deplasri spre
inga ale coninuturilor celorlalte noduri.
Subprogramul va avea parametrul k transmis prin valoare.
Subprogramul va avea parametrul k transmis prin referin.
Dac k=p, nu se efectueaz deplasri ctre stnga.
1

Lucrare in colectiv. Implementare a listelor alocate simplu inlnult. Scriei


set de subprograme care creeaz i gestioneaz o list liniar simplu nlnuit,
>eat secvenial (prin utilizarea unui vector).

Lucrare n colectiv. Implementare a listelor alocate simplu inlnuit. Scriei


set de subprograme care creeaz i gestioneaz o list liniar simplu nlnuit,
tea t nlnuit.

Sortai n numere naturale utiliznd algoritmul de sortare prin inserie. Programul


utiliza o list liniar a loca t nlnuit. Care sunt avantajele utilizrii listei alocate
anuit in cazul algoritmului de sortare prin inserie?

Creai o list liniar cu n noduri alocat secvenial. Nodul 1 va conine numrul


nodul 2 numrul 2, .a.m.d. Se genereaz aleator un numr natural k, mai mare
1 i mai mic dect n. Nodurile de la k la n vor fi, in aceast ordine, primele in
, urmate de nodurile de la 1 la k-1, in aceast ordine. Afiai lista dup p astfel
mversri. Observaie: aceasta este o modalitate de a genera aleator o
rmutare a primelor n numere naturale.

n cazul n care, pentru o list liniar alocat nlnuit, cmpul de adres al

t
mului nod reine adresa primului nod, se obine o list circular:

1 ~--1--M~r 1 1 1 1 ,. . . . . . . . . . . . . ....... 1 1 1
.. 1
Creai o list circular in care fiecare nod reine un numr natural. De
: menea, scrieisubprograme de inserare i tergere a unui nod al listei create.
140 Capitolul 5. Structuri de date

10. n jurul arbitrului sunt aezai N juctori numerotai n sens orar. Arbitrul,
ncepnd de la un juctor K num r pn la M. Per.soana la care s-a oprit
num rtoarea este elimin at din cerc. Arbitrul repet procedeul ncepnd cu
persoana urmtoare celei eliminate. Procedeul se repet pn cnd rmne un
juctor L. S se scrie un program care:

citete M, N, K i-1 determin pe L;


citete M, N, L i-1 determin pe K.
11. Urm rii secvena urmtoare, care se refer la o stiv, unde Push a este
operai a prin care se pune n stiv valoarea a, iar Pop este operaia prin care se
extrage din stiv.

Push 1; Push 2; Pop; Push 3; Push 4; Pop; Pop

Care din afirmaiile de mai jos nu este adevrat dup executarea secvenei
de mai sus?
a) Din stiv au fost extrase, in aceast ordine, valorile: 2, 4, 3;
b) stiva este vid; c) stiva conine valoarea 1; d) stiva are un singur nivel.

12. Scriei subprogramele care implementeaz o stiv.

13. Se citesc n valori numere naturale. Se cere ca, prin


utilizarea unei stive, vedei problema anterioar, valorile citite
s se afieze in ordine i nvers.

14. n figura alturat avem 4 vagoane, numerotate cu


1,2,3,4. Se presupune c pe linia c ncap toate cele 4
vagoane i c un vagon aflat pe linia c poate fi mutat numai
pe linia B. Se cere ca, prin mutri succesive de vagoane, s
avem pe linia B vagoanele ntr-o anumit ordine, in care c
primul vagon este cel aflat la ieirea de pe linia B. Care
Figura 5.1.
dintre irurile de vagoane de mai jos nu poate fi obinut?
a) 1 2 3 4; b) 4 3 2 1; c) 3 4 2 1; d) 3 4 1 2.

15. S se scrie un program care, pentru problema de mai sus, citete ca date de
intrare irul vagoanelor aflate pe linia A i irul vagoanelor care trebuie obinut pe
linia B. Se cere s se afieze irul mutrilor de tip Push nr_ vagon i Pop
nr_vagon (ai recunoscut, desigur, o structur de tip stiv) prin care se poate
obine iru l vagoanelor de pe lina B. Dac acest ir nu se poate obine, in momentul
in care se ajunge n situaia unei mutri imposibile, s se afieze mesajul
'Imposibil'.

16. Scriei un set de subprograme care gestioneaz o coad . Coada va fi


implementat prin utilizarea alocrii nlnuite.

Rspunsuri

1. d) 4. b) 11. b) 14. d)
Capitolul 6

Introducere n recursivitate

5. 1. Prezentare general

Recurslvltatea este una din noiunile fundamentale ale informaticii.


..r.ilizarea frecvent a recursivitii s-a fcut dup anii 80. Multe din limbajele de
;~og ramare evoluate i mult utilizate - Fortran, Cobol - nu permiteau scrierea
:~ogramelor recursive.

Definiia 6.1. Recursivltatea este un mecanism general de elaborare a


programelor. Ea const~ n posibilitatea ca un subprogram ~ se
autoapeleze.

Recurslvitatea a aprut din necesiti practice date de transcrierea direct a


'ormulelor matematice recursive. n timp, acest mecanism a fost extins, fiind utilizat
1'1 elaborarea multor algoritmi.

6.2. Modul n care se realizeaz autoapelul


n acest paragraf vom nva modul n care subprogramele se autoapeleaz.
'Aecanismul recursivitii i modul cum se gndete un algoritm recursiv vor fi
prezentate n paragrafele urmtoare.

6.2.1. Realizarea autoapelului n limbajul Pascal


Dup cum tim, n limbajul Pascal subprogramele sunt de dou feluri:
proceduri i funcii. Oricare ar fi tipul subprogramului, acesta se poate autoapela,
ns modul n care se realizeaz autotransferul difer.

-+ n cazul procedurilor, autoapelul se realizeaz prin apelul procedurii


respective, din interiorul ei. Apelul se face la fel ca n cazul n care procedura
este apelat din exterior.

~ ., Procedura prezentat n conti~uare este, recursiv i afieaz, pe rnduri


GX. separate, numerele 7, 6, ... , 1 .
.~>
142 Capitolul 6. Introducere n recursivitate

procedure exemplu(n:integer);
begin
if n<>O then
begin
writeln (n) 1
exemplu(n-1);
end
end;
begin
exemplu(?) ;
end.

-+ n cazul funciilor, autoapelul se realizeaz printr-o operaie de atribuire,


operaie prin care numele funciei trebuie s~ figureze n partea dreapt a
operatorului de atribuire.

~~: Funcia urmtoare calculeaz suma 1+2+ +7:

function suma(n1integer)1integer;
begin
suma:=O;
if n<>O then
suma:=n+suma(n-1);
end;
begin
writeln(suma(7));
end .

6.2 .2. Realizarea autoapelului n limbajul C++


Dup cum tim, n C++ funciile pot fi de tipul void sau de un alt tip. n acest
din urm caz, funciile returneaz o anumit valoare. Oricare ar fi tipul funciei ,
aceasta se poate autoapela, ns modul n care se realizeaz autotransferul, difer.

-+ n cazul funciilor de tip void, autoapelul se realizeaz prin apelul funciei


respective, din interiorul ei. Apelul se face la fel ca n cazul n care funcia
este apelat din exterior.

i,j?~
. :~), . Funcia de mai jos este recursiv. Ea afieaz, pe rnduri separate,
~?f.' numerele 7, 6, ... , 1:
linclude <iostre am.h>
void exernplu(int n)
{ if (ni=O)
{ cout<<n<<endl;
exemplu (n- 1) ;
}
}
main()
( exernplu(7);
}
lanual de informatic pentru clasa a Xl-a 143

~ n cazul funciilor care nu sunt de tipul void, autoapelul se realizeaz prin


instruciunea return. Ea este de iorma return . expresie, dar n
expresia respectiv trebuie s intre i funcia care se autoapeleaz.

yJ.. Funcia urmtoare calculeaz suma 1+2+ +7:


- """' #include <iostream. h>
int suma (int n)
{ if (nt=O) return n+suma(n-l);
}

main()
{ cout<<suma(7);
}

6.3. Mecanismul recursivitii

:J Problem. S se calculeze recursiv n!.

A) Pentru a scrie o funcie recursiv care efectueaz acelai calcul, vom porni de
a o definiie recursiv a lui n 1. Aceasta este:

1, n= O
n! = fact(n) = { n fact(n-,) , altfel cu nE N

De exemplu, pentru a calcula 3 t, procedrT) astfel:

3 ! =fact(3)=3Xfact(2)=3X2Xfact(l)=3X2X1Xfact(0)=3X2X1Xl=6.

Funcia recursiv fact nu face altceva dect s transcrle definiia recursiv


orezentat anterior:

var n : integer; #include <iostream.h>


int fact(int n)
function fact(n:integer): { if ( In) return 1;
integer; else return n*fact(n-1);
b egin }
if n=O then fact :=l
else fac t : =n*fact(n- 1) main()
end; { int n;
cout<<"n=";
begin cin>>n;
write ( n= ) 1 cout<<fact (n);
readln(n); }
writeln(fact(n))
end.
144 Capitolul 6. Introducere n recursivitate

2 Care este mecanismul prin care subprogramele se pot autoapela? S ne


~~i:' amintim modul n care subprogramele memoreaz parametrii transmii.

);> Pentru memorarea parametrilor, subprogramele folosesc o zon de


memorie numit stiv (mai exact, aceast zon se numete segment
de stiv).
);> Memorarea parametrilor transmii se face n ordinea n care acetia
figureaz
n antet: de la stnga la dreapta.
J;> Pentru parametrii transmii prin valoare, se memoreaz valoarea
transmis, iar pentru cei transmii prin referin se memoreaz adresa
variabilei.
);> n cadrul subprogramului, parametrii transmii i memorai n stiv
sunt variabile. Numele lor este cel din lista parametrilor formali.

n capitolul anterior am studiat proprietile structurii numit stiv. Exact


aceleai proprieti le are i segmentul de stiv. Singura diferen este dat de
faptul c gestiunea segmentului de stiv este fcut automat. Mai exact, codul n
limbaj main, obinut n urma compilrii, conine secvene prin care se
gestioneaz segmentul de stiv.

~ la apelul subprogramului se depun n stiv, n ordine, parametrii transmii.


De asemenea, tot n stiv se rezerv spaiu pentru variabilele locale (cele
declarate n subprogram). Acesta este un prim nivel al stivei.

~ n cazul n care subprogramul se autoapeleaz pe un al doilea nivel, se


depun din nou parametrii transmii i se rezerv un nou spaiu pentru
variabilele locale.

n continuare, prezentm grafic modul n care funcioneaz recursivitatea n


cazul funciei fact a programului anterior. Aceast funcie nu are variabile locale,
deci n stiv se depune doar parametrul n.

La primul apel al funciei fact se creeaz n


segmentul de stiv o variabil numit n, care
reine 3 - valoarea parametrului formal.

Funcia se autoapeleaz. De aceast dat


parametrul n ia valoarea 2. ln stiv se creeaz un
nou nivel, care reine n cu valoarea 2.

Funcia se autoapeleaz. Parametrul n ia valoarea


1. fn stiv se creeaz un nou nivel, care retine
1
n
cu valoarea 1.
vanual de informatic pentru clasa a Xl-a 145

Funcia se autoapeleaz .
Parametrul n ia valoarea
fact=l
o. n stiv se creeaz un nou nivel, care reine n
cu valoarea o. Funcia ia valoarea 1, autoapelul
nu mai are loc. Se revine pe nivelul 3.

-+1
fact=l
Pe nivelul 3 se efectueaz calculul1*1=1.
n .-- Se revine apoi pe nivelul 2.

Pe nivelul 2 se efectueaz calculul 2*1 .. 2.


fact=2
Se revine apoi pe nivelull.

n-+[2]_. Pe nivelull se efectueaz calculul 3*2 6.

..J facl=6
Se revine apoi n ma in ( ) .

Aici se afieaz 6 . adic s-a calculat 3 t .

B) Mai puin eficient, n! se poate calcula i printr-o funcie ca n exemplul urmtor:

:~~ varl~mta Pascal 1 ':t 1!


J!';''
var val,n,p:integer; #include <iostream.h>
procedura fact(val,n:intege r; void fact(int val,int n,int&
var prod:integer); prod)
begin ( if (val<-n)
if val<=n then { prod*aval;
begin fact(val+l,n,prod );
prod:=prod*val;
fact(val+l,n,prod ) }
end;
end; main()
{ int val,n,p l;
begin cout<<"n"; cin>>n;
write (n='); readln(n); fact(l,n,p);
p:=l; c:out<<p;
fact( l,n,p); }
writeln(p);
end.
146 Capitolul 6. Introducere n recursivtate

S analizm i pentru acest exemplu modul n care se efectueaz calculul,


pentru n=3. Funcia are trei parametri: doi transmii prin valoare, unul prin referin.

lat coninutul variabilelor dup primul apel:

Il 1 3 Referin ctre p 1
p
val n prod

Pentru c val este mai mic sau egal ca n se efectueaz: prod=prod*val;.


ntruct variabila p a fost transmis prin referin, programul lucreaz cu aceast
variabil, n loc de prod. n concluzie, se efectueaz p=p*val ; . Apoi, funcia se
autoapeleaz:

2 3. Referin ctre p

1 3 Referin ctre p

p
val n prod

Pentru c val este 2 - mai mic ca 3 - se efectueaz prod=prod*val, dup


care funcia se autoapeleaz.

3 3 Referin ctre p

2 3 Referin ctre p

1 3 Referin ctre p

p val n prod

Pentru c val este 3- mai mic sau egal cu 3- se efectueaz prod-Prod*val, deci p
ia valoarea 6, dup care se revine pe nivelul2, apoi 1, apoi n programul principal.

~'
.' ,1' Observaii

Dup cum rezult din aceste exemple, subprogramullucreaz cu datele aflate


pe un anumit nivel al stivei pentru variabilele transmise prin valoare, variabilele
locale i variabilele transmise prin referin.

Exist posibilitatea ca subprogramul s lucreze direct cu variabilele globale fr


ca acestea s fie transm se prin r!3ferin. Dup cum tim variabilele globale pot fi
accesate din orice subprogram. In exemplu, am preferat varianta de a trece ca
parametru variabila transmis prin referin, att din motive didactice ct i pentru
a asigura independena subprogramului. Dezavantajul este dat de faptul c stiva
va fi ncrcat suplimentar cu adresa acestei variabile.
Manual de informatic pentru clasa a Xl-a 147

./ n cazul unui numr mare de autoapelri, exist posibilitatea ca segmentul


de stiv s depeasc spaiul alocat, caz n care programul se va termina
cu eroare .

./ Recursivitatea presupune mai mult memorie in comparaie cu iterativitatea.

6.4. Cum gndim un algoritm recursiv?

.. Pentru a ne familiariza cu
exemple intuitive.
raionamentul recursiv, vom porni de la cteva

1. Wlrth. O camer de luat vederi are n obiectiv un televizor care transmite


imaginile primite de la camer. Evident, n televizor se va vedea un televizor,
iar n acesta un televizor... , .a.m.d.
Pe scurt, n orice televizor se vede un televizor.
2. Anun. n anumite restaurante am ntlnit anunul: "Azi nu se fumeaza!".
3. Constatare. povestea cu sracul care a prins un petior de aur. Acesta
tii
ii spune omului c daci da drumul l ndeplinete 3 dorine, oricare ar fi ele.
Omul i d drumul, i spune prima dorin, petiorul i-o ndeplinete, i spune
a doua dorin, petiorul i-o ndeplinete. A treia dorin a omului este s i
se indeplineasca 3 dorine ...

Lsnd gluma la o parte, constatm ca, n general, o g~ndire recursiv~


exprim~ concentrat o anumitll stare, care se repeta la Infinit. Aceast g~ndire se
aplic in elaborarea algf!rltmllor recurs/vi, dar cu o modificare esenial: adugarea
cond~lel de terminare. In absena acestei condiii, nu poate fi vorba de algoritm,
ntruct algoritmul trebuie s fie finit.

~ n elaborarea algoritmilor recursiv! se aplic raionamentul: ce se intmpl


la un nivel, se intmpl la orice nivel.
Subprogramul care se autoapeleaz trebuie s conin instruciunile
p corespunztoare unui nivel.

~ Starea tratat de subprogram se gsete pe un anumit nivel al stivei


(variabilele rezultate n urma transmiterii parametrilor i variabilele locale ale
subprogram ului).

~e
e
~~ Observaii

./ Un algoritm recursiv se elaboreaz utiliznd acest tip de gndire, nu o


r gndire precum cea folosit pn acum, cnd am elaborat algoritmi iterativi.
; ./ Pentru orice algoritm recursiv exist unul iterativ care rezolv aceeai
;a problem.
'\J
ra ./ Nu ntotdeauna alegerea unui algoritm recursiv reprezint un avantaj.
./ Numeroasele exemple care urmeaz v vor lmuri asupra celor afirmate.
148 Capitolul 6. Introducere n recursivitate

6.5. Aplicaii recursive

6.5.1. Aplicaii la care se transcrie o formul recursiv

D Aplicaia 6.1. Se citete xe z. Se cere programul pentru calculul funciei:

x -1 , x ;?:12
F(x) ={ F(F(x + 2)),x < 12

0 Rezolvare. Aceast aplicaie a fost tratat iterativ, prin utilizarea stivei. n cazul
tratrii recursive, nu facem altceva dect s transcriem definiia recursiv a funciei.

',,' ' i~,~;i,~~~ry:~


d, 1 ,'t; .vatlantPasc~i
. '
i.!'';r:::~;~ t~ti:!: <'
,;,.. ' ti ,, '
. ,..
:: 1' i
1
i:':~~li:l:,,.
"'' ,,.
"l-W':''rh
varlnta'' c-tilt=i;,' ;!i ::~
' 1 ,,)' "c: .' r 1 , ~ . t}
;; ' .
'( . ~~

var x:integer1 #include <iostream.h>


int XI
function manna
(x:integer):integer; int manna (int X)
begin { if (x>12} return x-11
if x>a12 el se
then manna:=x-1 re turn manna(manna(x+2)};
el se manna:=manna(manna(x+2)) }
end1 main()
begin { cout<<"X"'"I
write('x= ' }l cin>>XI
readln(x) ; cout<<manna(x) ;
writeln(manna(x)} }
end .

n comparaie cu abordarea iterativ, abordarea recursiv prezint avantajul


scrierii concentrate.

O Aplicaia 6.2. Se d funcia de mai jos, definit pe NXN. Se citesc numerele


m i n. S se calculeze Ack (m, n).

n+1, m=O
Ack(m,n)= Ack(m-1,1), n=O
{
Ack(m -1,Ack(m,n -1)), altfel

0 Rezolvare. i aceast aplicaie a fost tratat iterativ, prin utilizarea stivei. n


cazul tratrii recursive, nu facem altceva dect s transcriem definiia recursiv
a funciei.
Algoritmul recursiv nu necesit comentarii.
'~!anual de informatic pentru clasa a Xl-a 149

Varianta .~ascal
var m,n:integer; #include <iostream.h>
int m,n;
function
ack(m,n:integer) :integer; int Ack(int m,int n)
begin { if (lm) return n+1;
if m=O el se
then ack:=n+1 if (In)
el se return Ack(m-1, 1);
if n=O then ack:=ack(m-1,1) el se
el se re turn
ack:=ack(m-l,ack {m,n-1)) Ack(m-1,Ack(m,n -1));
end; }

begin main()
write('m='); readln(m); { cout<<"m"; cin>>m;
write('n='); readln(n); cout<<"n="; cin>>n;
writeln(ack(m,n) ) cout<<Ack(m,n);
end.

n comparaie cu abordarea iterativa, abordarea recursiv prezint avantajul

' scrierii concentrate i acela al scutirii programatorului de un efort suplimentar


n elaborarea algoritmului.

:J Aplicaia 6.3. irul lui Fibonaccl. Se consider irul definit astfel:


o. n=O
U" = 1, n=l
{ altfel
U"_l +U"_z
Se citete n, numr natural. S se calculeze Un.

0 Rezolvare. Funcia fib transcrie definiia recursiv:

r Varianta Pascal .. ,.; ' Varianta.C++


var n:integer; #include <iostream.h>
int n;
function
fib (n:integer):integ er; int fib (int n)
begin { if (In) return O;
if n=O then fib: =O el se
el se if (n==1) return 1;
if n=1 then fib:=1 el se
else fib: =fib(n-1)+fib(n-2 ) return fib(n-1)+fib{n-2 );
end;
begin main()
write('N='); readln(n); { cout<<n"; cin>>n;
writeln ( fib (n) ) cout<<fib(n);
end. }
150 Capitolul 6. Introducere n recursivitate

n aceast situaie, este corect s se foloseasc un program care calculeaz


Un iterativ. S ne imaginm cum funcioneaz aceast funcie.

Pentru calculul lui fib(n) este necesar s se cunoasc fib(n-1) i


fib (n-2). Parametrii acestor funcii sunt depui n stiv. Procedeul continu pn
cnd este calculat fib(n-1), apoi se reia calculul pentru fib(n-2). Acest lucru
este extrem de ineficient pentru valori mari ale lui n (ex. n=lOO). Se calculeaz
u 100 ca sum ntre u 99 i u 98 . Pentru calculul lui u 99 se calculeaz u 9 a i u 97 Dup
ce calculm u 99 , relum calculele pentru uga.

O astfel de recursivitate se numete recursivitate n cascad. Rulai


programul pentru o valoare mai mare a lui n i ... ateptai. Ct de simplu se
rezolv problema iterativ i ct este de rapid aceast metod...

Prezentm varianta iterativ, care nu necesit comentarii.

var n,fO,fl,f2,i:integer; #include <iostream.h>


begin
main()
write('n'); readln(n);
{ int n , fO O,f11,f2;
fO:=O;
cout<<"n"l cin>>n;
fl:=l;
if (In) cout<<fO;
if n=O then writeln(fO)
e l se
el se
if (n==l) cout<<fll
if n=l then writeln(fl)
el se
el se
{ for (int i =2;i<=n;i++)
begin
{ f2=fO+fli
for i:=2 to n do
fO fl;
begin
fl f2I
f2:=f0+fl;
}
fO:=flJ
cout<<f2 J
fl:f2
end;
}
writeln(f2)
end
end.

D Aplicaia 6.4. Se dau dou numere naturale a i b. Se cere s se calculeze cel


mai mare divizor comun al lor.

0 Rezolvare. Utilizm o definiie recursiv a celui mai mare divizor comun pentru
doui:l numere naturale a i b:

a a =b
cmmdc(a,b) = c~mdc(a - b, b),a > b
{
cmmdc(a,b - a),a < b
Manual de informatic pentru clasa a Xl-a 1 51

Aceast definiie este transcris n funcia recursiv cmm.dc:

var a,b:integer; #include <iostream.h>


int a,b;
function
cmmdc (a,b:integer):integer; int cmmdc (int a,int b)
begin { if (a==b} return a;
if amb then cmmdc:=a el se
else if a>b i f (a>b}
then cmmdc:=cmmdc(a-b,b) return cmmdc(a- b,b);
else cmmdc:=cmmdc(a,b-a) else return cmmdc(a,b-a);
end; }
begin
write('a='); readln(a); main()
write('bc'); readln(b); { cout<<"a="; cin>>a;
writeln(cmmdc(a,b)) cout<<"b="; cin>>b;
end . cout<<cmmdc(a,b);
}

Rezolvm aceeai problem iterativ (utiliznd definiia de mai sus):

var a,b:integer; #include <iostream . h>


main()
begin { int a,b;
write(a='); readln(a);
cout<<"a="; cin> >a;
write('b')l readln(b)l cout<<"b ; cin>>b;
while a<>b do while (al b)
if a>b then a:=a-b if (a>b) a=a-b;
else b:=b-a; el se
writeln('cmmdc ',a) cout<<"cmmdc"<<a;
end .

Pentru aceast problem, este Indiferent ce variant de rezolvare se alege.

O Aplicaia 6.5. S se scrie o funcie recursiv pentru a calcula suma cifrelor unui
numr natural.

li::1 Rezolvare. Iniial, prezentm varianta iterativ:

var n,s:integer; #include <iostream.h>


begin main()
write(n~) ; readln(n)l { int n, s=O;
810; cout<<"n"; cin>>n;
while n <> O do begin while (n)
s:=s+n mod 10; { s+=n%10;
n: ~:~n div 10; n/=10 ; }
end; cout<<"s"'"<<s;
writeln( 's=,s)
end.
' Reinem Ideea: se izoleaz ultima cifr, iar lui n i se atribuie ctul ntreg
' dintre vechea valoare i 10. Aceast idee folosete pentru a gsi o relaie de
recuren, necesar elaborrii variantei recursive. Relaiile sunt scrise prin
utilizarea operatorilor din Pascal (stnga) i C++ (dreapta):

0, n=O 0, n=O
S(n) = { S(n) = {
n mod 1O+ S(n div 10), altfel n% 10+S(n 1 10), altfel

Programul de mai jos calculeaz suma utiliznd relaia prezentat:

Varianta Pascal':
var n:integer 1 #include <iostream .h>
int n;
function s(n:inte ger):inte ger;
begin int s(int n)
if n=O then s:=O { if (In) return 01
e l :se s:=n mod 10 + s(n div 10) else return n%10 + s(n/10)1
endt }

begin main()
write('n ='}; readln(n }; { cout<<"n ; cin>>n1
writeln( s(n)) cout<<s (n) 1
end. }

posibilitatea ca un subprogram s~ se autoapeleze prin intermediul altui


Exist~
subprogram. Din moment ce s-a realizat autoapelul, este vorba de recursivitate i
cum acesta nu s-a realizat direct - ca n exemplele anterioare - o astfel de
recursivitate se numete lndlrect.

0 Aplicaia 6.6. Se considera irurile definite recurent astfel: a 0 ...a; b 0 b; a,b>O:

S se scrie un program care s citeasc a, b i n i s se calculeze an i bn.

: Varianta Pascal .
1
';
"''!''
1
.,.
!
:li:l
J 1 varianta c++ \!,,!{:t
' #include <iostream .h>
var a,b:real1 #include <math.h>
nsintege r; double a,b;
function bn(n:int eger):re al; int n;
forward;
function an(n:int eger):re alt double bn ( int n);
begin double an ( int n)
{ i f (In) return a1
if nO
then an:=a el se
el se an:=(an( n-l+bn(n -1))/3 re turn (an(n-l)+ bn(n-1)) /2;
}
end;
I.J.anual de informatic pentru clasa a Xl-a 153

function bn(nzinteger) : real; 1 double bn Cint n}


begin 1 { if (In} return b;
if nO then bn:=b else return
else bn:sqrt(an(n-l)*bn(n-1) sqrt(an(n-1)*bn(n-1));
end; }

main()
begin
{ cout<<"a="; cin>>a;
write('a'); readln(a);
cout<<"b=; cin>>b;
writa('b='}; readln(b};
cout<<"n="; cin>>n;
write('n='} ; readln(n);
cout<<an(n}<< ' '<<bn (n} ;
writeln(an(n ):5:10,' '
}
bn(n) : 5:10)
end.

6.5.2. Aplicaii la care nu dispunem de o formul de


recuren

O Aplicaia 6.7. S se scrie o funcie recursiv care citete caractere i le


afieaz in ordinea invers citirii. Sfritul irului este marcat de caracterul '10".

ltl Rezolvare. Conform principiului, ce se ntmpl la un nivel se ntmpl la orice


nivel, vom gndi funcia recursiv astfel:

se citete un caracter;
dac este diferit de o, se reapeleaz funcia;

se tiprete caracterul.

Raionamentul este suficient pentru a scrie programul.

procedura inv; #include <iostream.h>


var a:char; void inv()
begin { char a; cin>>a;
read(a)J if (al='O') inv();
if a<>'O' then inv; cout<<a;
write(a) }
end;
main()
begin { inv();
inv; cout<<endl;
writeln; }
end.

~ Exerciiu. Modificai programul astfel nct caracterul o - care marcheaz


sfritul irului - s nu fie tiprit.
154 Capitolul 6. Introducere n recursivitate

D Aplicaia 6.8. S se scrie o funcie recursiv pentru a transforma un numr


natural n, din baza 10 n baza k (1<k<10).

0 Rezolvare. S ne amintim algoritmul clasic de trecere din baza 10 n baza k.


Numrul se mparte la k, se reine restul, ctul se mparte la k, se reine restul...
pn cnd ctul este mai mic dect mpritorul. Rezultatul se obine prin scrierea
n ordine invers a resturilor obinute. Practic, tiprirea restului se face dup
autoapel (ca i la problema anterioar).

var n , b:integer; #include <iostream.h>


int n,b;
procedura
transform(n,b:integer); void transform(int n,int b)
var rest:integer; ( int restn%b;
begin if (n>sb) transform(n/b,b);
rest:=n mod b; cout<<rest;
if n>b }
then transform(n div b,b);
write(rest) main()
end; ( cout<<"n"; cin>>n;
cout<<"bazaa"; cin>>b;
begin transform(n, b);
write('n='); readln(n); }
write(baza='); readln(b);
transform(n,b);
writeln;
end.

D Aplicaia 6.9. Se d mulimea {1,2, ... ,n} i se cer toate permutrile acesteia.

Exemplu: pentru n=3 avem:


{3,1,2}, {2,3,1}, {2,1,3}, {3,2,1}, {1,3,2}, {1,2,3).

li'! Rezolvare. n vederea rezolvrii problemei, observm urmtoarele:

mu limea cu un singur element {1} are o singur permutare: {1);

din fiecare permutare a mulimii {1, 2, , n-1} ( ( a1, a:~, , an_1} ), se


obin urmtoarele permutri ale mulimii ( 1, 2, , n):
:a.'lual de informatic pentru clasa a Xl-a 155

r-7 Pentru n=3, privii reprezentarea din 321


_.A:-.
.:-:v; figura alaturata:
21 ~231
213
1
312

Figura 6.1.
Cazul n care nl

Avem n vedere posibilitatea de revenire la situaia iniial : dupa ce am


operat o interschimbare a elementelor ai i a:l, urmata de o reapelare a funciei
pentru valoarea k+l, interschimbam din nou ai cu a:J .

var p: array [1 . 8] of integer1 #include <iostream.h>


n,i:integert int p[lO],nJ
procedura tipar1 void tipar ( )
var i:integer1 { for (int i=l;i<=nJi++)
begin coutp [il 1
for i: =1 ton do write(p[i))J cout<<endl1
writeln )
end1
void permut(int k,int n,
procedura permut(k,n : integer; int p[10))
var p:vector); { int i,o,
var i,j,c:integer; if (kn+l) tipar()/
begin
if k=n+l 1
{ p[k]k;
then tipar for (il;i<kJi++)
el se { cp[i]J
begin p[i]p[k]J
p[k]tk; p[k)CI
for i :=l to k do permut(k+l,n,p);
begin c p[i]J
c:p[i )J p[i] .. p[k]J
p[i):p[k)J p[k)=c;
p [k): =c; }
permut(k+l,n,p)J }
Ct p[i); }
p[i) :p[k) 1
p[k) :c main()
end { cout<<"n="J
end cin>>n;
end; permut (l,n,p);
begin
write('nQ')J readln(n);
permut(l,n,p)
end.
156 Capitolul 6. Introducere n recursivitate

LI Aplicaia 6.10. Algoritmul Fiii. Se d o matrice binar. Valorile 1 delimiteaz


o anumit suprafa nchis n cadrul matricei (elementele aparinnd acestei
suprafee sunt marcate cu o). De asemenea, se dau coordonatele x i yale unui
element al matricei, semnificnd un punct din interiorul acestei suprafee.

$ '...:
' Fie matricea de mai jos:

o 1 1 o
ooo 1
A=
o 1 1 1
1 o o o

Suprafaa nchis este dat de elementele A ( 1, 1), A ( 2, 1) , A ( 2, 2) ,


A(2,3),A(3 , 1).

Considerm coordonatele ( 2, 3) ale unui punct situat n interiorul acestei


suprafee. Dup executarea programului, matricea trebuie s arate astfel:

1 1 o
1 1 1
A=
1 1 1 1
1 o o o

J. Algoritmul se dovedete extrem de util n colorarea unei suprafee nchise


atunci cnd sunt cunoscute coordonatele unui punct situat n interiorul ei.
Acest algoritm este cunoscut i sub denumirea de algoritmul FILL.

0 Rezolvare. Pentru rezolvare se folosete funcia scriu(), care se autoape-


leaz. Iniial,
matricea se bordeaz cu dou linii i dou coloane ce conin elemente
care au valoarea 1. Aceasta are ca scop evitarea testului de ieire din matrice.

Funcia Scriu () funcioneaz astfel:

testeaz dac elementul matricei la care s-a ajuns (de coordonate


(x, y)) are valoarea o;

n caz afirmativ, acesta ia valoarea 1, iar funcia se autoapeleatil


pentru fiecare dintre elementele nvecinate (sus, jos, dreapta, stnga);

n caz contrar, se iese din funcie.

Programul este prezentat n continuare:


Vanual de informati c pentru clasa a Xl-a 157

pr~gram umplere; #include <iostream.h>


var a:matrice: array int a[l.O) [lO),i,j,m,n,x,y;
[0 9,0 9] of integer;
i,j,m, n,x,y:integer; void scriu (int x,int y,
int a[l.OJ[10))
procedura scriu (x,y:integer; { if ( 1a [x] [y] )
var a:matrice); { a[x] [y]=l;
begin scriu(x+1,y,a);
if a[x,yJ=O then scriu (x, y+l., a.) ;
begin scriu(x-1,y,a);
a[x,y]:=l; scriu(x,y-1,a);
scriu(x+l,y,a); }
scriu(x,y+l,a); }
sc:riu(x-1,y,a);
sc:riu(x,y-l,a) main()
end { c:out<<"M="; c:in>>m;
end; cout<<"N="; cin>>n;
for (i=l;i<=m;i+ +)
begin for (:j=l;:i<=n;j++)
write( 0 M= 0 ) ; readln(m); { cout<<"a["<<i<<','
write( 0 N 0 ) ; readln(n) ; <<j<<"l=";
for i:=1 to m do cina[i] [:j];
for :i :=1 t.o n do }
begin
for (i=l; i<=n;i++)
write ( a [ , i, o, , j, ] =o);
{ a(O] [i]=l;
readln(a[i,j])
a[m+1] [il=l;
end;
}
for i:=l to n do
for (i=l;i <~;i+ +)
begin
{ a[i] [O]ml;
a(O,il ;o1;
a(i] [n+l]=l;
a(m+l,i] :=1
end;
for i:=l to m do cout<<"X="; cin>>x;
begin cout<<"Y="; cin>>y;
a[i,O] :=1 ; for (i=l;i<am;i++)
a[i,n+ll: l { for (:j=l;:i<=n;j++)
end; couta[iJ [j];
write( 0 X= 0 ) ; readln(x); cout<<endl;
write( 0 Y= 0 ) ; readln(y); )
for i:l tom do scriu(x,y,a);
bagin cout<<endl<<endl;
for j:=1 ton do for (i=l;i<=m;i++)
write(a[i,:j]); { for (j=l;:i<=n;j++)
writeln couta[i] [j];
end; cout<<endl;
sc:riu(x,y,a); }
writeln; }
writeln;
for i:=l to m do
begin
for j:=l ton do
write(a[i,:j]);
writeln
end
end.
158 Capitolul 6. Introducere n recursivitate

O Aplicaia 6.11. Problema fotografiei (aplicaie Fiii). O fotografie alb-negru


este reprezentat sub forma unei matrice binare. Ea nfieaz unul sau mai multe
obiecte. Poriunile corespunztoare obiectului (sau obiectelor) n matrice au valoarea
"1". Se cere s se determine dac fotografia reprezint unul sau mai multe obiecte.

n matricea urmtoare sunt reprezentate dou obiecte:

A=[t ~ ~ il
iar n matricea de mai jos este reprezentat un singur obiect:

A=[~ !!Il
Ca i n problemele anterioare, pentru a evita testul ieirii din matrice,
aceasta este bordat cu linii i coloane avnd valoarea "o". Algoritmul este tot cel
din problema anterioar (FIII), dar aici cutarea se face pe 8 direcii.
n programul principal se citete matricea i se caut primul element "1"
printre elementele acesteia. Se apeleaz apoi funcia compact< > care are rolul de
a marca cu o toate elementele matricei care aparin acestui prim obiect identificat.
La revenire, se testeaz dac mai exist elemente cu valoarea "1" n matrice. n
caz afirmativ, se poate trage concluzia c n fotografie aveam Iniial mal multe
obiecte (altfel, fotografia coninea un singur obiect) .

, '''ii'
,,JI, ' '
,". . :yarl~nta Pascal
j

var a1 array [0 9,0 9] of #include <iostream.h>


integer; int a[10] [10], i,j,m,n,
i,j,m,n,x,y1integer; x,y,gaeit;
gasit1boolean;
void compact(int x,int y,
procedura compact int a[10] [10])
(x, y1integer; var a1matrice);
{ if (a[x] [y])
begin
{ a[x] [y)O;
if a[x,y]=l then begin
compact(x-1,y,a);
a[x,y]IOt
compact(x-1,y+1,a);
compact(x-l,y,a);
compact(x,y+l,a);
compact(x-l,y+l,a);
compact(x+1,y+1,a);
compact(x,y+l,a)t
compact(x+l,y,a);
compact(x+l,y+l,a);
compact(x+1,y-1,a);
compact(x+l,y,a);
compact(x,y-1,a);
compact(x+1,y-1,a);
compact(x-1,y-1,a);
compact(x,y-l,a);
)
compact(x-1,y-1,a);
}
e nd
end;
.. ..al de informatic pentru clasa a Xl-a 159

Z~egin main()
~ite('M='}; readln(m); { cout<<"M=";cin>>m;
~ite('N='}; readln(n); cout<<"N=";cin>>n;
for i:=l to m do for (i=l;i<=m;i++)
for j:=l ton do for (j=l;j< .. n;:i++)
begin { cout<<"a["<<i<<','
wri te ( 'a [ ' 1 i 1 ' , ' 1 j, ' ] =' ) ; <<:i<<"l=";
readln(a[ilj]) cina[i] [j];
end; }
for i:=l to n do for (i=l;i<=n;i++)
begin { a(O] [i]=O;
a(O,i]:=O; a(m+ll [i]=O;
a(m+l,il :=O; }
end; for (i=l ; i<w.m;i++)
for i:=l to m do { a[i] [0]=0;
begin a[i] (n+ll=O;
a(i,O]:=O; }
a(i,n+l] :0 x=O ;
end; do
x:sO; { X++;
repeat y=O;
x:=x+l; do
y:=O; { y++;
repeat while (y 1=n &:&: a [x] [y] 1=1) ;
y:=y+l }
until (y=n) or (a[x,y]=l) while ((xl.,m) &:&:a[x][y]l=l);
until (x=m) or (a[x,y]l); compact(x,y,a);
compact(x,y,a); gasit=01
gasit:=false; for (i=l;i<=m;i++)
for i:=l tom do for (j=l;:i<=n;:i++)
for j :=l ton do if (a[i] [j]==l) gasit=l;
if a[i,j]=l then if (ga sit)
gasit: .. true; cout<<"mai multe obiecte" ;
if gasit else cout<<"un obiect";
then wri teln ( mai mul t .e }
obiecte)
else writeln( un obiect')
end .

Probleme propuse

1. Calculai recursiv suma a n numere naturale ctite.

2. Calculai recursiv expresiile:

a) 1X2+2X3+ +nx(n+1);
b) 1+1/2+ +1/n;
c) 1/(2X3)+2/(3*4)+ +n/((n+l)(n+2)).
160 Capitolul 6. Introducere n recursivitatE

3. Se citesc n i k (numere naturale n>k). Calculai recursiv C,~, prin utilizarea


formulei de recuren: c,; =
C,~~11 + C,~_ 1 Este eficient?

4. Scriei un program iterativ care rezolv problema anterioar utiliznd aceea


formul.

5. Calculai recursiv C: prin utilizarea formulei:


1, k = O;
c: = n- k + 1 ck - 1
{ altfel.
k "
Comparai timpul de rezolvare cu cel necesar pentru rezolvarea problemei 4.

6. Scriei un subprogram recursiv prin care calculatorul ghicete un numr nature


ascuns de dumneavoastr (numrul este cuprins ntre 1 i 30000). Aturc
cnd calculatorul propune un numr i, se va rspunde prin:
l, dac numrul este prea mare;
2, dac numrul este prea mic;
o, dac numrul a fost ghicit.

7. Scriei un subprogram recursiv care cal culeaz cte cuvinte distincte cu 2r.
caractere se pot forma cu n caractere A i n caractere B.

8. Calculai conform formulei urmtoare valoarea maxim reinut de un vector~


numere naturale cun componente:

V(J], Il = 1;
max(V[l],V[2], ... V[n]) =
{ max(max(VP ], V[2l, ... vrn - 1]), Y[nl) altfel.

9. Se citete un numr natural n . Se cere s se scrie o funcie recursiv ca:


returneaz cea mai mic baz n care se poate considera n.

10. Scriei o funcie recursiv care testeaz dac un numr natural n>l este prirr

11. Scriei o funcie recursiv care returneaz suma elementelor pare ale ur-
vector citit.
Exemplu: Pentru n4 i V= ( 2 1 2 1 s 1 6) , se returneaz 1 o.

12. Scriei o funcie recursiv prin care se testeaz dac un numr natural x s:c
regsete ntre componentele unui vector v cu n numere naturale.

13. Scriei o funcie recu rsiv care primete ca parametri dou numere natura:
i<j i un numr real xe [ i1jl i returneaz [xJ (parte ntreag din x). Nu s;
vor folosi funciile specializate ale limbajului.
::e informatic ntru clasa a Xl-a 161

3.:-ei o funcie recursiv care verific dac un vector cu componente numere


-:este palindrom (afiarea componentelor de la 1 lan coincide cu afiarea
.:.;; a n la 1).

:..: 1eio funcie recursiv care returneaz numrul cifrelor pe care le are un
..:. 'latural primit ca parametru.

Scrieiun subprogram recursiv care afieaz, cifr cu cifr, oglinditul unui


a natural.
plu: pentru n=123, se afieaz 321.

3-:tiei un subprogram recursiv care returneaz , oglinditul unui numr natural.

~~plu: pentru n=123, se returneaz 321.

S criei o funcie recursiv care testeaz dac un vector cu n numere naturale


-e numai valori distincte, caz n care funcia returneaz true, iar n caz contrar,
..,... eaz false.

Scriei un subprogram recursiv care descompune n toate modurile posibile un


r natural n n dou numere n 1 i nl, n 1~l a cror sum este n.

Pentru un vector cu n componente o sau 1 care are semnificaia de numr


, se cere s se scrie o funcie recursiv care afieaz numrul n baza 10.

E:lemplu: pentru n=4 i V= ( 1011 >, se va returna 11.


2 . Sc riei o funcie recursiv care afieaz valoarea unui polinom n punctul a.
::veficienii polinomului sunt dai ntr-un vector. Astfel, pentru V= ( 1, 2, 3 > avem
:o nomul P=xl +2x+3.
22. Fie funcia definit pe N.XN. Se citesc n i k. Se cere s se scrie o funcie
-ecursiv care evalueaz funcia:

O, k>n
S(n,k)== 1, kE {l,n}
{S(n -1 , k - 1) + kS(n - 1, k) 1< k< n

23. Cal cu lai s (n, k) nerecursiv.

24. Calculai recursiv i nerecursiv funcia definit pe N*XN:

0, k ==O sau k > n;


F(n, k) == 1 k == n;
{
F(n -l ,k -1) - nF(n - l,k) 1 < k < n.

Comparai eficiena celor dou moduri de calcul.


162 Capitolul 6. Introducere n recursivitate

25. S se calculeze recursiv i nerecursiv P (n, k), definit pe NXN:

P(n+k,k)=P(n,l) +P(n,2)+ +P(n,k), dac l<k<n;


P(n,k)=l, dac k=zl sau k=n;
P(n,k)=O,dac k>n.

26. Calculai iterativ i recursiv cel mai mare divizor comun pentru dou numere
naturale m i n, utiliznd algoritmul lui Euclid:

cmmdc(nrnmodn), n*O d ( ) { cmmdc(nrn%n), n;t;O


cmm dc (m11 ) =
{ m, cmm c mn =
n=O m, n=O
Pascal C++

27. Ce se afieaz la: wri teln ( t ( 12) ) ; 1 cout <<t ( 12) ; ?

function t(n:integer):inte ger; int t(int n)


begin { if (n) return lO*t(n/10)+
if n<>O then t:10*t(n div 10) n%10;
+(n mod 10) else return O;
else t:=O; }

a) 12;
b) 21;
c) eroare de executare;
d) o.
28. Ce calculeaz funcia urmtoare?

Varianta Pasc~l

fl,lnction
begin
if n<>O then return (n%2=0)*n +t(n-1);
t:ord(n mod 2=0)*n+t(n-1) elae return O;
else t: O; }
end;

a) suma primelor n numere naturale impare;


b) suma primelor n numere naturale pare;
c) suma numerelor naturale pare strict mai mici dect n;
d) suma numerelor naturale pare mai mici sau egale cu n.
informatic pentru clasa a Xl-a 163
.:ual de

~ Pentru care dintre numerele de mai jos, care sunt parametri de intrare pentru
:cia urmtoare, ultimele 2 numere afiate vor fi o?

~rocedure t(n:inte ger); void t(int n)


~gin { if (n>15)
if n>lS then { t(n/16) ;
begin cout<<n %16<<e ndl;
t(n div 16); }
writeln (n mod 16) else cout<<n <<endl;
end }
else writeln (n);
end;

~} 295;
~) 1024;
:. ) 1000;
:. ) 10000.

- estele de la 30 la 33 se refer la funcia de mai jos, unde Vl i v2 sunt vectori


;u n componente numere naturale:

t ciM'I_,t,, '_' ' '' c'' ':t ~'"''~


Varianta ++ .,. ,
, 1.
1 IH ~.t:1 .,

procedu ra t(n,i,js intege r); void t(int n, int i, int j)


begin { if (i<n && j<n)
if (i<=n) and (j<n) then { i f (Vl[iJ <V2 [jJ)
begin cout<<V l[i++l<< " "1
if Vl[iJ<V 2[jJ then else cout<<V Z(j++J<< w "1
begin t(n,i,j );
write (Vl(i], ' '); }
isi+l }
end
el se 11 Vl si V2 contin date
begin 11 incepan d cu indicel e 1
write (V2[j), ' ');
j :j+l
end;
t(n,i,j );
end;
end;

i v2 .. (4,5,1) ce se afieaz la
30. Dac n este egal cu 3, Vl:o(l, 2,3)
apelul t (n, 1, 1)?

a) 1 2 3;
b) 1 4 2 5 3 1;
c) cerina nu este corect;
d) 4 5 1.
164 Capitolul 6. Introducer e n recursivitate

31. Care dintre afirmaiile de mai jos sunt corecte dac n este 3 i apelul este
t(n,1,1) ?

a)

ntotdeauna se vor afia cel mult 6 numere;
b) ntotdeauna se vor afia cel puin 3 numere;
c) ntotdeauna se vor afi a cel mult 3 numere;
d) ntotdeauna se vor afia cel puin 6 numere.

32. Dac n este 3, pentru care din datele de mai jos se afieaz un numr maxirr
de valori distincte, dac apelul este t ( n, 1, 1)?

a) V1=(1,2 ,8) i V2:::o(4,5 ,6);


b) V1 .. (1,2,5) i V2 =(4 , 5 , 6 ) ;
c) V1=(4 ,5 ,6) i V2=(1,2 ,3);
d) V1=(1,2 ,3) i V2=(4,5 ,6).

33. Ce va afia funcia la apelul t(1,1,n) dac n=3, V1=(1,2 ,3)


V2=(4,5 ,6)?

a) 1 2 3; b) 1 2 3 4 5 6;
c) 4 5 6; d) nici o valoare.

Testele de la 34 la 36 se refer la programul u rmtor:

. .,.J ';.,, Varianta ~ascal ,,,


type vector=a rray[1 10] of #include <iostream .h>
integerJ int m, n,i , V[20];
var m,n,i:in teger;
V:veotor ; void b(int k, int n)
{ i f (n)
procedur a b(k,n:in teger); { b(k+l,n/ 2);
begin if (n%2) cout<<V[ k]<<endl;
if n<>O then }
begin }
b(k+l,n div 2);
if n mod 2=1 then main()
writeln( V[k]);; { int i,n;
end c in>>n;
end; for (il;i<un ;i++)
cinV[i );
begin
cin>>m;
readln (n) ;
b(l,m) 1
for i : =l ton do readln(V (i]);
}
readln (m);b(l,m );
end.

34. Dac n=4, V= ( 1, 2, 3, 4) i m=2, ce afieaz programul?


a) 4; b) 3; c) 2; d) 1.
nual de i nformatic pentru clasa a Xl- a 165

. Dac n=4, pentru care dintre valorile de mai jos ale lui m se afieaz dou

ori?

b) 3; c) 2; d) 1.

pentru care valoare a lui m se afieaz toate cele 4 valori ale

b) 16; c) o; d) Nu exist o astfel de valoare.

37. n funcia de mai jos nlocuii linia cu una dintre instruciunile urmtoare,
11

11

astfel nct funcia s-i ncheie execuia fr eroare pentru orice valoare admisibil
a argumentului:

Varianta Pascal
x(n:inte ger):inte gerl int x(int n)
begin {
if n<>O then if (n)
begin (
writeln( n); cout<<n1

end }
end; }

a) x:=x(n-2 ) ; a) re turn x(n-2) ;


b) x:=x(n mod 2); b) re turn x(n%2);
o) x:=x(n-1 ); c) re turn x(n-1);
d) x:=x(n div 2). d) re turn x{n/2).

Testele 38 i 39 se refer la funcia de mai jos:


.,...,.....
Varianta Pascal , ,
1
Varianta C++
'
function an(n:int eger):in teger; int an(int n)
begin {
if n=O then an: =l if (n==O) re turn 1;
e lse an:=3*an (n-1)+7 else return 3*an(n-1 )+7;
end; }

38. Dac funcia este apelat prin an< 4), de cte ori se autoapeleaz?

a) de 4 ori; b) de 3 ori; c) de s ori; d) depinde de stiv.

39. Pentru care dintre valorile de rnai jos, care sunt parametri de intrare pentru
funcia an, executarea funciei se termin cu eroare?

a) o; b) -1; C) 1; d) ~ici una dintre valorile de mai sus.


166 Capitolul 6. Introducere n recurslvi tatE

40. Pentru programul de mai jos, de cte ori se autoapeleaz funcia an?
..
'!<
;pf Varianta
. .r.
~

Pascal
. . . ~1; 1 :
- o
' - ti
" ~<' .
~: ,:. ;.1~"'
h ~~. ' ~' .~:~,,,; V~rianta:.~t:+ ~!:: ,,,!;~ .,..
functio n an(n:in teger):i nteger; #includ e <iostrea m.h>
begin int an( int n)
i f n=O then an:=2 { if (n==O) re turn 2;
el se el se
if n=l then an:=-1 if (n1) re turn 1;
el se an:=an( n-1)-an (n-2)+1 el se
end; re turn an(n-1) -an(n-2 )+1;
}
begin
writeln (an(4)) ; main()
end. { cout<<a n(4); }

a) de 8 ori; b) de 4 ori; c) de 9 ori; d) de 2 ori.

Indicaii / Rezolvri

Sn = {0, dacan = O
Sn_1 +n, altfel

7. Exist (2n) 1 permutri ale literelor. ntruct pentru fiecare permutare nu


conteaz dac s-a inversat A cu A, (2n) 1 se mparte la ni. Pentru c nu
conteaz dac s-a inversat B cu B <2n) 1 , se mparte din nou la
n 1. Se obine:

(2n) =C"
n:n.
' ' 211
8.
,,. .
ifil~:' ::~~~
.... ,::~.
1 1 -::-
Varianta Pascal V~r,lanta C++ ' -, c ;
' ' ',

functio n int Maxim( int n)


Maxim( n:intege r):integ er; { int max;
var max:int eger; i f (nal) return V[l];
begin el se
if n=l then Maxim:= V(1] { maxMa xim(n-1) ;
el se begin if (max<V[ n]) return V [n] ;
max:M axim(n-1 ); else return max;
if max<V(n ] then }
Maxim: V[n] }
el se Maxim:a max;
end;
end;
- jal de informatic pentru clasa a Xl-a 167

Se calculeaz cifra maxim a numrului i se adun 1.

De exemp\u, 'unc\\a oe mai ios se ape\eaz. -exi:m\n, 1.) .

,.tft'; Varianta Pascal \ :::.?:~-)~


function int Prim(int n,int i)
Prim(n,i:i nteger):bo olean; { if (i> (int) (sqrt(n)+~))
bag-in return 1;
if i>trunc(sq rt(n))+l el se
then Prim:=true if (n%i==O) return O;
else else return Prim(n,i+ l);
if n mod i=O }

1 then Prim:=fals e
else Prim:Prim (n,i+l);
end;
1

11.

function int Suma(int n)


Suma(n:in teger):inte ger; { if (nO) return O;
begin else return Suma(n-1)+
if nO (V[n]%20 )*V[n);
then sumas .. o }
else SumasSUm a(n-1)+
ord(V[n) mod 2=0)*V[n];
end;

12.

:.io '. 'ili'tl,,;~::i!


~ ., <::: ' ' ~f;~'\~~1' '... 1ant.a
'Var '' .ijl,'e ::t+,
't, .. '' 1" :',,, ., r~
1jr
' . ar anta..,'
t:i''I'IW 't'V 1 ~' lo' '
'il!l!!!l'
1iii!l' Pascal !1
'lF' ' ,,, .' ~,;' 11 " :t.rll
function int A.partine( int n, int X)
Apartine(n ,x1integer )1boolean; { if (n==O) return O;
begin el se
if n=O i f (V[nl==x) ret urn 1;
then el se
A.partiner false return A.partine( n-l,x);
el se )
i f V[n)=x
then A.partine:= true
el se
Apartiner Apartine(n -l,x);
end;
168 Capitolul 6. Introducere n recursivitate

13. Este clasicul algoritm de cutare binar.

function int P:tnt ( int i,. int j, float x)


Prnt(i,j:integor;x:real):integer; { i nt Mijloc;
var Mijloc:integer; if (j-i>l)
begin { Mijloc=(i+j)/2;
i f j-i>1 if (x==Mijloc)
then return Mijloc;
begin el se
Mijloc:=(i+j) div 2; if (x<Mijloc:)
if x=Mijloc return
then Pint:=Mijloc Prnt(i,Mijloc:,x);
else el se
if x<~l.lij loc then PZnt(Mijloc:,j,x);
Pint:~Pint(i,Mijloc,x) }
else Pint:=Pint(Mijloc,j,x) else return i;
end }
else Pint:i
end;

14. Iniial, se apeleaz cu Palindrom ( 1, n):

function
Palindrom(i,j:integer):boolean;
begin (i>=:ll roturn 1;
if i>=j eloo
then Palindrom:=true if (V[i] I=V[j]) return O;
el se else return
if V[i] <>V[j] Palindrom(i+1,j-1);
then Palindrom:=false }
else Palindrom:=
Palindrom(i+1,j-1);
end;

15.

func:tion Nrc:if (n:longint): int Nrcif(long n)


integer; { if (n<10) return 1;
begin else return Nrc:if(n/10)+1;
if n<10 }
then Nrc:if:=l
el se Nrcif: =NrCif (n div 10) +1;
end;
::!e i nformatic ntru clasa a Xl-a 169

~edure Oglinda (n:integ er); void Oglinda (int n)


vin { i f (n)
_f n<>O then { cout<<n% 10;
begin Oglinda (n/10);
write(n mod 10); }
Og1inda (n div 10); }
end;
rod;

- Variabila ninv, transmis prin referin, trebuie s rein, iniial, o.

~rocedure Oglinda (n:integ er; void Oglinda (int n, int& ninv)


var ninvzin teger); { if (n)
begin ( ninv=nin v*10+n% 10;
if n<>O then Oglinda (n/10,n inv);
begin }
ninvz~ninv*10+nmod 10; }
Oglinda (n div 10, ninv);
end;
end;

18. Funcia se apeleaz cu Distin cte (l,n):

1 ~ 1
Varianta Pascal ,
'.
, ''' ' .. ,. Varlanta C++ il
funotio n int Distinc te(int i,int n)
Distinc te(i,nzi nteger) zboolea n; { int gasit,j ;
var gasit:bo olean; if (i=n) return 1;
j:integ er; el se
begin { gasit=O ;
if i=n for (ji+1;j <=nJj++ )
then Distinc teztrue if (V[il ==V[j)) gasit=l ;
el se if (gasit) return O;
begin e lse return
gasitz false; Distinc te(i+1, n);
for jzi+1 ton do )
i f V[i] =V[j] }
then gasit:= true;
if gasit
then Distinc te:=fals e
else Distinc te:=
Distinc te(i+1,n );
end
end;
170 ' Capitolul 6. Introducere n recursivita te:

19. Apelai cu Descomp un ( 1, n) :

procedur a Descomp un(i,n:in teger); void Descomp un(int i,int n)


begin { if (i<=n/2)
if i<= n div 2 then { cout<<i<< " "<<n-i<< endll
begin Descomp un(i+l,n) t
writeln (i, ' ', n-i); }
Descomp un(i+l,n) t }
end
end1

20. Apelai cu Refac (n, n):

function int Refac(in t i,int n)


Refac(i, n:intege r):intege r; { if (iael) return V[l];
begin el se
if i=l then Refac :=V[l] return 2*Refac( i-1,n)+V [i]1
el se }
Refac:=2 *Refac(i -l,n)+V[i ];
endt

21 . Apelai cu Valoare (n,n, a) :

. ,, ' !1 d ' 1'1' 'j! + .,


i!V.~rlanta C+ofl ;.' .
function int Valoare ( int i, int n, int a)
Valoare( i,n,azint eger) zintegert { if (il) r e turn V[i];
begin else return a*Valoar e(i-1,
if il then Valoare:= V[l] n,a)+V[i ]J
else Valoare: =a*Valo are(i-1, }
n,a)+V[i ]J
endt

22. Este Ineficient s calculm recursiv.

23. S presupunem c avem de calculat s ( 8, s) . Mai nti calculm:

S(l,l) l, S(1,2)0 , S(1,3)0 , , S(1,8)0.Urmeaz:

8(2 , 1)1, S(2,2) l,S(2,3) 0, , 8(2,8)0


8(3,1)1 , 8(3,2)8 (211)+2 8(2,2)3 , 8(3,3)1 , 8(3,4)0 ,
8(4,1)1 , 8(4,2)8 (3,1)+2 8(3,2)7 ,

Cu excepia primei linii 8 <1,x), pentru calculul elementelor de pe linia i, s (i,k) ,


se:folosesc rezultatele aflte pe linia .i-1, adic 8 (i-1 , x).
~tan ual de informati( pentru clasa a Xl-a 171

.!S. n cazul n care k<n, avem:


P(n,k)=P (n-k+k,k )=P(n-k ,l)+P(n- k,2)+ +P(n-k,k ).

function int P(int n,int k)


P(n,k:in teger):in teger; { int i,s=O;
var i,s:integ er; if (k>n) return O;
begin el se
if k>n then PzO if (ksl 11 kn) return 1;
el se el se
if (k1) or (kn) { for Ci1;i<n -k;i++)
then Ptl s+=P(n-k ,i);
el se return s;
begin }
szO; }
for izl to n-k do
s:s+P(n -k,i);
P:=s;
end
end;

27. a); 28. d); 29. b); 30. a); 31. a), b); 32. a); 33. d);

34. c); 35. b); 36. a); 37.d);

38. a) ; 39. b) ;
40. a) Autoapelurile se efectueaz dup schema de mai jos:

Figura 6.2. Exemplu

Acum, vedei "pe viu" motivul pentru care, n cazul unor astfel de formule de
recuren, n care, n expresie, intervin mal muli operanzi ce se calculeaz
.
recursiv, este de preferat metoda iterativ.
Capitolul 7
Metoda DIVIDE ET IMPERA

7.1 . Prezentare genera l

DIVIDE ET IMPERA este o tehnic special i se bazeaz pe un principiu


extrem de simplu: descompunem problema n dou sau mai multe subprobleme
(mai uoare}, care se rezolv, Iar soluia pentru problema iniial se obine
combinnd sol uiile problemelor n care a fost descompus. Se presupune c
fiecare dintre problemele n care a fost descompus problema iniial, se poate
descompune n alte subprobleme, la fel cum a fost descompus problema iniial .
Procedeul se reia pn cnd (n urma descompuneril or repetate) se ajunge la
probleme care admit rezolvare imediat.

Evident, nu toate problemele pot fi rezolvate prin utilizarea acestei tehnici.


Fr teama de a grei, putem afirma c numrul lor este relativ mic, tocmai datorit
cerinei ca problema s admit o descompunere repetat.

DIVIDE ET IMPERA este o tehnic ce admite o implementare recursiv. Am


nvat principiul general prin care se elaboreaz algoritmii recursiv!: ce se ntmpl
la un nivel, se ntmpl fa orice nivel (avnd grij s asigurm condiiile de
terminare). Tot aa, se elaboreaz un algoritm prin DIVIDE ET IMPERA. La un anumit
nivel, avem dou posibiliti:

1) am ajuns la o problem care admite o rezolvare imediat, caz n care se


rezolv i se revine din apel (condiia de terminare);

2) nu am ajuns n situaia de la punctul 1, caz n care descompunem problema n


dou sau mai multe subprobleme, pentru fiecare din ele reapelm funcia,
combinm rezultatele i revenim din apel.

7.2. Aplicaii

7.2.1. Valoarea maxim dintr-un vector

O Problema 7.1. Se citete un vector cu n componente, numere naturale. Se


cere s se tipreasc valoarea maxim.

Problema de mai sus este binecunoscut. Cum o rezolvm utiliznd tehnica


DIVIDE ET IMPERA?
~ - u al de informatic pentru clasa a Xl-a 173

:;' Rezolvare. Trebuie tiprit valoarea maxim dintre numerele reinute n vector de
~:.. la j (iniial i=l i j =n).

Pentru aceasta, procedm astfel:

dac i=j, valoarea maxim va fi v[iJ;

contrar, vom mpri vectorul n doi vectori (primul vector va conine


componentele de la i la ( i+j) div 2, al doilea va conine componentele
de la (i+j) div 2 + 1 la j, rezolvm subproblemele (aflm maximul
pentru fiecare din ele) iar soluia problemei va fi dat de valoarea maxim
dintre rezultatele celor dou subprobleme.

=-ogramul este urmtorul:

var v:array[1 . 10) of #include <iostream.h>


integer; int v[lO] ,n;
n,i:integer;
int max(int i,int j)
funotion max(i,j:integer) { int a,b;
:integer; if (i==j ) return v[i);
var a,b:integer; el se
begin { ammax(i, (i+j)/2);
i f ij b~((i+j)/2+1,j);
then max: cov(i) if (a>b) return a;
el se else return b;
begin }
a:max(i,(i+j) div 2); }
b:max((i+j) div 2+1,j);
if a>b main()
then max:=a { oout<<"n="; oin>>n;
else max:=b; for (int i=l;i<n;i++)
end; { cout<<"v["<<i<<")a";
end; oinv[i] 1
}
begin
cout<<"max="<<max(l,n);
wri te ( 'n= ) ; }
readln(n) 1
for i:l to n do
begin
wri te ( 'v [ ' , i , ' ) =' ) 1
readln(v[iJ)
end;
writeln( 'max' ,max(l,n))
end.

1 Algoritmul prezentat este exclusiv didactic, n practic este preferat


f:~ algoritmul clasic . .
174 Capitolul 7. Metoda DIVIDE ET IMPER.A

7.2.2. Sortarea prin interclasare

O Problem a 7.2. Se consider vectorul a cu n componente numere ntregi (sa_


reale). S se sorteze cresctor, utiliznd sortarea prin interclasare.

Interclasarea a doi vectori a fost studiat. Dac dispunem de dou iruri


de
valori, primul cu m elemente, al doilea cu n elemente, ambele sortate,
atunci se
poate obine un vector care coni ne toate valorile sortate. Algoritmul de
interclasare
este performant, pentru c efectueaz cel mult m+n-1 comparri.

n cele ce urmeaz, vom utiliza algoritmul de interclasare n vederea sortr


unui vector prin interclasare.

li:1 Rezolvare. Algoritmul de sortare prin interclasare se bazeaz pe urmtoarea


idee: pentru a sorta un vector cun elemente l mprim n doi vectori
care, oda~
sortai , se interclaseaz.

Conform strategiei generale DIVIDE ET IMPERA, problema este descompus


~
alte dou subprobleme de acelai tip i, dup rezolvarea lor, rezultatele
se combi~
(n particular se interclaseaz). Descompunerea unui vector n ali doi
vectori car:
urmeaz a fi sortai are loc pn cnd avem de sortat
vectori de una sa_
dou componente.

n aplicaie, funcia sort sorteaz un vector cu maximum dou element


e
intero interclaseaz rezultatele; divimp implementeaz strategia
general '
metodei studiate.

type vector~array [1 10) of #includ e <iostre am.h>


integer 1
int a[lO] , n;
var aiVOCt Orl
n,izin teger1 void sort(in t p,int q,
int a[l0])
proced ura sort(p ,q : intege rJ {
var a:vecto r) l int m1
i f (a[p]>a [q])
var msinte ger; { m=a[Pl l
begin a[pJ=a [q];
i f a [p) >a [q) a[q)=m ,
then }
begin }
m: a[p) J
a[p]: ..a[q]l void interc (int p,int q,
a[q]:-m int m, int a[10))
end { int b[lO] ,i,j,kl
end1 i=pJ j=m+lJ k ml1

---
---
-----~
1.4anual de informatic pentru clasa a Xl-a 175

procedura interc while (i<=m && j<=q)


(p,q,m:integ er; var a:vector); if (a(i] <=a[j])
{ b[k]ca[i];
var b:vector;
i=i+l;
i,j,k:intege r;
k=k+l;
begin }
i:ap; j:=m+l; k : =l; el se
while (i<=m) and (j<=q) do { b(k]a[j];
if a[il<=a[j] then j=j+l ;
begin k=k+l;
b[k):aa[i); }
i:=i+l; k:k+l if (i<=m.)
end for (j=i;j<cm;j++ )
el se { b[k]=a[j] ;
begin k=k+l;
b[k]:=a[j]; }
j:=j+l; k:=k+l el se
end;
for (i=j;j< q;j++)
if i<=m. then { b[k]=a[i);
for j:=i tom do
begin k=k+l;
}
b[k] :a[j}; k:ak+l
end
k l ;
el se for (i=p;i<q;i++ )
for i: j to q do { a[i]=b[k];
begin kk+l;
b[k) :a(i]; k:k+l
end; }
k:l;
for i:=p to q do void divimp (int p,int q,
begin int a [10])
a(i]:=b(k); k: k+l { int m;
end if ((q-p)<l ) sort(p,q,a);
end; el se
{ m(p+q)/2 ;
procedura divimp divimp(p,m,a ) ;
(p,q:integer; var a:vector); divimp(m+l ,q,a);
var m.:integer; interc(p,q,m ,a);
begin }
if (q-p)<l then sort(p,q,a) }
el se
begin
main()
m:=(p+q) div 2;
{ int i;
divimp(p,m,a );
cout<<"n "; cin>>n;
divimp(m+l,q ,a);
interc(p,q,m ,a) for (i=l;i<n;i++ )
end { cout<<"a["<< i<<"l";
end; cina[i] 1
}
begin divimp(l,n,a );
write('n'); readln(n); for (i=l ; i <n;i++)
for i:=l to n do cout<<a[i]<< " " ;
begin }
write('a[,i , ']=') ;
readln(a[i))
end;
divimp(l,n,a );
for i:=l ton do writeln(a(i] )
end.

-
- . ~~~~~~
176 Capitolul 7. Metoda D IVIDE fT IMPERJ.

n continuare, calculm numrul aproximativ de comparri efectuat de


algoritm . Fie acesta T (n). Mai simplu, presupunem n=2k.

O problem se descompune n alte dou probleme, fiecare cu n /2


componente, dup care urmeaz interclasarea lor, care necesit n/2+n/2=n
comparaii:

Avem:
T(n) = T(2k) = 2(T(2k-l) + 2k-l ) = 2T(2k-l) + 2k =2T(2k- 2 + 2k-l ) + 2k =
2
2T(2k- )+2k +2k =...2k +2k + ... +2k =n+n+ ... +n =n k =n log 2n
'------v--'
dekori de kori

7.2.3. Sortarea rapid

O Problema 7.3. Fie vectorul a cun componente numere ntregi (sau reale). Se
cere ca vectorul s fie sortat cresctor.

0 Rezolvare. Este necesar o funcie POZ care trateaz o poriune din vector
cuprins ntre indicii dai de l i (limita inferioar) i ls (limita superioar) . Rolt.
acestei funcii este de a poziiona prima component a [li] pe o poziie k cuprins.1
ntre l i i ls, astfel nct toate componentele vectorului cuprinse ntre l i i k-l
s fie mai mici sau egale dect a [kl i toate componentele vectorului cuprinse
ntre k+1 i ls s fie mai mari sau egale d~ct a [k).

n aceast funcie exist dou moduri de lucru:

a) i rmne constant, j scade cu 1;


b) i crete cu 1, j rmne constant.

Funcia este conceput astfel:


iniial, iva lua valoarea li, iar j va lua valoarea ls (elementul care iniia
se afl pe poziia l i se va gsi mereu pe o poziie dat de i sau de j );
se trece n modul de lucru a);
att timp ct i<j, se execut:
dac a [il este strict mai mare dect a [j l, atunci se inverseaz
cele dou
rumere i se schimb modul de lucru;
i i j se modific corespunztor modului de lucru n care se afl
programul;
k ia valoarea comun a lui i i j.
E!.nual de informatic pentru clasa a Xl-a 177

Ex: Pentru a= ( 6, 9,3,1,2), li=l, ls=5; modul de lucru a):

i=l, j=S;
a[1 J >a [S], deci se inverseaz elementele aflate pe poziiile 1 i 5,
deci a= ( 2, 9, 3, 1, 6) i programul trece la modul de lucru b) ;
i =2 , j=5;
a [21 >a [51, deci a= (2,6 ,3, 1,9) i se revine la modul de lucru a);
i=2, j=4;
a [ 2 1 >a ( 4], deci a= ( 2, 1, 3, 6, 9); se trece la modul de lucru b );
ic:3, j=4;
funcia se ncheie, elementul aflat iniial pe poziia 1 se gsete
acum pe poziia 4, toate elementele din stnga lui fiind mai mici
dect el, totodat toate elementele din dreapta lui fiind mai mari
dect el (k=4).

modurilor de lucru se explic prin faptul c elementul care trebuie


Alternana
se compar cu un element aflat n dreapta sau n stnga lui, ceea ce
poziionat
mpune o modificare corespunztoare a indicilor i i j.

f Dup aplicarea funciei POZ, este evident c elementul care se afl iniial n
poziia l i va ajunge pe o poziie k i va rmne pe acea poziie n cadru l
vectorului deja sortat, fapt care reprezint esena algoritmului.

Funcia QUICK are parametrii l i i ls (limita inferioar i limita superioar).


n cadrul ei se utilizeaz metoda DIVIDE ET IMPERA, dup cum urmeaz:

se apeleaz Poz ;
se apeleaz QUICK pentru l i i k-1 ;
se ape l eaz QUICK pentru k+l i ls.

l'
Varianta Pascal
type vector=array [1 .. 100] of #include <iostream.h>
integer; int a[100],n,k;
void poz (int li,int ls,int&
var i,n,k:into ger;
k,int a[100])
a :veotor;
{ int i=li,:l=ls,c,i1=0,~1=-1;
procedura poz (li,ls:integer; while (i<:l)
var k:integ er; { if (a[i]>a(j])
va.r a:vector); { c=a (j]; a[j]=a[i];
a[il=c; c=il;
var i,j,c,i1,j1:integ er; i1=-:11; :11=-c;
begin }
i=i+il;
i1:=0; :1=:1+:11;
jl:=-1; }
i:=li; k=i;
j:=ls; }
178 Capitolul 7. Metoda DIVIDE ET IMPERA

while i<j do
void quick (int li,int ls)
begin { if (li<ls)
i f a[i] >a[j]
{ poz(li,ls,k,a);
then
quick(li,k-1);
begin
quick(k+l,ls);
c:=a[j]; }
a [ j] : a [ i] ; }
a [il :=c;
CJil; main()
il:=-jl; { int i;
jlJ-c cout<<"n="; ein>>n;
end~
for (il;i<n;i++)
i:=i+il;
{ eout<<"a["<<i<<"l";
j:j+jl
cina[i];
end; }
k:=i
quick(l,n);
end;
for (il;i<n;i++)
procedura quick(li,ls:integer); cout<<a[i)<<endl;
begin }
if li<ls
then
begin
poz(li,ls,k,a);
quick(li,k-1);
quick(k+l,ls)
end
end;
bagin
write( 'n');
readln(n) 1
for i:l to n do
bagin
write(a[,i,]');
readln(a[i])
end;
quick(l,n); ..,.
for i:l to n do
writeln(a[i])
end.

~~$1 Reinei! Sortarea rapid efectueaz n medie n log 2n operaii.


~ Demonstraia necesit cunotine de matematic pe care nu le avei la nivelul
acestui an de studiu ...
tJtanual de informatic pentru clasa a Xl-a 179

- .2.4. Turnurile din Hanoi

:J Problema 7.4. Se dau 3 tije simbolizate prin a, b, c.


::e tija a se gsesc discuri de diametre diferite, aezate
., ordine descresctoare a diametrelor privite de jos n
sus. Se cere s se mute discurile de pe tija a pe tija b , utiliznd ca tij intermediar
1a c, respectnd urmtoarele reguli:

la fiecare pas se mut un singur disc;

nu este perm is s se aeze un disc cu diametru! mal mare peste un disc


cu diametru! mai mic.

~ Rezolvare.
Dac n=1, se face mutarea ab, adic se mut discul de pe tija a pe tija b.

Dac n=2 , se fac mutrile ac, ab, cb.

n cazul n care n>2, problema se complic. Notm cu H (n, a, b, o) irul


mutrilor celor n discuri de pe tija a pe tija b, utiliznd ca tij intermedi ar , tija c .

Conform strategiei DIVIDE ET IMPERA, ncercm s descompunem problema


n alte dou subprobleme de acelai tip, urmnd apoi combinarea s~luillor. n
acest sens, observm c mutarea celor n discuri de pe tija a pe tija b, utili~nd ca
tij intermed i ar tija c, este echivalent cu:

- mutarea a n-1 discuri de pe tlja a pe tija c, utiliznd ca tij Intermediar tija b;


- mutarea discului rmas pe tija b;
- mutarea a n-1 discuri de pe tija c pe tija b , utiliznd ca tij intermediar tija a .

Parcurgerea celor trei etape permite definirea recursiv a irulu i


H(n,a,b,c) astfel:

ab, n= 1
H(n,a,b,c) ={ H(n - 1,a,c,b),ab,H(n - 1, c, b, a), n >1

/!.x: Privii urmtoarele exemple:


1} pentru n=2, avem: B(2, a, b, c) =H(1,a, c, b), ab,H( 1, c, b, a) =ac , ab, cb;

2) pentru n=3, avem:


B(3,a,b,c)aH(2,a,c,b), ab,H{2,c, b,a)=H(1 ,a,b, c),ac,B(1,b,c , a),
ab,H(1,c,a,b),cb,H{1,a ,b,c)=ab,ac,bc,ao,ca,c b,ab.
180 Capitolul 7. Metoda DIVIDE ET IMPERA

var a,b,c:char; #include <iostream . h>


n:integor; char a,b,c;
procedura han (n:integer; int n;
a,b,c:char);
begin void han (int n , char a,
if n=l then char b,char c)
writoln(a,b) { if (n==l) cout<<a<<b<<endl;
el se el se
begin { han(n-l,a,c,b);
han{n-l,a,c,b); cout<<a<<b<<endl;
writeln(a,b); han(n-l,c,b,a);
}
han(n-l,c,b,a)
}
end
end; main()
begin { cout<<"N="; cin>>n;
write('N='); readln(n); a=a; b='b't c=c;
a:='a'; b : c'b'; c:='c'; han(n,a, b,c);
}
han(n,a,b,c)
end.

7.2.5. Problema tieturilor

D Problema 7.5. Se d o bucat dreptunghiulara de tabl cu lungimea 1 i


nlimea:q, avnd pe suprafaa ei n guri de coordonate numere ntregi. Se cere
s se decupeze din ea o bucat de arie maxim care nu prezint guri. Sunt
permise numai t ieturi verticale i orizontale.

0 Rezolvare. Coordonatele gurilor sunt reinute n doi vectori XV i YV.


Dreptunghiul iniial, precum i dreptunghiurile care apar n procesul tierii sunt
memorate n program prin coordonatele colului din stnga-sus (X, Y), prin
lungime i nlime (L,H).

Pentru un dreptunghi (iniial pornim cu toat bucata de tabl), _verificm dac


avem sau nu o gaur n el (se caut practic prima din cele n guri). In situaia cnd
acesta prezint o gaur, problema se descompune n alte patru probleme de
acela i tip. Dac bucata nu prezint guri, se compar aria ei cu aria unei alte
buci fr gaur, gsit n fazele precedente.

Menion m c dreptunghiul de arie maxim fr guri este reinut prin


aceiai parametri ca i dreptunghiul cu guri, n zonele XF, YF, LF, BF.

n concluzie, problema iniial se descompune n alte patru probleme de


acelai tip, mai uoare, ntruct fiecare nou dreptunghi are cel mult n-1 guri, dac
dreptunghiul iniial avea n guri. La aceast problem compararea soluiilor const
n a reine dreptunghiul cu aria maxim dintre cele fr guri.
'lan ual de informatic pentru clasa a Xl-a 181

Fie dreptunghiul cu o gaur:

h 1 xv(i),yv(i)
x,y
Pentru a se afla n interiorul dreptunghiului, gaura trebuie s ndeplineasc
simultan cond ii ile:

1) xv(i) >x;
2) xv(i) <x+l;
3) yv(i) >y;
4) yv(i)<y+h.

Dac facem o tietur vertical prin aceast gaur, obinem dou dreptunghiuri:
1) x, y, xv(i) -x, h;
2) xv(i), y, l+x-xv(i), h.

n urma unei tieturi pe orizontal se obin cele dou dreptunghiuri:

1) X, y , l , yv ( i) -y;
2) x, yv(i), 1, h+y-yv(i ).

Programul este urmtorul:

, , :j,.. .'' Vari~nta Pascal.' ',


,, ..
type vect=array [1 . 9] of #include <iostream.h>
integer; int l , h,i,n,xf,yf,lf,
hf ,xv[lO] ,yv [lO] ;
var l,h,i,n,xf,yf,
lf,hf:integer; void dimp(int x,int y,int 1,
xv, yv:vect; int h , int& xf, int& yf,
int&: lf,int&: hf,
procedura dimp int xv[lO],int yv[ lO])
(x, y,l ,h:integer; { int gasit=O,i=l;
var xf,yf,lf,hf:integer; while (i<=n &:& !gasit)
var xv,yv:vect); if (xv [i)>x &&: xv[i]<l &:&:
var gasit:boolean; yv[i)>y &&: yv[i]<y+h)
i:integer; gasit=l;
e lse i++;
begin
if (gasit)
i:=1;
{ dimp(x,y,xv [i] -x,h,xf ,
gasit:=false; yf,lf,hf,xv,yv);
while (i<=n) and (not gasit) dimp(xv[i],y,l+x-xv[i],
do h,xf,yf,lf,hf,xv,yv);
if (xv[i]>x) and (xv[i]<l) dimp(x,y,l,yv[i]-y,xf,
and (yv[i] >y) and yf,lf,hf,xv,yv);
(yv[i]<y+h) dimp(x,yv[i],l,h+y-yv[i],
then gasit:=true ~f,yf, lf ,hf ,xv ,yv);
else i:=i+l; }
182 Capitolul 7. Metoda DIVIDE ET IMPERA

if. gasit el se
then if (l*h>lf*hf)
begin { xf=x;
dimp(x,y,xv[i]-x , yf..y;
h,xf,yf,lf,hf,xv, yv)l lfl;
dimp(XY[i],y,l+x -xv[i], hfh;
h,xf.,yf,lf,hf.,xv ,yv); }
dimp(x,y,l,yv[i] -y, }
xf.,yf,lf,hf,xv,y v)l
dimp(x,yv[i],l,h +y-yv[i], main ()
xf.,yf,lf,hf,xv,yv ) { cout<<"n"1 cin>>n1
end for (int il;i<n1i++)
el se { cout<<"x["<<i<<" ]c;
i f (l*h)>(lf*ht) cinxv[i];
then cout<<"Y["<<i<<" l"1
begin cinyv [il 1
XfiXI )
yfiYI oout<<"1"1 cin>>l1
lf.al1 cout<<"h"; cin>>h1
hflh dimp(O,O,l,h,xf ,yf,lf,
end hf,xv,yv);
cout<<"x"<<xf<< " y"<<yf
<<" l"<<lf<<" h "<<hf1
begin )
write ( 'n') ;
readln(n);
for ial to n do
begin
write ( 'x [ , i, l ) 1
readln(xv[i]);
~1ri te ( y [ ' , i, l ) 1
readln(yv[i])
end;
write( '1');
readln(l)l
write( 'h ) 1
readln(h) 1
lf :O;
h.f :01
dimp(O,O,l,h,xf, yf,
lf,hf,xv,yv) 1
writeln( 'x' ,xf, Y' ,yf.,
1' ,lf,. h',hf)
end.
Manual de informatic pentru clasa a Xl-a 183

7.3. Fractali

Fractalii au fost in trodui n anul 1975 prin lucrarea revoluionar a


matematicianului francez Benoit Mandelbrot, "O teorie a seriilor fractale", ce
reunete totodat diversele teorii dinaintea sa. El este cel care a inventat cuvntul
"fractal", de provenien latin ("frngere"- a sparge n fragmente neregulate).

Noiunea de fractal a aprut ca urmare a studiului vieii reale, n care


i nformaia genetic coninut in nucleul unei celule se repet la diferite scri.
Calculatorul permite ca o anum it figur (de exemplu, un segment) s se
transforme ntr-o alta, format din mai multe figuri iniiale (de exemplu , o linie
frnt) i fiecare figur obinut s se transforme n mod asemntor (aceste
transformri necesit foarte multe calcule).

Aceste forme geometrice au fost considerate n trecut haotice sau "aberai i


geometrice", iar multe dintre ele erau att de complexe nct necesitau
calculatoare performante pentru a le vizualiza. Pe parcurs, domenii ti i nifi ce ca
fizica, chimia, biologia sau meteorologia descopereau elemente asemntoare cu
fractalii n viaa real . Acetia au proprieti matematice extrem de interesante,
care de multe ori contrazic aparena, dar acestea depesc cu mult cunotine l e de
matematic din liceu.

nainte de a prezenta cteva exemple, trebuie cunoscute mai nti noiunile


de baz pentru a lucra n mod grafic. Acestea vor fi prezentate n continuare.

7.3.1. Elemente de grafic

7.3. 1.1 . General i t i (varianta Pascal)

Limbajul Pascal conine o serie de proceduri i funcii care permit realizarea


unor aplicaii grafice. Acestea sunt reunite n unitatea GRAPH, ce se gsete n
subcatalogul UNITS.

Pentru ca o imagine s poat aprea pe ecran, calcu latorul utilizeaz placa


video, cme difer n funcie de memoria video i ali pararrietri. Pentru a accesa o
plac video, trebuie s folosim r.~numite rutine speciale, speci~ice lor,, numite
Drlver-e. Limbajul Pascal dei ne o colecie de astfel de componente software i n
funcie de placa ce a fost detectat n sistem, se ncarc un driver sau altu l. Aceste '
fiiere au extensia ''bgi". Deoarece performanele componentelor hardware au'
depit cu mult capacitile CGA sau EGA, ne vom referi n continuare doar rla
driver-ul VGA (Video Graphlcs Array), dezvoltat de firma IBM. Driver-ul VGA poate
lucra Tn mai multe moduri, ns vom prefera modul standard de na l t rezo l uie
''vGAHI" (constant de tip ntreg), ce poate afia 640 x 480 puncte n 16 culori.
184 Capitolul 7. Metoda DIVIDE ET IMPERA

Selectarea driver-ului i a modului de lucru se face prin utilizarea procedurii


ini.tgraph. Aceasta are trei parametri: gdriver (de tip integer) care conine
codul asociat driver-ului, gmode (de tip integer) care reine modul de lucru i o
variabil de tip string, care arat calea ctre unitatea GRAPH. Forma general a
acestei proceduri este

initgraph(gdriver,gmode,'cale');.

Primii doi parametri sunt transm ii prin referin.

Iniializarea sistemului grafic se poate face tn dou feluri:

1) prin a solicita s se identifice automat placa grafic i corespunztor ei s


se ncarce un anumit driver i s se selecteze modul de lucru - cel mai bun din
punct de vedere al performanelor:
procedure initg;
begin
gdriver := detect;
initgraph(gdriver,gmode,c:\tp\bgi');
if graphresult<>O then
begin
writeln("Tentativa esuata!");
halt
end
end;

Constanta detect are valoarea o i se specific procedurii identificarea


automat a driver-ului i a modului de lucru.

Vom reine aceast procedur pentru c o vom utiliza n exemplele ulterioare.

2) prin indicarea cu ajutorul primilor doi parametri a unui driver i a unui mod
de lucru solicitate de programator (n acest caz, nu se poate executa programul pe
un calculator ce nu este dotat cu placa grafic specificat):
gdriver := VGA;
gmode :"' VGAHI;
initgraph(gdriver,gmode,'cs\tp\bgi');
if graphresult<>O then
begin
writeln("Tentativa esuata!");
halt
end;

Tentativa de iniializare grafic poate eua din diverse motive, cum ar fi: lipsa
unitii
GRAPH, calea indicat greit, etc. Testarea se realizeaz cu funcia tntreag
graphresult care returneaz o n caz afirmativ i o valoare diferit de o, n
caz contrar.

f: Odat intrai n modul grafic, nu se mai poate scrie pe monitor, ca pn


...Il" acum (cu write sau writeln). Ieirea din modul grafic se face prin
utilizarea procedurii closegraph.
Manual de informatic pentru clasa a Xl-a 185

7.3.1.2 . Generaliti (varianta C++)

Limbajul C++ (n varianta Borland), conine o serie de funcii care permit


realizarea unor apli caii grafice. Acestea sunt reunite in fiierul GRAPHJ:CS. H, ce se
gsete in folderul :INCLUDE.

Pentru ca o imagine s poat aprea pe ecran, calculatorul utilizeaz placa


video, care difer in funcie de memoria video i ali parametri. Pentru a accesa o
plac video, trebuie s folosim anumite rutine speciale, specifice lor, numite
Driver-e. Limbajul C++ deine o colecie de astfel de componente software i n
funcie de placa ce a fost detectat in sistem, se ncarc un driver sau altul. Aceste
fiiere au extensia "bgi". Deoarece performanele componentelor hardware au
depit cu mult capacitile CGA sau EGA, ne vom referi in continuare doar la
driver-ul VGA (VIdeo Graphlcs Array), dezvoltat de firma IBM. Driver-ul VGA
poate lucra n mai multe moduri, ins vom prefera modul standard de nalt
rezol uie "VGAH:r" (constant de tip Tntreg), ce poate afia 640 x 480 puncte in
16 culori. Fiierul ce conine driver-ul utilizat este "EGAVGA.CG:I".

Selectarea driver-ului i a modului de lucru se face prin utilizarea funciei


initgraph. Aceasta are trei parametri: gdriver (de tip integer) care conine
codul asociat driver-ului, gmode (de tip integer) care reine modul de lucru i o
variabil de tip string, care arat calea ctre unitatea GRAPH. Forma general a
acestei funcii este

initgraph(&gdriver,&gm ode,"oale"); .

Primii doi parametri sunt transmii prin referin.

Iniializarea sistemului grafic se poate face n dou feluri:

1) prin a solicita s se identifice automat placa grafic i corespunztor ei s


se Tncarce un anumit driver i s se selecteze modul de lucru - cel mai bun din
punct de vedere al pertor:manelor:
void init()
( gdriver a DETECT;
initgrapb(&gdriver,&gmode, "E:\\BORLANDC\\BGX");
if (graphresult())
( cout<<"Tentativa nereusita.";
cout<<"Apasa o tasta pentru a inchide ";
getch() 1
exit(l);
}
}

Constanta DETECT are valoarea o i se specific funciei identificarea


automat a driver-ului i a modului de lucru.

Vom reine funcia init () pentru c o vom utiliza ln exemplele ulterioare.


186 Capitolul 7. Metoda DIVIDE ET IMPERA

2) prin indicarea cu ajutorul primilor doi parametri a unui driver i a unui mod
de lucru solicitate de programator (n acest caz, nu se poate executa programul pe
un calculator ce nu este dotat cu placa grafic specificat):

gdriver := VGA; gmode := VGAHI;


initgraph( &gdriver, &gmode," E:\\BORL ANDC\\B GI");
if {graphre sult{))
{ cout<<"T entativa n ereusita . ";
cout<<"A pasa o tasta pentru a inchide ";
getch() 1
exit{1);
}

Tentativa de iniializare grafic poate eua din diverse motive, cum ar fi: lipsa
un itii GRAPHICS , ca lea i ndicat greit, etc. Testarea se realizeaz cu funcia

,
ntreag graphre sul t ( ) care returneaz o n caz afirmativ i o valoare diferit
de o, n caz contrar.

Odat intrain modul grafic, nu se mai poate scrie pe monitor ca pn acum


(de exemplu, cu cout). Ieirea din modul grafic se face prin utilizarea
procedurii closegra ph ( ) .

Ateniei Pentru a putea scrie i rula programe C++ ce utilizeaz modul grafic al
limbajului, trebuie bifat urmtoarea opiune , din meniu:

Options 1 Llnker 1 Libraries 1 Graphlcs library.

7.3. 1. 3. Setarea culorilor i procesu l de desenare (Pascal i C++)

Cu siguran, placa video utilizat de dvs. are performane superioare


modu lui standard VGA, ce se regsete in driver-ul limbajului Pascal sau C++.
Pentru a generaliza ns, vom considera modul menionat anterior, ce poate reda
16 culori, reprezentate pe 4 bii.

Fiecare culoare de baz are atribuit o constant de la o la 15, precum


urmeaz: o - black (negru); 1 - blue (albastru); 2 - green (verde); 3 - cyan
(turcoaz); 4 - red (rou); 5 - mage nta (violet); 6 - brown (maro); 7 - lightgre y
(gri deschis); 8 - darkgrey (gri nchis); 9 - lightblu e (albastru deschis); 10 -
lightgre en (verde deschis); 11 - lightcya n (turcoaz deschis); 12 -
lightred (rou deschis); 13 - lightmag enta (violet deschis); 14 - yellow
(galben) i 15- white (alb).

f Aceste culori sunt cele implicite. Pentru a utiliza mai multe culori (dar nu n
J,jitl acelai timp), se poate schimba setul (paleta) de culori. ntruct n acest
moment nu sunt necesare o multitudine de culori, nu vom prezenta n detaliu
acest aspect.
..,a., ual de Informatic pentru clasa a Xl-a 187

-+ Pentru a seta culoarea de fundal, se utilizeaz procedura (n Pascal) sau


funcia (n C++)

setbkcolor(c uloare);.

Exemple: setbkcolor ( 6) 1 sau aetbkcolor ( RED) ; .

-+ Selectarea culorii cu care se deseneaz se face cu ajutorul procedurii (n


Pascal) sau funciei (Tn C++)
setcolor(culo are);.

Exemplu: setcolor ( 15) ; sau setcolor (WHITE) ; .

~ Observaii

Schimbarea culorii nu afecteaz ce am desenat anterior, ci doar ce este scris


dup apelul acestei rutine.

n cazul limbajului C++, numele simbolic al culorii se scrie obligatoriu cu


majuscule.

Operaia de desenare

Oricare ar fi modul de lucru ales, un punct se reprezint printr-un pixel de


coordonate x (linia) i y (coloana), ambele valori intregi. Punctul din stnga-sus are
coordonatele <o, o>. Pentru a ne muta la poziia (x, y), vom folosi procedura (n
Pascal) sau funcia (Tn C++) moveto(x,y). Pentru a trasa o linie de la punctul
curent, determinat anterior, pan la o nou poziie, vom utiliza procedura (n
Pascal) sau funcia (n C++) lineto(xl,yl ). Astfel, vom obine o linie Tntre
punctele de coordonate (x,y) i (xl,yl).

Exemplu. Mai jos, este prezentat un program ce deseneaz o linie pe diagonala


principa l a ecranului (de la colul din stanga-sus la colul din dreapta jos):

VarlantaP~scal

begin main ()
initg; { init() 1
setcolor(red ); tcolor(RED ) 1
moveto(O,O); moveto(O,O);
lineto(getmax x,getmaxy); lineto(getma xx(),getmaxy ());
readln1 getch() 1
end. }

De asemenea, dou funcii foarte utile sunt get:maxx i getmaxy (n


Pascal) sau getmaxx() i getmaxy() (n C++). Acestea tntorc valoarea minim
i respectiv, maxim a coordonatelor de pe ecran. Astfel, cu ajutorul lor se poate
obine o independen relativ a programelor fa de modul grafic al sistemului.
188 Capitolul 7. Metoda DIVIDE ET IMPERA

7.3.2. Curba lui Koch pentru un triunghi echilateral

Se consider un triunghi echilateral. Fieca re latur a sa se transform aa


cum se vede in figura urmtoare (se mparte n trei segmente congruente, se
elimin segmentul din mijloc i se construiete deasupra un triunghi echilateral):

_/\_
Figura 7.1. Exemplu de transformare

Fiecare latur a acestui poligon se transform din nou, dup aceeai regul.
S se vizualizeze figura obinut dup ls pai {n um r citit de la tastatur).

AKceahst(Hcurb esteKcunhosc ut in literatut~~ de spedcialit~te ~a fii~d ct urba lui


1
f,,,,
oc erge van oc a ost materna 1c1an sue ez I a 1magma aceast
curb n anul 1904 ).

Programul principal va apela, pentru fiecare segment care constituie o latur


a triunghiului, o procedur numit generator. Aceasta execut transformarea de
ls ori, avnd ca parametri de intrare coordonatele punctelor care constituie
extremitile segmentului, numrul de transformri fcute (n) i numrul de
transformri care trebuie efectuate (ls). Pentru a nelege funcionarea procedurii,
trebuie s avem un minimum de cunotine specifice geometriei analitice (ce se
poate face fr matematic?).

Fie AB un segment de dreapt, unde A este un punct de coordonate (x 1,y1),


iar B are coordonatele (x 2 ,y2) . Dou puncte P1 i P2 mpart segmentul ntr-un
anumit raport, notat cu k

Y1 - k Y2
1-k
Demonstrai singuri aceste formule!

Fie segmentul AB cu A(x 1,y1) i B(x2,y2). Considerm punctele C i D care


mpart segmentul n trei segmente congruente.

Aflm coordonata punctului D:

k = DA =-2
DB '
x = x 1 +2x 2
1' 3 ' Y,, = Y1 +2
3 -
)'?

Problema const n stabilirea coordonatelor vrfului noului triunghi


echilateral. Acestea se obin dac se rotete punctul C n jurul punctului D cu
unghiul re 13. Rotaia o efectueaz procedura rotplan.
Manual de informatic pentru clasa a Xl-a 189

S prezentm algoritmul care st la baza procedurii generator:

se pornete de la segmentul AB;


se determin coordonatele punctului care constituie vrful triunghiului
echilateral (s-I notm cu V);
n cazul n care segmentul nu a fost transformat de ls ori, se apeleaz
generator pentru segmentele AC, CV, VD i DB;
contrar, se apeleaz procedura care traseaz linia frnt ACVDB.

in programul principal au fost alese punctele care determin triunghiul


echilateral iniial - plasat n centrul ecranului - i pentru fiecare segment ce
constituie o latur a acestuia s-a apelat procedura generator. Odat tras curba,
se coloreaz interiorul acesteia.

Programul este urmtoru l :

uses graph,crt; *include "graphics.h"


var L,gdriver,gmode, *include <iostream.h>
ls:integer; *include <stdlib.h>
xmax,ymax:integer; *include <conio.h>
#include <math.h>
procedura initg1 int gdriver,gmode,ls,LJ
void init()
procedure rotplan(xc,yc,xl,
yl:integer1 var x,y:integer;
( ... }

unghi:real); void rotplan(int xc,int yo,


begin int xl, int yl,int &x,
x : round(xc+(xl-xc)* int &y, float w1ghi)
cos(unghi)-(yl-yc)* {x = ceil(xc+(xl-xo)*cos(ungh i)-
sin(unghi)); (yl-yc)*sin(unghillJ
y ;a round(yc+(xl-xc)* y = ceil(yc+(xl-xc)*sin(ungh i)+
sin(unghi)+(yl-yc)* (yl-yc)*cos(unghi))J
cos(unghi)) }
end1 void desenez(int xl,int yl,
procedura desenez(xl,yl,x2, int x2,int y2,int x3,int y3)
y2,x3,y3:integer); { moveto(xl,yl);
begin lineto(div((2*xl+x2),3) .quot,
moveto(xl,yl); div((2*yl+y2),3) . quot)J
lineto((2*xl+x2) div 3, lineto(x3,y3)J
(2*yl+y2) div 3)1 lineto(div((xl+2*x2),3). quot,
lineto(x3,y3); div((y1+2*y2),3).quot);
lineto((xl+2*x2) div 3, lineto(x2,y2); }
(y1+2*y2) div 3)1 void generator(int xl,int yl,
lineto(x2 , y2); int x2,int y2,int n, int ls)
end1 { int x,y;
procedure rotplan(div((2*xl+x2),3) . quot,
generator(xl,yl,x2,y2, div((2*yl+y2),3).quot,
n,ls:integer); div((x1+2*x2),3).quot,
var x,y:integer; div((y1+2*y2),3).quot,
x,y,M PJ:/3);
190 Capitolul 7. Metoda D IVIDE ET IMPERA

begin if (n<ls)
rotplan((2*xl+x2) div 3, {generator(x1,y1,div((2*xl+x2),
(2*yl+y2) div 3, (x1+2*x2) div 3).quot,div{(2*yl+y2),
3, (y1+2*y2) div 3,x,y,pi/3); 3).quot,n+l,ls);
if n<ls then generator(div((2*xl+x2),
begin 3).quot,div((2*yl+y2),
generator(xl,yl, (2*xl+x2) 3),quot,x,y,n+l,ls);
div 3,(2*y1+y2) div 3, generator(x,y,div((x1+2*x2),
n+l, ls); 3).quot,div((y1+2*y2),
generator{{2*xl+x2) div 3, 3).quot,n+l,ls);
(2*yl+y2) div 3, generator(div((x1+2*x2),
x,y,n+l,ls); 3).quot,div((y1+2*y2),
generator(x,y, (x1+2*x2) div 3).quot,x2,y2,n+l,ls);
3,(y1+2*y2) div 3,n+l,ls); }
generator({x1+2*x2) div 3, else desenez(xl,yl,x2,y2,x,y);
(yl+2*y2) div 3, }
x2, y2, n+l, ls);
main()
end
{ cout<<"ls= "; cin>>ls;
else desenez{xl,yl,x2,y2,x,y);
init ();
end;
setcolor(6);
begin L = getmaxx()-320;
write('ls= '); readln(ls); generator(160,getmaxy()-150,
initg; 160+L,getmaxy()-150, 1,ls) ;
setcolor(red); generator(160+L,getmaxy()-
L:=getmaxx-320; 150,160+div(L,2).quot,
generator(l60,getmaxy-150, getmaxy() -150-
160+L,getmaxy-1SO,l,ls)/ ceil(L*(sqrt(3)/2)),l,ls);
generator(160+L,getrnaxy-150, generator(160+div(L,2) ,quot,
160+L div 2,getmaxy-150 - getrnaxy() -1SO-
L*round(sqrt (3)/2) , 1,ls) ; ceil(L*{sqrt(3)/2)),160,
generator(160+L div 2,getmaxy- getmaxy()-lSO,l,ls);
150-L*round(sqrt(3)/2),160, setfillstyle(1,4);
getmaxy- lSO,l , ls)/ floodfill(div(getmaxx(),2)
setfillstyle(l,blue); .quot,div(getmaxx(),
floodfill(getmaxx div 2, 2).quot,6);
getmaxy div 2, red); getoh()/
readln closegraph();
end . }

Privii mai jos rezultatele obinute pentru diferite valori ale lui la:

la = 2 ls ::: 3 ls =4
Figura 7.2. Exemple de fractali formai cu ajutorul curbei lui Koch (triunghi echilateral)
"'.anual de informatic pentru clasa a Xl-a 191

.... .3.3. Curba lui Koch pentru un ptrat

Se consider un ptrat. Fiecare latur a sa se transform dup cum se vede


, figura de mai jos:

Figura 7.3. Exemplu de transformare

Fiecare segment al liniei frnte astfel formate se transform din nou dup
aceeai regul. Se cere s se vizualizeze curba dup ls transformri (valoare
citit de la tastatur).

Transformarea i desenarea unui segment sunt realizate de procedura


desen. Aceasta are ca parametri de intrare coordonatele punctului care determin
segmentul, numrul de transformri efectuate (n) i numrul de transformri
cerut (ls).

Procedura conine urmtorul algoritm:

dac nu a fost efectuat numrul de transformri necesar, se


calculeaz coordonatele punctelor care determin linia frnt obinut
pornind de la segment i pentru fiecare segment din aceast linie se
reapeleaz procedura desen;

contrar, se deseneaz linia frnt obinut.

In final, figura se coloreaz. Programul este prezentat n continuare:

uses graph,crt; #include "graphica.h"


var gdriver,gmode,ls:integer; #include <iostream.h>
#include <atdlib.h>
procedura initg; #include <conio.h>
#include <math.h>
procedura rotplan(xc,yc,xl, int gdriver,gmode,la,L;
yl : integer;
var x,y:integer; void init()
unghi : real); {
}
192 Capitolul 7. Metoda DIVIDE ET IMPERA

procedura desen(xl,yl,x 2,
y2,n,ls:inte ger); void rotplan(int xc,int yc,
var x3,x4,x5,x6, x7,x8,xc, int xl,int yl,int &x,int &y,
y3,y4,y5,y6, y7,y8,yc:inte ger; float unghi)
{
begin
}
if n<=ls then
begin void desen(int xl,int yl,int
x3:=(3*xl+x2 ) div 4; x2,int y2,int n,int ls)
y3:=(3*yl+y2 ) div 4; { int x3,x4,x5,x6, x7,x8,
rotplan(x3,y 3,xl,yl,x4,y4 , xc,y3, y4,y5,y6,y7, y8,yc;
-pi/2); if (n<=ls)
xc:=(xl+x2) div 2; { x3=div(3*xl+ x2,4) .quot;
yo:=(yl+y2) div 2; y3=div(3*yl+ y2, 4).quot;
rotplan(xc,yo ,x3,y3,x5,y5 , rotplan(x3,y 3,xl,yl,x4,y4 ,
-pi/2); -M_PX/2);
rotplan(xc,y c,x3,y3, xc=div(xl+x2 ,2) .quot;
yc=div(yl+y2 ,2).quot;
x6,y6,pi/2);
rotplan(xc,y c,x3,y3,x5,y 5,
x8:=(x1+3*x2 ) div 4;
-M_PI/2);
y8:=(y1+3*y2 ) div 4;
rotplan(xc,y c,x3,y3,x6,y 6,
rotplan(x8,y 8,xc,yc,x7,y 7,
M_PJ:/2);
pi/2); x8=div(x1+3* x2, 4).quot;
desen(xl,yl, x3,y3,n+l,ls ); y8=div(yl+3* y2, 4) . q uot;
desen(x3,y3 ,x4,y4,n+l,ls ); rotplan(x8,y 8,xc,yc,x7,y 7,
desen(x4,y4, x5,y5,n+l,ls) ; M_ PJ:/2);
desen(xS,yS ,xc,yc,n+l,ls ); desen(xl,yl, x3,y3,n+l,ls );
desen(xc,yc, x6,y6,n+l,ls) ; desen(x3,y3 ,x4,y4,n+l,ls );
desen(x6,y6, x7,y7,n+l,ls) ; desen(x4,y4, x5,y5,n+l,ls) ;
desen(x7,y7 ,x8,y8,n+l,ls ); d e sen(xS,yS , xc,yc,n+l,ls );
desen(x8,y8 ,x2,y2,n+l,ls ); desen(xc,yc, x6,y6,n+l,ls );
if n = ls then begin desen(x6,y6 ,x7,y7,n+l,ls );
moveto(xl,yl ); desen(x7,y7 ,x8,y8,n+l,ls );
lineto(x3,y3 ); desen(x8,y8, x2,y2,n+l,ls) ;
lineto(x4,y4 ); if (n == ls)
lineto(xS,yS ); { moveto(xl,yl );
lineto(x6,y6 ); lineto (x3 , y3) ;
lineto(x7,y7 ); lineto(x4 , y4);
lineto(x8,y8 ); lineto(xS,yS );
lineto(x2,y2 ); lineto(x6,y6 );
lineto(x7,y7 );
end
lineto(x8,y8 );
end
lineto(x2,y2 ); }
end;
}
begin }
write('ls= '); readln(ls); main()
initg; setcolor(red ); ( cout<<"ls= "; oin>>ls;
desen(100,10 0,300,100,1, ls); init(); setcolor{6);
desen(300,10 0,300,300,1,1 s); desen(100,10 0,300,100,1, ls);
desen(300,30 0,100,300,1, ls); desen(300,10 0,300,300,1, ls);
desen(100,30 0,100,100,1,1 s); desen(300,30 0,100,300,1, ls);
setfillstyle( l,blue); desen(100,30 0,100,100,1, ls);
floodfill(getm axx div 2, setfillstyle( 1,3);
getmaxy div 2, red); floodfill(div {getmaxx(),2 )
readln .quot,div(ge tmaxy(),2).q uot,6);
end. getch(); closegraph() ;
.anual de informatic pentru clasa a Xl- a 193

Sunt prezentate mai jos imaginile obinute n urma rularii programului, pentru
4
:: erite valori ale lui ls:

ls==l ls=2

Figura 7.4. Exemple de fractali formai cu ajutorul curbei lui Koch (ptrat)

7.3.4. Arborele

Se d un segment AB. Cu ajutorul lui se construiete un arbore, aa cum se


vede in figura de mai jos:

Figura 7.5. Exemplu de transformare in cazul unul arbore

Lungimea fiecarei ramuri este o treime din lungimea iniial a segmentului.


Fiecare latur se transform Tn mod asemntor. Se cere sa se vizualizeze figura
astfel rezultat, dupa ls transformri.

Pentru obinerea ramurilor se procedeaz astfel:

se consider punctul situat pe dreapta determinat de segment i


pentru care avem:

se rotete acest punct n jurul punctului B(x2.y2) cu un unghi de 1r /4;


se rotete punctul n jurul lui B cu unghiul -re /4 .
194 Capitolul 7. Metoda DIVIDE ET IMPW

ln urma acestor rotaii se obin coordonatele punctelor care, mpreun c...


punctul B, determin segmentele ce costituie ramurile arborelui.

Procedura desenez are ca parametri de intrare coordonatele unui segment


numrul de transformri efectuate (n) i numrul de transformri care trebu1e
efectuate {ls). n cazul n care nu s-au efectuat toate transform~rile, se traseaz~
segmentul (cu o culoare oarecare), se calculeaz coordonatele punctelor care
determin ramurile i, pentru fiecare segment, se reapeleaz procedura.

Programul este prezentat mai jos:

uses graph,crt; #include "graphics. h"


#include <iostream. h>
var gdriver,gm ode,ls:inte ger; #include <stdlib.h>
xmax,ymax :integer1 #include <conio.h>
procedure initg; #include <math.h>
int gdriver,gm ode,ls,LI
void init()
procedure rotplan(xc ,yc,xl,
yl:integor 1 var x,ytintoge rt
{... }

unghi:rea l); void rotplan( )


{... )

procedure desenez(x l,yl,x2,y2, void desenez(in t xl,int yl,


n,ls linteger) 1 int x2,int y2,int n,int ls)
var x,y:intege r; { int x,y,
begin if (n<=ls)
if n<=le then { setcolor(l+ random(15 ))1
begin moveto(xl ,yl);
eetcolor(l+ random(15 ))1 lineto(x2,y 2)1
moveto(xl ,yl)l rotplan(x2 ,y2,div(3* x2-
lineto(x2,y 2)1 x1 ,2).quot,di v(3*y2-y1 ,2)
rotplan(x2 ,y2, (3*x2-x1) div .quot,x,y,M_ PI/4)1
2,(3*y2-yl ) div 2,x,y,pi/4 )1 desenez(x 2,y2,x,y,n +l,ls);
desenez(x 2,y2,x,y,n +l,ls)t rotplan(x2 ,y2,div(3* x2-
rotplan(x2 ,y2,(3*x2- xl) div x1,2),quot ,div(3*y2- yl,
2, (3*y2-yl) div 2,x,y,-pi/ 4)t 2),quot,x,y ,-M_PI/4) ;
deeenez(x 2,y2,x,y,n +l,ls)1 desenez(x 2,y2,x,y,n +l,ls)1
}
end
}
end1
begin main()
randomize; { randomize ();
write('lsa '); readln(ls) J cout<<"ls "1 cin>>1s;
init()l setcolor(6 )1
initg;
desenez(di v(getmaxx (),2)
setbkcolor (white)l
quot, getmaxy ( ) ,
desenez(ge tmaxx div 2,
div(getma xx(),2).qu ot,
getmaxy, getmaxx div 2,
getmaxy() -250,l,ls);
getmaxy-2 50,1,ls)l getoh();
readln closegraph ( ) 1
end. }
vanual de informatic pentru clasa a Xl- a 195

Pentru diverse valori ale parametrului de intrare ls, vom obine arborii:

ls =3 ls =5 ls =7
Figura 7.6. Exemple de fractali de tip arbore

~ Observaii

~ Exemplele grafice prezentate au fost generate pentru valori mici ale lui ls
deoarece la tiprire, detaliile sunt greu de observat peste o anumit limit .

./ Generarea fractalilor reprezint o apl i caie a recursivitii, tehnica aplicat


fiind DIVIDE ET IMPERA. Pentru valori mari ale lui ls, timpul de efectuare al
calculelor poate fi i de ordinul zecilor de secunde, ceea ce poate fi
considerat un inconvenient major.

Probleme propuse
1. Se citete a~1. numr real. Se cere s se scrie o funcie care calculeaz ln(a)
cu 3 zecimale exacte. Nu este permis utilizarea funciei logaritmice a limbajului.

2. Scriei o funcie care calculeaz prin metoda DIVIDE ET IMPERA suma numerelor
reinute dintr-un vector.

3. Referitor la problema anterioar: care este complexitatea algoritmului folosit?


Se va considera ca operaie de baz adunarea.

4. Se citeteun numr real xe ( -1oooo, 10000). S se afieze partea


fracionar. Exemple: pentru x=1.23, se va afia: 0.23 ; pentru x=-12.7, se va
afia o. 7 . Nu se vor folosi funcii specializate ale limbajului.

5. Se tie c ecuaia x 3 +x-1=0 are o singur rdcin real Tn intervalul <o, 1).
Scriei un program, care o afieaz cu 4 zecimale exacte.
196 Capitolul 7. Metoda DIVIDE ET IMPERA

6. Problema seleciei. Se consider un vector cun componente numere naturale


i l~t~. Se cere s se determine al t-lea cel mai mic element. Imaginai
o
rezolvare care utilizeaz funcia Poz de la sortarea rapid!
7. Seconsider un vector care reine n numere naturale. Se cere s se determine
dac exi st un element majoritar (adic un numr care se gsete n mai
mult de
[n 1 2]+ 1 elemente).
Victor Mitrana
8. Fiind dat x real, s se calculeze
funcii
l\G Jcu patru zecimale exacte! Nu se vor folosi
specializate ale limbajului.
9. Se pleac de la un ptrat a crui suprafa se divide n 9 pri egale prin
mprirea fiecrei laturi in 3 pri egale. Ptratul din mijloc se elimin. Cu
ptratele
rmase se procedeaz la fel. Vizualizai figura dup ls astfel de transform
n
(Covorul lui Sierpinsk1).

Rspunsuri

1. ln (a) =x (::> a=e>C (::> ex-a=O. Dac notm cu f (X) =ex-a, atunci trebuie
rezo lvat ecuaia f(x)O. Avem f(O)=e 0 -a==1-a<O i f(a)=e 4 -a>O. De
aici,
rezult c f(x) are o rdcin n intervalul (O,a). Cum f(x) este
strict
cresctoa re (ca diferen ntre funcia strict cresctoare e" i o constant ),
rdcina este unic . Algoritmul pe care l folosim se numete n matematic
"metoda Tnjum~t~irii intervalului', dar, din punct de vedere informatic, corespund e
metodei DIVIDE ET IMPERA.
Fie liaO i lsa, m=(a+b) /2. Dac f(li)Xf(m )<O, rdcina se gsete n
(li,m) , altfel rdcina este n [m,ls) . Condiia de terminare este ca
jli - lsj < 0.0001, pentru c trebuie s avem 3 zecimale exacte.

' Varianta Pascal . ." ..


1' Varianta C++
var a:real; #include <iostream .h>
function LogN{a, li,ls:dou ble): #include <math.h>
double; double a;
begin double LogN ( double a, double li,
if aal then LogN:=O double l s)
e l se { if (a==l) return O;
if abs(li-ls )< O.OOOl el se
then LogN:a( li+ls)/2 if (fabs(li-l s)<O.OO Ol)
el se return (li+ls)/2 ;
if (exp(li) -a )* el se
(e.x p((li+ls) /2) -a)<O if ((exp(li) -a)*
then {exp((li +ls)/2) -a)<O)
LogN:=Lo gN (a,li ,(li+ls)/ 2 ) return LogN(a,l i,
el se (li+ls)/2 );
LogN:=L ogN(a,(li +ls)/2,ls) else return LogN(a,
end1 (li+ls)/2 ,ls);
}
'anual de informatic pentru clasa a Xl-a 197

begin main()
write {'a=' ) ; readln(a); { cout<<"a="; cin>>a;
writeln(' rezultat cout<<"rezultat calculat "
calculat:',LogN(a,O,a):3 :3); <<LogN(a,O,a)<<endl;
writeln(' rezultat preluat cout<<"rezultat preluat "
ln(a):3:3); <<log(a)<<endl;
end. }

f Practic, la fiecare pas se injumtete intervalul n care se caut soluia i


aceasta corespunde strategiei generale DIVIDE ET IMPERA.

2. Programul este prezentat mai jos:


:.,
Varianta Pascal 1 Ilo 1! ,,,

type vector=array[1 9] of tinclude <iostream.h>


integer;
int n, i , t [10] 1
var v:vector; int Suma(int li, int ls)
n,i:integer; { if (li==ls) return v[li]J
else return
function Suma(li, (li+ls)/2)+
Suma(li,ls:integer):inte ger; Suma((li+ls)/2+1,1s);
begin }
if li=ls then Suma:=v(li] main()
el se { cout<<"n=";
Suma:=Suma(li,(li+ls) div 2) cin>>n;
+ Suma((li+ls) div 2+l,ls); for (isl;i<n;i++)
end; cinv [i];
begin cout<<Suma(l,n);
wri te ( n= ) ; }
readln(n);
for i:=l to n do
readln(v[iJ);
writeln(suma(l,n));
end .

3. Fiecare problem se descompune in alte dou i rezultatul se adun. Pentru


simplitate, considerai n=2~<. fn final, se obine o (n). Putei scrie i funcia recursiv
care calculeaz T (n), dar, pentru a obine rezultatul corect, luai n2~<:

4. A calcula [x] se reduce la DIVIDE ET IMPERA. Partea fracionar se obine uor,

dac calculm Jx- [x] .


198 Capitolul 7. Metoda D IVIDE ET IMPERA

5. Vedei problema 1.

6. Funcia Poz returneaz pozii a k pe care se va gsi, dup rularea ei, primul
element al vectorului. n plus, toate elementele de indice mai mic dect k sunt mai
mici sau egale dect A [kl i toate elementele de indice mai mare dect k sunt mai
mari sau egale dect A [kl . Altfel spus: elementul A [ 11 , care se afl dup rularea
funciei pe poziia k, este al k-lea cel mai mic element din vectorul A. Atunci, n
cazul n care k=t , problema este rezolvata. Dac t<k, elementul cutat are
indicele cuprins ntre l i i k-1 i relum rularea funciei Poz ntre aceste limite, iar
dac t>k, elementul cutat are indicele ntre k+l i ls i rel um rularea fu nciei
Poz ntre aceste limite. Datorit faptului c, la fiecare pas, se restrnge numrul
valorilor de cutare, se ajunge n situaia n care t=k.

Secvena este:

lil=1; li=l;
ls:=n; ls=n;
repeat do
poz(li,ls,k,a); { poz(li,ls,k,a);
if t<k then lsJ=k-1; i f (t<k) ls=k-1;
if t>k then li:=k+l; i f (t>k) lia k+1;
until t=k; }while ( t 1=k) ;
writeln('Elementul cautat cout<<"elementul cautat "
a [t]) 1 a[t] 1

7. Dup aplicarea algoritmului de la problema anterioar, elementul din mijloc


trebuie s fie majoritar.
Capitolul 8
Metoda 8ACKTRAC KING

3.1 . Prezentarea metodei

5. 1.1. Cnd se utilizeaz metoda backtracki ng?

Metoda backtracking se folosete n rezolvarea problemelor care ndeplinesc


: multan u rmtoarele condii i :

soluia lor poate fi pus sub forma unui vector S=xl,x::~, .. ,x0 , cu
X1EA1 , X 2 EA::~, . .. , XnEAo;

mulim i le A 1 , A2 , ... , An sunt mulimi finite, iar elementele lor se consider


c se afl ntr-o relaie de ordine bine stabilit;

nu se dispune de o alt metod de rezolvare, mai rapid .

n continuare, este prezentat un exemplu de problem care poate fi


>J..v
-"'"' rezolvat prin utilizarea tehnicii backtracking.

Generarea permutrilor. Se citete un numr natural n . S se 123


;enereze toate permutrile mulimii {1, 2, , n). De exemplu, pentru 132
::~ 3 , permutri le mulimii {1, 2, 3} sunt prezentate alturat. 213
231
=>entru aceast problem, A 1aA2=A3={1, 2, 3}. Fie permutarea 213. Ea 312
321
:ste scris sub form de vector, unde 2eA1 , leA2 i 3eA3

8.1 .2. Principiul care st la baza metodei backtracki ng

Principiul care st la baza metodei backtracking va fi prezentat printr-un


:xemplu, acela al generrii permutrilor. Cum se poate rezolva aceast
oroblem?

O prim soluie ar fi s generm toate elementele produsului cartezian:

{1,2,3}X(1,2 ,3}X{1,2,3} :{11, 12, 13, 21, 22, 23, 31, 32, 33}
X{1,2,3)= {111, 112, 113, 121, 122, 123, 131, 132, 133, 211,
2 12, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321,
322, 323, 331, 332, 333}.
200 Capitolul 8. Metoda backtracking

Apoi, urmeaz s vedem care dintre elementele acestui produs cartezian


sunt permutri, adic s conin numai numere distincte. Astfel, 111, 112 ...
nu sunt permutri, dar 123 este permutare, .a.m.d. Produsul cartezian are 27 de
elemente i dintre ele, doar 6 sunt permutri. in general, produsul cartezian are
nn elemente, din care permutri sunt doar n t. V dai seama c un astfel de
algoritm de generare a permutrilor este ineficient. ..

intrebarea este dac problema nu se poate rezolva eficient? S observm


c nu are rost s generm un element al produsului cartezian pentru ca apoi, s ne
dm seama c nu este permutare, deoarece nu este alctuit din numere distincte.
De exemplu, dac la un pas al algoritmului am generat 22, e clar c nu se poate
o
obine permutare, oricare ar fi num rul care urmeaz pe poziia 3.

Principiut metodei

+ M~toda backtracking are la baz un principiu simplu: dac fn procesul de


generare a unui vector soluie S=x1 x 3 , ,xn. pentru componenta k, atunci
cnd am generat deja x 1x 3 x~c, constatm c valoarea xk nu este bine
aleas (pstrand-o nu se va ajunge la o soluie), nu trecem componenta k+l
ci relum cutarea pentru alt valoare pentru componenta k, iar dac
aceast valoare nu exist, relum cutarea pentru componenta k-1.

~ Observai faptul c dup ce am analizat posibilele valori pe care le poate lua


componenta k, avem dou posibiliti: ori trecem la componenta k+1 (facem
pasul 'nainte), ori mergem la componenta k-1 (facem pasul napoi).

Trecem la exemplificarea algoritmului pentru generarea permutri lor, n


cazul n care n=3.

Componenta 1 va memora numrul 1. ntruct exist


permutri care ncep cu 1, trecem la elementul 2 - facem
pasul nainte.

Componenta 2 va memora numrull. l1 l1 1


Nu exist permutri care incep cu 1,1, motiv pentru care, 1 1 1 1
pentru aceeai component, vom reine valoarea urmtoare, 1 2
adic 2. intruct exist permutri care incep cu 1,2, vom trece la elementul
3 (nainte).

Componenta 3 va memora numrul! . 1112111


Nu exist permutri care sunt de forma 1,2,1, motiv pentru
care aceeai component va reine numrul urmtor, 2. 1112121
Nu exist permutri care sunt de forma 1,2,2, motiv pentru
care aceeai component va memora numrul urmtor, adic 1112131
3. Am obinut deja o prima soluie i o afii:!m .
Manual de informatic pentru clasa a Xl-a 201

Pentru componenta 3 , nu exist o alt valoare pe care o 1 3 0


1 1 1 1
putem utiliza. Din acest motiv, vom trece la elementul 2,
(napoi). Componenta 2 are deja memorat valoarea 2. Alegem valoarea
urmtoare, 3. ntruct exist permutri care incep cu 1,3, vom trece la
elementul urmtor, 3 (nainte).

Prima valoare care poate fi memorat este 1 . ntruct nu


exist permutri de forma 1, 3, 1 trecem la valoarea
urmtoare 2. Dar 1, 3, 2 este soluie i o afim.

Algoritmul continu pn cnd se ajunge la componenta de indice o. n acel


moment, au fost deja afiate toate permutrile.

Exerciiu. Artai cum funcioneaz algoritmul pn se ajunge la


componenta de indice o.

8.1 .3. O modalitate de implementare a metodei backtracking

Pentru uurarea nelegerii metodei, mai nti vom prezenta un subprogram


general, aplicabil oricrei probleme. Subprogramul va apela alte subprograme care
au intotdeauna acelai nume i parametri i care, din punct de vedere al
metodei, realizeaz acel ai lucru. Sarcina celui care face programul este s scrie
explicit, pentru fiecare problem fn parte, subprogramele apelate de acesta .

../ Evident, o astfel de abordare conduce la programe cu multe instruciuni. Din


acest motiv, dup nelegerea metodei backtracking, vom renuna la aceast
form standardizat. Dar, principiul rmne nemodificat.

lat subprogramul care implementeaz metoda. El va fi apelat prin


back(1) .

j,f, 1 1
rl::,,. ' Varianta C++ ...r,,,,. "'..":; .
,"'" v~~la"'ta ~~scai .. l",. : !:r 1 '/: lr, .

procedura back(k:integer); void back(int k)


begin {
if solutie(k) if (solutie(k)) tipar()/
then tipar el se
el se { init (k) 1
begin while(succesor(k))
init(k); if (valid(k)) back(k+l);
while s uccesor(k) do }
if valid(k) then back(k+l) }
end
end;
202 Capitolul 8. Metoda backtracking

S-I analizm! Subprogramul are parametrul k de tip ntreg. Acest parametru


are semnificaia de indice al componentei vectorului pentru care se caut o valoare
convenabil. Algoritmul va porni cu componenta de indice 1. Din acest motiv,
subprogram ul se va apela cu back ( 1). Dup cum observai, subprogramul
este recursiv.

-+ Iniial se testeaz dac s-a generat o soluie . Pentru aceasta, se apeleaz


subprogramul solutie (k).

Pentru permutri, vom avea o soluie cnd s-a generat o secven alctuit din n
numere distincte. Cum subprogramul este recursiv, acest fapt se intmpl atunc1
cnd s-a ajuns pe nivelul n+l.

-+ Dac s-a obinut o soluie, aceasta se afieaz. Pentru aceast operaie se


va utiliza subprogramul tipar.

-+ n situaia in care nu a fost obinut o soluie, se iniializeaz nivelul k .


Iniializarea se face cu valoarea aflat naintea tuturor valorilor posibile. Se
va folosi subprogramul init.

Pentru permutri, iniializarea se face cu o.

-+ Dup iniializare, se genereaz, pe rnd, toate valorile mulimii A~t. Pentru


aceasta se utilizeaz subprogramul succesor. Rolul su este de a atribui
componentei k valoarea urmtoare celei deja existente.

-+ Pentru fiecare valoare generat, se testeaz dac aceasta


ndeplineteanumite condiii de continuare. Acest test este realiza1
de subprogramul valid:

-+ n cazul n care condiiile sunt ndeplinite, se trece la


componenta k+l, urmnd ca generarea valorilor pe nivelul k s
continue atunci cnd se revine pe acest nivel;

-+ dac condiiile de continuare nu sunt ndeplinite, se


genereaz urmtoarea valoare pentru componenta k.

-+ Dup ce au fost generate toate valorile mulimii Al< se trece, implicit, la


componenta k-1, iar algoritmul se ncheie cnd k=O.

Pentru permutri, pe fiecare nivel, valorile posibile sunt A~ta { 1, 2, , n) .


Condiia de continuare, n acest caz este ca valoarea aflat pe nivelul k s fie
distinct n raport cu valorile aflate pe nivelurile inferioare.

Programul de generare a permutrilor este prezentat n continuare.


\1anual de info rmatic pentru clasa a Xl-a 203

var n:integer; linclude <iostream.h>


sol:array [1 . 10] of #include <iostream.h>
integer;
int n, sol[10];
procedura init(k:integer);
begin void init(int k)
sol[k]:=O { aol[kJ=O;
}
end;
function succesor int succesor(int k)
(ktinteger):boole an; { if (sol[k] <n)
begin { sol[k]++t
if aol[k]<n then return 1; }
begin el se return O1
}
sol[k]t=aol[k]+l t
succesor: .. true int valid(int k)
end { int i, ev=l;
else succesor:=false for (il;i <k-lt i++)
endt if (sol[kJ ==sol [i]) ev~o;

function valid return ev;


}
(k:integer):boole an;
var i:integert int solutie(int k)
begin { return k ..n+l;
validttrue; }
for i:=l to k-1 do
if ol[i]sol[k] then void tipar ( )
valid:=false { for {int i l;i<n;i++)
end; coutsol [il 1
cout<<endl;
function solutie }
(krinteger):boole an;
begin void back(int k)
solutie:=(k=n+l) { if (solutie(k)) tipar();
end; el se
{ init(k);
procedura tipar; while(succesor(k ))
var i:integer; if (valid(k)) back(k+1);
begin )
for it1 to n do }
write(sol[i]);
writeln main()
end; { cout<<"n"; cin>>n;
back(1);
procedure back(k:integer);
begin
if solutie(k)
then tipar
el se
begin
init (k) 1
w~le succesor(k) do
~f valid(k) then
back(k+1)
end
end;
begin
write('n=')t readln(n);
back(l)
end.
204 Capitolul 8. Metoda backtrackir=

8.1.4. Problema celor n dame

O Enun. Fiind dat o tabl de ah cu dimensiunea nXn, se cer toate


soluiile
de aranjare a n dame, astfel nct s nu se afle dou dame pe
aceeai linie, coloan sau diagonal (damele s nu se atace reciproc).

De exemplu, dac n=4, o soluie este reprezentat n figura 8.1., a). Modul de
obinere al soluie i este prezentat n figurile urm toare, de la b) la i):

~ .:
\lW 1 "

~
' '
,.... " .. ' ' !1: i.:,"
l .r. ,,, ...
" li '

a) b) c)

.-!.;:,~.
~
~-\
~
1'11 1'

1 ~ ~
:

',. ~ ...
~ 'i:::;jl:,
!" :r;;-!:- .11:
1;: ti,..: '
1 '

d) e) f)
,..,
~ ~
li:;. :;ii'' ' ;1 1!

-
1. :.:'
1

\liV \lW
~ \}JV
'::' ~
g) h) i)

Figura 8.1. Exemplu pentru n 4


\ianual de informati c pentru clasa a Xl-a 205

Comentarii referitoare la figurile anterioare


b) Observm c o dam trebuie s fie plasat singur pe linie. Poziionrn prima
dam pe linia 1, coloana 1.
c) A doua dam nu poate fi aezat decat n coloana 3.
d) Observm c a treia dam nu poate fi plasat n linia 3. ncercm atunci
plasarea celei de-a doua dame n coloana 4.
e) A treia dam nu poate fi plasat dect n coloana 2.
f) in aceast situaie dama a patra nu mai poate fi aezat. Tncercnd s
avansm cu dama a treia, observm c nu este posibil s o plasm nici n coloana
a-3-a, nici n coloana a-4-a, deci o vom scoate de pe tabl . Dama a doua nu mai
poate avansa, deci i ea este scoas de pe tabl . Avansm cu prima dam in
coloana a-2-a.
g) A doua dam nu poate fi aezat decat in coloana a 4-a.
h) Dama a treia se aeaz n prima coloan.

i) Acum este posibil s plasm a patra dam n coloana 3 i astfel am obin ut o


soluie a problemei.

Algoritmul continu fn acest mod pn cnd trebuie scoas de pe tabl


prima dam.

-+ Pentru cutarea i reprezentarea unei soluii folosim un vector cu n componente,


numit sol (avnd in vedere c pe fiecare linie se gsete o singur dam) . Prin
sol [il nelegem coloana n care se gsete dama de pe linia i.

Altu.rat, putei observa m~dul in care este reprezentat


soluia cu ajutorul vectorulUI sol .
2 4 1 3
- _ _ _ _
l 1 1 1 1

-+ Dou dame se gsesc pe aceeai diagonal dac i numai dac .este


Tndeplinit condiia:

lsol(i) -sol(j)l=li-jl
(diferena, n modul, dintre linii i coloane este aceeai).

Exemple:
a)
sol(l) = 1 i 1
sol(3) = 3 j = 3
lsol(l) - sol(3) 1 = 11 - 31 a 2
l i - jl = 11 - 31 = 2

Agura 8.2.
206 Capitolul 8. Metoda backtracking

b)
sol(l) = 3 i 1 =
sol(3) = 1 j =3
lsol(i) - sol(j) 1 = 13 - 11 = 2
li- jl = 11- 31 = 2

Figura 8.3.

1ntrucat dou dame nu se pot gsi n aceeai coloan, rezult c o soluie


este sub form de permutare. O prim idee ne conduce la generarea tuturor
permutrilor i la extragerea soluiilor pentru problem (ca dou dame s nu fie
plasate in aceeai diagonal) . Dac procedm astfel, nseamn c nu lucrm
conform strategiei backtracking. Aceasta presupune ca imediat ce am gsit dou
dame care se atac, s relum cutarea n alte condiii. Fa de programul de
generare a permutrilor, programul de generare a tuturor sol uiil or problemei celor
n dame are o singur condiie suplimentar, n subprogramul valid. Mai jos,
putei observa noua versiune a subprogramului valid. Dac l utilizai in locul
subprogramului cu acelai nume din programul de generare a permutrilor, vei
obine programul care rezolv problema celor n dame.

f unction valid(k:integer) : int valid(int k)


boolean; {
var i:integer; for (int i=1;i<k;i++)
if (sol[kl==sol[i] 11
begin abs(sol[k]-sol[i]) ~abs(k-i))
valid:true; return O;
for i : l to k-1 do return 1;
if (sol[k) sol[i l ) or }
(abs(sol[k]-sol[i ])=abs(k- i))
then
valid: false
end;

Problema este un exemplu folosit n mal toate lucrrile in care este


prezentat metoda backtracking.

In ceea ce ne privete, dincolo de un exemplu de backtracking, am avut


ocazia s vedem cat de mult seamn rezolvrile (prin aceast metod) a
dou probleme ntre care, aparent, nu exist nici o legtur.

Exerciii

1. Desenai configuraia tablei corespunztoare vectorului sol .. ( 3, 1, 4, 2, s) i


verificai dac aceasta reprezint o soluie a problemei damelor.
'Aanual de Informatic pentru clasa a Xl-a 207

2. Explicai de ce configuraia corespunztoare vecorului sol= ( 3 1 11 3 1 41 5 > nu


aste o soluie a problemei damelor. Care este poziia din sol la care nu s-a fcut
alegerea corect a unei valori valide?

3. Explicai de ce nu orice permutare a mulimii {11 21 ... 1 n) este o soluie a


oroblemei damelor pe o tabl cu n linii i n coloane.

4. Determinai, folosind metoda backtracking, o soluie care se obine pe o tabl cu


ase linii i ase coloane, tiind c dama plasat pe ultima linie trebuie s se afle
pe a doua coloan. Considerai c mai este util s completm vectorul sol
pornind de la poziia 1? Dac pornim de la poziia 1, ce adaptri trebuie fcute?

8.2. Mai puine linii n programul surs

Pan n prezent, am rezolvat dou probleme prin metoda backtracking:


generarea permutrilor i problema celor n dame. n ambele cazuri, am utilizat
subprogramul standard.

? Este Tntotdeauna necesar s-I folosim pe acesta sau putem reine numai
ideea i, dup caz, s scriem mai puin?

Evident, dup ce am neles bine metoda, putem renuna la subprogramul


standard. Pentru aceasta, ncorporm n subprogramul standard unele dintre
subprogramele pe care le-ar fi apelat.

Vom exemplifica aceast incorporare pentru problema celor n dame, deja


rezolvat standardizat.

-+ Putem elimina subprogramul init. Este foarte uor de realizat aceast


operaie. n locul apelului vom scrie instruciunea prin care componentei k i
se atribuie o.

-+ Putem elimina subprogramul solutie. ln locul apelului vom testa dac k


este egal cu n+l.

-+ Putem elimina subprogramul tipar. tn locul apelului vom scrie secvena


prin care se afieaz st.

-+ Putem elimina subprogramul succesor. fn locul apelului vom testa dac


st [kJ <n i avem grij s incrementm valoarea aflat pe nivelul curent.

Putei observa n continuare programul obinut. Este cu mult mai scurt!


Oricum, Ideea de rezolvare rmane aceeai. Subprogramele prezentate au fost
numai ncorporate, nu s-a renunat la ele.
208 Capitolul 8. Metoda backtracking

! .,. (, ,..,,..
Varianta Pascal .;, : ..'' Varianta C++
var sol:array[1 9] of integer; #include <iostream.h>
n:integer1 #include <math.h>
int n, sol[lO];
function
valid(k:integer):boolean l int :valid(int k)
{ for (int i=l;i<k;i++)
var i :integer; if {sol [k] ==sol [il 11
begin abs(sol[k]-sol[i])
valid:true; ==abs(k-i))
for i:=l to k-1 do return O;
if (sol[k]=sol[i]) or return 1;
(abs(sol(k]-sol[i])=abs( k-i)) }
then void back ( int k)
valid:=false { if (k==n+l) // solutie
end; //tipar
{ for (int i=l;i<=n;i++)
procedura back(k:integer); cout<<sol[i];
cout<<endl;
var i:.integer; }
begin el se
if kn+l {solutie} { sol[k]cO;
then while(sol[k]<n)
begin 11 succesor
{tipar} { sol[k]++i
for i:=l to n do if (valid(k))back(k+l);
write(sol[i));
writeln; }
end
main()
el se
begin { cout<<"n'""l cin>>n;
sol[k] :=O; {init} back(l);
while sol[k]<n do }
{succesor}
begin
sol[k]: .. sol[k]+l;
if valid(k)
then
back(k+l)
end
end
end1
begin
write( 'n=');
readln(n);
back(l)
end.

Uneori vei ntlni i o rezolvare precum urmtoarea, care n subprogramul


back, pentru succesor se folosete o instruciune repetitiv de tip for:
anual de informatic pentru clasa a Xl-a 209

t: Varianta Pascal .> :... '' . varianta C++

procedura back(k:int eger); void back(int k)


var i:integer; { int i;
begin if (k==n+l)
i f k=n+l { for (i=l;i<=n;i ++)
then cout<<sol [i];
begin cout<<endl ;
for i:=l to n do }
write(sol [i]); el se
writeln; for (i=l;i<=n;i ++)
end { sol[k]=i;
el se i f (valid(k))
for i:=l to n do back(k+l);
b egin }
sol[k] : =i ;
if valid(k)
then back(k+l)
end
end;

~ Exerciii
1. Testai subprogramuf anterior pentru problema generrii permutrilor.

2. Adaptai rezolvarea problemei permutrilor astfel nct s se afieze numai


permutrile n care oricare dou numere consecutive nu sunt a lturate.

3. Observai c ordinea de afiare a soluiilor depinde de ordinea n care se


consider elementele mulimilor Al, A2 , ... Ce modificri trebuie aduse
procedurii recursive back astfel nct permutarile de 4 elemente s fie afi ate n
o~~ea:4321,4312,4231,4213,4132,4123,3421,3412 ... 1243,1234 ?

4. Renu nai la utilizarea subprogramului valid, utiliznd un vector folosit , n


care folosit [il are valoarea o dac numrul i nu este deja folosit n soluie
i are valoarea 1 n caz contrar. Astfel, plasarea valorii i n vectorul soluie
(sol [kl ~i) trebuie nsoit de memorarea faptului c i este utilizat
(folosit [il ~1), la revenirea din recursie (cand se nltur valoarea de pe
poziia curent) fiind necesar memorarea faptului c i nu mai este utilizat n
so luie (folosit [il ~o). Condiia de validare se reduce n acest caz fa:

Dac folosit [i] =O atunci

5. toate modalitile diferite de a aeza patru obiecte identificate prin


Urm rii
numerele 1, 2, 3, 4 pe un cerc, la distane egale. Vom observa c nu toate
permutrile de patru obiecte sunt configuraii distincte, datorit distribuiei pe
cerc. Astfel permutrile 1234 , 2341, 3412 i 4123 reprezint una i aceeai
configura i e. Scriei un program care afieaz numai permutri le distincte
conform aezrii pe un cerc. Indicaie: se va considera ~ol [1] =1 i se vor
permuta doar celelalte elemente.
210 Capitolul 8. Metoda backtraclc-:::

8.3. Cazul n care se cere o singur soluie.


Exemplificare: problema colorrii hrilor

Sunt probleme care se rezolv cu metoda backtracking i in care se cere :


singur soluie.

Implementarea "ca la carte" presupune utilizarea unei variabile <*


semnalizare (de exemplu, variabila gata) care s fie iniial o, la obinerea solu ie
dorite aceasta primind valoarea 1 . Orice succesor va fi condiionat Tn plus dE
valoarea variabilei gata.

De aceast dat, pentru simplitate, vom renuna la programarea structura ~


i vom opri n mod forat programul.

-+ n Pascal, vei utiliza procedura halt.


-+ n C++, vei folosi funcia exit, cu parametrul EXIT_succEss
(o constant). Pentru a o putea utiliza, trebuie sa includei fiierul ante~
"stdlib.h":
#inolude<stdlib .h>.

ln ambele cazuri, secvena care determin oprirea forat este trecuta


imediat dup ce prima soluie a fost afiat.

~ Exerciiu. Modificai programul care rezolv problema celor n dame, astfel


nct acesta s afieze o singur soluie.

O Problema colorrii hrllor. Fiind dat o hart cu n ri, se cere o soluie de


colorare a hrii, utiliznd cel mult 4 culori, astfel incat dou ri cu frontier
comun s fie colorate diferit.

~ Este demonstrat faptul c sunt suficiente numai 4 culori pentru ca orice hart
.~ s poat fi colorat.

Pentru exemplificare, vom considera harta din figura 8.4., unde rile sunt
numerotate cu cifre cuprinse ntre 1 i 5 .

O soluie a acestei probleme este urmtoarea:

ara 1 - culoarea 1;
ara 2 -culoarea 2;
ara 3 -culoarea 1;
ara 4 -culoarea 3;
Figura 8.4.
ara 5 - culoarea 4 .
Manual de info rmati c pentru clasa a Xl-a 211

Harta este fu rnizat programului cu ajutorul unei matrice (tablou) An,n:

A(i,j) = {~: ara


altfel
i are frontiera comun cu ara j

Matricea A este simetric. Pentru rezolvarea problemei se utilizeaz


vectorul sol , unde sol [kl rei ne culoarea ataat rii k. Evident, orice soluie
are exact n componente.

var sol:array(1 9] of #incl ude <iostream. h>


integer; #incl ude <stdlib . h>
a:array[1 10 1 1 . 10] of int n 1 i, j, sol [10] 1 a [10] [10];
integer;
n1i 1 j:integer; int valid(int k)
{ for (int i=1;i<k;i++)
function
if (sol[k]==sol[i) &&
val id(k:integer):boolean;
a[i] [kl==1) return O;
begin
return 1;
valid:=true;
}
for i:~l to k-1 do
if (sol (k]=sol ( i)) void back(int k}
and (a[klil=1) { int i;
then valid:=false if (k==n+1)
end; { for (int i=1;i <=n;i++)
procedura back(k:integer); cout<<sol(i];
var i:integer; exit(EXIT_SOCCESS);
begin }
if k=n+1 then el se
begin for (i=1;i<=4;i++)
for j:=l ton do { sol[k]ci ;
write(sol [ j]); if (valid(k))
halt; back(k+1);
end }
el se }
for i:=l to n do
begin main()
sol[kl:=i; { cout<<"Numarul de tari =";
if valid ( k) cin>>n;
then back(k+l) for (int i=l;i<=n;i++)
end; for Cint j=1;j<= i - 1;j++)
end; { cout<<"a["<<I
begin <<','<<:!<<"]=";
write('Numarul de tari='); cina(i) (j] ;
readln(n); a ( j] [i] =a(i] [j];
for i:l to n do
for :1:=1 to i-1 do back(1);
begin }
wri te ( 'a [ , i 1 1 , j 1 ' l = ' ) ;
readln(a[i 1 j]);
a[j,i] :;:a[i,j ]
end;
back(1)
end.
212 Capitolul 8. Metoda backtrackinc

Exerciii

1. Soluia afiat este i soluia care utilizeaz un numr


minim de culori?
2. Dac rile din centrul figurii alturate sunt numerotate
cu 1, 2, 3, 4, iar cele de la exterior cu 5 i 6, care este
soluia afiat de programul dat? Este acesta numrul
minim de culori necesare?
3. Cte culori sunt suficiente pentru colorarea unei hri
particulare in care orice ar se nvecineaz cu cel Figura 8.5.
mult dou ri?
4. Dai exemplu de particularitate pe care poate s o aib o hart pentru a fi
suficiente dou culori pentru colorarea tuturor rilor?

8.4. Aplicaii ale metodei backtracking n


combinatoric

8.4.1 . O generalizare util

Acum, c am invat s generm permutrile mulimii {1, 2 n}, se pune


problema s vedem de ce este util acest algoritm. La ce folosete faptul c putem
aranja numerele {1, 2 n} n toate modurile posibile?

S observm c acest algoritm poate fi folosit pentru a aranja oricare n


elemente distincte n toate .11oduri1e posibile.

E,x: Exemple

1. Se d o mulime alctuit din n litere distincte. Se cer toate cuvintele care se


pot forma cu ele, astfel nct fiecare cuvnt s conin n litere distincte. De
exemplu, dac mulimea este {a,b,c), vom avea cuvintele: abc, acb, bac,
bea, cab i eba.

2 Se dau numele a n persoane. Se cere s se afieze toate modurile posibile n


care acestea se pot aeza pe o banc. De exemplu, dac n:o3, iar persoanele sunt
Ioana, costel i Mihaela, atunci soluiile sunt:

Ioana Costel Mihaela;


Ioana Mihaela Costel;
Costel Ioana Mihaela;
anual de informatic pentru clasa a Xl-a 213

n astfel de cazuri, cele n elemente distincte se memoreaz ntr-un vector v,


:: a cum vedei mai jos:

1 Ioana 1 Costel 1Mihaela 1


1 2 3 1 2 3

Atunci cnd s-a generat o permutare, de exemplu 213, vom afia


'7[2]V [l]V[3], adic bac, n primul caz sau Costel J:oana Mihaela, n al
:loilea caz.
Procedeul de mai sus poate fi folosit pentru oricare alt aplicaie din
n probleme cum ar fi : generarea tuturor submulimilor unei mulimi,
combinatoric ,
generarea aranjamentelor, a combinrilor sau a tuturor prilor unei mulimi.

p? Exerciiu. Scriei programul care rezolv exemplul 2.


, Mulimea permutrilor mulimii toate funciile
<11 21 n} reprezint
bijectlve f:(1121'''1n> - H1121 1n} . De exemplu, dac n=3,
permutarea 213 este funcia f:{11213}-H112,3} definit astfel:
f(1)=2; f(2)=1; f(3)=3.

8.4.2. Produs cartezian

O Enun. Se dau n mulimi: A1, A 2 , ... A", unde A1 =U1 2 1 ... 1 k 1 }, pentru
k==1, 2, 1 n. Se cere produsul cartezian al celor n mu limi.

Exemplu: A1 ={1,2}, A 2 ={1,2,3}, A 3 ={1,2,3}.


A1XA2XA3 ={(
1, 1, 1) , ( 1, 1, 2 ) , ( 1, 1, 3 ) , ( 1, 2 , 1) , ( 1, 2 , 2 ) , ( 1, 2, 3 ),
(1,3, 1), (1,3,2), (1,3,3), (2,1,1), (2,1,2), (2,1,3), (2,2,1),
( 2, 2, 2) 1 ( 2, 2, 3) , ( 2, 3, 1) , ( 21 3, 2) , (2, 3, 3) }

0 Rezolvare. De la inceput observm c este necesar s aflm toate soluiile.


S observm c o soluie este de forma x 1,x2, ,xD, cu x 1eA1 , x:~EA:~, ... ,
xnEAn De aici rezult necesitatea folosirii unui vector sol, cu n componente,
unde sol [1] va conine numerele naturale ntre 1 i k 1 , sol [21 va conine
numerele naturale ntre 1 i k 2 , ... , sol [nJ va conine numerele naturale ntre 1 i
kn Observm c valorile care pot fi luate sol [1] sunt ntre 1 i k 1 , valorile care
pot fi luate sol [2 J sunt ntre 1 i k 2 , ... , valorile care pot fi luate sol (nJ sunt ntre
1 i kn. Pentru a putea reine aceste valori, vom utiliza un vector a, cu n
componente, unde a [1] = k 1 , a [2 1= k:~ , ... , a [n] = k". Pentru exemplul dat,
vectorul a va reine ( 2, 3, 3) .
Important! S observm c orice valoare reinut de sol [il ntre 1 i k 1
indeplinete condiiile de continuare (este valid) .
Din acest motiv, nu mal este
necesar s utilizm subprogramul valid.
214 Capitolul 8. Metoda backtrackinc

Mai jos, putei observa programul care genereaz produsul cartezian al


mulimilor date:

var n,i:integer; #include <iostream.h>


sol,a:array[1 . 10] of int n, sol[lO],a[lO],i;
integer; void back(int k)
{ if (k==n+l)
procedura back(k:integer); { for (i=l;i<n;i++)
begin cout<<sol[i];
if k=n+l then
cout<<endl; }
begin
el se
for i1l to n do { sol[k]=O;
write(sol[i]); while(sol[k]<a[k])
writeln { sol[k]++; back(k+1); }
end )
}
el se
begin main()
sol [kJ :o O; {
while sol[k]<a[k] do cout<<"Numarul de multimi" 1
begin cin>>n;
sol[klsol[kJ+1; for(int il;i<n;i++)
back(k+l) { cout<<"a["<<i<<"]";
end cina[i] 1
end }
end; back(1);
)
begin
write('Numarul de multimi');
readln(n);
for i:=l to n do
begin
wri te ( 'a [ , i, '] ' ) 1
readln(a[i])
end;
back(l)
end.

J~ Observaii
1. Avem k1Xk:.~x... xk,. elemente ale produsului cartezian. De aici rezult c
algoritmul este exponenial.

2. O alt interpretare pentru metoda backtracking: fiind date n mulimi: A 1 , A2 , ... ,

A... produsul cartezian al lor A1XA:.~x XAz. se mai numete spaiul soluiilor. n
acest context, metoda backtracking caut una sau toate soluiile, care sunt
elemente ale produsului cartezian i care indeplinesc anumite condiii. Astfel, se
poate justifica faptul c, n generarea produsului cartezian, nu este necesar
subprogramul valid pentru c se genereaz toate elementele produsului
cartezian, fr a verifica anumite condiii.
Manual de informatic pentru clasa a Xl-a 2 ,-
.~

De i algoritmul este exponenia l , exist aplicaii utile, evident, atunci cnd


fiecare mulime A1 poate lua numai cteva valori i unde n este suficient de mic.

~ Exerciii
1. Tabelarea anumitor funcii. Se d funcia

unde fiecare mulime A1 este dat de numerele ntregi din intervalul [a 1 ,bd i

Se cere s se realizeze un tabel, n care pentru fiecare valoare din


domeniul de definiie s se afieze valoarea funciei corespunztoare acelei valori.

2. Scriei programul care genereaz toate "cuvintele" cu patru litere care au pdma
i ultima liter vocale, litera a doua consoan din mulimea {P, R, s, T} , iar a treia
1ter consoan din mulimea {B, M, R, T, V}.

3. Scriei programul care genereaz i numr eate cuvinte de cinci litere ale
alfabetului englez se pot forma, cu condiia s nu existe dou consoane al turate
i nici dou vocale alturate .

8.4.3. Generarea tuturor submulimilor unei mulimi

::J Enun. Fiind dat mulimea A={1 1 2, ,n}, se cere s se afieze toate
SJbm ulimile ei.

:tl Rezolvare. S ne amintim c submulimile unei mulimi A se pot reprezenta


:um vectorul caracteristic v, unde:

V[i] ={1, pentru i e A


O, pentru i e A
)e exemplu , dac AU~2,3}, pentru submu limea {1,3} vom avea
..,... ( 11 o1 1 >. De aici, rezult c problema se reduce la generarea tuturor valorilor
:osibile pe care le poate reine vectorul caracteristic.
Aceasta inseamn co soluie este de forma x1, x:~ 1 1 xn, unde
~e <o, 1}. i in acest caz, orice valoare ar reine componenta i, ea nu trebuie s
--de plineasc nici o condiie de continuare, motiv pentru care subprogramul valid
- .. este necesar.

ln continuare, putei observa programul care genereaz toate valorile pe


:.are le poate reine vectorul caracteristic:
216 Capitolul 8. Metoda backtracking

var n,i:int eger; #includ e <iostre am.h>


sol:arr ay[1 10] of i nt n, sol[lO ], i ;
intege r; void back(i nt k)
proced ura back (k:inte ger); { if (k==n+ l)
begin { for (i=l;i< =n;i++ )
if k=n+1 then cout<< sol[i);
begin cout<< endl;
for i:=1 to n do }
write( sol[il) ; el se
writel n { sol[kJ= -1;
end while( sol[k]< l)
el se { sol[k]+ +;
begin back(k +l);
sol[k]: =-1; }
while sol[k]< l do }
begin }
sol[k] :=sol[k ]+1;
main()
back(k +l)
{ cout<< "n="; cin>>n ;
end back(l );
end }
end;
begin
write ( 'n=');
readln (n);
back(l )
end.

~ Exerciii
valor.:
1. Problema nu este rezolvat in totalitate. Programul afieaz numai toate
program ul s.:
pe care le poate lua vectorul caracteristic. Completai-! astfel incat
afieze oate submulimile mulimii <1, 2 n} 1

2. Se citesc numele a 6 e~evi. Afiai toate submutimile mulimii celor 6 elevi.

in baza ;.
3. S se afieze toate numerele scrise in baza 10 a cror reprezentare
cu 1. Valorile n i k se citesc de ..i
are n cifre, dintre care exact k sunt egale
tastatur (n<12, k<n). De exemplu, pentru n:c3 i k2, se obin valorile: s i 6.

4. un program care genereaz combinaii de n cifre o i 1 cu proprieta:=.i.


Realizai
c in orice grup de 3 cifre consecutive exist cel puin
o cifr de 1. De exemo _
dac nc:4, se afieaz combinaiile: 0010, 0011, 0100,
0101, 0110, 0111, 1 0 c:
1010,1 011,11 00,110 1,1110 ,1111.
mul,....
5. Se citesc dou numere naturale n i s (n<10, s<lOOO ). S se afieze
elemen telor din fieca;
formate din n numere prime cu proprietatea c suma
mulime este exact s.
tanual de informatic pentru clasa a Xl-a 217

,
1
Observaii
Fiind dat o mulime
cu n elemente, avem 2n submulimi ale ei. Mulimea
dat~ i submulimea vid sunt submulimi ale mulimii datei De ce? Fiecare
component a vectorului caracteristic poate reine dou valori. Prin urmare,
numrul de submulimi este

222
~
...2=2" .
uenori

De aici rezult c algoritmul care genereaz toate submulimile mulim i 1 ,


2 ... , n este exponenial.

Uneori, vei rezolva probleme in care se d o mulime i se cere o submulime


a sa care ndeplinete anumite caracteristici. in anumite situaii, problema se
poate rezolva prin utilizarea unor algoritmi mai rapizi (polinomiali). Greeala
tipic care se face este c se genereaz toate submulimile, dup care se
selecteaz cea (cele) care indeplinete condiiile date.

Exemplu. Se d o mulime de numere reale. Se cere s se determine o


submulime a sa care are suma maxim. Problema se rezolv uor: se
consider ca fcand parte din submulime numai numerele pozitive. Altfel,
dac am genera toate submu limile...

4.4. Generarea combinrilor

Fiind dat mulimea A=U~2~ 1 n}, se cer toate submulimile ei cu p


mente. Problema este cunoscut sub numele de "generarea combinrilor de
ate cte p". Se tie c numrul soluiilor acestei probleme este

CP = n!
n (n - p)!p!

exemplu, dac n=4 i pa3, soluiile sunt urmtoarele:


{ 11 2 1 3} { 11 2 1 4 } , { 11 3 1 4} i { 21 31 4 }.

Enun. Se citesc n i p numere naturale, n~. Se cere s se genereze toate


<
~m ulimile cu p elemente ale mulimii A 1, 2, , n}.

Rezolvare. O soluie este de forma x 1, x 2, 1 :xp, unde x 1, x:~. ..., :xpe A.


lus, x1, x2, ... , xp trebuie s fie distincte. Cum la o mulime ordinea elementelor
prezint importan, putem genera elementele ei in ordine strict cresctoare .
~st observaie ne ajut foarte mult n elaborarea algoritmului.

Pentru k>1, sol [k] >sol [k-1].

~---- -r~=~- -
218 Capitolul 8. Metoda backtracking

b) Pentru fiecare ke{1,2, ,p}, soltk1~-p+k. S presupunem , prin


absurd, c aceast ultim relaie nu este respectat. Aceasta fnseamn c 3k,
astfel nct sol [k] >n-p+k. Deci:

sol [k+l] >n-p+k+1,

sol [p] >n-p+p=n.

Absurd. De aici rezult c:

l :S:sol [1] ~-p+l ,


sol[l]<sol[2]SD-p+2,

sol[n-1]<sol(n]~-p+p=n.

Relaiile de mai sus simplific mult algoritmul, pentru c innd cont de ele, nu mai
este necesar s se testeze nici o condiie de continuare.

var sol:array[l .. 9] of integer; #include <iostream.h>


n,p:inteoer; int n,p,sol[lO];
procedura back(k:inteoer); void back(int k)
var i:inteoer; { int i;
beoin i f (k==p+l)
if k=p+l { for (ilJi<p;i++)
then cout<<sol[i]J
begin cout<<endlJ
for it=l to p do }
write(sol[i]); el se
writeln; { if (k>ll sol[k]=sol [k-l]t
end else sol[k]=OJ
el se while(sol[k]<n-p+kl
begin { sol[k]++;
if k>l then sol[k] t =sol[k-1] back(k+l); }
elee sol[k]:O; }
)
while sol[k]<n-p+k do
beoin main()
sol[k] :=sol[k]+l; { cout<<"n"J cin>>n;
back(k+ll; cout<<"p="; cin>>p;
end back(l) 1
end }
end;
begin
wri te ( ' n= ) 1
readln(n);
write ( ' p= ' );
readln{p);
back(l);
end.

Examinnd raionamentul propus putem observa c, fn anumite cazuri,


ana\rz.a une\ >lc'o\em~ CC,\\\\lce \a \ln ~~c~~m C\l m\l\\ ma\ ra:?\\\.
c:-ual de informatic pentru clasa a Xl-a 219

.".fi Exerciii
Se dau coordonatele din plan a n puncte. Afiai coordonatele vrfurilor tuturor
::c:ratelor care au ca vrfuri puncte din mulimea considerat.

; . Se dau n substane chimice. Se tie c, n anumite condiii, unele substane intr


,. eacii chimice cu altele. Fiind date p perechi de forma ( i, j) cu semnificaia c
s..~stana i intr n reacie cu substana j, se cer toate grupurile de s<n substane
:sfel nct oricare dou substane din grup nu intr n reacie.

5.4. 5. Generarea aranjamente;pr

Se dau dou mulimi A={l,2, ,p} i B={1,2, ,n}. Se cer toate


~nciileinjective definite pe A cu valori n B. O astfel de problem este una de
;-enerare a aranjamentelor de n luate cte p (A~ ).

: xemplu: p=2, n=3. Avem: 12, 21, 13, 31, 23, 32. De exemplu, 21 este funcia
: :A-4B dat astfel: f (1) =2; f (2) =1. Avem relaiile:

ni
A~ = = n(n-1) ... (n-p+1).
(n - p)!

O Enun. Se citesc n i p . S se genereze toate aranjamentele de n luate cte p.


S observm c dac se cunoate fiecare submulime de p elemente a
m ulimii de n elemente, atunci aranjamentele se pot obine permutnd n toate
modurile posibile elementele unei astfel de mulimi. Pornind de la aceast
o bservaie, suntem tentai s generm toate submulimile cu p elemente ale
mulimii cun elemente i, din fiecare astfel de submulime, s obinem permutrile
el. Exerciiu!

Pe de alt parte, se poate lucra mult mai eficient. O soluie este de forma:
x1x2 xp. unde x1, x:~, ... , XpEB. n plus, x 1, x:~, ... , Xp trebuie s fie distincte.
Spre deosebire de algoritmul de generare a combinrilor, aici ne intereseaz toate
permutrile unei soluii (acestea sunt, la rndullor, alte soluii). Aceasta nseamn
c nu mai putem pune n soluie elementele n ordine cresctoare. S recapitulm:

- o soluie are p numere din B;

- numerele trebuie s fie distincte.

Rezult de aici c algoritmul este acelai de la permutri, diferena fiind dat


de faptul c soluiaare p numere, nun ca n cazul permutrilor.
:
220 Capitolul 8. Metoda backtracking

._ d
Varianta C++

var sol:ar ray[1 9]of intege r; #inclu de <iostre arn.h>


n,p:in teger; int n,p,so l[10];

functi on int valid (int k)


valid( k:inte ger):b oolea n; { for (int i=l;i< k;i++ )
var i:inte ger; if (sol[k l==so l[i])
begin return O;
valid: =true ; return 1;
}
for i:l to k-1 do
if sol[k] =sol[i ] then void back( int k)
valid: =false { int i,j;
end; if (k==p+ l)
proced ura back( k:inte ger); { f or (j=l;j< =p;j++ )
var i,j:in teger ; cout< <sol[j ];
begin cout<< endl;
if kp+l then
begin el se
for j:=l to p do for (i=l;i< =n;i++ )
write (sol[j ]); { sol[k] =i;
writel n if (valid (k))
end back(k +l);
el se
for i:=l to n do
begin main( )
sol[k ]:i; { cinn ;
if valid( k) then cin>>p ;
back(k +l) back( l);
end }
end;
begin
readln (n) J
readln (p);
back( l)
end.

~ Exerciii
care se pot forma
1. Se citesc n, p i apoi n litere distincte. Afiai toate cuvintele
cu p dintre ele.
numele care se
2. Se citesc n i apoi: numele mici a n persoane. tiind c toate
nume de biei, s se afieze
termin cu a reprezint nume de fat, celelalte fiind
Dou mulimi sunt distincte
toate mulimile de perechi fat-biat care se pot forma.
lu, pentru n=S, Maria , Ana,
dac cel puin una dintre perechi difer. De exemp
a-Dor u, Ana-C osmin },
Doina , Doru, Cosmi n, se afieaz mulimile: {Mari
{Doin a-Dor u,
{Ana- Cosmi n,Mar ia-Dor u}, {Mari a-Dor u,Doin a-Cos rnin},
-Cosm in}.
Maria -Cosm in}, {Ana- Doru,D oina-C osmin }, {Doin a-Dor u,Ana
Manual de informatic pentru clasa a Xl-a 221

3. Cei n acionari ai unei firme trebuie s organizeze un numr maxim de edine


tip mas~ rotund~ ta care s~ participe exact p dintre ei. tiind c oricare dou
edine trebuie s difere fie prin acionarii prezeni, fie prin vecinii pe care
i au
acetia la mas, stabilii numrul de edine pe care le pot organiza. De exemplu,
dac n=.O. i p3, atunci sun\ posibi\e s conftgurai"l cliterite ale celor 3
acionari
aezai la masa rotund : 1-2-3; 1-3-2; 1-3-4; 1-4-~; 2-3-4;
2-4-3
(configura iile 2-3-1 i 3-1-2 nu se consider, deoarece sunt echivalente,
la
masa rotund, cu configuraia 1-2-3).

8.4.6. Generarea tuturor partiiilor mulimii {1, 2, ... , n}

Definiia 8.1. Fie mulimea A=< 1, 2, , n}. Se numete partiie a


mulimii A, un set de :Jc;;n mulimi care ndeplinesc condiiile de mai jos:

Exemplu. Considerm mulimea A=< 1, 2, 3}. Avem partiiile:


{1,2,3}
{1, 2} {3}
{1, 3} {2}
{2,3} {1}
{1} {2} {3}

D Enun. Se citete un numr natural, n. Se cer toate partiiile mulimii


A= { 11 2 1 , n} .

0 Rezolvare. Chiar dac tim s generm toate submulimile unei mulimi, tot nu ne
ajut s generm toate partiiile.

1 Pentru a putea genera toate partiiile, trebuie s gsim o metod prin care s
putem reine o partiie. O prim idee ne conduce la folosirea unui vector, sol, astfel:
dac sol [il k, atunci elementul i se gsete n mulimea k a partiiei. Totui, nu
tim cte mulimi sunt in partiia respectiv . Exist o partiie care conine n mulimi
atunci cnd fiecare element este ntr-o mulime i una care conine toate mulimile,
adic tocmai mulimea A. Cu alte cuvinte, numrul mulimilor dintr-o partiie este
ntre 1 i n.

2 Pentru a avea o ordine n generarea soluiilor, elementele mulimii A trebuie s


aparin de submulimi consecutive ale partiiei.

-+ Din acest motiv, sol [il va lua valori ntre 1 i


l+max{s ol [1], sol [2] 1 1 sol [i-1]}.
222 Capitolul 8. Metoda backtracklng

Prin aceast condiie se evit situaia in care, de exemplu, vectorul sol reine
<1, 3, 1). Aceasta ar avea semnificaia c elementele 1 i 3 se gsesc in
submulimea 1 a partiiei, iar elementul 2 se gsete in submulimea 3 a partiiei. ln
acest caz, lipsete submulimea 2 a partiiei.

S exemplificm funcionarea algoritmului pentru cazul n=3:

- sol=(l,1,l) - A1 =(1,2,3);

- so1=(1,1,2)- A1 =(1,2} A2 ={3};

- sol=(1,2,l) - A1 ={1,3} A2 =(2};

- sol=(1,2,2)- A1 ={1} A2 =(2,3};

- sol-::(1,2,3)- A1 ={1} A2 ={2} A3 ={3}.

~.11 S observm c nici in cazul acestei probleme nu trebuie s verificm existena


fi .! anumitor condiii de continuare.

Analizai programul astfel obinut!


' .~ ...;;. ' .!ly'..: ' . ":. " '1
Varianta Pascal r , arlanta C+-f:,
var sol:array[0 . 10]of integer; #include <iostream.h>
n,i,j,max~:integer; int n, sol[10],
max[lO],i,j,maxim;
oroced",;re t.~art ..... a.~~ "'C,.~~""""C. '-"\
"l:1o-.":...-,;"
{ maximlJ
m.axim:=l;
for (i2;i<nJi++)
for i:=2 to n do
if (maxim<aol[i])
if maxim<sol[i]
maxim-sol (i] 1
then maxim1gsol[i];
cout<<"Partitie "<<endl;
writeln( 'Partitie ) 1
for (il;i<=maxim;i++)
for i:=1 to maxim do
{ for (j1; j<-n;j++)
begin
if (sol[j)uzi)
for j:a1 ton do
cout<<:l<<" ";
if sol[j]i
cout<<endl;
then write (j, 1 1 )
1
}
writeln1
}
end;
end; void back(int k)
{ int i,j,maxprec;
procedura back (k1integer); if (kn+l) tipar();
var i,j,maxprec;integer; else
begin { maxprecO;
if k=n+l for (j1;j<=k-1;j++)
then tipar if (maxprec<aol[j])
el se maxprec=sol[j];
begin for (i1;i<=maxprec+1;i++)
maxprec:=O; { sol[k)=i; max[k]=sol[k]J
for jz=1 to k-1 do back(k+l);}
if maxprec<sol[j] then }
maxpreCI"'80l[j]; }
Manual de informatic pentru clasa a Xl-a 223

for i:=l to maxprec+l do main()


begin ( cout<<"n=";
sol [k] Pit cin>>n;
back(k+l) back(l);
end; }
end
end;

begin
write('n='); readln(n);
back(l);
end.

~ Exerciiu. Putei arta c oricrei partiii i aparine un unic coninut al


vectorului sol, obinut ca n program?

Indicaie. Observai c ntotdeauna elementul 1 aparine primei submulimi a


partiiei, elementul 2 poate aparine submulimilor 1 sau 2 ale partiiei, ... ,
elementul n poate aparine submulimilor, 1, 2 sau n ale partiiei. Pornind de aici,
construii vectorul sol!

innd cont de faptul c oricrei partiii i corespunde un unic coninut al


1
~ Jtt' vectorului sol i oricrui coninut al vectorului sol ii corespunde o unic
partiie, am obinut, practic, o funcie bijectiv de la mulimea partiiilor
mulimii A la mulimea coninuturilor generate de algoritm ale vectorului sol.
Pornind de la aceast bijecie, n loc ca algoritmul s genereze partiiile, el
va determina coninuturile vectorului sol. Apoi, pentru fiecare coninut al
vectorului sol, se obine o partiie .

/ Exerciiu. Modificai programul precedent pentru ca acesta s afieze toate


partiile care conin exact 3 submulimi.

8. 5. Alte tipuri de probleme care se re-zolv prin


utilizarea metodei backtracking

8.5 .1. Generaliti

Toate problemele pe care le-am ntlnit pn acum admit solui i care


ndeplinesc urmtoarele caracteristici:
-+ soluiile sunt sub form de vector;
-+ toate soluiile unei probleme au aceeai lungime, unde prin lungime
nelegem numrul de componente ale vectorului soluie.
224 Capitolul 8. Metoda backtracking

Exemple. Fie mulimea A== (1, 2 X?-}. Atunci:


1

a) Toate permutrile mulimii A au lungimea n.

b) Toate submulimile fU p elemente ale mulimii A (generarea combinrilor) au


lungimeap.

c > Toate soluiile sub form de vector ale problemei generrii tuturor partiii lor
mulimii A au lungimea n.

ln realitate, cu ajutorul metodei backtracking se pot rezolva i probleme care nu


ndeplinesc condiiile de mai sus. Astfel, exist probleme n care nu se cunoate de la
nceput lungimea soluiei, exist probleme care admit mai multe soluii de lungimi
diferite, exist probleme n care soluia este sub forma unei matrice cu dou sau trei
linii etc. Exemplele urmtoare v vor convinge.

8.5.2. Generarea partiiilor unui numr natural

O Enun. Se citete un numr natural n. Se cere s se tipreasc toate modurile


de descompunere a lui ca sum de numere naturale. De exemplu , pentru nc:4,
avem:4,31,22,211,13,121,112,1111.

f Ordinea numerelor din sum este important . Astfel, se tiprete 11.2 dar
J;. i 211, 121.

0 Rezolvare. De la nceput, observm c nu se cunoate lungimea unei soluii.


Ea poate fi cuprins ntre 1, n cazul n care numrul n sine constituie o
descompunere a sa i n, atunci cnd numrul este descompus ca sum a n
numere egale cu 1.

Trscem la stabilirea algoritmului pe care l vom folosi.

1. Fiecare component a vectorului sol trebuie s rein o valoare mai


mare sau egal cu 1.

2. Mai nti s observm c, n procesul de generare a soluiilor, trebuie ca


n permanen s fie respectat relaia

sol[l]+sol[2]+ sol[k]~.

3. Avem soluie atunci cnd

so1[1]+sol[2]+ sol[k] =n.

Rezult de aici c trebuie s cunoatem, la fiecare pas k, suma


s= sol [1] +sol [2] + sol [k-1].
Manual de inform atic pentru clasa a Xl- a
225
O prim posibilitate ar fi ca la fiecare pas s calculm
aceast sum. Dar, se
poate lucra eficient. Suma va fi reinut n perma
nen intr-o variabil global,
numit s.

Mai jos, este prezentat funcionarea algoritmului pentru n=4:

~~ie
[lo 1o o J1l1lo o 11111110
s=O,I<=l s=l,k =2 s=2,k::=3
~
s=3,k=4

~ie ~ie ~ie


s=2,k=3
2
Il 1 2 1o 1o 1 1 3
s=l,k =2 s=3, k=3 s=l,k =2

'
Observaimodul in care ca lculm suma la fiecare pas. De cte
ori se trece
la componenta urmtoare (k+l) , las se adun sol
[kJ, de cte ori se face
pasul napoi (se trece la componenta k-1), din s se
scade sol [kl.
Programul este prezentat n continuare:

Varia nta Pasca l ' ' .., . .,. Vari a ni~ C++
var sol: array [1 . 100] of integ er; #incl ude <iost ream. h>
n,i,s :inte ger; int sol[lO O], n,i,s ;
proce dura back (k:in teger ); void back (int k)
begin
{ if {s===n )
if s=n then begin { for (i=l;i <==k -l;i++ )
for i:=l to k-1 do cout< <sol CiJ;
write (sol[ iJ); cout< <endl ;
write ln; }
end el se
else begin { sol[k ]=O;
sol[k ]:=O; while (sol[ k]+s <n)
while sol[k ]+s<n do ( sol[k ]++;
begin s+=s ol[k] ;
sol[k ] :=sol [kl+l ; back( k+l);
s:=s+ sol[k ]; back( k+l); s-=so l[k];
s: =s-so l[k]
end; }
end }
end;
main( )
begin
{ cout< <"n=" ; cin>> n;
write {'n= ') ; readl n{n);
back (l);
back{ l) }
end.
226 Capitolul 8. Metoda backtracking

~Exerciii
1. Cum trebuie procedat n cazul n care se cere ca soluiile s fie afiate o singur
dat? Spre exemplu, dac s-a afiat descompunerea 1,1, 2 s nu se mai afieze
2 , 1,1sau1, 2,1?
Indicaie: procedeul a mai fost ntlnit, de exemplu la generarea combinrilor.
Soluiile se vor genera n ordine cresctoare. Modificai programul n acest sens.
2. Adaptai metoda de rezolvare astfel nct s se genereze numai partiiile formate
din numere naturale distincte.
3. Adaptai metoda de rezolvare astfel nct s se genereze numai partiiile formate
din cel puin p numere naturale distincte (n i p citite de la tastatur).
4. Adaptai metoda de rezolvare astfel nct s se genereze numai partiiile formate
din numere naturale aflate n intervalul [a, bl (n, a i b citite de la tastatur).
5. Rezolvai problema scrierii numrului natural n ca sum de numere naturale
alese dintr-o mulime format din k valori date {v1, v2, ... , vk}. Astfel, 10 se
poate scrie ca sum de numere alese din mulimea {2,3,6} n felul urmtor:
10=2+2+2+2+2, 10=2+2+3+3,10=2+2+6.

8.53. Plata unei sume cu bancnote de valori date

O En un. Se dau suma s i n tipuri de monede avnd valori de a 1 ,a2 , ,a0 lei. Se
cer toate modalitile de plat a sumei s utiliznd aceste monede. Se presupune
c se dispune de un numr nelimitat de exemplare din fiecare tip de moned.

lat soluiile pentru Suma=5, n=3 (trei tipuri de monede) cu valorile 1, 2, 3:

1) 1 de 2, 1 de 3; 2) 1 de 1, 2 de 2 ; 3) 2 de 1, 1 de 3;
4) 3 de 1, 1 de 2; 5) 5 de 1;

0 Rezolvare. Valorile celor n monede sunt reinute de vectorul a. Astfel, a [1] va


reine valoarea monedei de tipul 1, a[2] valoarea monedei de tipul 2, .a.m.d.
Numrul de monede din fiecare tip va fi reinut de vectorul sol . Astfel, sol [1] va
reine numrul de monede de tipul 1, sol [2] va reine
numrul de monede de tipul 2, .a. m .d . 1n aceste condiii, o sol 2 O 1
ffiffij
soluie pentru exemplul anterior arat ca alturat, unde suma 5 a 1 2 3
se formeaz cu dou monede de 1 i o moned de 3.

.11..~ Ce observm?
22 /
,,.anual de informatic pentru clasa a Xl-a
situaie corespunde
torului sol care rein o. Aceast
1. Exist componente ale vec ul. Din ace st motiv, fiecare
v nu este luat fn calc
:az ulu i n care mo ned a respecti are aflat naintea tuturor celo
r
component a vectorului
sol va fi iniializat cu o valo
oosibile, adic cu -1.
de tipuri de monede).
componente (n este numrul
2. Orice soluie are exa ct n t luate n calcul.
edele, chiar i cele care nu sun
Acest numr include toate mon
manen sum a obinut
la un
rioar, vom reine n per
3. Ca i la pro blem a ante
, avem la dispoziie suma:
moment dat. Astfel, la pasul k
l[k -1]
ol[ 2] + + a[k -l] *so
s a(l ]*s ol[ l] + a(2 ]*s

4. Avem soluie dac:


a[n ]*s ol[ n] =S um a
s = a[l ]*s ol[ l] + a[2 ]*s ol[ 2] + +

prin desene, ca la problema ante


rioar, modul
~ Exerciiu. lncercal s arttruai,sum a.. s i n3 .
de obinere a tuturor soluiilor
pen
gramul:
n continuare, este prezentat pro
~ ..cl.' ,~~ .,.~~" ........
. f 1a......
: .,, ,;.Y~ )\!:'!: ..
.. ~' .: ..... ,,;;,. ' ~ '' ++ ~ ..1 'irr
. "',~. . Pascal ......., "': .'' :..', ~: 1
'', 1 , '"1 . :1!.~ Varianta
1

#in clu de <io stre am .h>


var sol ,a: arr ay[ 1 100 ) int sol [lO O], a(lO O),
of int ege r; n,i ,s,s um a;
n,i ,s,S um a:in tag arJ
r); voi d bac k(i nt k)
pro ced ura bac k (k: int ega { if (s=:aSUJIIa)
beg in { cou t<< "So 1ut ie "<< end ll
if ssu ma the n for(il;i<~k-1;i++
)
beg in if( sol [i] )
wr ite ln( So lut ie ); cou t<< sol [i]< <"m one de de
"
for i:= l to k-1 do <<a [i]< <en dl;
if sol [i]< >O the n cou t<< end l;
wr ite ln (so l[i] , mon eda }
de ',a [il ) ;
el se
wr ite ln;
{ sol (kJ :o-1 ;
end wh ile( sol [k] *a[ k]+ s<S um a
el se &:&: k<n +l)
beg in {
sol [k] :=- 1; sol ,(kl ++;
a)
wh ile (so l[k) *a[ k]+ s<S um s+a sol (k] *a( k];
and (k< n+l ) do
bac k(k +l) ;
beg in s-" .so l [)tl *a[ k];
sol [k] :=s ol[ k]+ l;
}
s:= s+s ol[ k)* a[k );
}
bac k(k +1) ;
}
s:= s-s ol[ k]* a[k l
end ; mai n ()
end { cou t<< "gu mac "; cin> >Su ma;
end ; cou t<< "n "; cin >>n;
228 Capitolul 8. Metoda backtracking

begin for (i=l;i <=n;i ++)


write ('sum a='); readln (suma ); { cout< <"a["< <i<<" ]=";
write ('n=') ; readl n(n); cin>> a[i];
for i:=l to n do }
begin back( l);
write {'a[ ,i,'l= '); }
readl n(a[i ]);
end;
back( l)
end.

~ Exerciiu. Adaptai rezolvarea problemei plii


unei sumei cu bancnote date
cunoscnd, n plus, pentru fiecare valoare ai numrul
lim it bi de bancnote cu
valoarea respectiv.. disponibile. Astfel, pentru s=100 , a=<
2, 5, so), b= <10, 6, 3) ,
varinata s=l.Ox 5+l.x5 0 nu corespunde cerinei deoarece
nu avem la dispoziie 10
monede de 5, ci doar 6.

8.5.4. Problema labir intul ui

O Enun. Se d un labirint sub form de matrice cu m linii i n coloane. Fiecar


e
element al matricei reprezint o camer a labirintului.
ntr-una din camere, de
coordonate lin i col, se gsete un om. Se cere s se
gseasc toate ieirile
din labirint. Nu este permis ca un drum s treac de dou
ori prin aceea i camer .
O prim problem care se pune este precizarea modului de codificare a
ieirilor din fiecare camer a labirintului.

Fie 1 (i, j) un element al matricei. Acesta poate lua valori


ntre o i 15. Se
consider ieirile spre nord, est, sud i vest, luate fn aceast ordine. Pentru
fiecare
direcie cu ieire se reine 1, iar in caz contra
r, se reine o. Un ir de patru cifre :.
sau o formeaz un numr in baza 2. Acest numr este
convertit n baza 10 .
reinut n 1 <i, j ) . De exemplu, pentru o camer
care are ieire n nord i ve s~
avem 1001m =9(10 l

Exem plu. Alturat este prezentat un labirint. Acolo


unde nu este permis trecerea dintr-o camer n alta, se 15 11., "10 1 if 14
marcheaz cu o linie oblic. De asemenea,
matricea 111 1~ 114 ~ 1)
reine i valorile corespunztoare ieirilor, aa
cum sunt ...7
ele cerute de program. 11.- " ...6 15

0 Rezol vare

1. O camer vizitat se reine prin coordonatele ei:


lin (linia) i col (colana) .
Din acest motiv, pentru a reine un traseu vom utiliza o matric
e cu dou coloane i
mai multe linii: sol. De exemplu, dac camera iniial
este cea de coordonate
( 2, 2 > o soluie este <2 , 2 >, ( 2, 3 ). ( 1, 3 ) .
Manual de informatic pentru clasa a Xl-a 229

2. Nu toate solui ile au aceeai lungime, ntruct exist trasee de lungime d iferit.
Se obine o soluie atunci cnd coordonatele camerei unde s-a intrat sunt n afara
matricei (nu au linia ntre 1 i m i nu au coloana intre 1 i n). Evident, atunci cnd
s-a gsit o situaie, aceasta se afi eaz.
3 Spunem c o camer este accesi bil dac exist intrare din camera curent
ctre ea. Atenie la modul (vedei programul) Tn care testm dac o camer este
accesibil sau nu. Este o operaie in care se testeaz conin u tul unui anumit bit.
Acesta se obine efectu nd un I logic intre dou valori. De exemplu, dac testm
i e irea spre sud , atunci efectum I logic ntre 0010( 21=2<lo> i valoarea reinut
n matrice pentru camera curent. Dac valoarea obinut este diferit de o, atunci
avem ieire din camera cu rent ctre sud.
4 . nainte de a intra ntr-o camer accesibil se testeaz dac respectiva camer
a mai fost vizitat sau nu. Pentru aceasta utilizm funcia vizitat. ln caz c a
fost vizitat, se face pasul inapoi.
Analizai programul:

Varianta Pa~cal
var sol : arr ay [1 100,1 . 2] of # include <iostream.h>
integer; int sol [100] [ 2] , 1 [10] [10],
l:array [0 . 10,0 . 10] of m,n, i,j,lin,col;
integer; i nt vizitat ( int k, int lin,
m,n,i , j,lin,col:intego r; int col)
function vizitat (k,lin, [ int v O;
col:integer):boo lean; for (i.,l;i<=k;i++)
begin if (sol [i] [O]==lin &&
vizitat: = false; sol [i] [l]a=col) val;
for i: =l to k-1 do 1 return v;
if (sol[i,l]=lin) and }
(sol[i,2]=col)
void tipar (int k,i nt lin,
then vizitat:=true; int col)
end; { cout <<" Solutie "<<end l. ;
procedura for (i.,1 ; i<=k-1;i++)
tipar(k,lin,col:i nteger); cout<<sol[i] [0] <<" "
begin <<sol [i] [1] <<e ndl;
writeln('Solutie '); if ( lino:nO)
for i: =1 to k-1 do cout<<"iesire prin nord"
writeln(sol [i , 1],' , <<endl ;
sol[i,2 ]); el se
if lin.. o then i f (lin==m+l)
writeln('ie sire prin nord ' ) cout<<"iesire prin sud"
el se <<endl;
if lin=m+l then el se
wri teln ( iesire pri n sud' ) if (col==O)
el se cout<< "iesire prin vest"
if col= O t:hen <<endl ;
writeln(' l esire prin vest') el se
el se cout<< "iesire prin est"
writeln( iesire prin est '); <<endl;
readln; }
end;
230 Capitolul 8. Metoda backtracking

procedura void back(int k, int lin,


back{k,lin,col:i nteger); int col)
var i : integer; { if (lin==O 11 lin==m+1 11
begin col==O 11 col==n+1)
if (lin=O) or {lin~+1) or tipar(k,lin~col);
{col=O) or {col=n+1) el se
then tipar{k,lin,col) {
el se sol [k] [0) =lin;
begin sol[k] [l)acol;
sol[kl1]:=lin;
for (int i=1;i<"'4 1i++)
sol[k~2J:=col;
switch(i)
for i:=1 to 4 do
{
case i of
1:if (l[lin,col] case 1:
and 8<>0) and not if {l[lin] [col] & 8 &&
vizitat(k, lin-11col) 1 vizitat(kl lin-1,col))
then back(k+1,lin-1,c ol)1
back(k+1,lin-1~col); break;
2:if {l[lin,col] case 2:
and 4<>0) and not if (l[lin] [col] & 4 &&
vizitat(kllinlcol +1) 1 vizitat(k, lin,col+l))
then back(k+lllin,col +l);
back(k+11lin~col+1)1 break;
J:if (l[lin,col) case 3:
and 2<>0) and not if (l[lin] [col] & 2 &&
vizitat{kllin+11 ool) 1 vizitat(k 1 lin+l,col))
then back(k+l,lin+l,c ol);
back(k+1 1lin+1,col); break;
41if (l[lin 1 col] case 4:
and 1<>0) and not if (l[lin] [col] & 1 &&
vizitat(k,lin,co l-1) 1 vizitat(k, lin 1Col-1))
then back(k+l,lin,col -1);
baok(k+1,lin,col -1) break1
end; {oase} }
end }
end;
begin main()
write( 'M ) 1 { cout<<"M";
readln (m) 1 cin>>m1
write( 'N ) 1 cout<<"N";
readln(n) 1 cin>>nl
for i:1 to m do for (i=l1i<=m1i++)
for :1:=1 ton do for(:lll:l<=n;:l++ )
begin { cout<<"l["<<i<<" ,"
wri te ( ' l [ 1 i, ' 1 ' , :1 1 ' J=' ) 1 <<:!<<")";
readln(l[i 1 :1]) cinl [il [j];
end1 }
wri te ( lin.. ' ) 1 cout<<"Linie=";
readln (lin); cinlin;
write{ 'col'"') 1 cout<<"Coloana.. ";
readln(col)l cin>>col;
back(11lin~col) back(1,lin,col);
end.
\1anual de informatic pentru clasa a Xl- a 231

? Intrebare. Cum s-ar putea gsi un drum de lungime minim de la camera


iniial ctre ieirea din labirint? Prima idee care ne vine in minte este s
9 enerm toate ieirile, ca in program, pentru a o putea depista pe cea de lungime
m inim . Ei bine, rspunsul nu este satisfctor. Nu u itai, tehnica backtracking
n ecesi t un timp exponenial. Problema se poate rezolva cu mult mai eficient. Dar,
pentru asta, trebuie s studiem teoria grafurilor. Toate la timpul lor...

~ Exerciii
1. Adaptai rezolvarea pentru un labirint Tn care fiecare csu reine valoarea 1
sau o (1 semnificnd csu plin , prin care nu se poate trece, iar o csu liber ,
pe unde se poate trece). Ca i in problema prezentat , deplasarea se poate face
dintr-o csu in orice alt csu alturat, orizontal sau vertical , cu condiia ca ea
s existe i s fie l iber. Val idai poziia iniial a omului (lin, col), astfel nct
aceasta s coresp und unei csue libere. Esti mai spai u l de memorie utilizat
in aceast vari a nt.

2. Realizai o variant a rezolvrii de la 1, adugnd cte o linie sau coloa n


s uplimentar pe fiecare margine a labirintului, astfel nct s nu se mai testeze ca
celula in care se trece s existe. Plasarea ntr-o celul de pe margine este
echivalent cu obinerea unei soluii.

8.5.5. Problema bilei

O Enun. Se d un teren sub form de matrice cu m linii i n coloane. Fiecare


element al matricei reprezint un subteren cu o anum it altitudine dat de valoarea
reinut de element (numr natural). lntr-un astfel de subteren, de coordonate
(lin, col) se gsete o bil . tiind c bila se poate deplasa Tn orice poriune de
teren aflat la nord, est, sud sau vest, de altitudine strict inferioa r poriunii pe care
se gsete bila. Se cere s se gseasc toate posibi litile ca bila s prseasc
terenul.
6 8 9 3
Exemplu. Fie terenul a l tu rat. Iniial, bila se afl n subterenul
de coordonate ( 2, 2). O posibilitate de ieire din teren este dat 9 7 6 3
de drumul: (2,2), (2,3), (3,3), (3,4) . n program, 5 8 5 4
altitudinile subterenului vor fi reinute de matricea t.
8 3 7 1

0 Analiza problemei i rezolvarea ei. Problema seamn cu cea anterioar,


deci putem gndi c dac inlocuim testul de intrare Tntr-o camer cu cel de
altitudine mai mic, am rezolvat-o! Este adevrat , se obine o rezolvare, dar se
poate i mai uor. S analizm : mai este necesar s testm dac bila nu a ajuns
pe un teren pe unde a mai trecut? Nu, deoarece, la fiecare pas, bila se deplaseaz
pe un teren de altitudine strict inferioar . Prin urmare, problema este mai uoar
dect precedenta.
232 Capitolul 8. Metoda backtracking

n rest, vom propune o rezolvare n care sol este o matrice cu 3 coloane i


un numr mare de linii. Astfel, sol (k, 1) va reine direcia n care pleac bila (1 pt
nord, 2 pentru est, 3 pentru sud i 4 pentru vest), sol (k, 2) va reine linia
subterenului, iar sol (k, 3) va reine coloana subterenului.

~ Exerciiu. Artai, prin reprezentare grafic, modul de funcionare a


algoritmului, pe baza structurii de date propus.

Varianta Pascal .
l' 1
.. ~, :.. ' ...;~ Varianta C+;+- , , .' , i, 1,.. :.!
var sol:array [1 100,1 3] #include <iostream .h>
of integer1
t:array [0 10,0 10] int sol[100] [3],t[10] [10],
of integer; m,n,i,j,l in,col1
m,n,i,j,l in,col:in teger;
procedur a t ipar(k:in teger); void tipar(in t k)
begi n { cout<<"S olutie "<<endl;
writeln( 'Solutie ); for(i=l;i< =k-1;i++ )
for i:=1 to k-1 do cout<<so l [i] [1] <<" "
writeln( sol [i, 2],' ', <<sol[i] [2]<<end l;
sol[i,J] )I
end; void b a ck(int k, i n t lin, int col)
procedur a { if (linu=O 1 1 lin==m+1 11
back(k,l in,col:in teger); col==O 1 1 col==n+1 )
begin tipar(k) l
if (lin=O) or (linm+1 ) or el se
(col=O) or (coln+1) { sol[k] [0 ]=0;
then tipar(k) sol [k) [1] =lin;
olse begin sol[k] [2) r:ocol;
sol[k,1]: =0; while (sol[k] [0)<4)
sol [k,2] :=lin; (
sol[k,J) :=col1 sol[k) [0]++;
while sol[k,1]< 4 do switch(s ol [k] [0])
begin {
sol[k,1J: =sol(k,1 ]+11 case 1:
case sol[k,l] of if(t[lin- 1] [col]<t[ lin] [col])
1:if t[lin-1,c oll< back(k+ l,lin-l,co l); break;
t[lin,co l] then case 2:
back(k+ 1,lin-1,c ol); i f(t[lin) [col+l]< t[lin] [col])
2:if t[lin,col +1]< back(k+ l,lin,col +l); break;
t[lin,co l] then case 3:
back(k+1 ,lin,col+ 1) J if(t[lin +l l [col)<t[l in] [col])
3:if t[lin+1,c ol]< back(k+1 ,lin+1,co l ); break;
t[lin,co l) then case 4:
back(k+ l,lin+1,c ol)J if (t [lin] [col -1] <t [lin] [col])
4:if t[lin,col -1]< back(k+ l,lin,col -1); break;
t[lin,co l) then )

_j
back(k+1 ,lin,col- 1); }
end1 {case} }
end end end; }
begin main ( )
write('M =')1 readln(m ); { cout<<"m ="; cin>>m;
write('N =')1 readln(n );
~~ cout<<"n ="; cin>>n;
~
Vanual de informatic pentru clasa a Xl-a 233

for i:=1 to m do for (i=l;i<=m;i++)


for j:=1 ton do for (j=1;j <=n;j++)
begin { cout<<"t["<<i<<" ,"<<j<<"l=";
write('t[,i, , ,j, cint [il [j ];
' ] = .); }
readln(t[i,j]) cout<<"lin~; cin>>lin;
end; cout<<col="; cin>>col;
write(lin=');re adln(lin); back(1,lin,col);
write('col=');rea dln(col); }
back(1,lin,col)
end.

p? Exerciiu. Modificai programul astfel nct s se afieze i direcia n care


bila prsete terenul.

8.5.6. Sritura calului

O Enun. Se consider o tabl de ah nxn i un cal plasat 1 16 11 20 3


in colul din stnga, sus. Se cere s se afieze o posibilitate 10 21 2 17 12
de mutare a acestei piese de ah, astfel nct s treac o 15 24 19 4 7
si ngur dat prin fiecare ptrat al tablei. Alturat, observai o 22 9 6 13 18
soluie pentru n=5. 25 14 23 8 5

0 Analiza problemei i rezolvarea ei. Fiind dat o poziie n care se gsete


calul, acesta poate sri in alte 8 poziii. Pentru a scrie mai puin cod, cele 8 poziii
sunt reinute de vectorii constani x i y . Astfel, dac lin i col sunt coordonatele
poziiei unde se gsete calul, acesta poate fi mutat in:

(lin+x [O ] , col.+y [O] ) . (lin+x [7], col+y [7 l ) .

Reinei acest procedeu! De altfel, acesta poate fi folosit pentru problemele


deja prezentate. Matricea t reine poziiile pe unde a trecut calul. fn rest, s-a
procedat ca la problema anterioar .

Varianta ~ascal ., . '


Varianta C++ . 1
'
const x:array [1 8] of #include <iostream .h>
integer=(-1,1,2, 2,1,-1,-2,-2); #include <stdlib .h>
y:array[l. . 8] of
integer=(2,2,1,- 1,-2,-2,-1,1); const int x[S]={-1,1,2,2,1 ,-1,
var n:integer; -2,-2};
st: array[1 1000,1 . 2] of const int y[8]={2,2,1, - 1,-2,-2,
integer; -1,1};
t: array[-1 . 25,-1 25] of
integer; int n,sol[1000] [2],t[25] (25];

procedura back(k, lin, void back ( int k,int lin,


col:integer); int col)
var i,linie,coloana: integer; { int linie,coloana,i;
234 Capitolul 8. Metoda backtracking

begin if (k=-n*n)
if k=n*n { for (i=l;i<=k-l;i++)
then cout<<sol[i] [0]<<" "
begin <<sol[i] [l]<<endl;
for i:=1 to k-1 do cout<<lin<<" "<<col;
writeln(st[i,1], ' ' exit(EXIT_SUCCES S);
st[i,2]); }
writeln(lin,' ,col); el se
halt; { sol[k] [O]=lin;
end sol[k] [l]=col;
el se for (i=O;i<=7;i++)
begin { linie=lin+x[i];
st[k,1] :=lin; coloana=col+y[i] ;
st[k,2] :=col; if (linie<=n && linie>=1
for i:=1 to 8 do
&& coloana<=n &&
begin
coloana>=l &&
linie:=lin+x[i];
t[linie] [coloana]==Ol
coloana:=col+y[i ];
{
if (linie<=nl and
t[linie] [coloana)=l;
(linie>=l) and
back(k+l,linie,co loana);
(coloana<=n) and
(coloana>=1) and t[linie] [coloana]=O;
}
(t[linie,coloana]g O)
}
then
}
begin
}
t[linie,coloana] :=1;
back(k+l,linie,
main()
coloana) 1
t [linie,coloana]:a O; { cout<<"n=";
end; cin>>n;
end back(1,1,1);
e .n d
end;

begin
write ('n=');
readln(n);
back(1,1,l);
end.
Vanual de informatic pentru clasa a Xl-a 235

Probleme propuse

Avem la dispoziie 6 culori: alb, galben, rou , verde, albastru i negru. S se


precizeze toate drapelele tricolore care se pot proiecta, tiind c trebuie
respectate regulile:

orice drapel are culoarea din mijloc galben sau verde;


cele trei culori de pe drapel sunt distincte.

2. Dintr-un grup de n persoane, dintre care p femei, trebuie format o delegaie


qe k persoane, din care 1 femei. S se precizeze toate delegaiile care se
pot forma.

3. La o mas rotund se aeaz n persoane. Fiecare persoan reprezint o


firm. Se dau k perechi de persoane care aparin unor firme concurente. Se
cere s se determine toate modalitile de aezare la mas a persoanelor,
astfel7ncat s nu stea alturi dou persoane de la firme concurente.

4. Se d o permutare a primelor n numere naturale. Se cer toate permutrile care


se pot obi ne din aceasta astfel incat nici o succesiune de dou numere,
existent n permutarea iniial, s nu mai existe n noile permutri.

5. Se cer toate soluiile de aezare n linie a m cini i n pisici astfel nct s nu


existe o pisic aezat ntre doi cini.

6. Anagrame. Se citete un cuvnt cu n litere. Se cere s se tipreasc toate


anagramele cuvntului citit. Se poate folosi algoritmul pentru generarea
permutri lor?

7. Se dau primele n numere naturale. Dispunem de un algoritm de generare a


combinrilor de n elemente luate cte p pentru ele. Se consider un vector cu
n componente iruri de caractere, unde, fiecare ir reprezint numele unei
persoane. Cum adaptai algoritmul de care dispunei pentru a obine
combinri l e de n persoane luate cte p?

8. Se citesc n numere naturale distincte. Se cere o submu lime cu p elemente


astfel nct suma elementelor sale s fie maxim 7n raport cu toate
submulimile cu acelai numr de elemente.

9. S se determine s numere de cte n cifre, fiecare cifr putnd fi 1 sau 2, astfel


nct oricare dintre aceste s numere s coincid exact in m poziii i s nu
existe o poziie n care s apar aceeai cifr n toate cele s numere.
236 Capitolul 8. Metoda backtracking

10. Fiind dat un num~r natural pozitiv n, se cere s~ se produc la ieire toate
descompunerile sale ca sum de numere prime.

11. "AttUa i regele". Un cal i un rege se afl pe o tabl de ah. Unele cmpuri
sunt "arse", poziiile lor fiind cunoscute. Calul nu poate clca pe cmpuri "arse",
iar orice micare a calului face ca respectivul cmp s devin "ars" . S se afle
dac exist~ o succesiune de mutri permise (cu restriciile de mai sus), prin
care calul s poat ajunge la rege i s revin la poziia iniial. Poziia iniial
a calului, precum i pozi i a regelui sunt considerate "nearse".

12. Se dau n puncte n plan prin coordonatele lor. Se cer toate soluiile de unire a
acestor puncte prin exact p drepte, astfel nct mulimea punctelor de
intersecie ale acestor drepte s fie inclus n mulimea celor n puncte.

13. Gsii toate soluiile naturale ale ecuaiei 3x+y+4xz= 100.

14. S se ordoneze in toate modurile posibile elementele mulimii {1 1 21 1 n}


astfel nct numerele i, i+l, ... , i+k s fie unul dup cellalt i n aceast
ordine (1=1 1 i+Jc;n).

15. Se consider o mulime de n elemente i un numr natural k nenul. S se


calculeze cte submulimi cu k elemente satisfac, pe rnd, condiii l e de mai jos
i s se afieze aceste submulimi.

conin p obiecte date;


nu conin nici unul din q obiecte date;
conin exact un obiect dat, dar nu conin un altul;
conin exact un obiect din p obiecte date;
conin cel puin un obiect din p obiecte date;
conin r obiecte din p obiecte date, dar nu conin alte q obiecte date .
16. Se d un numr natural par N. S se determine toate iruril e de N paranteze
care se nchid corect.
Exemplu: pentru N=6: < C ( ) ) ) 1 ( () () ) 1 () () () 1 () ( () ) 1 ( () ) ().

17. Se dau N puncte albe i N puncte negre n plan, de coordonate intregi. Fiecare
punct alb se unete cu cte un punct negru, astfel nct din fiecare punct, fie el
alb sau negru, pleac~ exact un segment. S~ se determine o astfel de
configuraie de segmente astfel nct oricare dou segmente s nu se
intersecteze. Se citesc N perechi de coordonate corespunznd punctelor albe
i N perechi de coordonate corespunznd punctelor negre.

18. S se genereze toate permutrile de N cu proprietatea c oricare ar fi 2Si~.


exist 1SjSi astfel nct

Ivei> -vCj > 1=1.


vanual de informatic pentru clasa a Xl-a 237

Exemplu: pentru N=4, permutrile cu proprietatea de mai sus sunt:


2134, 2314, 3214, 2341, 3241, 3421, 4321.

' 9. O trup cuN actori ii propune s joace o pies cu A acte astfel nct:

oricare dou acte s aib distribuie diferit;


in orice act exist, evident, cel puin un actor;
de la un act la altul, vine un actor pe scena sau pleac un actor de pe
scen (distribuia a dou acte consecutive difer prin exact un actor).

S se furnizeze o soluie , dac exist vreuna.

20. Fiind dat un numr natural N i un vector v cuN componente ntregi, se cere:

s se determine toate subirurile cresctoare de lungime [N/5];


q s se calculeze p(l)+p(2)+ +p(k), unde p(k) reprezint numarul
subiruri lor cresctoare de lungime k.

21. Pe malul unei ape se gsesc c canibali i m misionari. Ei urmeaz s treac


apa i au la dispoziie o barc cu 2 locuri. Se tie c, dac att pe un mal, ct
i pe cellalt avem mai muli canibali dect misionari, misionarii sunt mncai
de canibali. Se cere s se scrie un program care s furnizeze toate soluiile de
trecere a apei, astfel nct s nu fie mncat nici un misionar.

22. Se d un careu sub form de matrice cu m linii i n coloane. Elementele


careului sunt litere. Se d, de asemenea, un cuvnt. Se cere s se gseasc
n careu prefixul de lungime maxima al cuvntului respectiv. Regula de cutare
este urmtoarea:

a) se caut litera de nceput a cuvntului;

b) litera urmtoare se caut printre cele 4 elemente nvecinate cu elementul


care conine litera de nceput, apoi printre cele 4 elemente nvecinate cu
elementul care conine noua liter, . a . m . d.

23. Se dau coordonatele a n puncte din plan. Se cere s se precizeze 3 puncte


care determin un triunghi de arie maxim . Ce algoritm vom folosi?

a) Generarea aranjamentelor; b) Generarea combinrilor;

c) Generarea permutrilor; d) Generarea tuturor submulimilor.

24. Fiind date numele a n soldai , ce algoritm vom utiliza pentru a lista toate
grupele de cte k soldai? Se tie c ntr-o grup, ordinea prezint importan .

a) Generarea aranjamentelor; b) Generarea combinrilor;

c > Generarea permutrilor; d) Generarea tuturor partiiilor.


238 Capitolul 8. Metoda backtracking

25. Fiind date n numere naturale, ce algoritm vom utiliza pentru a determina
eficient o submulime maximal de numere naturale distincte?

a) se genereaz toate submulimile i se determin o submulime maximal


care ndeplinete condiia cerut;
b > se genereaz toate partiiile i se caut o submulime maximal care
aparine unei partiii oarecare i care ndeplinete condiia cerut;

c) se compar primul numr cu al doilea, al treilea, al n-lea, al doilea cu al


treilea, al patrulea, al n-lea, ... i atunci cnd se gsete egalitate se e limin un
numr dintre ele.

d) nici un algoritm dintre cei de mai sus.

26. Dispunem de un algoritm care genereaz permutrile prin backtracking.


Primele dou permutri afiate sunt: 321, 312. Care este urmtoarea
permutare care va fi afiat?

a) 321; b) 123; c) 213; d) 231.

Indicaii

6. Dei
algoritmul este asemntor, nu este acelai, trebuie pus o condiie
suplimentar. De exemplu, in cuvntul "mama" nu se poate inversa a de pe poziia
2 cu a de pe poziia 4.

7. Dac vectorul care reine numele persoanelor este v, n loc s se afieze i, se


va afia V[i].

23. b)

24. a)

25. d)
Explicaie: primele dou variante prezint soluii exponeniale, a treia este n
o (nl >. Dar dac sortm numerele, atunci le putem afia pe cele distincte dintr-o
singur parcurgere. Sortarea se poate efectua in o (nXlog (n) ), iar parcurgerea
n O(n). Prin urmare, complexitatea este O(nXlog(n)).

26.d)

Explicaie: pe fiecare nivel al stivei se caut succesorii n ordinea n, n-1, ... , 1.


Capitolul 9
Introducere n teoria grafurilor

9.1. Grafuri neorientate

9.1 .1. Introducere


Uneori, algoritmii trebuie s prelucreze date referitoare la anumite
elemente ntre care exist anumite relaii. S analizm exemplele urmtoare:

1. Se dau n orae. Unele dintre ele sunt unite prin osele directe (care nu mai
trec prin alt ora).
2. Se cunosc relaiile de prietenie dintre n persoane.
3. Se dau n ri i se cunoate relaia de vecintate ntre ele.
4. Se dau n triunghiuri, iar unele dintre ele sunt asemenea.

Pentru fiecare dintre aceste exemple se poate imagina o reprezentare


graficcare s exprime relaiile existente.
-+ Convenim ca fiecare element s-I numim nod sau vrf.
Astfel, n cazul 1. nodul este oraul, n cazul 2. nodul este persoana, n
cazul 3. nodul este ara i n cazul 4. nodul este triunghiul. Convenim ca un nod
(vrf) s-I notm cu un cercule n care s nscriem numrul lui (de la 11a n).

-+ Relaia existent ntre dou noduri o vom reprezenta grafic unindu-le


printr-un segment de dreapt. Convenim ca un astfel de segment s-I numim
muchie i dac ea unete nodurile i i j, s-o notm cu ( i, j).

n cazul 1., muchia (i,j) are


semnificaia c ntre oraele i i j exist o osea
direct. n cazul 2., muchia <i, j) are
semnificaia c persoanele i i j sunt prietene, n
cazu 1 3 muchia <i, j > are semnificaia
c rile i i j sunt vecine, iar n cazul 4 , c
triunghiurile i i j sunt asemenea.

Procednd aa, obinem o descriere grafic


precum cea din figura 9.1 i convenim ca o astfel
de reprezentare s-o numim graf neorlentat. Figura 9.1.
Exemplu de graf neorlentat
240 Capitolul 9. Introducere n teoria grafurilor

Desigur, aceast abordare este intuitiv. Teoria grafurilor este fundamental


matematic i n cele ce urmeaz ne propunem s-o prezentm sistematic.

9.1.2. Definiia grafului neorientat

Definiia 9.1.1 . Un graf neorientat este o pereche ordonat G= (V, E) .


unde:

-+ v = {v1 , v 2 , vn> este o mulime finit i nevid . Elementele


mulimii v se numesc noduri (vrfuri).
-+ E este o mulime finit
de perechi neordonate de forma (v1 , vj) ,
unde i:;tj, i v 1 ,vjev. Elementele mulimii E se numesc muchii.
Semnificaia unei muchii este aceea c unete dou noduri.

Un graf poate fi desenat aa cum se observ


n exemplul urmtor (vezi figura 9.2.), unde
G={V,E),

V= {1,2 1 3 ,4,5,6};
E = {(1,2), (1,3), (1,5), (2,3), (3,4),
(4,5)}

Notaie: n graful G= (V, E), vom nota


cu n numrul nodurilor i cum numrul
muchiilor. Figura 9.2.
Alt exemplu de graf neorientat

Observaii

./ Dou noduri distincte pot fi unite prin cel mult o muchie. n exemplul de
mai sus, <1., 2) este muchia care unete nodul 1 cu nodul 2. Dac scriem
(2,1.), ne referim la aceeai muchie (perechea este neordonat) .

./ Nu exist o muchie care unete un nod cu el nsui (o muchie unete


dou noduri distincte).

Definiia 9.2. n graful G=(V,E), nodurile distincte v 1 ,vjEG sunt


adiacente dac exist muchia (v11 vj) EE.
Vom spune c muchia (vi, vj) EE este incident la nodurile vi i vj.

n exemplul dat anterior, nodurile 1. i 5 sunt adiacente, dar nodurile 2 i s nu


sunt adiacente. Muchia ( 4, 5) este incident la nodurile 4 i 5.

Definiia este restrictiv, n unele lucrri vei ntlni definiii mai puin restrictive, de
1

exemplu, poate exista o muchie de la un nod la el nsui sau nu se cere ca mulimea


nodurilor s fie finit.
\llanual de informatic pentru clasa a Xl-a 241

Definiia 9.3. ntr-un graf neorientat, prin gradul unui nod v se nelege
numrul muchiilor incidente cu nodul v i se noteaz cu d(v). Un nod
cu gradul o se numete nod izolat, iar unul cu gradul 1 se numete nod
terminal.

n exemplul dat, d(2 >=2, d( 1) =3, iar d( 6) =O (6 este nod izolat).

O relaie util: fie un graf neorientat cun noduri i m muchii. Dac notm cu d1,
dl .... , a., gradele celor n nodu,i, atunci avem relaia:-

" d1 +d 2 +d 3 +.~d-:-=2m.l
~ Demonstraie: fiecare muchie face s creasc gradele celor dou noduri la
care este incident cu cte o unitate. Prin urmare, se obine re l aia anterioar.

Pentru a ne l ege bine noiunile prezentate n acest paragraf, ne vom referi la


exemplele din 9 .1.1:

- fie gradul nodului i este k. Pentru exemplul 1., ea are


afirmaia:
semnificaia c din oraul i pleac (sosesc) k osele, pentru exemplul 2., are
semnificaia c persoana i are k prieteni, pentru exemplul 3., are semnificaia c
ara i se nvecineaz cu k. ri , iar pentru exemplul 4., are semnificaia c pentru
triunghiul i se cunosc k triunghiuri asemenea. Aici trebuie fcut observaia c ar
putea s existe i alte triunghiuri asemenea cu el, dar modul n care putem afla
aceasta va fi tratat separat.
- fie afirmaia: nodurile i sunt adiacente. Pentru exemplul 1., ea are
i j
semnificaia c oraele i sunt unite printr-o osea care nu trece prin alte
i j
orae, pentru exemplul 2., are semnificaia c persoanele i i j sunt prietene,
pentru exemplul 3., are semnificaia c rile i i j sunt vecine, iar pentru
exemplul 4. , are semnificaia c triunghiurile i i j sunt asemenea.

- fie afirmaia: nodul i este izolat. Pentru exemplul 1., nseamn c nu exist nici
o osea care leag oraul i cu alt ora, pentru exemplul 2 ., nseamn c
persoana i nu are nici un prieten, pentru exemplul 3 ., nseamn c ara i nu se
nvecineaz cu nici o ar (este situat pe o in su l), pentru exemplul 4., nseamn
c nu exist nici un triunghi dintre celelalte n-1 triunghiuri care s fie asemenea cu
triunghiul i.

~ Exerciiu
Dai un exemplu inspirat din viaa real, pentru care s gsii graful asociat.
Astfel, vei rspunde la ntrebrile: ce semnificaie a~ nodurile sau muchiile i ce
nseamn gradul unui nod.
242 Capitolul 9. Introducere n teoria grafurilor

9.1.3. Memorarea grafurilor

n acest paragraf, prezentm principalele structuri de date prin care grafurile pot
fi memorate n vederea prelucrrii lor. De la nceput, precizm faptul c vom alege o
structur sau alta n funcie de2 :
a) algoritmul care prelucreaz datele referitoare la graf;

b) memoria intern pe care programul o are la dispoziie;

c) dac graful conine multe muchii sau nu.

Pentru fiecare structur de date pe care o vom folosi, vom avea cte o
procedur (funcie) care citete datele respective. Toate aceste subprograme se
gsesc grupate n unitatea de program grafuri .pas (pentru Pascal) i n
grafuri. cpp (pentru C++). Vom fi astfel scutii ca, pentru fiecare program pe care l
realizm, s fim nevoii s adugm liniile de cod necesare citirii i ne permite s ne
concentrm exclusiv asupra algoritmului.

. Toate subprogramele pe care le utilizm citesc datele dintr-un fiier text, n


({~ care, pe prima linie vom scrie numrul de noduri (n), iar pe urmtoarele linii,
cte o muchie ( i, j), ca n exemplul de mai jos, n care este prezentat un
graf i liniile fiierului text care este citit pentru el:

0 Fiierul text:
1
1
1
3
5
2

2 3
3 4
Figura 9.3.
4 5
Exemplu de graf neorientat

Trecem la prezentarea structurilor prin care putem memora datele referitoare la


un graf.

A. Memorarea grafului prin matricea de adiacen

A.. ... - o matrice ptratic, unde elementele ei, ai,j au semnificaia:

a .. =
I,J
{1,O, pentru {i, j) e E
pentru (i, j) ~ E

2
Modul de alegere a structurii il vei inelege pe parcursul studiului acestui capitol.
~ianual de informatic pentru clasa a Xl-a 243

Pentru graful din figura 9.3, matricea de adiacen este prezentat n


continuare:

o o 1
1 1 o
1 o 1 o o o
1 1 o 1 o o
A6.6 =
o o 1 o 1 o
1 o o 1 o o
o o o o o o
(:1, Observaii

1 . ntruct, din modul n care a fost definit graful, rezult c nu exist muchii de la un
nod la el nsui, rezult c elementele de pe diagonala principal rein o:

a;,; =0, "r:/ie {1,2, ... ,n}.

2 Matricea de adiacen este simetric:

a;, 1 = a 1.;, "r:/i,j E {1,2, ...,n} .

Evident, deoarece muchia ( i, j >coincide cu muchia <j 1 i >.


3 Suma elementelor de pe linia i, ie { 1, 2, . . 1 n}, are ca rezultat gradul nod~ lui
i , d ( i), pentru c astfel se obine suma nodurilor j, j e <1, 2, , n}, pentru care
exist muchie de la i la j, adic suma muchiilor incidente lai.

De exemplu, pentru graful de mai sus, suma elementelor de pe linia 1 este 3,


adic gradul nodului 1, d ( 1).

4. Tot aa, suma elementelor de pe coloana j, j e {1 1 2, ... , n}, are ca rezultat


gradul nodului j, d(j).

1 Raionamentul este asemntor cu cel de la observaia precedent.

s . Suma tuturor elementelor matricei de adiacen este, de fapt, suma gradelor


tuturor nodurilor, adic dublul numrului de muchii (2m).

6 . Dac graful citit are un numr mic de muchii, atunci matricea de adiacen este o
form ineficient de memorare a lui, pentru c ea va reine o mulime de o.

Subprogramele pe care le vom utiliza pentru aceast modalitate de memorare


sunt prezentate n continuare:
244 Capitolul 9. Introducere n teoria grafurilor

type mat_ad=array[l.. 50, 1.. 50] of void CitireN


integer; (char Nume_fis[20],
procedura CitireN int A[SO] [50], int& n)
(NUme_Fis:string; {
var A:Mat_ad; var n:integer); int i,j;
var f:text; fstreamf (Nume_fis, ios:: in);
i,j:byte; f>>n;
begin while ( fij)
Assign(f,Nume_Fis); A[i] [j]=A[j] [i]=1;
Reset(f); Readln(f,n); f.close() 1
while(not eof(f)) do }
begin
readln(f,i,j);
A[i,j]:=l; A[j,i] :=1;
end;
close(f);
end;

Programul urmtor citete datele referitoare la un graf i afieaz matricea


sa de adiacen:

#include grafuri.cpp"
int A[50] [50],n;
n,i , j:integer; main()
begin {
CitireN( Graf. txt ,A, n); CitireN("Graf . txt",A,n);
for i:=1 to n do for (int i=1;i<-n;i++)
begin { for (int ja1;j< n;j++)
for j:=1 ton do cout<<A[i] [j]<< ;
write (A[i,j], ') ; cout<<endl;
writeln; }
end; }
end.

B. Memorarea grafului prin liste de adiacen


Listele de adiacen reprezint o alt form de memorare a grafurilor, n ca:e
pentru fiecare nod se cunoate lista nodurilor adiacente cu el. De exemplu, pentr_
graful din figura 9.4., listele de adiacen sunt:

0 1 -> 2,3,5
2 -> 1 , 3
3 -> 1,2,4
4 - ~ 3,5
5 -> 1,4
6 ->
Figura 9.4.
Manual de informatic pentru clasa a Xl-a ~45

n acest caz, se uti lizeaz un vector cu n componente, pe care l vom numi


Start i o matrice T cu 2 linii i 2m coloane. Semnificaii le sunt:
Start - pentru fiecare nod i , start [i] specific coloana din T unde
ncepe lista nodurilor adiacente cu i. Dac reine o, nseam n c nodul i nu
are noduri adiacente.
T (o, i > - reprezint un nod al listei nodurilor adiacente.
T <1 , i) - reprezint indicele coloanei din T unde se gsete urmtorul
element din list. Dac reine o, atunci acesta este ultimul elerment din lista
succesorilor.
1 2 3 4 5 6

Start 15 17 19 l11l12l O 1
1 2 3 4 5 6 7 8 9 10 11 12
T[O] 2 1 3 1 5 1 3 2 4 3 5 4
T [1] o o 1 o 3 o 2 4 8 o 10 6

4 Exemplu de utilizare

Dorim s vedem care este lista nodurilor adiacente cu nodul 3. Start [3] =9,
adic lista ncepe n coloana 9 a matricei T. Primul nod adiacent cu nodul 3 este 4.
Urmtorul se gc':!lsete la indicele a. Urmtorul nod adiacent cu nodul 3 este nodul 2.
Urmtorul se gsete la indicele 4. Acesta este nodul 1 . El este ultimul din list,
pentruT(1,4)=0 (T[l] [4)).

n continuare, vom arta modul n care se construiesc listele de adiacen .


Pentru fiecare muchie (i, j) se completeaz dou coloane ale matricei T, pentru c
trebuie nregistrat faptul c i este adiacent cu j i j este adiacent cu i. Astfel,
vom pune pe j ca prim element n lista nodurilor adiacente lui i i pe j ca prim
element in lista nodurilor adiacente cu i.

Con siderm primul caz, n care vom pune pe j, ca prim element n lista
nodurilor adiacente cu i. Variabila k, care are iniial valoarea o, va reine indicele
ultimei coloane din T completat. O astfel de operaie se realizeaz n patru pai:

1 . Pentru c trebuie completat o nou coloan nT, se incrementeaz k;


2. T (o , k) va reine j, pentru c succesorul lui i este j;
3 T ( 1, k > va reine Start [ i], pentru c indicele coloanei n care se gsete
primul nod adiacent (pn la aceast nou introducere, cnd devine al doilea din list)
este n Start [ i 1 ;
4. Start [il va reine k, pentru c, de acum, primul nod din lista nodurilor
adiacente cu i, este j, care se gsete n coloana de indice k.
246 Capitolul 9. Introducere n teoria grafurilor

Mai jos, putei observa subprogramele care construiesc listele de adiacen


(funciile au fost adugate n grafuri .pas i respectiv, grafuri . cpp):

type void Citire_~static


lista=array[O l , l SO]of integer; (char Nume_fis[20],
pornire=array(l SO] of integer; int T[2] [50],
int Start[SO], int& n)
procedura Citire_LA~static {
(Nume_fis:string;var T:Lista; int i,j,k=O;
var Start:pornire;var n:integer); fstream
var i,j,k:integer; f(Nume_fis,ios :: in);
f1text; f>>n;
begin while (fij)
k:=O; { k++;
Assign(f,Nume_Fis); Reset(f); T[O] (k] =j;
Readln(f,n); T[l] (k]=Start(i];
while(not eof(f)) do Start[i]k1
begin k++;
readln(f,i,j); k:=k+l; T[O] [k]=i;
T[O , k]Jj; T[l,k] :Start[i]; T[l] [k] =Start [j l 1
Start!il:=k; k:k+l; Start[j]=k1
T[O,k]:=i; T[l,k] :=Start(j]; }
Start[j):=k; f .close () 1
end; }
close(f);
end.

.~ -
!
':- . ~~
Programul urmtor citete datele despre un graf i afieaz, pentru fiecare
..... . nod, lista nodurilor adiacente:

uses grafuri; #include "grafuri.cpp"


var Start:pornire; T:lista1 int T[2] [50],Start(50],
n,i,man:integer; n,i,ma.n;
begin main()
Citire_~static {Citire_~static
('Graf.txt',T,Start,n); ("Graf.txt",T,Start,n);
for i1=l to n do for (int i=l1i< n1i++)
begin {
writeln ('Noduri adiac. cu ,i); cout<<"Noduri adiac. cu "<<
man: ...start[i]; iendl;
while (man<>O)do manStart(i]1
begin while (man)
write(T[O,man], '); { cout<<T (0] (man] <<" "1
man:aT(l,man] 1 ma.n=T(ll (man]; }
end; cout<<endl;
writeln }
end; }
end.
Manual de informatic pentru clasa a Xl-a 247

c. Memorarea grafului prin lista muchiilor

Se utilizeaz un vector cu m componente, unde m este numrul muchiilor.


Fiecare component va reine cele dou noduri la care muchia respectiv este
incident i, n anumite cazuri alte informaii referitoare la muchia respectiv.
Reinei c exist algoritmi pentru grafuri care prelucreaz datele pornind de la
aceast reprezentare (vedei arbori pariali). Uneori, va fi necesar s sortm
muchiile, fie dup nodul de pornire, fie dup alt informaie asociat lor.

Mai jos, putei observa cum se descrie un vector (v) care reine muchiile
unui graf:

type muchie=record struct muchie


x,y:integer; { int x,y;
end; };
var V:array[1 .. 50) of muchie; muchie V[50];

~Exerciiu. Realizai un subprogram care citete i memoreaz datele


referitoare la muchiile unui graf memorat prin lista muchiilor.

~~..i : Observaie foarte Important


.~

Uneori, nodurilor unui graf li se asociaz anumite informaii. De exemplu,


dac nodurile unui graf reprezint orae, pentru fiecare astfel de nod se poate
memora numrul obiectivelor turistice. n astfel de cazuri, pe lng una dintre
metodele de memorare prezentate mai sus, vom asocia grafului un vector cu n
(numrul de noduri ale grafului) componente, unde fiecare component va reine
informaiile referitoare la nodul respectiv. Pentru exemplul dat, fiecare component
a grafului reine numrul de obiective turistice.

9.1 .4. Graf complet

S considerm mulimea elevilor unei clase. Teoretic, oricare doi elevi din
clas se cunosc. Pentru a transpune n limbaj specific teoriei grafurilor aceast
situaie, vom considera c fiecare elev este un nod al grafului. Pentru c oricare doi
elevi se cunosc, nseamn c oricare dou noduri sunt unite printr-o muchie.
Astfel, am obinut un graf aparte, pe care-I vom numi graf complet.

Definiia 9.4. Prin graf complet vom nelege un graf neorientat n care
oricare dou noduri sunt adiacente. Vom nota un graf complet prin K", unde
n este numrul de noduri ale grafului.
248 Capitolul 9. Introducere n teoria grafurilor

;3. ,~. Alturat, avei un graf complet cu 4 noduri (K,):


~:;i
'
: ~~

Figura 9.5.
Exemplu de graf complet

Relaii utile:

1. ntr-un graf complet, gradul oricrui nod este n-1. Evident, din fiecare nod,
pleac (sosesc) n-1 muchii.
n(n -1)
2. ntr-un graf complet, avem relaia: m = , unde m este numrul de
2
muchii, iar n, numrul de noduri.

)!. Demonstraie: fiecare muchie unete 2 noduri. Numrul muchiilor va fi egal


cu numrul de submulimi cu 2 elemente ale mulimii celor n noduri.
Acest numr este C2 = n(n - J) .
n 2
n(n - 1)
3. Avem 2- 2- grafuri neorientate cu n noduri.

)!. Demonstraie: am vzut c numrul maxim de muchii pe care le poate avea


~ un graf neorientat este:

n(n - 1)
., 2
.r
i corespunde unui graf complet. Se tie c, fiind dat o mu~ime A cun elemente,
avem 2n submulimi disjuncte ale acesteia (aici este inclus i submulimea vid
i A). Prin urmare, avem:
n(n - 1)
2- 2-
submulimi ale numrului maxim de muchii. Ori, fiecrei submulimi de muchii i
corespunde un graf nemientat, pentru c nodurile sunt aceleai.

9.1.5. Graf parial, subgraf

Definiia9.5. Un graf parial al unui graf neorientat dat G= (V1 E) este un


graf G1=(V1 E1), unde E1!::E
Manual de informatic pentru clasa a Xl-a 249

f, Un graf parial al unui graf dat, este el nsui sau se obine din G prin
suprimarea anumitor muchii. Privii exemplul de mai jos:

Figura 9.6.
Obinerea unui
graf parial

--->
rezult

G={V,E)

4 Exemple din viaa real


1. Fiind date n persoane, ntre unele dintre ele exist o relaie de prietenie. Asociem
acestei situaii un graf G. Dup un timp, unele persoane se ceart. n teoria grafurilor,
aceasta nseamn c n G se suprim anumite muchii i astfel, se obine un graf
parial G1.

2. Fiind date n orae, unele dintre ele sunt unite printr-o osea direct (care nu mai
trece prin alte orae). Asociem situaiei date un graf G. Datorit precipitaiilor, anumite
osele se inund i nu mai pot fi utilizate. Aceasta nseamn c 1'n G se suprim
anumite muchii i se obine un graf parial G .

Intrebare: cte grafuri pariale are un graf neorientat cu n noduri? Indicaie:


? Cte submulimi are mulimea muchiilor {1 , 2, ,m}?

lli Definiia 9.6. Un subgraf al unui graf neorientat G.., .<v, E) este un graf
:.I!.) G1 .. (V11 E1), unde v1cv. E1c::E, iar muchiile din E 1 sunt toate muchiile din
' E care sunt incidente numai la noduri din mulimea v 1 .

( ., Un s~bgraf al unui graf G este el nsui sau se obine din G prin suprimarea
anumttor noduri i a tuturor muchiilor incidente cu acestea. Privii exemplul de
mai jos:

Figura 9.7.
Obinerea unui
subgraf

--->
rezult

G= (V,E)
250 Capitolul 9. Introducere n teoria grafurilor

4 Exemple din realitate

1. Se dau n firme. ntre unele din acestea se stabilesc relaii de colaborare. Asociem
situaiei date un graf G. intre timp, anumite firme se desfiineaz . Aceasta inseamna
c n G vom elimina anum ite noduri i muchiile incidente lor, obinnd un subgraf al
luiG, G1.

2 Mai multe calculatoare (n) sunt legate n reea cu ajutorul unor cabluri. Asociem
situaiei date un graf G. ntre timp, anumite calculatoare se defecteaz. Astfel, se
obine un subgraf al lui G, G1 .

? ntrebare: cte subgrafuri are un graf neorientat cu n nodu~i? lnd.icale: care


este numarul de submulimi ale mulimii {1, 2, . , n}? lntrucat mulimea
nodurilor, v, este nevid, vom face abstracie de mulimea vid.

9.1 .6. Parcurgerea grafurilor neorientate

Prin parcurgerea grafurllor nelegem o modalitate de vizitare a nodurilor


3

acestuia. Parcurgerea eficient a grafurilor este esenial n teoria grafurilor,


deoarece o mulime de algoritmi consacrai au la baz o astfel de parcurgere.
Din acest motiv, n acest paragraf nu vom insista pe aplica~le parcurgerilor i ne vom
mrgini numai la prezentarea algoritmilor de parcurgere. In paragrafele urmtoare,
vei gasi multe exemple utile, n care parcurgerea grafurilor joac un rol fundamental.

Exist dou modaliti generale de parcurgere i anume: parcurgerea n


lime (BF) i parcurgerea n adncime (DF). Acestea vor fi tratate separat.

9.1 .6.1. Parcurgerea n lime (BF - Breadth First)

-+ Parcurgerea n lime se face ncepnd de la un anumit nod i, pe care l


considermvizitat.

-+ Vizitm apoi toate nodurile adiacente cu el fie ele j 1, j 2, ... jk, vizitate n
aceast ordine.

-+ Vizitm toate nodurile adiacente cu j1, apoi cu j2 .... , apoi cu jk,

-+ Parcurgerea continu n acest mod pn cnd au fost vizitate toate nodurile


accesibile.

3
n acest paragraf vom exemplifica parcurgerile doar in cazul grafurilor conexe. Cum
noiuneanu a fost prezentat pn n acest moment. precizm doar c vom exemplifica
parcurgerea grafurilor n care oricare dou noduri sunt "legate printr-o succesiune
de muchii.
Manual de informatic pentru clasa a Xl-a 251

Exemple de parcurgeri BF ale aceluiai graf, pornind de la noduri diferite:

Pentru graful alturat avem:

Nod pornire 1: 1 3 6 2 7 5 4
Nod pornire 3: 3761254
Nod pornire 6: 6 3 1 7 2 5 4

Figura 9.8.

~ Parcurgerea BF se efectueaz prin utilizarea structurii numit coad, avnd grij


ca un nod s fie vizitat o singur dat. Atunci cnd un nod a fost introdus n coad
se marcheaz ca vizitat. Coada va fi alocat prin utilizarea unui vector.

Algoritmul este urmtorul:

Nodul de pornire este introdus n coad i este marcat ca vizitat.


Ct timp coada este nevid
Pentru nodul aflat la nceputul cozii:
se trec n coad toate nodurile adiacente cu el, care nu au fost vizitate i
se marcheaz ca vizitate;
se afieaz;
se extrage din coad.

Vom utiliza urmtoarele notaii:

i_c - indicele primei componente a cozii;


a_ c - indicele ultimei componente a cozii;
coada - vectorul care memoreaz coada propriu-zis;
s - vector ce reine nodurile vizitate:

0, noduli nu a fost vizitat


s[i] ={
1, noduli a fost vizitat

fn continuare, vor fi prezentate dou exemple de implementri ale


parcurgerii n lime (BF) a unui graf, memorat prin liste de adiacen i
matrice de adiacen:
252 Capitolul 9. Introducere n teoria grafu rilor

1. Programul urmtor parcurge BF un graf memorat prin liste de adiacen:

Varianta C++ "

uses grafuri; #incl ude "grafuri.cpp"


var n,i_c,sf_c,p:integer; int n, coada[50],s(50],i_c=1 ,
coada,s:array[1 50] of sf_c=1,T[2] [50],Start[50],p;
integer;
T:lista; void bf ( int nod)
Start:pornire; { coada[i_ c]=nod;
s[nod]=1;
procedura bf(nod:integer); while (i_ c<=sf_ c)
begin { p=Start[coada[i_c]];
i_c : =1;sf_c:=1; while (p)
coada[i_c]:=nod; { i f (s[T[O] [p]]==Ol
s[nod] :=1; {sf_ c++;
while i_c<=sf_c do coada[sf_ c]=T[O] [p];
begin s [T [0] [p]] =1;
p:=Start[coada[i_ c]]; }
while p<>O do p=T [1] [p];
begin }
if s[T[O,p]J=O then cout<<coada[i_c]<<endl;
begin i _c++;
sf_c:=sf_ c+1; }
coada[sf_c]:=T[O,p]; }
s[T[O,p]) :=1;
end; main( l
p:=T[1,p]; {
end; Citire_LA_.Astatic("Graf. txt",T
writeln(coada[i_c]); ,Start,n) 1
i_c:=i_ c+1; bf(6);
end }
end;
begin
Citire_LA_Astatic('Gra f.txt',T,
Start,n);
bf(J);
end.

2. Programul urmtor parcurge BF un graf memorat prin matricea de adiacen:

'1 varlanta 'r,1, ,,''!i1il:i~:,


: Pas~a. ..: li
: . ;j:ii~.:- Varianta C++ :
1, ;1:
.
uses grafuri; #include "grafuri.cpp"
var n,i_c,sf_c,i:integer;
coada,s:array[1 50] of int n, coada[SO),s[SO],i_c=l,
integer; sf_ c=1,A[50] [50] ,i;
Azmat_ad;
void bf(int nod)
procedura bf(nod:integer); {
begin coada[i_c]=nod;
i _c:=1; sf_c:=l; s[nodl=l;
lanual de informatic pentru clasa a Xl-a 253

coada [i_c:) :-nod; while (i_c<=sf_c:)


s[~odl :=1; { i=l;
whi le (i_c<=sf_c:) do while (i<=n)
bagin {if (A[coada[i_c)] [i]s=l
i:=l; &&: s[iJ=",O)
while i<n do { sf_c++;
bagin coad.a[sf_cJ=i;
if ((A[c:oada[i _c:] ,il=l) s[il=l;
and (s [i l =O)) }
then i++;
bag in }
sf_c::=sf_c:+l;; c:out<<coada [i_c:]<<endl;
c:oada[sf_c):=i; i_c:++;
a[i]:l; )
end; }
i:i+l;
end; main()
writeln(c:oada[i_c])l ( CitireN("Graf.txt",A,n);
i _c:ai_c+l; bf(l);
}
end
end;

bag in
CitireN('Graf.txt' , A, n);
bf(l);
end.
1

9.1.6.2. Parcurgerea n adncime (OF - Depth First)

Parcurgerea n adncime se face ncepnd de la un anumit nod i, pe care l


considerm vizitat.
Dup vizitarea unui nod, se viziteaz primul dintre nodurile adiacente,
nevizitate nc, apoi urmtorul nod adiacent, pn cnd au fost vizitate toate
nodurile adiacente cu el.

Parcurgerea continu n acest mod pn cnd au fost vizitate toate nodurile


accesibile.

:x: Exemple de parcurgeri DF ale aceluiai graf, pornind de la noduri diferite:

Pentru graful alturat, avem:


Nod pornire 1: 1 3 7 6 2 5 4
Nod pornire 3: 3 7 6 1 2 5 4
Nod pornire 6 : 6 3 7 1 2 5 4

Figura 9.9.
254 Capitolul 9. Introducere n teoria grafurilor

Exemple de implementri ale parcurgerii OF

1. Programul urmtor parcurge DF un graf memorat prin liste de adiacen:

uses grafuri; #include "grafuri . opp"


var n:integer; int s[SO],n;
s:array[l 50] of integer; T [2] [50] , Start [50];
T:lista;
void df (int nod)
Start:pornire;
{ int p;
prooedure df(nod:integer); cout<<nod<<" " 1
var p:integer; p=Start [nod] 1
begin s[nod]=1;
writeln(nod,' '); while (p)
p:=Start[nod]; { if (s[T[O] [p]J==O)
s[nod] :=1; df(T[O] [p] );
while p<>O do p=T [1] [p] 1
begin }
if s[T[O,p]]=O }
then df(T[O,p]);
p:=T[1,p]; main()
{
end
end; Citire_LA..JI,static ("Graf. txt",
T,Start,n) 1
begin df {1) i
Citire_LA_Astatio('Graf.txt',T, }
Start,n);
df(1);
end.

2. Programul urmtor parcurge DF un graf memorat prin matricea de adiacen:

usas grafuri; #include "grafuri.opp"


var n:integer; int s[50],A[50] [50],n;
s:array[l 50]of integer;
void df_ r{int nod)
A:mat_ad;
{ int k;
procedura df_ r(nod:intagar); oout<<nod<<" "1
var k:integar1 s[nod]=l;
bagin for (k 1;k<=n;k++)
write (nod, ') 1 if (A[nod] [k] ==1 &:&: s [kJ =O)
s[nod]:=1; df_r(k) 1
for k:=1 to n do
if (A[nod,k]=l) and (s[k]=O)
then df_r(k); main()
end; { CitireN( "Graf. txt" ,A,n) 1
df_r(1);
begin }
CitireN( 'Graf.txt ,A,n);
df_r(1);
end.
Manual de informatic pentru clasa a Xl-a 255

9.1.6.3. Estimarea timpului necesar parcurgerii grafurilor

~ Parcurgerea BF (sau DF) a grafurilor, pornind de la matricea de adiacen , se


face n O(n2 ). Practic, pornind de la un nod i, se caut pe linia ia matrice;
toate nodurile adiacente cu el i pentru toate cele gsite se procedeaz n mod
analog.

~ Parcurgerea BF (sau DF) a grafurilor pornind de la listele de adiacen se face


n o (m). Pornind de la un nod i, se caut toate nodurile adiacente cu el, dar
acestea se gsesc deja grupate n lista asociat nodului respectiv i numrul
lor corespunde numrului de muchii incidente acestuia. Algoritmul va selecta,
pe rnd, toate muchiile, de unde rezultatul de mai sus.

9.1. 7. Lanuri

Relum exemplele de la paragraful 9 .1.1.

Pentru exemplul 1, ntrebarea este: fiind date dou orae a i b, se poate


ajunge cu maina din a n b?
Pentru exemplul 2. O persoan, a, afl o informaie important. Persoana
transmite informaia tu~uror prietenilor, acetia, la rndullor, transmit informaia tuturor
prietenilor lor, .a.m.d. Intrebarea este: informaia ajunge la persoana b?
Pentru exemplul 4. Fiind date dou triunghi uri, a i b, sunt ele asemenea? S
observm c nu este obligatoriu ca s se fi introdus de la nceput faptul c triunghiul a
este asemenea cu triunghiul b. Aceast informaie poate fi dedus, de exemplu, prin
faptul c a este asemenea cu k, k cu 1 i 1 cu b.

Analiznd aceste ntrebri pe graful asociat fiecrei situaii n parte, ajungem la


concluzia c n toate cazurile trebuie s existe o succesiune de noduri de la
nodul a la nodul b cu proprietatea c oricare dou noduri sunt adiacente. Dac
aceast succesiune nu exist, rspunsul este negativ, altfel rspunsul este pozitiv.
Sau, exprimat n teoria grafurilor, aceasta nseamn c rspunsul depinde de
existena unui lan de la a la b. De acum, putem prezenta definiia lanului.

Definiia 9.7. Pentru graful neorientat G= (V, E), un lan L=[v1 ,v2 ...vp]
este o succesiune de noduri cu proprietatea c oricare dou noduri vecine
sunt adiacente, adic (v1 ,va)EE, (v;r,v3)EE, ... , (vp_1 ,vp)EE. De
altfel, un lan poate fi definit prin succesiunea de muchii (v1 , va) EE, (v2 , v 3 ) EE, ... ,
(Vp-ltVp)EJ!!.

-+ Vrfurile v 1 i vP se numesc extremitile lanului.


-+ Numrul p-1 se numete lungimea lanului. Acesta este dat de numrul de
muchii ce unesc nodurile lanului.
256 Capitolul 9. Introducere n teoria grafurilor

Definiia 9.8. Se numete lan elementar un lan care conine numai noduri
distincte.

Exemple: pentru graful din figura alturat:

1. [1, 2, 5) este un lan elementar cu lungime 2 ,


ntre nodurile 1 i 5 .
2. [1,3,4,1,2) este un lan (care nu este
elementar) de lungime 4, ntre nodurile 1 i 2.

Figura 9.1 O.

O Problema 9.1. Fiind dat un graf i dou noduri ale sale a i b, s se scrie un
program care decide dac ntre ele exist un lan sau nu, iar n caz c acest lan
exist, se cere s se afieze lanul.

0 Rezolvare. Exist un lan de la a la b, dac i numai dac o parcurgere DF sau


BF, care pornete de la nodul a , va ajunge s viziteze nodul b. Rm n e de rezolvat
problema modului n care reinem lanul de la a la b . S ob se rvm c fiecare metod
de parcurgere a grafului, pornind de la un nod j , se l ecteaz un altul i, dac cele
dou noduri sunt adiacente i dac nodul i este vizitat pentru prima dat. Pentru a
rei ne seleci ile astfel efectuate, vom utiliza un vector T, iar elementele acestuia au
semnificaia urmtoare:

. {j,
T[1] =
dac i este descendent al lui j
O, dac i nu a fost selectat
S
mai observm c un nod este selectat o singur dat, deci, n final, T va
reine, pentru fiecare nod i, nodul j de la care a fost selectat. Pentru nodul de la care
a pornit parcurgerea (a) vom avea T (a) = O, pentru c acest nod nu a fost selectat de
algoritm. De aici, rezult c drumul poate fi reconstituit, pornind de la T, astfel: se
afieaz b, apoi T [b) , apoi T [T [b) ) ... pn cnd se obin e valoarea o. Pentru ca
drumul s nu fie afiat n ordine inve rs fa de modul n care a fost obinut ,
subprogramul refac care l reconstituie i l afieaz este recursiv. Programul de mai
jos afieaz drumul, pornind de la matricea de adiacen a grafului:

;i;:;,i!li:liliiii1 1~:!Ya.r~a.nta Pascal 1:.-~d. ;: ''


' Varianta C++ ,,
uaes grafuri; #include "grafuri . cpp"
var n,al,bzinteger; int
a,Tzarray[l SO] of integer; s[SO] ,A[SO] [50] , n,T[SO] , a,b;
A:mat_ ad;
void refac (int nod)
procedura refac (nod:integer) ; {
begin i f (nodi =O)
if nod<>O then {
begin
refac (T[nod] );
write(nod,' 1 );
refac (T[nod]) ;
cout<<nod< <" 1 ...
}
end }
end;
\Aanual de informatic pentru clasa a Xl-a 257

procedure df_r(nod:integer); void df_r(int nod)


var k:integer; {
begin int k;
s[nod]:=l; s[nod]=l;
for k:=l to n do for (k=l;k<=n;k++)
if (A[nod,k]=l) and (s(k]=Ol if (A[nod] [k) ""''1 && s [k] :a O)
then {
begin T[k]=nod;
T[k]:=nod; df_r(k);
df_r(k); }
end }
end;
main()
begin {
CitireN('Graf.txt',A,n); CitireN("Graf.txt",A,n);
write('a='); readln(al); cout<<"a="; cin>>a;
write('b='); readln(b); cout<<"b="; cin>>b;
df_ r(al); df_r(a);

,
if (T[b]<>O) then refac(b); if (T[b]taO) refac(b);
end. }

Observaii foarte importante


1. S observm c vectorul T poate fi folosit pentru a obine lanuri de la nodul a la
oricare alt nod al grafului.
2 Dac refacem rezolvarea prin utilizarea parcurgerii n lime, vom observa c
lanu l obinutare lungimea minim . Prin natura ei, parcurgerea BF selecteaz nodurile
n ordinea "depl1rii" lor fa de nodul de la care a nceput parcurgerea. Astfel, la
inceput se viziteaz primul nod (a), apoi nodurile pentru care lungimea lanului de la a
la ele este 1, apoi nodurile pentru care lungimea lanului de la a la ele este 2, .a.m.d.

Programul care urmeaz afieaz un lan de lungime minim intre nodurile a i b:

.... ;t "'
Varianta Pascal
uses grafuri; #include "grafuri.cpp"
var int n,coada[50],s[50],
n,al,b,i_c,sf_c,i:integer ; i_o=l, sf_ c ..l,
s,T,coada : array[l . SO] of A(SO] [50] ,i,T[SO] ,a,b;
integer;
A:mat_ ad; void refac (int nod)
{ i f (nodi=O)
procedura refac (nod:integer); {refac (T[nod]);
begin cout<<nod<<" ";
if nod<>O then }
begin }
refac (T[nod]);
write (nod, ' ');
end
end;
258 Capitolul 9. Introducere n teoria grafurilor

procedura bf(nod:integer); void bf(int nod)


begin { coada[i_c)=nod;
i_c : =1; s[nod]=l;
sf_c: =l; while (i_c<=sf_c)
coada[i_c] :=nod; { i=l;
s[nod] :=1; while (i<=n)
while i_c<=sf_c do { if (A[coada[i_c]] [iJ==l
begin && s[iJ==O>
i:=l; sf_c++;
while i<=n do coada[sf_c]=i;
begin s[i]=l;
if (A[coada[i_c},il=l) and T(i]=coada[i_c];
(s[iJ=O) }
then i++;
begin }
sf_c:=sf_c+l; i_c++;
coada[sf_c]:=i; }
s[i] :=1; }
T[i]:=coada[i_c];
main()
end;
{
i:=i+l;
end; CitireN("Graf .txt" ,A,n);
i_e:=i_c+l; cout<<"a=";
cin>>a;
end
end; cout<<"b=";
cin>>b;
begin bf(a);
if (T[b]I=O) refac(b);
CitireN( 'Graf.txt ,A,n);
}
write ( 'aa' ) ;
readln(al);
wri te ( ' b= ' ) ;
readln(b);
bf (al);
if T[b] <>O then refac(b);
end.

Matricea lanurllor. ntrebri referitoare la situaiile prezentate la 9 .1.1:

a) pentru exemplul 1, ntrebarea este: cum putem afla, pentru fiecare ora n parte,
oraele n care putem ajunge cu maina?

b) pentru exemplul 4, ntrebarea este: cum putem afla, pentru fiecare triunghi n
parte, care sunt triunghiurile asemenea cu el?

Revenind la graful asociat acestor situaii, problema const n a afla pentru


fiecare nod i, nodurile j, pentru care exist un lan de la i la j. Evident, rezultatele
pot fi reinute ntr-o matrice cu n linii i n coloane (matrice ptratic). Aceast
matrice se numete matricea lanurllor, iar elementele ei au semn ificaia:

{~.
dac exist lan de la i la j
L(i,j) = 'in caz contrar
IAanual de informatic pentru clasa a Xl-a 259

:J Problema 9.2. Fiind dat un graf G, cum putem obine matricea lanurilor?

~ Rspunsul este uor de dat. Parcurgem graful ncepnd cu nodul1. Pentru toate
-odurile j vizitate, vom avea L <1, j ) =1, completnd astfel prima linie a matricei.
;poi, vom parcurge din nou, graful, pornind de la nodul 2. Pentru toate nodurile j,
:izitate, vom avea L(2, j) =1, apoi parcurgem graful ncepnd cu nodul 3 .... .a.m.d.
O anumit mbuntire a algoritmului se obine dac inem cont de faptul c matricea
~urilor este simetric (de ce?). Lsm ca exerciiu scrierea acestui program.
1trebare: care este complexitatea acestui algoritm?

9.1 .8. Graf conex

Revenind la exemplele de la 9 .1 . 1, putem pune ntrebrile:


a) pentru exemplul !: se poate ajunge cu maina din orice ora n oricare altul?
b) pentru exemplul4: toate triunghiurile sunt asemenea ntre ele?

Dac la ambele ntrebri rspunsul este afirmativ, ce semnificaie are el pentru


grafurile asociate? Aceasta nseamn c pentru orice pereche de noduri, exist un
lan care le are ca extremiti. Sau, n limbajul specific teoriei grafurilor, cele dou
grafuri sunt conexe.

Definiia 9.9. Un graf neorientat G= (V, E) este conex, dac pentru orice
pereche de noduri x, yeV, exist un lan n care extremitatea iniial este x
i extremitatea final este y.

Exemple Figura 9.11 .

1 . Graful alturat este conex. De exemplu,


ntre nodurile 1 i 5 exist lanul [ 1, 2, 3, 4, 5), dar
i lanul [1 ,3,4,5]. ntre nodurile 3 i 5 exist
lanul [3 ,4, s), .a.m.d.

Oricum am alege dou noduri, exist lanul cerut de


definiie.

2 Graful alturat nu este conex. De exemplu, ntre Figura 9.12.


nodurile 1 i 4 nu exist nici un lan.

1,~,
,~j Un graf cu un singur nod este, prin definit,ie, conex. Aceasta pentru c nu exist
dou noduri diferite pentru care s se pun problema existenei unui lan.
260 Capitolul 9. Introducere n teoria grafurilo

O Problema 9.3. Fiind dat un graf Go: (V, E >, s se scrie un program care s decid
dac graful dat este sau nu conex.

0 Rezolvare. innd cont de cele nvate, problema nu este grea. Putem utiliza
una din metodele de parcurgere nvate, DF sau BF. Ideea este urmtoarea: dac ,
pornind de la un nod, printr-una din metodele de parcurgere, ajungem s vizitm toate
celelalte noduri, atunci graful dat este conex. Cum putem ti dac am vizitat toate
nodurile? Simplu, dup parcurgere, toate componentele vectorului s rein 1. Pute1
scrie acest program?

9.1 .9. Componente conexe


Analizm, din nou, exemplele de la 9 .1.1.
a) Pentru exemplull: se cere o mulime de orae, astfel nct s se poat circula cu
maina ntre oricare dou orae din mulime, iar dac un ora nu aparine acester
mulim i , atunci nu putem ajunge cu maina de la el ia oricare ora din mulime.
b) Pentru exemplul 4: se cere o mulime de triunghiuri astfel nct oricare dou
triunghiuri din aceast mulime sunt asemenea, iar dac un triunghi nu aparine
acestei mulimi, el nu este asemenea cu nici unul din mulime.
Observm c fiecare astfel de mulime este maximal n raport cu relaia de
incluziune. Dac nu ar fi aa, ar exista o alt mulime care ar include-o.

Fie graful asociat unuia dintre cazurile prezentate. n termeni din teoria
grafurilor, problema se reduce la determinarea nodurilor unei componente conexe.

Definiia 9.10. Fie G=(V,E) un graf neorientat i Gl=(V1 ,Ed un subgraf


al su.Atunci G1 == (V1 , E 1 ) este o component conex a grafului
G= (V. E) dac sunt ndeplinite condiiile de mai jos:

a) Oricare ar fi x,yev1. exist un l an de la x la y.


b) Nu exist un alt subgraf al lui G, ~= (V:z,E:~) cu V 1 C:V:z care
nden'inete condiia a)
.

$i': Exemple

1. Graful alturat este alctuit din dou componente


conexe. Prima este alctuit din nodurile 1, 2, 3 i
muchiile care le unesc pe acestea, a doua este
format din nodurile 4 i 5 i muchia care le unete.

Figura 9.14.
2. Graful din figura 9.14. conine 3 componente
conexe. Aa cum un graf, cu un singur nod, este
conex, tot aa un nod izolat alctuiete el singur o
G
component conex.

0
Manual de informatic pentru clasa a Xl - a 261

.~ Observaii
'")
'r>

1 . Cte componente conexe poate avea un graf neorientat cun noduri? Numrul
lor este cuprins ntre 1, pentru un graf conex i n corespunztor unui graf cu toate
nodurile izolate.

2. n unele probleme, se d un graf neorientat, care nu este conex i se cere s


se adauge un numr minim de muchii, astfel nct graful s devin conex. n
astfel de cazuri, se determin componentele conexe, fie ele e1, e:~ .... ep. Fie p
numrul lor. Vom aduga p - 1 muchii, prima unete un nod din e1 cu unul din e:~, a
doua unete un nod din e 2 cu unul din C 3 , ... , ultima unete un nod din Cp- 1 cu
unul din ep.

CJ Problema (de programare).9.4. Fiind dat un graf neorientat, se cere s se


afieze nodurile fiecrei componente conexe.

0 Rezolvare. Dup cum uor v putei da seama, o parcurgere a grafului (DF sau
BF) pornind de la un anumit nod, viziteaz toate nodurile componentei conexe care
l conin e . Pentru fiecare nod vizitat, s [il reine 1. Dac, dup o parcurgere, mai
rmn noduri nevizitate, parcurgerea se reia ncepnd de la primul nod nevizitat.
Evident, numrul componentelor conexe este egal cu numrul de parcurgeri
necesare pentru a fi vizitate toate nodurile.

varlanta P.asc~l . ,::, 1


i""

uses grafuri; #include grafuri.cpp


var n,i:integer; int s[50],A[50] [SO],n,i;
s:array [l . SO]of integer;
void df_r{int nod)
A:mat_ad;
{ int k;
procedura d f_r(nod:integer); cout<<nod<<" ";
var k: integer; s[nod]=l;
beHin for (kal;k<=n;k++)
write (nod, ' '); if((A[nod] [kJ==l)&&
s[nod] :=1 ; (s[kl==O))
for k:=l to n do