Sunteți pe pagina 1din 310

IC

OG
1. Tehnici de programare
1.1. Subprogramele

G
1.1.1. Definiia subprogramului

DA
tii deja c blocul este unitatea de baz a oricrui program C++ i c este ncapsulat
ntr-o instruciune compus, delimitat de caracterele { ... }. El este format din dou pri:
 Partea declarativ conine definiii de elemente necesare algoritmului pentru rezolvarea

PE
problemei: constante (const), variabile de memorie i tipuri de date (typedef). Definirea
lor se face cu ajutorul instruciunilor declarative.
 Partea executabil sau partea procedural conine instruciunile care descriu paii
algoritmului care trebuie implementat pentru rezolvarea problemei. Aceste instruciuni
se numesc instruciuni imperative. Ele sunt: instruciunea expresie (prin care se
I
evalueaz o expresie) i instruciunile de control (prin care se modific ordinea de
execuie a programului). Instruciunea expresie prin care se atribuie unei variabile de
memorie o valoare se mai numete i instruciune de atribuire, iar instruciunea

expresie prin care se cere execuia unui subprogram se mai numete i instruciune
procedural.
IC

Mai tii c n limbajul C++ blocurile sunt ncapsulate n funcii, orice program C++ fiind
o colecie de definiii de variabile i funcii. Funcia este un bloc precedat de un antet
prin care se precizeaz numele ei i, dac este cazul, tipul rezultatului pe care-l ntoarce
CT

prin chiar numele su i, eventual, parametrii de execuie (valori care se transmit blocului
i care sunt necesare atunci cnd se execut blocul):
<tip rezultat> <nume funcie>(<list parametri>)
DA

Una dintre funciile programului C++ este funcia rdcin. Ea este obligatorie i este
primul bloc cu care ncepe execuia programului. Numele su este main. Antetul acestei
funcii este:
void main()
DI

ceea ce semnific faptul c funcia nu ntoarce nici un rezultat (void) i nu necesit


parametri pentru apelare parantezele () nu conin list de parametri.
RA

Scop: exemplificarea structurii unui program C++.


Enunul problemei: Se consider trei numere naturale, a, b i c. S se verifice dac pot
forma o progresie aritmetic.
ITU

Se vor executa urmtorii pai:


Pas1. Se ordoneaz cresctor cele trei numere (se schimb valorile ntre ele, astfel nct
s se respecte relaia de ordine a b c).
Pas2. Dac ntre valorile celor trei variabile exist relaia b=(a+c)/2, atunci cele trei
ED

numere formeaz o progresie aritmetic.



4 Tehnici de programare

IC
#include <iostream.h>
void main() antetul funciei

OG
{
int a,b,c,x; partea declarativ
cout<<"a= "; cin>>a;
cout<<"b= "; cin>>b;

G
cout<<"c= "; cin>>c;
executabil

if (a>b) {x=a; Secven de instruciuni

DA
a=b; care se execut repetat
b=x;} de trei ori, de fiecare
if (b>c) {x=b; dat cu alte date de
b=c; intrare:

PE
c=x;}; 1) a i b
if (a>b) {x=a; 2) b i c
a=b; 3) a i b
partea

b=x;};
I
if (b==(a+c)/2.)
cout<<a<<","<<b<<","<<c<<"sunt in progresie aritmetica";
else
cout<<a<<","<<b<<","<<c<<"nu sunt in progresie aritmetica";

}
IC

Prin definiie:
CT

Subprogramul este o secven de instruciuni care rezolv o anumit


sarcin i care poate fi descris separat de blocul rdcin i lansat n
execuie din cadrul unui bloc, ori de cte ori este nevoie.
DA

n limbajul C++, subprogramele se mai numesc i funcii.

1.1.1.1. Necesitatea folosirii subprogramelor


n practica programrii pot s apar urmtoarele cazuri:
DI

a. O secven de instruciuni se repet de mai multe ori n cadrul unui program (ca n
programul C++ din exemplul anterior). Secvena de instruciuni care se repet poate
fi implementat sub forma unui subprogram.
b. Rezolvarea unei anumite sarcini este necesar n mai multe programe, ca, de exem-
RA

plu, diferite operaii matematice (extragerea radicalului, extragerea prii ntregi sau a pr-
ii fracionare dintr-un numr real, ridicarea unui numr la o putere etc.), diferite operaii cu
tablouri de memorie (crearea, parcurgerea i sortarea tabloului de memorie, tergerea
sau inserarea unui element etc.), diferite operaii cu fiiere (deschiderea unui fiier,
ITU

nchiderea unui fiier, testarea sfritului de fiier etc.). Secvena de instruciuni care
rezolv o anumit sarcin ce poate s apar n mai multe programe poate fi implemen-
tat cu ajutorul unui subprogram.
c. Orice problem poate fi descompus n subprobleme. Subproblemele n care este
descompus se numesc module. Descompunerea poate continua pn cnd se obine
ED

Informatic 5
un modul cu rezolvare imediat. Aceast metod de rezolvare a unei probleme se

IC
numete tehnica top-down de proiectare a algoritmilor. Ea este foarte util n cazul
programelor care trebuie s rezolve probleme complexe (de exemplu, prelucrarea

OG
vectorilor). n aceste cazuri se obin programe foarte mari i complexe. Pentru a obine
programe mai simple i mai clare, se poate descompune problema iniial n subpro-
bleme, fiecare subproblem fiind descris printr-un subprogram.

G
Scop: exemplificarea modului n care o problem poate fi descompus n subprobleme

DA
folosind tehnica top-down.
Enunul problemei: Se introduc de la tastatur mai multe numere ntregi, ntr-un vector
alfa. S se transfere n vectorul beta elementele pozitive din alfa i apoi s se afieze
elementele vectorului beta, ordonate cresctor.

PE
Problema poate fi mprit n patru subprobleme (module):
 crearea vectorului alfa, prin introducerea valorilor de la tastatur;
 crearea vectorului beta, prin copierea valorilor pozitive din vectorul alfa;
 sortarea vectorului beta;
I
 afiarea elementelor vectorului beta.

Modulul principal
(problema de la care se pornete)

IC

Modulul 1 Modulul 2 Modulul 3 Modulul 4


(creare alfa) (creare beta) (sortare beta) (afiare beta)
CT

Aadar, n toate cele trei cazuri prezentate, soluia o reprezint subprogramele.


DA

1.1.1.2. Terminologie folosit pentru subprograme


ntr-o structur modular n care fiecare Modul apelant
modul este descris printr-un subpro-
DI

gram, modulele se clasific astfel: Transfer Modul apelat


 Modul apelant. Este modulul care, control
pentru rezolvarea propriei probleme,
apeleaz la alte module, fiecare
RA

dintre ele rezolvnd o anumit sub-


problem. La apelare, el transfer
controlul modulului apelat. n exem- apelare
plul anterior, Modulul principal este
ITU

Revenire
modulul apelant. control
 Modul apelat. Este un modul apelat
de un alt modul, pentru a-i rezolva o
subproblem. Dup ce i termin execuia, el red controlul modulului apelant. n
ED

exemplul anterior, Modulul 1, Modulul 2 i Modulul 3 sunt module apelate.



6 Tehnici de programare
Vom considera funcia rdcin main() ca fiind modulul principal sau programul

IC
principal, iar celelalte funcii (module) pe care le vom defini le vom numi subprograme.

1.1.1.3. Avantajele folosirii subprogramelor

OG
n practic, pentru rezolvarea unor probleme complexe care ajut la ndeplinirea unor
activiti, cum sunt de exemplu prelucrrile de texte, contabilitatea unei ntreprinderi,
inventarierea unor depozite de materiale, gestionarea unei biblioteci etc., trebuie s se
conceap programe sofisticate numite aplicaii. n construirea unei aplicaii, folosirea

G
subprogramelor ofer urmtoarele avantaje:
 Se face economie de memorie intern. Un grup de instruciuni care trebuie s se

DA
execute de mai multe ori ntr-o aplicaie (chiar cu date de intrare i de ieire diferite)
se va scrie o singur dat ntr-un subprogram i se va executa prin apelarea subpro-
gramului ori de cte ori este nevoie.
 Se favorizeaz lucrul n echip pentru aplicaiile mari. Fiecare programator va putea

PE
s scrie mai multe subprograme, independent de ceilali programatori din echip.
Pentru a realiza subprogramul, este suficient s i se precizeze programatorului speci-
ficaiile subprogramului: datele de intrare, datele de ieire i problema pe care trebuie
s o rezolve.
 Depanarea i actualizarea aplicaiei se fac mai uor. Dup implementare i intra-
I
rea n exploatare curent, o aplicaie poate necesita modificri, ca urmare a schimbrii
unor cerine. Este mult mai simplu s se gndeasc modificarea la nivelul unui
subprogram, dect la nivelul ntregii aplicaii.

 Crete portabilitatea programelor. Subprogramele sunt concepute independent de


restul aplicaiei i unele dintre ele pot fi preluate, fr un efort prea mare, i n alte
IC

aplicaii, n care trebuie s fie rezolvate sarcini similare.

1.1.2. Parametrii de comunicare


CT

Pe de o parte, subprogramul nu este o entitate independent. El trebuie asamblat n interio-


rul programului, adic trebuie stabilite legturi ntre modulul apelant i modulul apelat.
DA

Pe de alt parte, n procesul de prelucrare dintr-un modul sunt necesare date care trebuie
prelucrate (date de intrare) i care uneori trebuie s fie preluate din modulul apelant. La
rndul su, n urma prelucrrilor, modulul apelat furnizeaz rezultate (date de ieire) ctre
modulul care l-a apelat. Datele care circul astfel ntre module se numesc parametri de
DI

comunicare. Aadar:

Parametrii de comunicare se folosesc pentru a realiza legtura dintre module.


RA

parametri de intrare parametri de ieire


returnate

Subprogram
valori
ITU

parametri de parametri de
intrare-ieire intrare-ieire
ED

Informatic 7
Dup modul n care intervin n comunicarea cu modulul apelant, parametrii de comunicare

IC
se clasific n:
 Parametrii de intrare. Sunt date care urmeaz s fie prelucrate de subprogram (SP)

OG
i care i sunt comunicate de ctre modulul apelant (P). Subprogramul le primete n
momentul activrii: P SP .
 Parametrii de ieire. Sunt rezultate obinute de subprogram n urma prelucrrii i pe
care le comunic modulului apelant. Modulul apelant le primete dup ce subprogra-
mul i termin execuia: SP P .

G
 Parametrii de intrare-ieire. Sunt date care particip la calculul datelor de ieire i
sunt accesibile att modulului apelant, ct i modulului apelat. Valoarea lor poate fi

DA
modificat att de subprogram, ct i de modulul apelant. Subprogramul le primete la
activare, iar modulul apelant le primete dup ce subprogramul i termin execuia:
P SP .
Parametrii de ieire i parametrii de intrare-ieire prin care subprogramul transmite rezul-

PE
tatele modulului apelant se mai numesc i valori returnate de ctre subprogram. La
apelarea subprogramelor, parametrii de intrare pot fi i constante sau expresii, iar parame-
trii de ieire i parametrii de intrare-ieire pot fi numai variabile de memorie.
I
1.1.3. Elementele subprogramului
n limbajul C++ exist trei elemente implicate n utilizarea unui subprogram:
 definiia subprogramului conine numele subprogramului, tipul argumentelor i

al valorilor returnate i specific ceea ce trebuie s realizeze subprogramul;


 prototipul subprogramului comunic compilatorului informaii despre subpro-
IC

gram (modul n care se poate apela subprogramul);


 apelul subprogramului execut subprogramul.
CT

#include<iostream.h>
Modul apelant
void scrie(); Prototipul subprogramului main()
void main()
DA

{scrie(); Apelul subprogramului


} Modul apelat
scrie()
void scrie() Antetul subprogramului
DI

{cout<<"Subprogram"; Definiia subprogramului


} Corpul subprogramului

Subprogramul se poate identifica printr-un nume care este folosit att pentru definiia
RA

subprogramului, ct i pentru prototip i activarea lui (apelarea lui).


Apelarea subprogramului n cadrul unui bloc nseamn activarea subprogramului,
adic lansarea lui n execuie. Subprogramul poate fi apelat ori de cte ori este nevoie (nu
exist restricii pentru numrul de apeluri).
ITU

Modulul apelant se execut secvenial (instruciune cu instruciune). La apelarea subpro-


gramului, este prsit blocul modulului apelant i se trece la executarea instruciunilor din
subprogram. Dup ce se termin executarea acestor instruciuni, se revine la blocul
apelant i se continu execuia cu instruciunea care urmeaz apelului.
ED

8 Tehnici de programare
Apelarea subprogramelor

IC
Modulul 1
Modulul principal
(subprogramul 1)
(programul principal)

OG
apeluri de subprograme

G
Modulul 2
(subprogramul 2)

DA
PE
1.1.4. Clasificarea subprogramelor
Pentru clasificarea subprogramelor se pot folosi dou criterii:
 modalitatea de apel, determinat de modul de returnare a valorilor rezultate;
I
 autorul.
1.1.4.1. Clasificarea n funcie de modalitatea de apel

Subprogramele se mpart n:
 subprograme apelate ca instruciuni procedurale;
IC

 subprograme apelate ca operanzi.


Deoarece, n limbajul C++, toate subprogramele, indiferent de modul n care sunt apelate,
se numesc funcii, pentru a identifica cele dou tipuri de subprograme, le vom denumi ca
CT

funcii procedurale i funcii operand.


Funcii procedurale
DA

Funcia procedural este subprogramul care returneaz una, mai multe sau nici o
valoare. Valorile se returneaz prin intermediul parametrilor.
Modalitatea de apel. Subprogramul se apeleaz printr-o instruciune procedural care
are urmtoarea sintax (o instruciune expresie care are un singur operand apelul
DI

subprogramului):
nume_subprogram (list_parametri);
RA

opional
Observaii:
1. n list, parametrii sunt separai prin virgul.
2. Parametrii pot fi nume de variabile de memorie, expresii sau valori constante. Ei se mai
ITU

numesc i argumentele funciei.


Exemple de apeluri de funcii procedurale implementate n limbajul C++:
clrscr();
Apelul unei funcii procedurale fr parametri (CLeaR SCReen) care terge infor-
ED

maiile afiate pe ecranul calculatorului.



Informatic 9
randomize();

IC
Apelul unei funcii procedurale fr parametri care iniializeaz generatorul de nu-
mere aleatoare.

OG
swab(s1,s2,n);
Apelul unei funcii procedurale cu trei parametri: copiaz n caractere (n fiind un
numr par), din irul de caractere s1, la nceputul irului de caractere s2, inver-
snd caracterele adiacente. Parametrul s2 este un parametru de intrare-ieire, iar
parametrii s1 i n sunt parametri de intrare.

G
gotoxy(x,y);
Apelul unei funcii procedurale cu doi parametri: n modul de lucru text, mut

DA
cursorul n fereastra de text curent, n poziia precizat prin coordonatele x i y.
Parametrii x i y sunt parametri de intrare.
Funcii operanzi

PE
Funcia operand este un subprogram care returneaz un rezultat prin chiar
numele su, i eventual i alte rezultate, prin intermediul parametrilor.

Modalitatea de apel. Subprogramul se activeaz n interiorul unei expresii unde este


I
folosit ca operand. Expresia poate s apar fie n membrul drept al unei instruciuni de
atribuire, fie n cadrul unei instruciuni de control, fie n lista de parametri ai unei alte
funcii (funcie operand sau instruciune procedural). De exemplu:

nume_expresie = nume_variabil +|-|*|/ nume_funcie (list_parametri);


IC

opional
Observaii:
1. La fel ca i la subprogramele apelate ca instruciuni procedurale, parametrii din list
CT

sunt separai prin virgul i pot fi nume de variabile de memorie, expresii sau valori
constante.
2. n cazul funciei operand care returneaz un singur rezultat prin chiar numele ei,
parametrii din lista de parametri sunt de obicei numai parametri de intrare.
DA

3. Funcia operand poate fi apelat i ca o funcie procedural. n acest caz se pierde


valoarea returnat prin numele ei.

Exemple de apeluri de funcii operand implementate n limbajul C++:


DI

x=3.5;e=5+floor(x);
La calculul expresiei care se atribuie variabilei e se activeaz funcia floor() prin
care se determin cel mai mare ntreg mai mic dect valoarea parametrului.
RA

Funcia are un singur parametru x, care este parametru de intrare i are


valoarea 3.5. Rezultatul (data de ieire) este furnizat prin numele funciei i are
valoarea 3. Aadar, variabilei de memorie e i se va atribui valoarea: 8 (5+3).
for(i=0;i<=sqrt(n);i++);
ITU

La calculul expresiei ce se atribuie valorii finale a contorului structurii repetitive


for, se activeaz funcia sqrt(n) care furnizeaz radicalul de ordinul 2 din
valoarea parametrului. Funcia are un singur parametru n, care este parametru de
intrare.
ED

10 Tehnici de programare

IC
x=sqrt(pow(3,2)+ pow(4,2));
La calculul expresiei care se atribuie variabilei x se activeaz de dou ori funcia
pow(): o dat pentru a calcula 3 la puterea 2, returnnd valoarea 9, i o dat

OG
pentru a calcula 4 la puterea 2, returnnd valoarea 16. Funcia pow() are doi
parametri de intrare: primul este baza, iar al doilea este exponentul. Rezultatul este
furnizat prin numele funciei. Rezultatul obinut prin evaluarea expresiei 9+16 = 25
va fi parametru de intrare pentru funcia sqrt()care extrage radicalul de ordinul 2
din valoarea lui. Rezultatul funciei sqrt() data de ieire este furnizat prin

G
numele funciei i are valoarea 5. El este atribuit variabilei de memorie x. Aadar
variabila de memorie x va avea valoarea 5.

DA
1.1.4.2. Clasificarea n funcie de autor
Subprogramele se mpart n:
 subprograme standard sau subprograme de sistem;

PE
 subprograme nestandard sau subprograme utilizator.
Subprograme de sistem
Sunt subprograme predefinite de autorii limbajului de programare, care sunt furnizate m-
preun cu limbajul de programare. Ele se gsesc grupate, dup funciile pe care le reali-
I
zeaz, n bibliotecile limbajului de programare. Aceste subprograme rezolv probleme
generale ale utilizatorului, ca de exemplu:
 probleme matematice: calculul funciilor trigonometrice (sin(), cos() etc.), calculul unor

funcii matematice (radicalul sqrt(), exponenialul exp(), logaritmul log(), puterea


pow()), calculul prii ntregi i fracionare dintr-un numr real (modf(), fmod()) etc.
IC

 operaii cu fiiere: deschiderea unui fiier fopen(), nchiderea unui fiier fclose() etc.
nainte de apelarea unui astfel de subprogram, trebuie fcut cunoscut compilatorului
CT

prototipul subprogramului, prin instruciunea pentru preprocesor:


#include <nume_fisier_antet.h>;

Aadar, lucrul cu un subprogram de sistem presupune dou operaii:


DA

 includerea fiierului care conine prototipul subprogramului n fiierul surs al


programului,
 apelarea subprogramului.
Subprograme utilizator
DI

Sunt subprograme create de programator pentru a rezolva unele sarcini (cerine)


specifice aplicaiei sale. Astfel, n exemplul de program prin care se verific dac trei
numere pot forma o progresie aritmetic, pentru ordonarea celor trei numere a, b i c,
RA

programatorul poate construi un subprogram care s execute secvena de instruciuni


prin care se realizeaz interschimbarea a dou valori, secven care se repet de trei ori
n cadrul programului.
Aceste subprograme trebuie declarate sau definite de programator nainte de apelul lor
ITU

din funcia rdcin sau dintr-un alt subprogram.


Lucrul cu un subprogram utilizator presupune dou operaii:
 definirea subprogramului i, dac este cazul, precizarea prototipului.
 apelarea subprogramului.
ED

Informatic 11

IC
1.1.5. Reguli pentru construirea subprogramelor C++
1.1.5.1. Definiia subprogramului

OG
Definiia unui subprogram este format din antetul i corpul subprogramului:
<antetul subprogramului>
{
<declaraii proprii subprogramului>

G
<instruciuni>
[return <expresie>;]
}

DA
a. Antetul subprogramului. Este o linie de recunoatere a subprogramului, n care i se
atribuie un nume. El specific nceputul subprogramului.
b. Corpul subprogramului. La fel ca orice bloc C++, este ncapsulat ntr-o instruciune

PE
compus, delimitat de caracterele {...} i este format din dou pri:
 Partea declarativ. Conine definiii de elemente folosite numai n interiorul
subprogramului: tipuri de date, constante i variabile de memorie. Nu se pot
defini i alte subprograme (nu este valabil tehnica de imbricare a subprogra-
melor existent n alte limbaje de programare).
I
 Partea executabil. Conine instruciunile prin care sunt descrise aciunile reali-
zate de subprogram.
Antetul subprogramului

Subprogramul trebuie s aib un antet prin care se precizeaz interfaa dintre programul
IC

apelant i subprogram. El conine trei categorii de informaii:


 Tipul rezultatului. Pentru funciile operand se precizeaz tipul rezultatului furnizat de
subprogram prin chiar numele su. Pentru funciile procedurale, tipul rezultatului este
CT

void (nu ntoarce nici un rezultat prin numele su; rezultatele vor fi ntoarse prin
parametrii subprogramului). Dac nu se precizeaz tipul rezultatului, compilatorul va
considera c acesta este implicit de tip int.
 Numele subprogramului. Este un identificator unic, care se atribuie subprogramului.
DA

Numele trebuie s respecte aceleai reguli ca orice identificator C++.


 Parametrii folosii pentru comunicare. Pentru fiecare parametru se precizeaz
numele i tipul.
Antetul unui subprogram este de forma:
DI

tip_rezultat nume_subprogram (list_parametri)

Lista de parametri este de forma:


RA

tip1 p1, tip2 p2, tip3 p3, ... tip_n p_n

tipul parametrului identificatorul parametrului separator


ITU

Exemplul 1:
float alfa(int a, int b, float c)
Acesta este antetul unei funcii operand care furnizeaz un rezultat de tip float. Numele
funciei este alfa, iar parametrii folosii pentru comunicare sunt a i b de tip int i c de tip float.
ED

12 Tehnici de programare
Exemplul 2:

IC
void beta(int a, float b, float c, char d)
Acesta este antetul unei funcii procedurale. Numele funciei este beta, iar parametrii folosii

OG
pentru comunicare sunt: a de tip int, b i c de tip float i d de tip char.
Exemplul 3:
void gama()
Acesta este antetul unei funcii procedurale. Numele funciei este gama i nu folosete
parametri pentru comunicare.

G
Observaii:

DA
1. Separarea parametrilor n list se face prin caracterul virgul (,). Dac exist mai muli
parametri de acelai tip, ei nu pot pot fi grupai ca la declararea tipului variabilelor
de memorie. Pentru fiecare parametru trebuie precizat tipul.
2. Tipul parametrilor poate fi:

PE
 orice tip standard al sistemului folosit pentru date elementare ntreg (int,
unsigned, long), real (double, float, long double) sau caracter (char sau
unsigned char) , tipul pointer sau orice tip de structur de date (vector, matrice,
ir de caractere sau nregistrare);
 orice tip definit de utilizator nainte de a defini subprogramul.
I
3. Pentru rezultatul funciei nu se poate folosi tipul tablou de memorie.
Exemplu:

float a[10] tablou(int v, unsigned n)

Acest antet de subprogram va produce eroare deoarece tipul funciei este tablou de
IC

memorie.
4. Numele subprogramului poate fi folosit n trei locuri distincte:
CT

 n prototipul subprogramului, unde are un rol declarativ;


 n antetul subprogramului, unde are un rol de definiie, dar i declarativ;
 n apelul subprogramului, unde are rol de activare.
DA

Corpul subprogramului
Corpul subprogramului este un bloc care conine att instruciuni declarative, ct i instruc-
iuni imperative. Variabilele de memorie declarate n corpul subprogramului se numesc
DI

variabile locale. n cazul unei funcii operand, ultima instruciune din corpul subprogramului
trebuie s fie instruciunea return, care are sintaxa:
return <expresie>;
RA

Valoarea obinut prin evaluarea expresiei <expresie> va fi atribuit funciei operand (va fi
valoarea returnat prin numele funciei). Rezultatul expresiei trebuie s fie de acelai tip cu
tipul funciei sau de un tip care poate fi convertit implicit n tipul funciei.
ITU

Cnd compilatorul C++ ntlnete ntr-un subprogram instruciunea


Atenie return, termin execuia subprogramului i red controlul modu-
lului apelant. Prin urmare, dac vei scrie n subprogram, dup
instruciunea return, alte instruciuni, ele nu vor fi executate.
ED

Informatic 13
1.1.5.2. Prototipul subprogramului

IC
Este o linie de program, aflat naintea modulului care apeleaz subprogramul, prin care
se comunic compilatorului informaii despre subprogram (se declar subprogramul).

OG
Prin declararea programului, compilatorul primete informaii despre modul n care se
poate apela subprogramul i poate face verificri la apelurile de subprogram n ceea ce
privete tipul parametrilor folosii pentru comunicare i a modului n care poate face
conversia acestor parametri.

G
Un subprogram, pentru a putea fi folosit, trebuie declarat. Pentru declararea lui se folosete
prototipul. El conine trei categorii de informaii, la fel ca i antetul subprogramului: tipul
rezultatului, numele subprogramului i tipul parametrilor folosii pentru comu-

DA
nicare. Pentru fiecare parametru din antetul subprogramului, se poate preciza numai
tipul, nu i numele lui.
Prototipul unui subprogram este de forma:

PE
tip_rezultat nume_subprogram (list_tipuri_parametri);

Lista tipului parametrilor este de forma:


tip_1, tip_2, tip_3, ... tip_n
I
tipul parametrului separator
Observaii:

1. Separarea tipurilor de parametri n list se face prin caracterul virgul (,). Lista trebuie
IC

s conin attea tipuri de parametri ci parametri au fost definii n antetul sub-


programului. n list se precizeaz tipul de dat la care se refer, n aceeai ordine n
care au fost scrii parametrii la definirea lor n antet.
CT

2. Spre deosebire de antetul subprogramului, prototipul se termin cu caracterul ;.


Pentru funciile al cror antet a fost precizat anterior, prototipurile vor fi:
Exemplul 1:
DA

float alfa(int, int, float);


Exemplul 2:
void beta(int, float, float, char);
Exemplul 3:
DI

void gama();

1.1.5.3. Activarea (apelul) subprogramului


RA

Subprogramul trebuie s fie cunoscut, atunci cnd se cere prin apel activarea lui:
 Dac subprogramul este standard, trebuie inclus fiierul care conine prototipul sub-
programului n fiierul surs.
 Dac subprogramul este utilizator, trebuie declarat fie prin folosirea prototipului, fie
prin definirea lui naintea apelului.
ITU

n funcie de modul n care a fost definit, subprogramul se activeaz fie printr-o instruciune
procedural, fie ca operand ntr-o expresie.
Pentru funciile al cror antet a fost precizat anterior, activarea se poate face astfel:
ED

14 Tehnici de programare
Exemplul 1:

IC
int x,y; float z,w;
w = alfa(x,y,z);

OG
Exemplul 2:
int x; float y,z; char w;
beta(x,y,z,w);
Exemplul 3:
gama();

G
Orice subprogram trebuie declarat i definit. Declararea unui sub-
Atenie program este necesar pentru ca el s fie cunoscut de subpro-

DA
gramele care l apeleaz. Declararea lui poate fi fcut fie prin proto-
tip, fie prin definiia lui (antetul mpreun cu corpul subprogramului). Pentru a declara subpro-
gramul, fie scriei prototipul naintea subprogramelor care l apeleaz, putnd scrie apoi defi-
niia lui oriunde n program, fie definii subprogramul naintea subprogramului care l apeleaz.

PE
#include<iostream.h>
void scrie() Antetul subprogramului
{cout<<"Subprogram"; Definiia subprogramului
} Corpul subprogramului
I
void main() Modul apelant main()
{scrie(); Apelul subprogramului
}

Modul apelat scrie()


IC

Aadar:
 Prototipul subprogramului declar subprogramul.
 Apelul subprogramului execut subprogramul.
CT

 Antetul subprogramului specific numele subprogramului i tipul argumentelor i al


valorilor returnate, iar corpul subprogramului l definete, adic specific ceea ce
trebuie s realizeze subprogramul.
DA

1.1.5.4. Parametrii de comunicare


Dac pentru comunicarea ntre subprogram i blocul apelant se folosesc parametri, acetia
vor fi scrii dup numele subprogramului, ntre paranteze rotunde, astfel:
DI

 n antet, pentru fiecare parametru se precizeaz denumirea simbolic folosit n


interiorul subprogramului. Aceti parametri se numesc parametri formali. n prototip,
pentru fiecare parametru se precizeaz tipul de dat la care se refer, n aceeai
ordine n care au fost scrii la definirea lor n antet.
RA

 La activarea subprogramului, parametrilor de comunicare li se vor atribui valori concrete


cu care se va executa subprogramul la acel apel. Aceste valori vor fi comunicate la
apelul subprogramului, dup numele subprogramului, ntre paranteze rotunde, n
aceeai ordine n care au fost scrii la definirea lor n antet. Comunicarea trebuie s
ITU

respecte aceeai succesiune, tipuri de date i numr de parametri ca i n lista de


parametri formali, deoarece atribuirea valorilor se face respectnd regula de
coresponden. Aceti parametri se numesc parametri actuali.
Observaii.
ED

1. Numele parametrilor actuali pot fi diferite de numele parametrilor formali.



Informatic 15
2. Tipul parametrilor formali poate s fie diferit de tipul parametrilor actuali, numai cnd

IC
parametrii efectivi pot fi convertii implicit n tipul parametrilor formali (la fel ca n cazul
operaiei de atribuire).

OG
Transferul parametrilor
Programul principal
x a Subprogramul
y b
void alfa(int x, float y);

G
alfa(a,b);

x 2

DA
alfa(2,3); y 3

PE
parametri formali
parametri actuali regula de
coresponden
I
Scop: exemplificarea modului n care poate fi construit un subprogram C++.

Enunul problemei: S se construiasc un subprogram care s calculeze valoarea


absolut a unui numr real. Numele subprogramului este mod_r.
IC

Acest subprogram va fi construit n dou variante: ca funcie procedural i ca funcie


operand. n ambele cazuri modulul apelant va fi funcia rdcin, iar modulul apelat va fi
subprogramul mod_r.
CT

Varianta 1:
n cazul funciei procedurale, subprogramul va afia valoarea modulului numrului i nu
va furniza niciun rezultat funciei rdcin care l apeleaz. El va primi valoarea num-
DA

rului de la funcia rdcin prin intermediul parametrului.

Tipul rezultatului este void funcia


#include <iostream.h> nu furnizeaz nici un rezultat.
DI

void mod r(float a)


{if (a<0) cout<<-a; Parametrul subprogramului este a
else cout<<a;} este un parametru de intrare.
RA

Parametrul din antetul subpro-


void main() gramului este parametru formal.
{float x;
cout<<"numarul="; cin>>x; Parametrul x cu care se apeleaz
ITU

mod r(x);} subprogramul este parametru


actual.

Apelul subprogramului din funcia rdcin


se face printr-o instruciune procedural.
ED

16 Tehnici de programare
Varianta 2:

IC
n cazul funciei operand, subprogramul va returna funciei rdcin, prin numele su,
valoarea absolut a numrului. El va primi

OG
valoarea numrului de la funcia rdcin prin Funcia furnizeaz ca rezultat va-
intermediul parametrului. loarea absolut a numrului prin
chiar numele ei. Tipul rezultatului
#include <iostream.h> este float, la fel ca al numrului
pentru care se calculeaz valoarea

G
float mod r(float a) absolut.
{if (a<0) a=-a; Parametrul subprogramului este a

DA
return a;} este un parametru de intrare.
Parametrul din antetul subpro-
void main() gramului este parametru formal.
{float x;

PE
cout<<"numarul="; cin>>x; Prin instruciunea return se
cout<<mod r(x);} precizeaz valoarea care va fi
furnizat prin numele funciei (a).
I
Apelul subprogramului din funcia rdcin Parametrul x cu care se apeleaz
se face printr-un operand a crui valoare se subprogramul este parametru
afieaz prin fluxul cout. actual.

1. Scriei un program prin care s calculai aria unui triunghi. Valorile


IC

Tem pentru laturile triunghiului se introduc de la tastatur n funcia


rdcin, iar aria se calculeaz ntr-un subprogram. Vei construi
subprogramul n dou variante:
CT

a) valoarea ariei se afieaz n funcia rdcin;


b) valoarea ariei se afieaz n subprogram.
Executai programele instruciune cu instruciune, folosind tasta F7.
DA

2. Scriei un subprogram care s returneze numrul de cifre ale unui numr natural,
transmis ca parametru.
1.1.5.5. Utilizarea stivei de ctre subprograme
DI

n memoria intern, fiecrui subprogram i se aloc o zon de memorie n care este ncr-
cat codul executabil. Ai vzut c, la apelarea unui subprogram, compilatorul i pred con-
trolul, adic ncep s se execute instruciunile subprogramului, pn la ntlnirea unei
instruciuni return sau pn la sfritul blocului care formeaz corpul subprogramului,
RA

dup care compilatorul red controlul modulului apelant, adic va continua execuia cu
instruciunea care urmeaz, n modulul apelant, imediat dup instruciunea care a apelat
subprogramul. Acest mecanism de transfer al controlului se poate realiza deoarece, ntr-o
zon de memorie intern numit stiva sistemului (stack), se pstreaz temporar infor-
ITU

maii despre subprogramul apelant. Aceste informaii sunt introduse n stiv atunci cnd
este apelat subprogramul. Ele formeaz instana subprogramului.
Etapele executate la apelarea subprogramului sunt:
1. Se ntrerupe execuia modulului apelant.
2. Se pregtete stiva sistemului, astfel:
ED

Informatic 17
 se introduce adresa de revenire n modulul apelant;

IC
 se introduc valorile parametrilor cu care a fost apelat subprogramul;
 se rezerv spaiu pentru variabilele locale declarate n subprogram.

OG
3. Se lanseaz n execuie codul executabil al subprogramului apelat.
Instana subprogramului

G
Adresa de revenire Contextul subprogramului
Este adresa instruciunii, din

DA
modulul apelant, care urmeaz
dup instruciunea care a Parametrii Variabilele locale
apelat subprogramul. Aceast subprogramului Valoarea variabilelor locale
instruciune se va executa Vor fi introdui n stiv n declarate n subprogram.

PE
dup ce s-a terminat execuia ordinea n care apar, de la
instruciunilor din corpul dreapta la stnga, n lista
subprogramului i s-a redat de parametri din antetul
controlul modulului apelant. subprogramului.
I
Etapele executate la terminarea subprogramului sunt:
1. Se elibereaz din stiv spaiul ocupat de variabilele locale i de parametri.
2. Se extrage din stiv adresa de revenire n modulul apelant.
3. Se continu execuia cu instruciunea de la adresa extras din stiv.

Astfel, pentru exemplele anterioare de declaraii de subprograme, la apelarea lor, n stiv


se vor introduce urmtoarele informaii:
IC

beta(x,y,z,w)
alfa(x,y,z) variabile locale beta
CT

variabile locale alfa x


x y
y z gama()
DA

z w variabile locale gama


adresa de revenire adresa de revenire adresa de revenire
Aadar, n timpul execuiei subprogramului, n stiv sunt pstrate datele cu care el lucrea-
DI

z: variabilele locale i parametrii cu care a fost apelat. Instruciunile subprogramului pot


modifica aceste date. Modificrile se execut asupra valorilor memorate n stiv. Cnd se
termin execuia subprogramului, trebuie s se reia execuia modulului apelant cu
instruciunea de adres de revenire. Pentru a se ajunge n stiv la adresa de revenire,
RA

spaiul ocupat de parametri i de variabilele locale este eliberat i se pierd valorile lor.
ITU

Scop: exemplificarea modului n care este folosit stiva sistemului la apelarea unui
subprogram.
Enunul problemei: S se verifice dac un numr natural n, citit de la tastatur, este
numr prim. Pentru testarea numrului se va folosi un subprogram.
ED

18 Tehnici de programare
Funcia prim(a) furnizeaz, prin numele su, o valoare ntreag ce poate fi interpretat

IC
ca o valoarea logic: 0 false sau 1 true. n variabila local x se calculeaz valoarea
funciei prim (1 sau 0, n funcie de numrul a dac este sau nu este numr prim).

OG
#include <iostream.h>
#include <math.h>
int prim (int a) //parametrul formal a
{int i,x=1; //variabilele locale n funcia prim()
if(a%2==0&&a!=2) return 0;

G
else {for(i=3;i<=sqrt(a)&&x;i++,i++)
if(a%i==0) x=0;

DA
return x;}}
void main()
{int n; cout<<"n = "; cin>>n; //n=variabila local n funcia main()
if (prim(n)) cout<<"Este numar prim"; //parametrul actual n

PE
else cout<<"Nu este numar prim";}
Coninutul stivei sistemului va fi:
dup ce s-a terminat execuia
se ncarc n stiv dup se execut funciei prim()se elibereaz
ce s-a ntrerupt execuia
I
funcia spaiul ocupat n stiv
funciei main() prim()
x

se execut i s-a reluat execuia


funcia a funciei main()de
main() la adresa adr_rel
IC

vrful adr_rel
stivei n n n
CT

se extrage din stiv adresa adr_rel de la


care se reia execuia funciei main()

1. Scriei un subprogram n care calculai cel mai mare divizor comun a


DA

Tem dou numere naturale (a i b). Folosii acest subprogram pentru a


calcula cel mai mare divizor comun a n numere introduse de la
tastatur. Artai care este coninutul stivei n timpul execuiei programului.
2. Folosii subprogramul care testeaz dac un numr natural este numr prim, pentru a
DI

rezolva urmtoarea problem: se introduc de la tastatur n numere naturale; s se


afieze cte numere sunt prime.
3. Folosii subprogramul pentru calculul celui mai mare divizor comun a dou numere,
RA

pentru a rezolva urmtoarea problem: se introduc de la tastatur dou numere,


s i m; s se afieze toate perechile de numere care au suma s i cel mai mic
multiplu comun m.
ITU

1.1.6. Transferul de parametri ntre subprograme


Schimbul de date ntre modulul apelant i subprogram se face prin intermediul parametrilor
de comunicaie.

Transferul de parametri este o tehnic folosit pentru schimbul de date ntre module.
ED

Informatic 19
Exist urmtoarele metode de transfer:

IC
1. Transfer prin valoare
 Modulul apelant transmite prin parametru, ctre subprogram, date de intrare. n mo-

OG
mentul apelrii subprogramului, o copie a valorii parametrului este ncrcat n stiv.
El este vzut n subprogram ca o variabil local, care este iniializat cu valoarea
transmis de modulul apelant prin parametrul actual din apel. Valoarea acestei
variabile se poate modifica n subprogram, dar aceast modificare nu se va reflecta i
n modulul apelant, deoarece modificarea se face n stiv, i, la terminarea execuiei

G
subprogramului, zona din stiv n care este memorat parametrul este eliberat.
 Parametrul prin intermediul cruia se face transferul prin valoare se numete

DA
parametru valoare.
 Acest transfer se folosete n general numai pentru parametrii de intrare. n
cazul n care parametrii transmii prin valoare sunt parametri de ieire sau de
intrare-ieire, pentru a putea transmite rezultatul obinut n subprogram, ctre

PE
modulul apelant, se pot folosi variabile de tip pointeri (sunt prezentai n Anex).
 Exemplu de antet de subprogram pentru un astfel de transfer (subprogramul
furnizeaz, prin parametrii ma i mg, media aritmetic, i respectiv media geome-
tric, a dou numere transmise subprogramului prin parametrii a i b).
I
void medie(int a, int b, float *ma, float *mg)

parametri valoare parametri valoare


transfer prin valoare transfer prin valoare folosind


IC

variabile de tip pointeri


Apelarea acestui subprogram se va face prin: medie(x,y,&m1,&m2); Para-
CT

metrilor a i b li se transmit, din modulul apelant, valorile variabilelor x i respec-


tiv y, iar parametrilor de tip pointer, ma i mb, valoarea adreselor variabilelor m1 i
respectiv m2.
2. Transfer prin referin
DA

 n momentul apelrii subprogramului, n stiv este ncrcat adresa de memorie la


care se gsete valoarea parametrului. Subprogramul va lucra direct n zona de me-
morie n care se gsete data. Att modulul apelant ct i subprogramul lucreaz
asupra aceleiai date, i orice modificare a valorii acestui parametru fcut n subpro-
DI

gram se va reflecta i n modulul apelant. La terminarea execuiei subprogramului,


este eliberat din stiv zona n care este memorat adresa parametrului.
 Parametrul prin intermediul cruia se face transferul prin referin se numete
parametru variabil.
RA

 Acest transfer se recomand pentru parametrii de intrare-ieire sau parametrii


de ieire. Modulul apelant transmite, prin aceti parametri, date de intrare-ieire
ctre subprogram, subprogramul preia data, o prelucreaz i o returneaz modu-
lului apelant. Acest parametru mai poate fi i un rezultat (dat de ieire) obinut n
ITU

urma prelucrrilor din subprogram, care este returnat apoi modulului apelant.
 Distincia dintre un parametru valoare i un parametru variabil (definirea tipului de
transfer) se face n lista de parametri formali din antetul subprogramului n
care parametrii variabil sunt precedai de operatorul adres de memorie &.
ED

20 Tehnici de programare
 Exemplu de antet de subprogram pentru un astfel de transfer (pentru un subpro-

IC
gram care rezolv aceeai problem ca i n exemplul precedent):

void medie (int a, int b, float &ma, float &mg)

OG
parametri valoare parametri variabile

transfer prin valoare transfer prin referin

G
Apelarea acestui subprogram se va face prin: medie(x,y,m1,m2);
Din modulul apelant se transmit: parametrilor a i b, care sunt parametri valoare

DA
valorile variabilelor x i respectiv y , iar parametrilor ma i mb, care sunt de tip
parametri variabil adresele variabilelor m1 i respectiv m2.
Observaie:

PE
Pentru transmiterea unor rezultate din subprogram ctre modulul apelant (pa-
rametru de ieire sau de intrare-ieire) se folosete fie transferul prin referin, fie
transferul prin valoare, folosind variabile de tip pointeri.

Observaii:
I
1. Parametrii actuali corespunztori parametrilor valoare pot fi exprimai prin:
 valoare (constant);
 expresie;

 variabil de memorie;
 adres a unei variabile de memorie (este obligatorie, n cazul n care parametrii
IC

formali sunt de tip pointer).


2. Parametrii formali corespunztori parametrilor valoare pot fi iniializai n antetul
subprogramului. La apelul subprogramului, parametrilor formali li se atribuie valoarea
CT

parametrilor actuali. Dac lipsete un parametru actual, parametrul formal va fi iniia-


lizat cu valoarea din list:
#include<iostream.h>
DA

int test(int a=10, int b=20) {return a+b;}


void main()
{cout<<test(30,40)<<endl; //afieaz 70
cout<<test(30)<<endl; //afieaz 50
DI

cout<<test();} //afieaz 30
3. Parametrii actuali corespunztori parametrilor variabil pot fi exprimai numai prin
variabile de memorie.
RA

Scop: exemplificarea modului n care pot fi transmii parametrii ntre subprograme.


Enunul problemei: S se construiasc un subprogram care s realizeze inter-
ITU

schimbarea valorilor a dou variabile de memorie ntregi.


Numele subprogramului este schimb. Modulul apelant va fi funcia rdcin, iar modulul
apelat va fi subprogramul schimb. Din funcia rdcin se vor transfera subprogramului
parametrii x i y, care reprezint variabilele a cror valoare se interschimb. Acest subpro-
ED

gram va fi construit n trei variante, n funcie de modul n care sunt transferai parametrii:

Informatic 21

IC
Varianta 1 Varianta 2
Transferul parametrilor se face prin Transferul parametrilor se face prin va-
valoare. loare, folosind variabile de tip pointer.

OG
#include<iostream.h> #include<iostream.h>
int schimb(int x, int y) int schimb(int *x, int *y)
{int z; {int z;
z=x; x=y; y=z;} z=*x; *x=*y; *y=z;}

G
void main() void main()
int a,b; int a,b;
cout<<"a= "; cin>>a; cout<<"a= "; cin>>a;

DA
cout<<"b= "; cin>>b; cout<<"b= "; cin>>b;
schimb(a,b); schimb(&a,&b);
cout<<a<<" "<<b;} cout<<a<<" "<<b;}

PE
Varianta 3
Transferul parametrilor se face prin Tem
referin.
#include<iostream.h>
I
Comparai cele trei variante ale subpro-
int schimb(int &x, int &y) gramului schimb. Executai fiecare vari-
{int z; ant, pentru urmtoarele date de intrare:
z=x; x=y; y=z;} a=10 i b=20. Ce constatai? Explicai

void main() rezultatele obinute. Desenai diagrama


int a,b; stivei pentru fiecare variant de transfer de
IC

cout<<"a= "; cin>>a; parametri.


cout<<"b= "; cin>>b;
schimb(a,b);
CT

cout<<a<<" "<<b;}
1. Scriei un program n care s calculai media aritmetic (ma) i media
Tem geometric (mg) a dou numere ntregi (a i b) introduse de la
DA

tastatur. n funcia rdcin se citesc valorile pentru a i b i se


afieaz valorile celor dou medii care se vor calcula n subprogramul medie. Vei
implementa dou variante pentru subprogram, pornind de la urmtoarele anteturi:
a. void medie(int a, int b, float *ma, float *mg)
DI

b. void medie(int a, int b, float &ma, float &mg)


2. Scriei un subprogram care returneaz prima cifr i numrul de cifre ale unui numr
natural n transmis ca parametru. De exemplu, pentru n=608, subprogramul retur-
neaz valorile 6 i 3.
RA

(Bacalaureat Sesiunea iunie - iulie 2004)


3. Realizai urmtoarele cerine, utiliznd limbajul C++:
a. Scriei definiia unui subprogram mindiv care determin cel mai mic dintre
ITU

divizorii mai mari dect 1 ai unui numr natural transmis prin intermediul
parametrului a (a>1) i returneaz acest divizor prin intermediul parametrului b.
b. Scriei programul care citete dou numere naturale a i b (a<b) i determin cel
mai mare numr prim din intervalul nchis [a,b] cu ajutorul subprogramului definit
la punctul a). Dac nu exist un astfel de numr, se va afia mesajul Nu exista.
ED

(Bacalaureat Simulare 2006)



22 Tehnici de programare
4. Se tie c este definit o funcie nrap care:

IC
 primete prin intermediul parametrului nr un numr natural de cel mult 9 cifre i
prin intermediul parametrului cif o cifr ntre 0 i 9;
 returneaz numrul de apariii ale cifrei cif n scrierea numrului nr n baza 10.

OG
De exemplu, pentru numrul 2535 i cifra 5, se returneaz 2, iar pentru numrul
2535 i cifra 7, se returneaz 0.
a. Scriei antetul subprogramului nrap.
b. Scriei declarrile de date i programul principal, n care se verific dac un

G
numr natural k citit de la tastatur are toate cifrele distincte sau nu, folosind
apeluri ale subprogramului nrap.

DA
(Bacalaureat Simulare 2004)

1.1.7. Clasificarea variabilelor de memorie


Unui subprogram aflat n execuie i se rezerv propriul spaiu de memorie n interiorul zonei

PE
de memorie rezervat programului principal. Subprogramele pot fi privite ca blocuri care
conin, pe lng instruciuni, i alte obiecte, precizate prin:
 lista de parametri formali;
 instruciuni declarative din zona declarativ a subprogramului;
 instruciuni declarative ntr-un bloc din subprogram.
I
Exist mai multe zone de memorie n care sistemul de operare poate aloca spaiu de
memorare variabilelor:

zona de adrese libere (heap)


variabile globale variabile locale
(alocarea stiva sistemului (stack)
IC

(alocarea implicit)
implicit)
segmentul de date
CT

Deoarece att n modulul apelant ct i n subprogram sunt definii mai muli identificatori
pentru aceste obiecte (variabile de memorie i constante) problema care se pune este:
care este domeniul de vizibilitate al identificatorilor, n funcie de locul n care sunt
declarai, i care este durata de via a unei variabile de memorie? innd cont de aces-
DA

te caracteristici ale variabilelor de memorie, ele pot fi clasificate dup urmtoarele criterii:
Criterii pentru clasificarea variabilelor de memorie
DI

Domeniul de vizibilitate Durata de via


Reprezint zona din program n care Reprezint perioada de timp n care
este permis accesul la variabil. variabilei i se aloc spaiu n memorie.
RA

 variabile globale tot programul;  variabile cu durat local dura-


 variabile locale blocul n care au ta de execuie a blocului n care au
fost declarate. fost declarate;
ITU

 variabile cu durat static dura-


ta de execuie a programului;
 variabile cu durat dinamic
durata de alocare a memoriei n tim-
ED

pul execuiei programului.



Informatic 23
1.1.7.1. Durata de via a variabilelor de memorie

IC
n funcie de durata de via, variabilele de memorie se clasific n:
1. Variabile cu durat local

OG
 Sunt variabile create n interiorul unui subprogram; compilatorul le creeaz i le
distruge automat, atunci cnd ncepe execuia subprogramului, respectiv cnd se
termin execuia lui.
 La fiecare nou apelare a subprogramului, vor avea o valoare nedefinit (valoarea rezi-

G
dual din zona de stiv care li se aloc). De aceea, ele trebuie ntotdeauna iniializate.
 Sunt pstrate temporar n stiv (numai pe timpul execuiei subprogramului).

DA
2. Variabile cu durat static
 Sunt create atunci cnd ncepe execuia subprogramului i dureaz pe tot timpul
execuiei subprogramului; ele corespund de regul variabilelor globale.
 Sunt iniializate cu valoarea 0.

PE
 Spaiul de memorie li se aloc la compilare, n segmentul de date.
3. Variabile cu durat dinamic
 Sunt create n timpul execuiei programului i dureaz att timp ct sunt necesare.
 Spaiul de memorie li se aloc n timpul execuiei programului, n zona de memorie
I
liber (heap).

1.1.7.2. Domeniul de vizibilitate al identificatorilor


Domeniul de vizibilitate al identificatorilor este o caracteristic a oricrui identificator


(nume de variabil, nume de constant, nume de funcie, nume de tip de dat) i reprezint
IC

zona de program n care un identificator definit poate fi referit (este vizibil). De exemplu,
dac dou variabile de memorie cu acelai nume au fost declarate n subprograme diferite,
vor avea fiecare dintre ele ca domeniu de vizibilitate subprogramul n care au fost decla-
CT

rate. n funcie de domeniul de vizibilitate, variabilele de memorie se clasific n:


1. Variabile locale
 Sunt variabile definite n corpul unui subprogram, n orice bloc al subprogramului
DA

(n orice instruciune compus) i sunt variabile proprii subprogramului.


 Asupra lor pot fi executate operaii (sunt vizibile) numai din interiorul blocului n care
au fost declarate (blocul subprogramului sau blocul unei instruciuni compuse).
 Folosirea lor este util pentru a se elimina confuziile care apar atunci cnd se folo-
DI

sesc variabile cu acelai nume n dou subprograme diferite.


 Variabilele definite n interiorul funciei rdcin main() sunt tot variabile locale
(sunt definite ntr-un bloc).
 Durata lor de via este local numai pe perioada execuiei blocului (subpro-
RA

gram sau instruciune compus).


 La declarare, variabilele locale nu sunt iniializate cu o valoare. Ele pstreaz
valoarea atribuit anterior zonei de memorie alocate (valoare rezidual).
 Parametrii formali ai unui subprogram sunt variabile locale.
ITU

 Variabilelor locale li se aloc spaiu n stiv de fiecare dat cnd se apeleaz


subprogramul. Cnd subprogramul i termin execuia, variabilele locale sunt
eliminate din stiv i se elibereaz spaiul ocupat de ele.
2. Variabile globale
 Sunt variabile definite n afara oricrui subprogram.
ED

24 Tehnici de programare
 Ele sunt vizibile n toate subprogramele care sunt declarate dup definirea lor.

IC
Oricare dintre aceste subprograme poate folosi i modifica valoarea lor.
 Folosirea lor este util atunci cnd unele date se folosesc n comun de ctre modu-

OG
lele unui program care nu se apeleaz unele pe altele.
 Durata lor de via este static pe toat perioada execuiei programului (din
momentul n care au fost declarate i pn n momentul n care se termin
execuia programului).
 Domeniul de vizibilitate al unei variabile globale poate fi controlat n funcie de locul

G
n care o declarai, innd cont de urmtoarea observaie: atunci cnd declarai o
variabil global, ea va putea fi folosit de orice subprogram declarat dup ea,

DA
dar nu poate fi folosit de un subprogram declarat naintea ei.
 La declarare, variabilele globale sunt iniializate cu valoarea 0.
Reguli pentru vizibilitatea identificatorilor:

PE
1. n interiorul unui bloc, un identificator nu poate fi definit dect o singur dat.
Dac vei folosi acelai nume pentru dou obiecte diferite (variabil, constant sau tip de
dat), apariia acestui nume n cadrul unei instruciuni va produce eroare la compilare.
2. Un identificator nu poate fi folosit n exteriorul blocului n care a fost definit.
3. Un identificator poate fi declarat n blocuri diferite, de acelai tip sau de tipuri
I
diferite. n acest caz se rezerv cte o zon de memorie pentru fiecare identificator
declarat, de dimensiune corespunztoare tipului declarat. Pentru un identificator folosit
ntr-o instruciune, se stabilete tipul i zona de memorie alocat, cutndu-se n cel
mai interior bloc care conine att instruciunea, ct i declaraia identificatorului.

Conflictele de nume ntre variabile definite n domenii incluse unul n altul se rezolv
IC

astfel: compilatorul ascunde temporar identificatorul exterior, care i pierde


vizibilitatea:
 Dac exist o variabil global i o variabil local cu aceleai nume, n subprogramul
CT

n care s-a definit variabila local compilatorul va folosi ntotdeauna variabila local.
 Dac exist dou variabile locale cu acelai nume, una definit pentru tot subprogramul,
iar cealalt ntr-un bloc din acelai subprogram, compilatorul va ascunde variabila local
definit pentru tot subprogramul, pe durata execuiei blocului n care a mai fost definit.
DA

Exemplul 1:
float x1; P x1
DI

sb1
void sb1(float x2) x2
{..................}
RA

x1: variabil global


x2: variabil local
Este vizibil n toate Este vizibil numai n sb1. Orice ncercare de referire la
subprogramele (inclusiv sb1). ea dintr-un alt subprogram va fi semnalat cu mesajul de
eroare Undefined symbol.
ITU

Instruciunea x1=10; poate s apar n orice subprogram, n schimb instruciunea x2=10;


poate s apar numai n subprogramul sb1 i afecteaz numai valoarea variabilei din
acest subprogram.
ED

Informatic 25

IC
Exemplul 2:

float x,y; P
x y

OG
void sb1(float a)
{float b; sb1
...................}
a b

G
x, y: variabile globale
Sunt vizibile n toate subprogramele

DA
(inclusiv sb1). a, b: variabile locale
Sunt vizibile numai n sb1.
Instruciunea cout<<x<<y<<a<<b;
 poate s apar n sb1 (deoarece aici sunt vizibile toate variabilele);

PE
 nu poate s apar n nici un alt subprogram (deoarece nu sunt vizibile variabilele a i b).
Exemplul 3:
int a; P
a
I
void sb1(float a)
{.................}
sb1
a
a: variabil global

Este vizibil n toate


IC

subprogramele, mai puin a: variabil local


subprogramul sb1. Este vizibil numai n sb1.
Instruciunea a=10;
CT

 dac se gsete n orice subprogram diferit de sb1, afecteaz valoarea variabilei


globale a (de tip int);
 dac se gsete n subprogramul sb1 afecteaz valoarea variabilei locale a (de tip float).
DA

Exemplul 4:

float a; P a
DI

void sb1(float b)
{......
............ sb1 b
{char b;
RA

.........}
} IC1 b

a: variabil global
ITU

Este vizibil n toate


subprogramele.
b: variabil local
b: variabil local Este vizibil numai n
Este vizibil numai n sb1, mai instruciunea compus IC1.
ED

puin instruciunea compus IC1.



26 Tehnici de programare

IC
Instruciunea b=10;
 dac se gsete n orice subprogram diferit de sb1, va fi considerat identificator
necunoscut;

OG
 dac se gsete oriunde n subprogramul sb1, mai puin n instruciunea compus
IC1, afecteaz valoarea variabilei locale b de tip float;
 dac se gsete n instruciunea compus IC1, afecteaz valoarea variabilei locale b
de tip char.
Recomandri:

G
1. Valoarea unei variabile globale poate fi modificat din interiorul oricrui subprogram.
Din aceast cauz, programatorul trebuie s fie foarte atent la aceste variabile. n plus,

DA
folosirea lor degenereaz coerena programrii modulare, deoarece creeaz
dependene ntre module, la proiectarea lor.
2. Variabilele locale protejeaz integritatea programelor, adic modificarea acestor vari-
abile ntr-un subprogram nu afecteaz i alte subprograme. Ele asigur astfel porta-

PE
bilitatea subprogramelor (independena unui subprogram fa de alte subprograme).
3. Constantele globale sunt avantajoase deoarece permit modificarea unei valori
constante n ntreg programul, adic, schimbnd valoarea constantei n programul
principal, actualizarea ei va fi vzut n toate subprogramele.
I
Este recomandabil folosirea parametrilor n locul variabilelor globale deoarece:
 Prin variabilele globale datele sunt partajate ntre toate modulele. Orice modul poate
modifica aceste date. Din aceast cauz, se creeaz dependene nedorite ntre module.
 Parametrii permit o identificare clar a datelor partajate de anumite module, prin preci-

zarea explicit a acestor date n lista de parametri din antetul subprogramului i prin lista
IC

de parametri din instruciunea cu care se apeleaz subprogramul.


Observaii:
CT

Transferul datelor (comunicarea) ntre subprogram i modulul apelant se poate face prin
intermediul parametrilor sau al variabilelor globale.
1. Un subprogram, cu ct are mai puini parametri (folosete mai multe variabile
globale), cu att este mai uor de scris i apelat.
DA

2. Un subprogram, cu ct are mai muli parametri (folosete mai puine variabile


globale), cu att este mai flexibil, mai portabil (poate fi implementat uor n programe
diferite i nu influeneaz modulul apelant).
DI

Parametrii se deosebesc de variabilele globale. Ei sunt iniializai, n


Atenie momentul apelului, cu valori primite din modulul apelant (valorile sunt
parametrii actuali):
 n cazul transferului prin valoare, i se atribuie o valoare, o expresie sau coninutul
RA

unei variabile de memorie;


 n cazul transferului prin referin, subprogramul primete o adres de memorie la
care este stocat variabila primit ca parametru.
ITU

Scop: exemplificarea domeniului de vizibilitate i a duratei de via a variabilelor de


memorie.
Executai urmtorul program. Precizai tipul fiecrei variabile de memorie vizibile n
ED

fiecare dintre funcii. Notai valorile afiate pe ecran. Explicai rezultatele afiate.

Informatic 27

IC
#include<iostream.h>
int i; float x; char c;
void sb1(int a) //se pot folosi variabilele a,b,c,i,x

OG
{int i, b=10;
i=b; b+=a; a=i;
{int i;
for (i=1;i<=3;i++) cout<<i<<endl; }
cout<<i<<" "<<b<<endl; }

G
float a;
void sb2(float x) //se pot folosi variabilele a,b,c,i,x

DA
{int b,c; a=x; b=c=x;
cout<<a<<" "<<b<<endl; }
void main() //se pot folosi variabilele a,c,i,x
{int x=100; a=20.5; c='A';i=30;

PE
sb1(20); sb2(a); cout<<a<<endl;
sb1(x); sb2(2.5); cout<<a<<endl;
sb1(c); sb2(i); cout<<a<<endl;}

1.1.8. Alegerea modului de implementare a subprogramului


I
Implementarea unui subprogram se poate face ca funcie operand sau ca funcie procedu-
ral. Alegerea modului de implementare difer n funcie de problema care trebuie rezolvat.

IC

Scop: exemplificarea modului n care pot fi implementate subprogramele.


Enunul problemei 1: Se consider trei numere naturale, a, b i c. S se verifice dac pot
CT

forma o progresie aritmetic.


Pentru rezolvarea problemei, vom folosi subprogramul schimb care va fi implementat iniial
ca funcie procedural i apoi ca funcie operand. Va fi apelat de trei ori, pentru a ordona
cresctor cele trei numere.
DA

Subprogramul implementat ca funcie procedural va folosi numai parametrii de comunicare,


pentru schimbul de date cu funcia rdcin. Pentru a ordona cresctor cele trei numere,
subprogramul va fi apelat de trei ori, folosind o instruciune procedural.
DI

n antetul funciei procedurale void schimba(int &x,int &y); parametrii x i y sunt


parametri formali, adic variabile de memorie folosite n cadrul subprogramului. Ei sunt
parametri de intrare-ieire deoarece sunt folosii pentru a transmite date dinspre program
ctre subprogram (ca date de intrare n subprogram), i invers, la terminarea execuiei
RA

subprogramului, dinspre subprogram ctre program (ca date de ieire din subprogram). n
apelurile funciei procedurale (instruciunile procedurale) schimba(a,b);, i respectiv
schimba(b,c);, parametrii a i b i respectiv b i c sunt parametrii actuali, adic
valorile atribuite pentru datele declarate n funcie ca parametri de comunicare cu care se
ITU

execut subprogramul la acel apel. Aadar, la apelul schimba(a,b); variabilei x i se va


atribui valoarea variabilei a, iar variabilei y i se va atribui valoarea variabilei b. Dup
executarea subprogramului, prin variabilele x i y se vor comunica rezultatele obinute n
urma executrii subprogramului, adic variabila a va avea valoarea variabilei x (n urma
ED

interschimbrii, vechea valoare a variabilei b), iar variabila b va avea valoarea variabilei y

28 Tehnici de programare
(n urma interschimbrii, vechea valoare a variabilei a). n schimb, la apelul schimba(b,c);

IC
variabilei x i se va atribui valoarea b, iar variabilei y i se va atribui valoarea c.
Programul obinut prin folosirea funciei procedurale este:

OG
#include <iostream.h>
void schimba(int &,int &); prototipul
subprogramului
void main()

G
{int a,b,c;
cout<<"a= "; cin>>a; parametri actuali

DA
cout<<"b= "; cin>>b;
cout<<"c= "; cin>>c;
if (a>b) schimba(a,b);
if (b>c) schimba(b,c); apeluri de subprogram

PE
if (a>b) schimba(a,b);
if (b==(a+c)/2.)
cout<<a<<","<<b<<","<<c<<"sunt in progresie aritmetica";
else
cout<<a<<","<<b<<","<<c<<"nu sunt in progresie aritmetica";}
I
void schimba(int &x,int &y) antetul subprogramului
{int z;
z=x; x=y; y=z; subprogramul

} parametri formali
IC

Observaii rezultate din exemplul prezentat:


1. Citirea i scrierea datelor prelucrate de algoritm se execut n programul principal.
2. Comunicarea datelor ntre modulele apelante i modulele apelate se face numai prin
CT

intermediul perechilor parametru formal parametru actual.


3. Parametrilor dintr-o pereche parametru formal parametru actual li se poate atribui
acelai nume. Obligatoriu este ns s se respecte acelai tip de dat n cadrul perechii
i ordinea de scriere a parametrilor n cele dou liste prin care se asigur regula de
DA

coresponden.
n exemplul prezentat, explicai modul n care se face transferul datelor
Tem ntre funcia rdcin i subprogram, prin intermediul parametrilor de
DI

comunicare.
Subprogramul implementat ca funcie operand va furniza funciei rdcin un rezultat prin
numele subprogramului, iar cellalt printr-un parametru de intrare-ieire. Pentru a ordona
cresctor cele trei numere, subprogramul va fi apelat de trei ori, ca operand n instruciuni
RA

de atribuire, prin care valoarea returnat de funcie se atribuie uneia dintre variabilele care
se interschimb, iar celeilalte variabile i se transmite noua valoare prin intermediul unui
parametru al subprogramului.
Programul obinut prin folosirea funciei operand este:
ITU

#include<iostream.h>
int schimba(int &,int);
void main()
{int a,b,c;
ED

Informatic 29

IC
cout<<"a= "; cin>>a; cout<<"b= "; cin>>b; cout<<"c= "; cin>>c;
if (a>b) b=schimba(a,b);
if (b>c) c=schimba(b,c);

OG
if (a>b) b=schimba(a,b);
if (b==(a+c)/2.)
cout<<a<<","<<b<<","<<c<<"sunt in progresie aritmetica";
else cout<<a<<","<<b<<","<<c<<"nu sunt in progresie aritmetica";}
int schimba(int &x,int y)

G
{int z; z=x; x=y; y=z;
return y;}

DA
n acest caz, x este un parametru de intrare-ieire, deoarece este folosit pentru a trans-
mite date, ca i n exemplul precedent, ntre funcia rdcin i subprogram, iar y este un
parametru de intrare, fiind folosit pentru a transmite date numai dinspre funcia rdcin
ctre subprogram (ca date de intrare n subprogram). n urma prelucrrilor din subprogram,

PE
rezultatul obinut n variabila de memorie y va fi transmis programului prin numele funciei.
n apelurile funciei operand (expresiile din instruciunile de atribuire) b=schimba(a,b); i
respectiv c=schimba(b,c);, parametrii a i b i respectiv b i c sunt parametrii actuali,
adic valorile atribuite pentru datele declarate n funcia operand ca parametri de
I
comunicare cu care se execut subprogramul la acel apel. Aadar, la apelul
b=schimba(a,b); variabilei x i se va atribui valoarea variabilei a, iar variabilei y i se va
atribui valoarea variabilei b. Dup executarea subprogramului, prin variabila x i prin
numele funciei (creia i se returneaz valoarea variabilei y) se vor comunica rezultatele

obinute n urma executrii subprogramului, adic variabila a va avea valoarea variabilei x


(n urma interschimbrii, vechea valoare a variabilei b), iar variabila b va avea valoarea
IC

returnat de funcie prin numele ei (n urma interschimbrii, vechea valoare a variabilei a).
n schimb, la apelul c=schimba(b,c); variabilei x i se va atribui valoarea b, iar variabilei
y i se va atribui valoarea c.
CT

Enunul problemei 2: S se rezolve calculul combinrilor definite astfel:


C(n,k) = n!/(k!*(n-k)!)
Pentru a calcula valoarea combinrilor, trebuie evaluate trei expresii factorial: p1=n!, p2=k!
DA

i p3=(n-k)!. Calcularea acestor expresii se face folosind aceeai metod:


for(i=1;i<=n;i++) p1=p1*i;
for(i=1;i<=n-k;i++) p2=p2*i;
DI

for(i=1;i<=k;i++) p3=p3*i;
Cei trei algoritmi de calcul se deosebesc numai prin valoarea final a contorului i. Pentru
implementarea lor se poate folosi un subprogram fact care se va executa de trei ori, de
fiecare dat cu alte date de intrare (n, k i respectiv n-k).
RA

Pentru calculul factorialului se poate folosi un subprogram, fie de tip funcie procedural, fie
de tip funcie operand, astfel:
Programul obinut prin folosirea funciei procedurale este:
ITU

#include<iostream.h>
void fact(int n,unsigned long &p)
{for(int i=1,p=1;i<=n;i++)p=p*i;}
void main()
ED

30 Tehnici de programare

IC
{int n,k; unsigned long p1,p2,p3;
cout<<"n= "; cin>>n; cout<<"k= "; cin>>k;
fact(n,p1); fact(k,p2); fact(n-k,p3);

OG
cout<<"Combinari= "<< p1/(p2*p3);}
Observaii:
1. Variabilele de memorie n i k din programul principal, a cror valoare este transmis ca
parametru actual n apelurile de funcie, sunt de acelai tip ca i parametrul formal n din

G
antetul funciei operand. n acelai mod, variabilele de memorie p1, p2 i p3 din
programul principal, a cror valoare este transmis pentru al doilea parametru actual
din apelurile de procedur, sunt de acelai tip ca i variabila de memorie p folosit n

DA
subprogram i care reprezint al doilea parametru formal din antetul procedurii.
2. Activarea subprogramului se face printr-o instruciune procedural. Numele subpro-
gramului apare n dou situaii: n antetul funciei i n cele trei apeluri ale funciei

PE
procedurale (instruciuni procedurale).
Programul obinut prin folosirea funciei operand este:
#include<iostream.h>
unsigned long fact(int n)
I
{int i; unsigned long p=1;
for(i=1;i<=n;i++) p=p*i;
return p;}
void main()

{int n,k; cout<<"n= "; cin>>n; cout<<"k= "; cin>>k;


cout<<"Combinari= "<< fact(n)/(fact(k)*fact(n-k)); }
IC

Observaii:
1. Variabilele de memorie n i k din programul principal, a cror valoare este transmis ca
CT

parametru actual n apelurile de funcie, sunt de acelai tip ca i parametrul formal n din
antetul funciei operand. n acelai mod, variabila de memorie p din subprogram, a
crei valoare este returnat prin numele funciei operand, este de acelai tip ca i
rezultatul funciei precizat n antetul funciei.
DA

2. Activarea subprogramului se face n cadrul unei instruciuni de atribuire n care numele


lui apare ca operand. n cadrul programului, numele subprogramului apare n dou
situaii: n antetul funciei i n cele trei apeluri ale funciei operand (n instruciunea de
afiare a rezultatului expresiei prin care se calculeaz valoarea combinrilor).
DI

3. Comparaie. n varianta funciei procedurale, n funcia rdcin sunt necesare n


plus trei variabile p1, p2 i p3. n schimb, n varianta funciei operand, n subprogram
se folosete n plus variabila local p.
RA

Comparai, pentru fiecare problem, cele dou variante de implementare a


Tem subprogramului. Precizai, pentru fiecare caz, ce tip de subpro-
gram este mai bine s folosii. Justificai rspunsul.
ITU

Recomandri:
1. Se recomand folosirea funciilor operand atunci cnd subprogramul furnizeaz un
singur rezultat.
2. Se recomand folosirea funciilor procedurale atunci cnd subprogramul nu furni-
zeaz nici un rezultat sau furnizeaz mai multe rezultate.
ED

Informatic 31

IC
1.1.9. Tablourile de memorie i subprogramele
Dac parametrii de ieire sau de intrare-ieire ai unui subprogram sunt de tip vector, nu

OG
trebuie s folosii transferul prin referin, deoarece identificatorul unui tablou de memorie
este o adres de memorie. Prin urmare, dac se folosete transferul prin valoare, n stiv
se va transfera adresa vectorului, i orice modificare fcut n vector va fi vizibil i din
modulul apelant.
Exemplul 1 Se citesc de la tastatur elementele de tip ntreg a doi vectori, a i b, care au

G
aceeai dimensiune, n. Elementele vectorilor sunt de tip int. Se va obine vectorul c prin
adunarea elementelor celor doi vectori: a i b. Se sorteaz cresctor vectorul c i apoi se

DA
afieaz. Se folosesc urmtoarele subprograme: citeste() pentru a citi elementele unui
vector, scrie() pentru a afia elementele unui vector, sort() pentru a sorta elementele
unui vector i aduna() pentru a aduna elementele a doi vectori.
#include <iostream.h>

PE
void citeste(int x[], int n)
{for (int i=0;i<n;i++) {cout<<"x("<<i+1<<")= "; cin>>x[i];}}
void afiseaza(int x[], int n)
{for (int i=0;i<n;i++) cout<<x[i]<<" ";}
I
void aduna(int x[], int y[], int z[], int n)
{for (int i=0;i<n;i++) z[i]=x[i]+y[i];}
void sort(int x[],int n)

{for (int i=0;i<n-1;i++)


for (int j=i+1,aux;j<n;j++)
IC

if (x[i]>x[j]) {aux=x[i]; x[i]=x[j]; x[j]=aux;}}


void main()
{int a[20],b[20],c[20],n;
CT

cout<<"numarul de elemente "; cin>>n;


cout<<"primul vector"<<endl; citeste(a,n);
cout<<"al doilea vector"<<endl; citeste(b,n);
aduna(a,b,c,n); sort(c,n);
DA

cout<<"vectorul rezultat, sortat"<<endl; afiseaza(c,n);}


Atunci cnd transmitei un vector ca parametru nu trebuie s preci-
Atenie zai lungimea fizic a vectorului la declararea parametrului. Paran-
DI

tezele ptrate care urmeaz dup numele unui vector informeaz


compilatorul c acest parametru este un vector.
Dac subprogramul este folosit numai pentru un vector, acesta poate fi declarat ca variabil
global.
RA

Exemplul 2 Se citesc de la tastatur cele n elemente de tip ntreg ale unui vector i o
valoare ntreag x. S se afieze de cte ori apare, n vector, valoarea x. Se folosesc
urmtoarele subprograme: citeste() pentru a citi elementele vectorului i numar()
ITU

pentru a numra apariiile valorii x n vector.


#include <iostream.h>
int a[100],n,x;
void citeste()
{for (int i=0;i<n;i++) {cout<<"a("<<i+1<<")= "; cin>>a[i];}}
ED

32 Tehnici de programare

IC
int numar()
{for(int i=0,k=0;i<n;i++) k+=(x==a[i]);
return k;}

OG
void main()
{cout<<" n="; cin>>n; cout<<" x="; cin>>x; citeste();
cout<<"Numarul "<<x<<" a fost gasit in vectorul citit de ";
cout<<numar()<<" ori";}

G
1. Pentru un vector cu elemente ntregi, scriei cte un subprogram
Tem care calculeaz:
a. suma elementelor vectorului;

DA
b. suma elementelor pozitive din vector;
c. media aritmetic a elementelor vectorului;
d. media aritmetic a elementelor pozitive din vector.
2. Scriei un subprogram care construiete (fr a afia) vectorul v care conine, n

PE
ordine descresctoare, cele mai mici n numere naturale pare. De exemplu, pentru
n=7, vectorul v va conine valorile 12, 10, 8, 6, 4, 2, 0. Valoarea lui n (n<100) se
transmite ca parametru, vectorul v fiind i el parametru al subprogramului.
(Bacalaureat Simulare 2004)
I
3. Funcia sum primete prin intermediul parametrului v un vector de numere reale cu 50
de componente i prin intermediul parametrului k un numr natural nenul (1<k<50). El
returneaz suma tuturor elementelor vi ale vectorului, cu proprietatea c ik.
a. Scriei definiia complet a subprogramului sum.

b. Scriei programul care citete de la tastatur un ir s de 50 de numere reale i


apoi dou numere naturale n i m (1<m<n<50) i afieaz suma elementelor din
IC

ir cu indicii cuprini ntre m i n (inclusiv m i n) folosind apeluri ale funciei sum.


(Bacalaureat Sesiunea iunie - iulie 2004)
CT

1.1.10. Dezvoltarea programelor


Tehnica top-down este o tehnic de proiectare a algoritmilor prin rafinare iterativ. Ea
DA

const n descompunerea problemei iniiale n subprobleme, care la rndul lor vor fi supuse
aceluiai proces de descompunere, pn cnd se obin subprobleme cu rezolvare
imediat. Folosirea acestei tehnici are urmtoarele avantaje:
 Atenia programatorului se poate concentra la un moment dat numai asupra unei
DI

singure subprobleme, i nu asupra ntregului ansamblu de subprobleme care formea-


z problema pe care trebuie s o rezolve.
 Se favorizeaz lucrul n echip, deoarece fiecare subproblem va putea fi rezolvat
de cte un programator, i nu un singur programator trebuie s rezolve ntreaga
RA

problem.
Subproblemele n care este descompus problema folosind tehnica top-down se numesc
module. Fiecare modul poate fi i el descompus n alte module, pn se obin module cu
rezolvare imediat.
ITU

Rezolvarea unei subprobleme (modul) se face folosind un subprogram, adic fiecare


modul va fi implementat cu ajutorul unui subprogram.
ED

Informatic 33

IC
Modulul principal

OG
Modulul 1 Modulul 2 Modulul 3

G
Modulul 11 Modulul 12 Modulul 13 Modulul 31 Modulul 32

DA
n limbajul C++ nu se poate folosi dect dezvoltarea ascendent, adic
subprogramele sunt definite unul dup altul.

Observaie: Pentru a apela, dintr-un subprogram, orice alt subprogram definit n acelai

PE
fiier surs (n acelai program), se vor declara subprogramele naintea funciei rdcin
main(), prin prototip, dup care se vor defini subprogramele, dup funcia rdcin main().
#include<iostream.h>
void sb1(); //Prototipul subprogramului sb1()
I
void sb2(); //Prototipul subprogramului sb2()
void sb3(); //Prototipul subprogramului sb3()
void main() {sb1(); }
void sb1() //Antetul subprogramului sb1()

{cout<<"Subprogramul 1"<<endl;
sb2();} //Apelul subprogramului sb2()definit ulterior
IC

void sb2() //Antetul subprogramului sb2()


{cout<<"Subprogramul 2"<<endl;
CT

sb3();} //Apelul subprogramului sb3()definit ulterior


void sb3() //Antetul subprogramului sb3()
{cout<<"Subprogramul 3"<<endl;}
Recomandare: Pentru claritatea programului, se recomand declararea tuturor sub-
DA

programelor prin prototip, la nceputul fiierului surs, iar definirea lor, ulterior (eventual,
dup funcia rdcin main().
DI

Scop: exemplificarea modului n care poate fi implementat un algoritm cu ajutorul


subprogramelor, folosind metoda de proiectare top-down.
Enunul problemei 1: S se rezolve ecuaia de gradul 2: ax2+bx+c=0. Coeficienii ecuaiei
RA

sunt numere ntregi.


Folosind tehnica top-down problema poate fi mprit n subprobleme, astfel:
 introducerea coeficienilor,
 calcularea discriminantului delta,
ITU

 rezolvarea ecuaiei de gradul 1,


 rezolvarea ecuaiei de gradul 2 cu rdcini reale distincte,
 rezolvarea ecuaiei de gradul 2 cu rdcini reale identice,
 rezolvarea ecuaiei de gradul 2 cu rdcini complexe,
 analizarea coeficienilor ecuaiei de gradul 2 i afiarea rezultatelor.
ED

34 Tehnici de programare
Problema poate fi descompus n subprobleme care vor fi rezolvate cu ajutorul

IC
subprogramelor. Structura modulelor este urmtoarea:
Modulul principal

OG
(rezolvare ecuaie de gradul 2)

Modulul 1 Modulul 2 Modulul 3 Modulul 4 Modulul 5

G
(calculeaz (rezolv (rezolv (rezolv (rezolv
discriminantul ecuaia de ecuaia de ecuaia de ecuaia de

DA
delta) gradul 1) gradul 2 cu gradul 2 cu gradul 2 cu
rdcini reale rdcini reale rdcini
distincte) identice) complexe)

PE
Specificaiile fiecrui modul (subprogram) sunt:
1. Modulul 1 (delta):
 Date de intrare: a, b, c coeficienii ecuaiei de gradul 2;
 Date de ieire: discriminantul d;
 Funcia modulului: calcularea discriminantului delta.
I
2. Modulul 2 (ec1):
 Date de intrare: b, c coeficienii b i c ai ecuaiei de gradul 2;
 Date de ieire: nici una;

 Funcia modulului: rezolvarea ecuaiei de gradul 1 i afiarea rezultatului (soluia x


sau un mesaj).
IC

3. Modulul 3 (ec2 2r):


 Date de intrare: a, b, c coeficienii ecuaiei de gradul 2;
 Date de ieire: x1, x2 cele dou soluii reale distincte ale ecuaiei;
CT

 Funcia modulului: rezolvarea ecuaiei de gradul 2 cu soluii reale distincte.


4. Modulul 4 (ec2 1r):
 Date de intrare: a, b coeficienii ecuaiei de gradul 2;
 Date de ieire: x cele dou soluii reale identice ale ecuaiei;
DA

 Funcia modulului: rezolvarea ecuaiei de gradul 2 cu soluii reale identice.


5. Modulul 5 (ec2 2c):
 Date de intrare: a, b, c coeficienii ecuaiei de gradul 2;
DI

 Date de ieire: u, v partea real i partea imaginar ale celor dou soluii com-
plexe ale ecuaiei;
 Funcia modulului: rezolvarea ecuaiei de gradul 2 cu soluii complexe.
Pentru rezolvarea subproblemei modulelor 1 i 4 se vor folosi subprograme de tip funcie
RA

operand (delta i ec2_1r), deoarece aceste module furnizeaz modulului principal un sin-
gur rezultat de tip ntreg, respectiv real, iar pentru rezolvarea subproblemelor modulelor 2,
3, i 5 se vor folosi subprograme de tip funcie procedural, deoarece ele furnizeaz mo-
dulului principal mai multe rezultate (ec2_2r i ec2_2c) sau nici un rezultat (ec1). n pro-
ITU

gramul principal (modulul principal) se vor executa urmtoarele aciuni:


 Se introduc de la tastatur coeficienii ecuaiei: a, b, c.
 Se analizeaz coeficientul a al ecuaiei.
 Dac ecuaia de gradul 2 a degenerat ntr-o ecuaie de gradul 1, se rezolv ecuaia
ED

de gradul 1.

Informatic 35
 Dac ecuaia de gradul 2 nu a degenerat ntr-o ecuaie de gradul 1, se analizeaz

IC
discriminantul delta calculat prin funcia delta() i, n funcie de valoarea lui,
se apeleaz subprogramele prin care se rezolv fiecare caz.

OG
Programul obinut este:
#include<iostream.h>
#include<math.h>
void ec1(int,int);

G
int delta(int,int,int);
void ec2 2r(int ,int ,int ,float &, float &);
float ec2 1r(int ,int );

DA
void ec2 2c(int ,int ,int ,float &, float &);
void main()
{int a,b,c; float x1,x2;

PE
cout<<"a= "; cin>>a; cout<<"b= "; cin>>b; cout<<"c= "; cin>>c;
if (a==0) ec1(b,c);
else
if (delta(a,b,c)>0)
{ec2 2r(a,b,c,x1,x2);
I
cout<<"Ecuatia are doua radacini reale diferite "<<endl;
cout<<"x1= "<<x1<<endl; cout<<"x2= "<<x2<<endl;}
else
if (delta(a,b,c)==0)

{cout<<"Ecuatia are doua solutii reale identice "<<endl;


cout<<"x1=x2= "<<ec2 1r(a,b);}
IC

else
{ec2 2c(a,b,c,x1,x2);
CT

cout<<"Ecuatia are solutii complexe "<<endl;


cout<<"x1= "<<x1<<"+i*"<<x2<<endl;
cout<<"x2= "<<x1<<"-i*"<<x2<<endl;}}
void ec1(int b,int c)
DA

{float x;
if (b==0)
if (c==0) cout<<"Ecuatia are o infinitate de solutii"<<endl;
else cout<<"Ecuatia nu are solutii"<<endl;
DI

else
{x=-(float)c/b;
cout<<"Ecuatia a degenerat in ecuatie de gradul I "<<endl;
cout<<"cu radacina x= "<<x;}}
RA

int delta(int a,int b,int c)


{int d=pow(b,2)-4*a*c;
return d;}
ITU

void ec2 2r(int a,int b,int c,float &x1, float &x2)


{x1=(-b+sqrt(delta(a,b,c)))/(2*a);
x2=(-b-sqrt(delta(a,b,c)))/(2*a);}
float ec2 1r(int a,int b)
{float x=(float)(-b)/(2*a);
ED

return x;}

36 Tehnici de programare

IC
void ec2 2c(int a,int b,int c,float &u, float &v)
{u=(float)(-b/(2*a)); v=sqrt(abs(delta(a,b,c)))/(2*a);}
Refacei programul astfel:

OG
Tem a. Pentru a transmite datele ntre module, nu folosii parametrii de comu-
nicaie, ci variabilele globale;
b. Nu folosii prototipurile funciilor (Atenie! Deoarece funcia delta() este activat n
subprogramele ec2 2r() i ec2 2c() trebuie s o definii naintea lor.)

G
Enunul problemei 2: n fiierul meteo.txt sunt nregistrate, pe mai multe rnduri, perechi
de numere ntregi separate prin spaiu, care reprezint temperaturile zilnice minim i

DA
maxim din Romnia, ntr-o perioad de timp. S se afieze temperatura minim,
temperatura maxim i temperatura medie din Romnia din acea perioad.
Pentru memorarea temperaturilor se folosesc doi vectori: a pentru temperaturile mini-
me i b pentru temperaturile maxime.

PE
Folosind tehnica top-down problema poate fi mprit n subprobleme, astfel:
 crearea celor doi vectori prin citirea datelor din fiier,
 calcularea temperaturii minime,
 calcularea temperaturii maxime,
I
 calcularea temperaturii medii.
Problema poate fi descompus n subprobleme, care vor fi rezolvate cu ajutorul subpro-
gramelor. Structura modulelor este urmtoarea:

Modulul principal
(citirea i afiarea informaiilor)
IC
CT

Modulul 1 Modulul 2 Modulul 3 Modulul 4


(citete tempe- (calculeaz (calculeaz (calculeaz
raturile din fiier n temperatura temperatura temperatura
doi vectori) minim) maxim) medie)
DA

Specificaiile fiecrui modul (subprogram) sunt:


1. Modulul 1 (citete):
 Date de intrare: niciuna;
DI

 Date de ieire: a i b vectorii n care se memoreaz temperaturile minime,


respectiv maxime i n numrul de zile ale perioadei analizate (lungimea logic
a vectorilor);
RA

 Funcia modulului: crearea celor doi vectori prin citirea temperaturilor din fiier.
2. Modulul 2 (min):
 Date de intrare: a vectorul n care se memoreaz temperaturile minime i n
numrul de zile ale perioadei analizate (lungimea logic a vectorului);
ITU

 Data de ieire: temperatura minim din perioada analizat;


 Funcia modulului: calcularea temperaturii minime din perioada analizat.
3. Modulul 3 (max):
 Date de intrare: b vectorul n care se memoreaz temperaturile maxime i n
numrul de zile ale perioadei analizate (lungimea logic a vectorului);
ED

Informatic 37
 Data de ieire: temperatura maxim din perioada analizat;

IC
 Funcia modulului: calcularea temperaturii maxime din perioada analizat.
4. Modulul 4(media):

OG
5. Date de intrare: a i b vectorii n care se memoreaz temperaturile minime,
respectiv maxime i n numrul de zile ale perioadei analizate (lungimea logic a
vectorilor);
 Data de ieire: temperatura medie din perioada analizat;
 Funcia modulului: calcularea temperaturii medii din perioada analizat.

G
Pentru rezolvarea subproblemei modulelor 2, 3 i 4, se vor folosi subprograme de tip

DA
funcie operand (min, max i media), deoarece aceste module furnizeaz modulului
principal un singur rezultat de tip ntreg (min, max) i de tip real (media), iar pentru
rezolvarea subproblemei modulului 1 se va folosi un subprogram de tip funcie
procedural (citeste), deoarece el furnizeaz modulului principal mai multe rezultate

PE
(vectorul cu temperaturile minime, respectiv maxime, i lungimea logic a vectorului). n
programul principal (modulul principal) se vor executa urmtoarele aciuni:
 Se creeaz cei doi vectori, prin citirea datelor din fiier, apelndu-se subprogramul
citete().
 Se afieaz temperatura minim apelndu-se subprogramul min().
I
 Se afieaz temperatura maxim apelndu-se subprogramul max().
 Se afieaz temperatura medie apelndu-se subprogramul media().
Programul obinut este:

#include <fstream.h>
void citeste(int &, int a[], int b[]);
IC

int max(int n, int b[]);


int max(int n, int b[]);
CT

float media(int n, int a[], int b[]);


void main()
{int a[50],b[50],n;
citeste(n,a,b);
DA

for (int i=0;i<n;i++) cout<<a[i]<<" "<<b[i]<<endl;


cout<<"Temperatura minima= "<<min(n,a)<<endl;
cout<<"Temperatura maxima= "<<max(n,b)<<endl;
cout<<"Temperatura medie= "<<media(n,a,b)<<endl;}
DI

void citeste(int &n, int a[], int b[])


{fstream f("meteo.txt",ios::in);
int i=0;
RA

while (f>>a[i]>>b[i]) i++;


n=i; f.close();}
int min(int n, int a[])
{int m=a[0];
ITU

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


if (a[i]<m) m=a[i];
return m;}
int max(int n, int b[])
{int m=b[0];
ED

38 Tehnici de programare

IC
for (int i=1;i<n;i++) if (b[i]>m) m=b[i];
return m;}
float media(int n, int a[], int b[])

OG
{int s=0;
for (int i=0;i<n;i++) s=s+a[i]+b[i];
return (float)s/(2*n);}

1. Refacei programul, astfel:

G
Tem a. Nu folosii prototipurile funciilor.
b. Pentru a transmite datele ntre module, nu folosii parametrii de

DA
comunicaie, ci variabilele globale.
2. Calculai suma:
2 3 4 5 2n+1 n
s=1-x+x /2!-x /3! +x /4!-x /5!+...+ (-1) x /(2n+1)!
unde x i n sunt dou numere naturale care se citesc de la tastatur.

PE
Descompunei problema n subprobleme. Rezolvai fiecare subproblem cu
ajutorul unui subprogram.

1.1.11. Subprogramele de sistem


I
Compilatorul C++ v pune la dispoziie o bibliotec cu sute de funcii, pe care le putei
folosi pentru a rezolva o anumit sarcin. Pentru a putea folosi o funcie de sistem,
trebuie s tii s interpretai prototipul funciei pe care vi-l pune la dispoziie autodocu-

mentarea (help-ul) limbajului de programare.


Exemplul 1
IC

Funcia sqrt() din fiierul antet math.h furnizeaz, prin numele ei, radical de ordinul 2
din parametrul x. Ea are prototipul:
CT

double sqrt(double x);


Interpretai prototipul funciei, astfel:
 Rezultatul funciei este de tip real double.
 Funcia are un singur parametru de tip real double.
DA

Exemplul 2
Funcia poly() din fiierul antet math.h furnizeaz, prin numele ei, valoarea unui poli-
nom de gradul degree, cu coeficienii coefs, pentru x precizat. Ea are prototipul:
DI

double poly(double x, int degree, double coefs[]);


Interpretai prototipul funciei, astfel:
 Rezultatul funciei este de tip real double.
RA

 Funcia are trei parametri: unul de tip real, pentru x double, unul de tip ntreg, pentru
gradul polinomului int, i unul de tip vector de numere reale, pentru coeficienii
polinomului double [ ].
Conflictele de nume dintre o funcie de sistem i o funcie utili-
ITU

Atenie zator se rezolv astfel: dac ai creat o funcie utilizator, creia i-ai
atribuit acelai nume cu al unei funcii de sistem, compilatorul va
alege funcia utilizator.
ED

Informatic 39

IC
Funcii de sistem utile
Funcii matematice fiier antet math.h
Funcia Tip rezultat Tip parametri Furnizeaz Exemplu

OG
abs(x) int int modulul lui x abs(-12) 12
fabs(x) double double fabs(-1.2) 1.2
floor(x) double double cel mai apropiat ntreg floor(11.5) 11
floorl(x) long double long double mai mic sau egal cu x floor(-2.7) -3
ceil(11.5) 12

G
ceil(x) double double cel mai apropiat ntreg
ceill(x) long double long double mai mare sau egal cu x ceil(-2.7) -2
sin(x) double double sinus de x sin(0.5)0.479426

DA
cos(x) double double cosinus de x cos(0.5)0.877583
tan(x) double double tangent de x tan(0.5)0.546302
sqrt(x) double double radical de ordinul 2 din x sqrt(9) 3
pow(x,y) double double x la puterea y pow(2,4) 16

PE
pow10(x) double int 10 la puterea x pow10(2)100
Funcii utile pentru operaiile de citire i scriere fiierul antet conio.h
clrscr() terge informaiile de pe ecran. Aceast funcie se scrie la nceputul programului, ca pe
ecran s fie afiate numai rezultatele obinute n urma executrii programului.
I
getch() Ateapt introducerea unui caracter de la tastatur, pe care nu-l va afia pe ecran.
Rezultatul furnizat este de tip int i este codul caracterului introdus.
Funcii pentru generarea numerelor aleatoare fiier antet stdlib.h
randomize() Iniializeaz generatorul de numere aleatoare cu un numr aleator.

rand() Furnizeaz un rezultat de tip int care este un numr aleator cuprins ntre 0 i
32767.
IC

Exemplu Se simuleaz aruncarea unui zar. Pentru a genera un numr cu valoarea cuprins
ntre 1 i 6, se genereaz aleator un numr, cu funcia rand(), i se calculeaz restul mpririi
CT

acestui numr la 6 (care poate lua o valoare de la 0 la 5), la care se adaug o unitate.
#include<iostream.h>
#include <stdlib.h>
void main()
DA

{randomize(); //Se iniializeaz generatorul de numere aleatoare.


cout<<rand()%6+1<<" ";}
//Se genereaz aleator un numr cu valoarea cuprins ntre 1 i 6.
1. Precizai tipul funciei rand(). Dai un exemplu de apel pentru
DI

aceast funcie.
Tem
2. Precizai tipul funciei fabs(). Dai un exemplu de apel pentru
aceast funcie. Precizai tipul parametrului.
RA

Rspundei:
1. Ce se va afia n urma execuiei urmtoarei secvene de program?
ITU

int a,b,c;
void sb(int &b){cout<<a<<" "<<b<<" "<<c;}
void main()
{cout<<a<<" "<<b<<" "<<c; a=10; b=20; c=30; sb(a);
ED

cout<<a<<" "<<b<<" "<<c;}



40 Tehnici de programare
2. Ce se va afia n urma execuiei urmtoarei secvene de program?

IC
float x;
void sb(int x) {x=1;}

OG
void main() {x=2.5; sb(x); cout<<x;}
3. Ce se va afia n urma execuiei urmtoarei secvene de program?
float x;
void sb1(int &x) {cout<<x; x=1; cout<<x;}

G
void main() {x=2.5; sb(x); cout<<x;}
4. Ce se va afia n urma execuiei urmtoarei secvene de program?

DA
int x;
void sb1(int x) {x=10; cout<<x; }
void sb2(int x) {x=20; cout<<x; }
void main() {x=30; sb1(x); cout<<x; sb2(x); cout<<x;}

PE
5. Ce se va afia n urma execuiei urmtoarei secvene de program?
int a,b;
int sb(int a)
{int i=0; while (a!=0) {a/=10; i++;}
I
cout<<b; return i;}
void main() {a=12345; b=sb(a); cout<<b;}
6. Ce se va afia n urma execuiei urmtoarei secvene de program?

int x;
void sb1(int x) {x=20; cout<<x; }
IC

void sb2(int &x) {x=30; cout<<x; }


void main() {x=50; cout<<x; sb1(x); cout<<x; sb2(x); cout<<x;}
7. Ce se va afia n urma execuiei urmtoarei secvene de program?
CT

int x;
void sb1(int); void sb2(int &);
void sb1(int x) {x=20; sb2(x);}
DA

void sb2(int &x) {x=30; sb1(x);}


void main() {x=50; cout<<x; sb1(x); cout<<x; sb2(x); cout<<x;}
8. Ce se va afia n urma execuiei urmtoarei secvene de program?
int a,b;
DI

void sb1(int x, int y) {x=x-y; y=y-x;}


void sb2(int x, int y) {a=sb1(x,y); b=sb1(y,x);}
void main() {a=1; b=2; sb1(a,b); cout<<a<<b<<; sb1(b,a); cout<<a<<b;}
RA

9. Ce se va afia n urma execuiei urmtoarei secvene de program?


int sb(int a)
{int i=0; while (a!=0) {int i=10; a/=2; i++;}
return i;}
ITU

void main() {cout<<sb(23);}

Adevrat sau Fals:


1. Antetul de funcie int f(int x; int y); este corect.
ED

2. Antetul de funcie f(int x, int y) nu este corect.



Informatic 41
3. Antetul de funcie void f(int x[25], int &n) este corect.

IC
4. La apelul unei funcii, parametrii actuali sunt nlocuii cu parametrii formali.
5. Urmtorul program produce eroare la compilare:

OG
#include <iostream.h>
#include <math.h>
int d(int a, int b){return sqrt(a*a+b*b);}
void main() {cout<<d(5,4);}

G
6. Urmtorul program nu produce eroare la compilare:
#include <iostream.h>

DA
#include <math.h>
float mg(int x, int y, float & mg)
{mg=sqrt(x*y); return sqrt(x*y);}
void main() {float x; cout<<x<<" "<<mg(3,4,x); }

PE
7. Urmtorul program produce eroare la compilare:
#include <iostream.h>
int f(int x, int y)
{for (int i=x;i<y;i++) if(i>x+1 && i<y-1) return i;
return x+y; }
I
void main(){cout<<f(1,5); }
8. Urmtorul program produce eroare la compilare:
#include <iostream.h>

int f(int x=20, int y=10) {return x/y;}


void main() {cout<<f(15,5)<<" "<<f(15)<<" "<<f(); }
IC

Alegei:
1. Care dintre urmtoarele anteturi de subprogram este un antet corect pentru o funcie
CT

real cu parametru ntreg?


a. double f(long x); b. double f(int x)
c. long double f(int x) d. float f(int x);
2. Care dintre urmtoarele anteturi de subprogram sunt corecte?
DA

a. int f(int x); b. f(int x, int y, char z)


c. int f(int x,y) d. float f(int x; int y)
3. Funcia m() are doi parametri reali i furnizeaz cea mai mic valoare dintre cei doi
parametri. Care dintre urmtoarele instruciuni afieaz cea mai mic valoare dintre
DI

a, b i c?
a. cout<<m(a,b,c); b. cout<<m(m(a,b),m(b,c));
c. cout<<m(a,m(b,c)); d. cout<<m(m(a,b),c);
RA

4. Se consider c urmtoarea funcie furnizeaz cel mai mare divizor comun a dou
numere transmise ca parametru.
int cmmdc(int a, int b)
{while (...) if (a>b) a-=b; else b-=a;
ITU

return a;}
Ce condiie trebuie scris n instruciunea while?
a. a>b b. a!=b c. a==b d. a<b
5. Se consider c urmtoarea funcie testeaz dac numrul transmis ca parametru
ED

este un numr prim.



42 Tehnici de programare

IC
int prim(int n)
{int i=3;
if (n%2) while (...) if (n%i==0) return 0; else i+=2;

OG
else return 0;
return 1;}
Ce condiie trebuie scris n instruciunea while?
a. i<sqrt(n) b. i<n/2 c. i<=sqrt(n) d. i<= n/2

G
6. Pentru fiecare antet al subprogramului sb din coloana A, exist n coloana B valorile
care vor fi afiate pe ecran. Alegei atribuirile corecte:

DA
int a,b;
void sb(...){int a; a=m; n+=a; m=n;}
void main(){a=10; b=20; sb(a,b); cout<<a<<" "<<b<<" ";}
A B

PE
A1. void sb(int m, int n) B1. 30,30
A2. void sb(int &m, int n) B2. 10,30
A3. void sb(int m, int &n) B3. 10,20
A4. void sb(int &m, int &n) B4. 30,20
a. A1 B4; A2 B1; A3 B3; A4 B2;
I
b. A1 B3; A2 B1; A3 B4; A4 B2;
c. A1 B4; A2 B1; A3 B2; A4 B3;
d. A1 B1; A2 B4; A3 B2; A4 B3;

7. Se consider urmtorul program:


int a,b;
IC

void sb(int &a, int b){a++; b--; a++;}


void main()
{a=5; b=10; sb(a,b); cout<<a<<" "b<<" ";
CT

a=10; b=20; sb(a,b); cout<<a<<" "b;}


Ce valori se vor afia pe ecran?
a. 5,10,10,20 b. 5,9,10,19 c. 7,10,12,20 d. 7,9,12,19
DA

8. Care dintre urmtoarele subprograme adun dou valori ntregi transmise ca parametri?
a. int s(int x, int y) b. void s(int x, int y, int &z)
{int z=x; z+=y; return z;} {z=x+y;}
c. int s(int &x, int &y) d. void s(int x, int y)
DI

{s=y; s=s+x; } {int z=y+x; return z;}


9. Care dintre urmtoarele subprograme realizeaz interschimbarea valorilor a dou
numere ntregi transmise ca parametri?
RA

a. void s(int x, int y) b. void s(int x, int y)


{int z=y; y=x; x=y;} { x=y+x; x=y-x; y=y-x;}
c. void s(int &x, int &y) d. void s(int &x, int &y)
{x=x-y; y=x+y; x=y-x;} { x=y+x; x=y-x; y=y-x;}
ITU

10. Subprogramul z1 are un parametru ntreg i returneaz o valoare real. Care este
antetul corect al subprogramului z1 ?
a. int z1(float n) b. float z1(int n)
c. void z1(float n) d. void z1(float &n; float r)
(Bacalaureat Sesiunea august 2004)
ED

Informatic 43
11. Subprogramul intersch realizeaz interschimbarea valorilor a dou variabile ntregi

IC
transmise prin intermediul parametrilor formali x i y. Antetul subprogramului este:
a. int intersch(int &x, &y) b. void intersch(int x, int y)

OG
c. void intersch(int &x, int &y) d. int intersch(int x)
(Bacalaureat Simulare 2003)
12. Care dintre urmtoarele subprograme returneaz cea mai mic valoare dintre dou
numere ntregi transmise ca parametri?

G
a. int m(int &x, int &y) b. void m(int &x, int &y)
{m=x; if(y<x) m=y; {if(y<x) m=y;

DA
return m;} else m=x;}
c. int m(int x, int y) d. int m(int x, int y)
{if(y<x) x=y; {if(y<x) return y;
return x;} else return x;}

PE
13. Subprogramul cifre calculeaz numrul i de cifre ale unui numr natural n
transmis ca parametru i construiete vectorul v format din cifrele lui n. Care este
antetul corect al unui astfel de subprogram?
a. void cifre(long n, vector v, int &i)
b. void cifre(long n, int i, vector v
I
c. void cifre(long n; vector v; int &i)
d. void cifre(long &n; vector v; int i)
(Bacalaureat Sesiunea iunie - iulie 2003)

14. Dac a este o variabil global i la nceputul subprogramului sub este definit o
variabil local a, atunci n instruciunea a=a+1 din subprogramul sub, a se refer la:
IC

a. variabila global a b. nu se poate defini a ca variabil global i variabil local


c. variabila local a d. unul la variabila local, iar altul la variabila global
(Bacalaureat Sesiunea iunie - iulie 2004)
CT

15. Se presupune c este definit o funcie min care primete dou valori reale prin
intermediul a doi parametri i returneaz cea mai mic dintre cele dou valori.
Stabilii care dintre urmtoarele expresii este egal cu cea mai mare dintre valorile
reale a i b.
DA

a. min(a,b) a b b. a - min(a,b) + b - min(a,b)


c. a + b - min(a,b) d. min(a,b)
(Bacalaureat Simulare 2003)
16. Este definit o funcie min care primete dou valori reale prin intermediul a doi
DI

parametri i returneaz cea mai mic dintre cele dou valori. Stabilii care dintre
urmtoarele expresii nu este egal cu cea mai mic dintre valorile reale a, b i c.
a. a + b + c - min(a,b) min(a,c) b. min(min(a,b)),min(a,c))
RA

c. min(min(a,b),c) d. min(a,min(b,c))
(Bacalaureat Sesiune special 2003)
17. Este definit funcia max care primete dou valori ntregi prin intermediul parame-
trilor formali a i b (primul fiind a i al doilea b) i returneaz cea mai mare cifr din
ITU

irul infinit al zecimalelor raportului a/b. Astfel, max(5,12)=6 deoarece 5/12=


0.41666, iar max(1,8)=5 deoarece 1/8=0.125000 Stabilii care dintre urmtoa-
rele expresii este adevrat dac i numai dac m este divizor al lui n.
a. max(n,m)<=0 b. max(m,n)==0 c. max(m,n)==0>0 d. max(n,m)!=0
(Bacalaureat Sesiune iunie - iulie 2003)
ED

44 Tehnici de programare
18. Se tie c exist o variabil global v de tip vector i c vectorul v este format numai

IC
din 0 i 1. tiind c subprogramul alturat returneaz numrul de componente nenule
aflate pe primele n poziii ale vectorului v, stabilii ce este incorect n definiia acestuia.

OG
a. returneaz o valoare nedeterminat int f(int a)
b. nu este corect antetul funciei {int k=0;
c. totul este corect for (int i=0;i<n;i++)
d. este incorect instruciunea for k+=v[i];}
(Bacalaureat Sesiune iunie - iulie 2003)

G
19. n subprogramul alturat, i este: void fa(unsigned int x)
a. parametru de intrare b. variabil global {unsigned int i;

DA
c. parametru de ieire d. variabil local for (i=1;i<=n;i++)
(Bacalaureat Simulare 2004) cout<<i<< ;}
20. Subprogramul scif returneaz suma cifrelor unui numr natural transmis ca para-

PE
metru. Stabilii valoarea expresiei scif(scif(518) + scif(518)).
a. 14 b. 10 c. 28 d. 1
(Bacalaureat Simulare 2005)
21. Subprogramul alturat z1 are un singur parametru ............../*antet*/
real a. tiind c secvena float x=4.25;
I
{a=a*10;
cout<<x<< <<z1(r);, afieaz 4.25 2, stabi- return (int)a%10;}
lii care este antetul corect al subprogramului z1?
a. void z1(float &a) b. void z1(float a)

c. int z1(float &a) d. int z1(float a)


(Bacalaureat Sesiunea iunie - iulie 2004)
IC

22. Pentru valori strict pozitive ale parametrului a, funcia f definit alturat returneaz
valoarea 1 dac i numai dac valoarea lui a este un numr natural care:
CT

a. are ultima cifr mai mic sau egal cu 5


int f(int a)
b. are cel puin o cifr mai mic sau egal cu 5
{while (a%10>5) a/=10;
c. are prima cifr mai mic sau egal cu 5 return a>0;}
d. are cel mult o cifr mai mic sau egal cu 5
DA

(Bacalaureat Sesiunea special 2004)


23. Pentru subprogramul urmtor, variabila ntreag x i variabila real r=4.25, stabilii
cte dintre secvenele alturate afieaz valoarea 4.
int z1(float &a) x=z1(r); cout<<x+z1(r);
DI

{if (a<0) a=-a; x=z1(r); cout<<z1(r)+x;


a*=10; cout<<z1(r)+z1(r);
return (int)a%10; x=z1(r); cout<<x+x;
RA

a. 4 b. 3 c. 2 d. 1
(Bacalaureat Sesiunea iunieiulie 2004)
24. Pentru variabilele n, i i j ntregi, secvena alturat afieaz cel cin>>n;
mai mare i cel mai mic divizor propriu al numrului natural divi(n,i,j);
ITU

neprim citit (1 i n sunt divizori improprii). Care este antetul corect cout<<i<<j;}
pentru subprogramul divi?
a. int divi(int &n, int i, int j) b. int divi(int n, int &i, int j)
c. void divi(int n, int i, int j) d. void divi(int n, int &i, int &j)
ED

(Bacalaureat Sesiunea iunieiulie 2004)



Informatic 45
25. Este definit o funcie smax care primete dou valori ntregi prin intermediul a doi

IC
parametri i returneaz suma tuturor cifrelor celor dou numere. De exemplu,
smax(73,608) returneaz 24. Stabilii n ce mod se poate apela funcia smax

OG
pentru a determina suma cifrelor unui numr ntreg n.
a. smax(n,n) b. smax(n,0) c. smax(n,1) d. nu se poate utiliza
(Bacalaureat Sesiune special 2003)
Miniproiecte:

G
Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:
a. descompunerea problemei n subprobleme i rezolvarea fiecrei subproble-

DA
me cu ajutorul unui subprogram;
b. specificaiile fiecrui modul (subprogram);
c. explicarea noiunilor teoretice folosite pentru realizarea subprogramelor;
d. alte trei exemple de probleme n care se vor folosi subprograme create pentru

PE
rezolvarea problemei iniiale.
1. Se citesc de la tastatur n numere naturale. S se afieze numerele care au cea mai
mare sum a divizorilor proprii.
2. Se citete de la tastatur un numr natural n. S se afieze numerele rotunde mai
mici dect n. Un numr rotund este un numr care, reprezentat n binar, are acelai
I
numr de cifre de 0 i de 1.
3. Se citesc de la tastatur dou numere naturale n i m, care reprezint numrul de
elemente a doi vectori cu numere ntregi, a i b. Elementele celor doi vectori se citesc

de la tastatur. Afiai cte dintre componentele vectorului a sunt strict mai mici dect
componentele vectorului b.
IC

4. Se citesc de la tastatur dou mulimi de numere ntregi. Afiai intersecia, reuniunea


i diferena dintre cele dou mulimi.
5. Se citesc de la tastatur n numere naturale. S se verifice dac numrul format cu
CT

prima cifr a fiecrui numr este palindrom.


6. Se citesc de la tastatur: un numr q (2q9), care reprezint o baz de numeraie,
un numr c, care reprezint o cifr din aceast baz de numeraie, i n numere
naturale. S se afieze numerele care au cele mai multe cifre c, atunci cnd sunt
DA

reprezentate n baza q.
7. Se citete de la tastatur o mulime de n numere naturale. S se elimine din aceast
mulime numerele palindrom care au cel mai mare numr de cifre.
8. ntr-o fabric lucreaz n muncitori. n funcie de calificare, fiecrui muncitor i se atri-
DI

buie o categorie salarial. Exist 5 categorii salariale: p1, p2, p3, p4 i p5 (valori
reale cuprinse ntre 1 i 3 de exemplu, 1; 1,5; 2; 2,5 i 3) i un salariu tarifar de
baz, pe or. ntr-un vector se memoreaz orele lucrate de muncitori. ntr-un alt vec-
tor, se memoreaz categoria salarial a fiecrui muncitor. Salariul brut al unui munci-
RA

tor este dat de produsul dintre numrul de ore lucrate, salariul tarifar pe or i cate-
goria salarial. Salariul net se obine prin deducerea impozitului de 16% din salariul
brut. Numrul n, valorile din cei doi vectori, valorile pentru categoriile salariale p1, p2,
p3, p4 i p5 i salariul tarifar orar se citesc de la tastatur. Afiai salariul brut i
ITU

salariul net ale fiecrui muncitor i totalul salariilor brute, pentru toi cei n muncitori.
9. ntr-un fiier text sunt scrise pe un rnd, separate prin spaiu, n numere reale care
reprezint nlimea unor elevi. Fiecare elev se identific prin numrul de ordine, la
citirea nlimii din fiier. S se afieze ordinea n care trebuie aranjai cresctor, dup
ED

nlime, cei n elevi, elevul care este cel mai nalt i elevul care este cel mai scund.

46 Tehnici de programare

IC
1.2. Recursivitatea
1.2.1. Definiia procesului recursiv

OG
Un proces poate fi descris printr-un subprogram.

Procesul recursiv este procesul care, n timpul execuiei, genereaz apariia unor
procese similare lui, aflate n legtur direct cu procesul care le genereaz.

G
Exemplu de proces recursiv: Suntei ntr-o localitate necunoscut i cutai cldirea

DA
muzeului. ntrebai prima persoan ntlnit. Traseul fiind complicat, v explic n ce fel s
ajungei la strada urmtoare de pe traseul ctre muzeu. Aici vei ntreba urmtoarea per-
soan cum s ajungei la muzeu i ea v va ndruma la strada urmtoare de pe traseu
.a.m.d. Fiecare persoan pe care o ntrebai v furnizeaz o soluie care v apropie de

PE
muzeu, astfel nct ultima persoan chestionat v va arta clar unde este muzeul. Aceas-
t identificare a traseului este un proces recursiv. Fiecare chestionare a unei persoane
genereaz acelai tip de proces: deplasare pe o poriune a traseului i o nou chestionare.
Se consider c o noiune este definit recursiv dac, n cadrul definiiei, apare nsi
noiunea care se definete. n exemplul de mai sus, traseul este definit recursiv, printr-un
I
nou traseu ctre muzeu (traseu care pornete din locaia n care v gsii la un moment dat).
Considerm fraza urmtoare: Sportul nseamn s facei micare, iar micarea nseamn
c facei sport.. Chiar dac noiunile sport i micare se autodefinesc printr-un proces

recursiv, fraza nu furnizeaz nici un fel de informaie ori considerm c sportul nseamn
c facei sport, ori micarea nseamn s facei micare.
IC

Procesele recursive pot fi:


 Finite. ncheierea execuiei procesului se face dup un numr determinat de operaii
CT

executabile (n cazul modelrii lor cu ajutorul subprogramelor, dup un numr deter-


minat de instruciuni executabile). n exemplul anterior, vei ajunge la muzeu dup ce ai
chestionat un numr determinat de persoane, deci procesul este finit.
 Infinite. Sunt opuse proceselor finite. n exemplul anterior, definiia sportului este un
DA

proces infinit, deoarece ea nu se oprete dup un numr determinat de definiii.


Procesele descrise prin subprograme sunt procese finite. De aceea, trebuie definit
condiia de terminare. Prin aceast condiie, se descrie modul prin care un proces finit nu
devine un proces infinit.
DI

De exemplu, dac vrei s calculai modulul unui nu- x pentru x>0


mr, putei s generai un proces recursiv, astfel: dac mod(x) =
numrul este pozitiv, modulul este egal cu numrul; alt- mod(-x) pentru x0
RA

fel, este egal cu modulul din valoarea numrului nmul-


it cu -1 (pentru ca valoarea s devin pozitiv). Astfel, mod(5)=5, iar mod(-5)=mod(-(-5))
=mod(5)=5. Condiia de terminare a procesului recursiv este ca variabila x s fie
pozitiv. Funcia matematic poate fi implementat cu ajutorul urmtorului program:
ITU

#include <iostream.h>
int modul(int x)
{if(x>=0) return x; else return modul(-x);}
void main()
{int x; cout<<"x= "; cin>>x; cout<<modul(x);}
ED

Informatic 47
Putei s generai un proces recursiv pentru calculul

IC
valorii maxime dintre dou numere a i b, astfel: a pentru a>b
dac a>b, maximul este valoarea primului numr, max(a,b) =
max(b,a) pentru ab

OG
adic a; altfel, este egal cu maximul dintre b i a.
Astfel, max(5,2)=5, iar max(2,5)=max(5,2)=5. Con-
diia de terminare a procesului recursiv este ca variabila a s fie mai mare dect
variabila b. Funcia matematic poate fi implementat cu ajutorul urmtorului program:
#include <iostream.h>

G
int max(int a,int b)
{if (a>b) return a; else return max(b,a);}

DA
void main()
{int a,b; cout<<"a= "; cin>>a; cout<<"b= "; cin>>b;
cout<<max(a,b);}
Scriei un program n care se citesc dou numere de la tastatur, a i b,

PE
i se afieaz valoarea minim dintre cele dou numere. Valoarea
Tem
minim se va calcula cu ajutorul unei funcii n care formula de calcul
este definit printr-un proces recursiv.
I
Scop: Exemplificarea modului de descompunere a problemei n procese recursive.
Enunul problemei. S se calculeze suma primelor n numere naturale. Valoarea lui n se

introduce de la tastatur.
Aceast problem poate fi rezolvat prin doi algoritmi:
IC

 folosind iteraia (algoritm iterativ);


 folosind recursivitatea (algoritm recursiv).
Aceti algoritmi (iterativ sau recursiv) se bazeaz pe urmtoarea metod se consider
CT

funcia suma(n) care se genereaz astfel:


Suma(0) 0
Suma(1) Suma(0)+1
DA

iterativ Suma(2) Suma(1)+2 recursiv


.....................
Suma(n) Suma(n-1)+n
Acestui proces de calcul i se pot asocia dou funcii matematice:
DI

 funcia iterativ definiia iterativ a unei funcii se face printr-o expresie care conine
numai valori cunoscute;
 funcia recursiv definiia recursiv a unei funcii se face printr-o expresie care
RA

conine nsi funcia.


0 pentru n=0
Funcia matematic iterativ asociat acestui Suma(n) =
proces de calcul este cea alturat, iar pro- 1+2+3+...+n pentru n0
gramul care folosete algoritmul iterativ este:
ITU

#include <iostream.h>
int suma(int n)
{int i,s=0;
if (n==0) return 0;
else {for (i=1;i<=n;i++) s=s+i; return s;}}
ED

48 Tehnici de programare

IC
void main()
{int n; cout<<"n= "; cin>>n; cout<<"suma= "<<suma(n);}
Funcia matematic recursiv asociat aces- 0 pentru n=0

OG
tui proces de calcul este cea alturat, iar pro- Suma(n) =
gramul care folosete algoritmul recursiv este: n+Suma(n-1) pentru n0
#include <iostream.h>
int suma(int n)

G
{if (n==0) return 0; else return suma(n-1)+n;}
void main()

DA
{int n; cout<<"n= "; cin>>n; cout<<"suma= "<<suma(n);}
Observaii:
1. Recurena este realizat prin autoapelul funciei suma.
2. n algoritmul recursiv, pentru calcularea sumei sunt necesare dou elemente:

PE
 formula de recuren: suma(n)=n+suma(n-1)
 o valoare iniial cunoscut: suma(0)=0
3. n algoritmul recursiv, numele funciei poate s apar n corpul funciei i n membrul
stng al unei instruciuni de atribuire, spre deosebire de algoritmul iterativ, unde poate
I
s apar numai n membrul drept al instruciunii de atribuire. Din aceast cauz, n
algoritmul iterativ se folosete o variabil suplimentar s pentru calculul sumei.
4. Ideea de baz a recursivitii este aceea c fiecare nou autoapel al funciei
(autogenerarea unui nou proces de acelai fel) ne apropie de soluia final,

care corespunde valorii iniiale, cunoscute.


IC

Scop: Exemplificarea modului n care se execut apelurile recursive.


CT

Enunul problemei. S se calculeze factorialul unui numr n: n!=123...n. Valoarea lui


n se introduce de la tastatur.
i aceast problem poate fi rezolvat prin doi algoritmi:
DA

 folosind iteraia (algoritm iterativ);


 folosind recursivitatea (algoritm recursiv).
Algoritmul (iterativ sau recursiv) se bazeaz pe urmtoarea metod se consider funcia
fact(n) care se genereaz astfel:
DI

Fact(0) 1
Fact(1) 1*Fact(0)
iterativ Fact(2) 2*Fact(1) recursiv
RA

.....................
Fact(n) n*Fact(n-1)

Funcia matematic iterativ asociat acestui 1 pentru n=0


ITU

proces de calcul este cea alturat, iar pro- Fact(n) =


gramul care folosete algoritmul iterativ este: 123... (n-1) n pentru n0
#include <iostream.h>
unsigned long fact(int n)
ED

{int i; unsigned long p=1;



Informatic 49

IC
if (n==0) return 1;
else {for (i=1;i<=n;i++) p*=i; return p;}}
void main()

OG
{int n; cout<<"n= "; cin>>n; cout<<"factorial= "<<fact(n);}
Funcia matematic recursiv asociat acestui 1 pentru n=0
proces de calcul este cea alturat, iar pro- Fact(n) =
gramul care folosete algoritmul recursiv este: nFact(n-1) pentru n0

G
#include <iostream.h>
unsigned long fact(int n)

DA
{if (n==0) return 1; else return n*fact(n-1);}
void main()
{int n; cout<<"n= "; cin>>n; cout<<"factorial= "<<fact(n);}
S analizm modul n care se execut cei doi algoritmi, pentru a calcula valoarea funciei

PE
fact(4)=4!.
4!=4*3! =4*6 =24 rezultatul final

3!=3*2! =3*2 =6
I
se calculeaz

Algoritmul 2!=2*1! =2*1 =2


iterativ

1!=1*0! =1*1 =1
IC

0!=1 valoare cunoscut


CT

4!=4*3! 4!=4*6=24 rezultatul


final
se nlocuiete valoarea
trebuie calculat

DA

3!=4*2! 3!=3*2=6

2!=4*1! 2!=2*1=2
DI

1!=4*0! 1!=1*1=1

0!=1
RA

valoare cunoscut

Algoritmul recursiv
ITU

Se observ c:
1. Execuia algoritmului iterativ se face ntr-o singur etap, care const n rezolvarea
problemei pornind de la o valoare iniial cunoscut, pn la obinerea valorii finale
(valoarea cerut), adic de jos n sus.
ED

50 Tehnici de programare
2. Execuia algoritmului recursiv se face n dou etape: n prima etap se descompune

IC
problema, pornind de la valoarea cerut pn la valoarea iniial, cunoscut, adic de
sus n jos, iar n a doua, se rezolv problema pornind de la valoarea iniial

OG
cunoscut pn la obinerea valorii cerute, adic de jos n sus.

1.2.2. Reguli pentru construirea unui subprogram recursiv


1. Corpul unui subprogram recursiv descrie algoritmul folosind dou elemente:

G
 Cazul general al soluiei. Conine toate prelucrrile necesare pentru a reduce
dimensiunea problemei n vederea apropierii de rezultatul final. Cea mai impor-

DA
tant operaie care se execut este autoapelul. n exemplul funciei fact, cazul
general al soluiei este format din instruciunea return n*fact(n-1); care
conine autoapelul.
 Cazul de baz al soluiei. Conine o operaie care rezolv un caz special al

PE
problemei, fr a se folosi autoapelul. n exemplul funciei fact, cazul de baz al
soluiei este format din instruciunea return 1; care nu conine autoapel.
2. Recursivitatea este un proces repetitiv i este obligatoriu s existe o condiie de oprire
a repetiiei. Cele dou cazuri se combin folosind o structur alternativ if...else.
Condiia de oprire a recursivitii este exprimat printr-o expresie logic ce trebuie s
I
depind de parametrii subprogramului sau de variabilele sale locale (n exemplul
funciei fact expresia logic este (n==0)). Aceast expresie logic este folosit
pentru a face trecerea de la cazul general la cazul de baz al soluiei.

3. Orice definiie recursiv trebuie s asigure condiia de consisten, adic valoarea


funciei trebuie s fie direct calculabil sau calculabil cu ajutorul unei valori direct
IC

calculabile. Aceasta nseamn c modificarea parametrilor i/sau a variabilelor locale,


de la o activare la alta, trebuie s asigure condiia de ieire din recursivitate. n exem-
plul urmtor, funcia recursiv nu ndeplinete condiia de consisten, deoarece modi-
CT

ficarea parametrului n de la o activare la alta (n=n+1) ne ndeprteaz de condiia de


ieire din recursivitate (n=0) :
int s(int n);
DA

{if n==0 return 0; else return n+s(n+1);}


Observaie:
Din exemplele prezentate se observ c, nainte de a construi algoritmul recursiv, trebuie
definit funcia matematic recursiv. Ea ajut la identificarea cazului de baz al soluiei i
DI

a cazului general al soluiei.


Exemplul 1 Exemplul 2
S se calculeze suma: S se calculeze:
RA

2 2 2 2 2n+1 2
S = 1 + 3 + 5 + 7 +...+ (2n-1) S = 1 - 2 + 3 - 4 +...+ (-1) n
Suma este egal cu suma calculat anterior, la Suma este egal cu suma calculat anterior, la
care se adaug numrul, numai dac este par. care se adaug ptratul numrului, dac este un
numr impar, sau se scade ptratul numrulului,
ITU

dac numrul este par.


0 pentru n=0 0 pentru n=0
Suma(n) = Suma(n-1) pentru n par Suma(n) = Suma(n-1)+n*n pentru n impar
n+Suma(n-1) pentru n impar Suma(n-1) -n*n pentru n par
ED

Informatic 51
1. Identificai, n fiecare exemplu de funcie matematic recursiv, cazul

IC
Tem de baz i cazul general al soluiei. Scriei cte un program n care
calculai valoarea sumelor definite mai sus. Folosii n fiecare

OG
program, pentru calculul sumei, o funcie implementat iterativ i o funcie implementat
recursiv. Afiai ambele rezultate obinute, prin evaluarea fiecrei funcii. Comparai
rezultatele obinute.
2. Scriei cte o funcie matematic recursiv pentru calculul fiecrei expresii de mai jos.

G
Implementai aceste funcii matematice cu ajutorul subprogramelor recursive:
S = 13 + 25 + 37 + 49 +...+ n (2n+1)
n-1
S = 12 - 24 + 36 - 48 +...+ (-1) n(2n)

DA
P = 2 4 6 8 . .. 2n
P = 1 4 7 10 . .. (3n-2)
3. Scriei un subprogram recursiv care calculeaz produsul a dou numere naturale, a i
b, prin adunarea repetat a lui a de b ori (a b = a + a + a + ... + a).

PE
1.2.3. Variabilele locale i subprogramele recursive
O variabil local a unui subprogram este definit n interiorul subprogramului i poate fi
I
folosit numai n cadrul su. n cazul subprogramelor recursive, fiecare autoapel al subpro-
gramului nseamn un nou proces, cruia i se rezerv o nou zon de memorie intern n
care s se execute. Implicit, nseamn i o nou definire a variabilei locale, adic o nou zon
de memorie intern alocat pentru variabila local, numai pentru acel apel al subprogramului.

Aadar, variabila local este unic pentru un apel al subprogramului. Dac subprogra-
mul este apelat recursiv de n ori, vor exista n imagini ale aceleiai variabile locale, cte
IC

una pentru fiecare apel. Fiecare imagine va avea un coninut diferit, corespunztor
apelului.
CT

La activarea fiecrui subprogram recursiv, vrful stivei sistemului urc, i se salveaz n


stiv instana subprogramului apelant. n acest mod, n stiv se vor regsi toate instanele
activrii subprogramului recursiv. nainte de a se reveni dintr-o activare a unui subprogram
recursiv, vrful stivei coboar i este adus la valoarea anterioar activrii.
DA

n exemplul urmtor este prezentat un subprogram recursiv n care se poate urmri acest
comportament al variabilei locale (n exemplu, variabila ch). Se introduce un ir de carac-
tere de la tastatur, caracter cu caracter, fr s se foloseasc un vector de caractere. irul
de caractere se termin cu caracterul 0. S se afieze inversat acest ir de caractere.
DI

#include <iostream.h>
void invsir()
{char ch; cin>>ch;
RA

if (ch!='0') invsir();
cout<<ch;}
//if (ch!='0') cout<<ch;} pentru a nu se afia caracterul 0
void main()
ITU

{cout<<"Scrieti textul "; invsir();}


S urmrim cum se execut acest program atunci cnd se introduce irul de caractere
"abc0":
1. Se apeleaz subprogramul invsir().
ED

2. Se creeaz prima imagine a variabilei locale ch, care corespunde primului apel.

52 Tehnici de programare
3. Se citete valoarea variabilei ch: 'a'. Prima imagine a variabilei locale conine

IC
valoarea 'a'. Fiind diferit de '0', se apeleaz din nou subprogramul invsir().
4. Se creeaz a doua imagine a variabilei locale ch, care corespunde celui de al doilea apel.

OG
5. Se citete valoarea variabilei ch: 'b'. A doua imagine a variabilei locale conine
valoarea 'b'. Fiind diferit de '0', se apeleaz din nou subprogramul invsir().
6. Se creeaz a treia imagine a variabilei locale ch, care corespunde celui de al treilea apel.
7. Se citete valoarea variabilei ch: 'c'. A treia imagine a variabilei locale conine
valoarea 'c'. Fiind diferit de '0', se apeleaz din nou subprogramul invsir().

G
8. Se creeaz a patra imagine a variabilei locale ch, care corespunde celui de al patrulea
apel.

DA
9. Se citete valoarea variabilei ch: '0'. A patra imagine a variabilei locale conine
valoarea '0'. Fiind '0', se trece la execuia instruciunii urmtoare din subprogram.
10. Se execut instruciunea cout<<ch;, prin care se scrie pe ecran valoarea pstrat n
imaginea variabilei ch, corespunztoare celui de al patrulea apel '0'.

PE
11. Se termin de executat al patrulea apel al subprogramului. Se pred controlul celui de
al treilea subprogram apelat. Instruciunea care urmeaz s se execute este
cout<<ch;, prin care se afieaz pe ecran valoarea pstrat n imaginea variabilei ch.
Coninutul corespunztor celui de al treilea apel este 'c'.
12. Se termin de executat al treilea apel al subprogramului. Se pred controlul celui de al
I
doilea subprogram apelat. Instruciunea care urmeaz s se execute este cout<<ch;,
prin care se afieaz pe ecran valoarea pstrat n imaginea variabilei ch. Coninutul
corespunztor celui de al doilea apel este 'b'.

13. Se termin de executat al doilea apel al subprogramului. Se pred controlul primului


subprogram apelat. Instruciunea care urmeaz s se execute este cout<<ch;, prin
IC

care se afieaz pe ecran valoarea pstrat n imaginea variabilei ch. Coninutul


corespunztor primului apel este 'a'.
14. Se termin execuia subprogramelor apelate.
CT

vf adr3
ch 'c'
vf adr2 adr2
ch 'b' ch 'b'
DA

vf adr1 adr1 adr1


ch 'a' ch 'a' ch 'a'
primul apel al doilea apel al treilea apel al patrulea apel
DI

ch 'a' ch 'b' ch 'c' ch '0'


ch diferit de '0' ch diferit de '0' ch diferit de '0' ch egal cu '0'
RA

afieaz ch ('a') afieaz ch ('b') afieaz ch ('c') afieaz ch ('0')

adr1 adr2 adr3


ITU

vf adr3
ch 'c'
vf adr2 adr2
ch 'b' ch 'b'
ED

vf adr1 adr1 adr1


ch 'a' ch 'a' ch 'a'

Informatic 53

IC
Adncimea recursivitii este numrul de activri (apeluri) succesive
ale unui subprogram recursiv.

Pentru exemplul anterior, adncimea recursivitii este 4 (au fost patru apeluri).

OG
Observaie: Implementarea recursiv a unui algoritm este eficient numai dac
adncimea recursivitii nu este mare.
Scriei un program prin care se citesc n numere ntregi de la tastatur (n
Tem

G
este o valoare care se citete de la tastatur) i se afieaz n ordinea
invers citirii. Nu se va folosi un vector pentru numere.

DA
1.2.4. Implementarea recursiv a algoritmilor elementari
1.2.4.1. Algoritmul pentru determinarea valorii minime (maxime)

PE
Pentru calcularea valorii minime dintr-un ir de n numere citite de la tastatur, se vor folosi
funciile min() i max() care au fost definite recursiv:
#include <iostream.h>
int max(int a,int b){if (a>b) return a; else return max(b,a);}
int min(int a,int b){if (a>b) return b; else return min(b,a);}
I
void main()
{int a,b,x,y,n,i;
cout<<"n= "; cin>>n; cout<<"numar= "; cin>>a; x=a; y=a;

for (i=2;i<=n;i++)
{cout<<"numar= "; cin>>a; x=max(x,a); y=min(x,a);}
IC

cout<<"maxim= "<<x<<endl<<"minim= "<<y;}

1.2.4.2. Algoritmul pentru calculul c.m.m.d.c. a dou numere


CT

Un alt algoritm elementar pe care l putem implementa folosind recursivitatea este calculul
celui mai mare divizor comun dintre dou numere naturale a i b. Valorile lui a i b se intro-
duc de la tastatur.
DA

Varianta 1. Soluia recursiv se bazeaz pe algoritmul lui Euclid (condiia b0):


1. Se mparte a la b i se obine restul r (r a mod b).
2. Se execut operaiile de atribuire ab; br.
3. Dac b0, atunci se revine la pasul 1, adic se reia execuia funciei atribuindu-se
DI

parametrilor de intrare urmtoarele valori: parametrului a valoarea b, iar parametrului


b valoarea a mod b. Dac b=0, atunci cmmdca.
Pentru algoritmul recursiv se definete funcia matematic recursiv:
RA

a pentru b=0
cmmdc(a,b) = b pentru a=0
cmmdc(b, a mod b) pentru a0 i b0
ITU

De exemplu, dac a=18 i b=12, calculul celui mai mare divizor comun se desfoar,
folosind algoritmul recursiv, astfel:
1. cmmdc(18,12): b0 (120) i a0 (180)
cmmdc(18,12) = cmmdc(12, 18 mod12) = cmmdc(12,6).
2. cmmdc(12,6): b0 (60) i a0 (120) cmmdc(12,6) = cmmdc(6, 12 mod 6) = cmmdc(6,0).
ED

3. cmmdc(6,0): b=0 (0=0) cmmdc(6,0) = a = 6.



54 Tehnici de programare
Programul care folosete algoritmul recursiv este:

IC
#include <iostream.h>
int cmmdc(int a, int b)

OG
{if (a==0) return b;
else if (b==0) return a;
else return cmmdc(b,a%b);}
void main()
{int a,b; cout<<"a= "; cin>>a; cout<<"b= "; cin>>b;

G
if (cmmdc(a,b)==0)
cout<<"cmmdc nu se poate calcula; ambele numere sunt 0";

DA
else cout<<"cmmdc("<<a<<","<<b<<")= "<<cmmdc(a,b);}
Varianta 2. Soluia recursiv se bazeaz pe algoritmul prin scderi repetate (condiia
ab):

PE
1. Se scade, din numrul mai mare, cellalt numr: dac a>b, se execut operaia de
atribuire a a-b, iar dac b>a se execut operaia de atribuire b b-a.
2. Dac ab, atunci se revine la pasul 1 adic se reia execuia funciei atribuindu-se para-
metrilor de intrare urmtoarele valori: dac a>b parametrului a i se atribuie valoarea
a-b, iar dac b>a parametrului b i se atribuie valoarea b-a; n ambele cazuri, cellalt
I
parametru rmne neschimbat. a pentru b=0 sau a=b
Dac a=b, atunci cmmdc a. b pentru a=0
Pentru algoritmul recursiv se definete cmmdc(a,b) = cmmdc(a-b, b) pentru a>b
funcia recursiv alturat.

cmmdc(a, b-a) pentru b>a


De exemplu, dac a=18 i b=12,
IC

calculul celui mai mare divizor comun se desfoar folosind algoritmul recursiv, astfel:
1. cmmdc(18,12): (b0 (120) i ab (1812)) i a0 (180) i a>b (18>12)
cmmdc(18,12) = cmmdc(18-12,12) = cmmdc(6,12).
CT

2. cmmdc(6,12): (b0 (120) i ab (612)) i a0 (60) i b>a (12>6)


cmmdc(6,12) = cmmdc(6, 12-6) = cmmdc(6,6).
3. cmmdc(6,6): a=b (6=6) cmmdc(6,6) = a = 6.
Programul care folosete algoritmul recursiv este:
DA

#include <iostream.h>
int cmmdc(int a, int b)
{if (a==0||a==b) return b;
DI

else if (b==0) return a;


else if (a>b) return cmmdc(a-b,b);
else return cmmdc(a,b-a);}
void main()
RA

{int a,b; cout<<"a= "; cin>>a; cout<<"b= "; cin>>b;


if (cmmdc(a,b)==0)
cout<<"cmmdc nu se poate calcula;ambele numere sunt 0";
else cout<<"cmmdc("<<a<<","<<b<<")= "<<cmmdc(a,b);}
ITU

1.2.4.3. Algoritmi pentru prelucrarea cifrelor unui numr


Exemplul 1 Extragerea cifrelor unui numr. Ca exemplu de implementare recursiv a
algoritmului care extrage cifrele unui numr, vom calcula suma cifrelor unui numr natural
n. Algoritmul const n extragerea repetat a unei cifre (calculnd restul mpririi la 10), din
ED

Informatic 55
ceea ce mai rmne din numr dup extragerea unei cifre (calculnd ctul mpririi la 10).

IC
Paii care se execut sunt:
1. Se iniializeaz suma cu valoarea 0.

OG
2. Dac numrul este diferit de 0, se adun la sum ultima cifr din numr (n mod 10) i
se elimin aceast cifr din numr (n div 10) dup care se reia pasul 2, adic se reia
execuia funciei atribuind parametrului de intrare valoarea n div 10. Dac numrul n
are valoarea 0, atunci s-a obinut suma cifrelor.

G
Pentru algoritmul recursiv, se 0 pentru n=0
definete funcia alturat: Suma(n) =

DA
De exemplu, dac se calculea- n mod 10 +Suma(n div 10) pentru n>0
z suma cifrelor numrului
5372, funcia recursiv se va executa astfel:
Suma(5372) = 5372 mod 10 + Suma(5372 div 10) = 2 + Suma(537) = 2 + (537 mod 10 + Suma(537 div

PE
10)) = 2 + 7 + Suma(53) =9 + (53 mod 10 + Suma(53 div 10)) = 9 + 3 + Suma(5) = 12 + 5 mod 10 +
Suma(5 div 10) = 12 + 5 + Suma(0) = 17 + 0 = 17
#include <iostream.h>
int suma(int n)
I
{if (n==0) return 0; else return n%10+suma(n/10);}
void main()
{int n; cout<<"n= "; cin>>n; cout<<"suma cifrelor= "<<suma(n);}

Scriei o funcie recursiv prin care calculai suma cifrelor pare dintr-un
Tem numr.
IC

Exemplul 2 Compunerea unui numr cunoscnd cifrele sale. Cifrele se citesc de la


tastatur prin intermediul variabilei de memorie cifra. Funcia are un singur parametru: n,
CT

care reprezint valoarea numrului obinut din cifrele obinute pn la acel apel. Iniial,
valoarea parametrului n (valoarea la primul apel) este 0. Dac numrul citit este o cifr, se
reia execuia funciei atribuindu-se parametrilor de intrare vechea valoare nmulit cu 10, la
care se adaug cifra citit. Dac numrul citit nu este o cifr, atunci funcia va returna
DA

valoarea final a numrului n.


n pentru cifra<0 sau cifra>9
Numar(n) =
Numar(n*10+cifra) pentru cifra0 i cifra 9
DI

Implementarea recursiv cu ajutorul unui subprogram de tip funcie operand se


evalueaz funcia numar(0):
RA

#include <iostream.h>
unsigned long numar(unsigned long n)
{int cif; cout<<"cifra= "; cin>>cif;
if (cif<0 || cif>9) return n; else return numar(n*10+cif);}
ITU

void main() {cout<<"numarul= "<<numar(0);}


i implementarea recursiv, cu ajutorul unui subprogram de tip funcie procedural:
#include <iostream.h>
void numar(int &n)
{int cif; cout<<"cifra= "; cin>>cif;
ED

56 Tehnici de programare

IC
if (cif>=0 && cif<=9) {n=n*10+cif; numar(n);}}
void main()
{int n=0; numar(n); cout<<"numarul= "<<n; }

OG
Exemplul 3 Obinerea inversului unui numr. Pornind de la variantele recursive
definite anterior, pentru extragerea cifrelor unui numr i pentru compunerea unui numr
din cifrele sale, inversul unui numr n se poate determina folosind un algoritm recursiv n
care nr reprezint valoarea n+nr pentru n<10

G
numrului inversat. Iniial, va- Inv(n,nr) =
loarea parametrului nr (la pri- Inv(n div 10,10*(nr*(n mod 10))) pentru n10
mul apel) este 0.

DA
Implementarea cu ajutorul unui subprogram de tip funcie operand se evalueaz funcia
inv(n,0):
#include <iostream.h>

PE
unsigned long inv(unsigned long n, unsigned long nr)
{if (n<10) return nr+n; else return inv(n/10,10*(nr+n%10));}
void main()
{unsigned long n;
cout<<"n= "; cin>>n; cout<<"invers= "<<inv(n,0); }
I
i implementarea recursiv, cu ajutorul unui subprogram de tip funcie procedural:
#include <iostream.h>
void inv(int n,int &nr)

{if(n<10) nr=nr+n; else {nr=10*(nr+n%10); inv(n/10,nr);}}


void main()
IC

{int n,nr=0; cout<<"n= "; cin>>n; inv(n,nr); cout<<nr<<endl;}


Folosind funciile recursive definite anterior, scriei un program prin care
CT

Tem afiai numerele palindrom din intervalul [a,b] a i b se citesc de la


tastatur.

1.2.4.4. Algoritmul pentru verificarea unui numr dac este prim


DA

Pentru a determina dac un numr natural n este prim, se poate defini funcia iterativ
prim(n,i), astfel:
true dac n nu este divizibil prin i, V i[2,sqrt(n)]
DI

prim(n,i) =
false dac n este divizibil prin i, i[2,sqrt(n)]

Din algoritmul iterativ se observ c funcia prim are valoarea true numai dac numrul n
RA

nu este divizibil cu nici unul dintre numerele cuprinse ntre 2 i [sqrt(n)]. Altfel spus, se
evalueaz toate funciile prim(n,i), i dac cel puin una dintre aceste funcii are valoarea
false, atunci numrul nu este prim. Algoritmul recursiv poate fi descris prin funcia:
true pentru i=1
ITU

prim(n,i) =
(n mod i 0) and prim(n,i-1) pentru 2 i [sqrt(n)]

i se evalueaz funcia prim(n,sqrt(n)):


ED

Informatic 57

IC
#include <iostream.h>
#include <math.h>
int prim(int n,int i)

OG
{if(i==1) return 1;
else return (n%i!=0) && prim(n,i-1);}
void main()
{int n; cout<<"n= "; cin>>n;
if (prim(n,sqrt(n))) cout<<"Numarul "<<n<<" este prim ";

G
else cout<<"Numarul "<<n<<" nu este prim ";}
sau prin funcia:

DA
true pentru i=[sqrt(n)]
prim(n,i) =
(n mod i 0) and prim(n,i+1) pentru 1 i< [sqrt(n)]

PE
i se evalueaz funcia prim(n,2):
#include <iostream.h>
#include <math.h>
int prim(int n,int i)
I
{if (i==sqrt(n)) return 1;
else return (n%i!=0) && prim(n,i+1);}
void main()

{int n; cout<<"n= "; cin>>x;


if (prim(n,2)) cout<<"Numarul "<<n<<" este prim ";
IC

else cout<<"Numarul "<<n<<" nu este prim ";}


n cazul celor dou variante defi- true pentru i=1
nite pentru funcia recursiv se fac prim(n,i) =
CT

false pentru n mod i = 0 i i1


multe autoapeluri inutile. De ace- prim(n,i-1) pentru n mod i 0 i i1
ea, se poate mbunti funcia
recursiv, definindu-se n felul urmtor:
DA

#include <iostream.h>
#include <math.h>
int prim(int n,int i)
{if(i==1) return 1;
DI

else if (n%i==0) return 0;


else return prim(n,i-1);}
void main()
{int n; cout<<"n= "; cin>>x;
RA

if (prim(n,sqrt(n))) cout<<"Numarul "<<n<<" este prim ";


else cout<<"Numarul "<<n<<" nu este prim ";}
Artai cum se execut funcia recursiv prim() pentru a testa numrul
Tem 27 i pentru a testa numrul 29. Refacei funcia recursiv astfel nct, n
ITU

programul principal, s evaluai funcia prim(n,2). Folosii funcia


definit recursiv pentru a afia primele n numere prime.
ED

58 Tehnici de programare
1.2.4.5. Algoritmi pentru determinarea divizorilor unui numr

IC
Exemplul 1: Afiarea divizorilor unui numr. Se genereaz divizorii posibili (d) ai
numrului n, pornind de la valoarea 1. Dac divizorul posibil este mai mic dect n/2, se

OG
verific dac numrul n estre divizibil prin el. Dac este divizibil, se afieaz divizorul d. Se
reia apoi execuia funciei, pentru urmtorul divizor posibil. Se va evalua funcia
divizor(n,1).
#include <iostream.h>

G
void divizor(int n, int d)
{if (d<=n/2)

DA
{if (n%d==0) cout<<d<<" "; divizor(n,d+1);}}
void main()
{int n; cout<<"n= "; cin>>n; divizor(n,1);}
sau

PE
#include <iostream.h>
void divizor(int n, int d)
{if (d<=sqrt(n))
{if (n%d==0)
I
if (d!=n/d) cout<<d<<" "<<n/d<<" ";
else cout<<d<<" ";
divizor(n,d+1);}}
void main()

{int n; cout<<"n= "; cin>>n; divizor(n,1);}


IC

Exemplul 2: S se descompun un numr n factori primi. Se genereaz factorii primi


posibili (f) ai numrului n, pornind de la valoarea 2 a factorului, pn cnd se elimin din
numr toi factorii primi (n=1). Se folosete parametrul p pentru a calcula exponentul facto-
CT

rului prim. Dac f este factor prim, se apeleaz funcia pentru numrul din care s-a eliminat
un factor prim (n/f) i pentru valoarea exponentului p incrementat cu 1. Dac f nu este
factor prim n numrul n obinut, se verific dac a fost factor prim (p0) caz n care se
afieaz factorul prim (f) i exponentul (p) dup care se apeleaz funcia pentru
DA

urmtorul factor prim posibil (f+1) cu exponentul 0. Dac s-au eliminat din numr toi
factorii primi, se verific dac ultimul factor a fost factor prim (p0) caz n care se afieaz
factorul prim (f) i exponentul (p). Se va evalua funcia factor(n,2,0).
#include <iostream.h>
DI

void factor(int n, int f, int p)


{if (n>1)
if (n%f==0) factor(n/f,f,p+1);
else {if (p!=0) cout<<f<<" la puterea "<<p<<endl;
RA

factor(n,f+1,0);}
else if (p!=0) cout<<f<<" la puterea "<<p;}
void main()
{int n; cout<<"n= "; cin>>n; factor(n,2,0); }
ITU

Scriei un program prin care afiai suma divizorilor primi ai unui numr.
Tem Folosii o funcie definit recursiv, prin care determinai divizorul prim al
numrului, dup care l adunai la sum.
ED

Informatic 59
1.2.4.6. Algoritmi pentru conversia ntre baze de numeraie

IC
Se convertete un numr n scris n baza 10 ntr-un numr scris n baza q (1<q<10). Dac
n<q, nseamn c numrul este reprezentat deja n baza q, deoarece se folosesc aceleai

OG
cifre pentru reprezentarea lui. n cazul n care nq algoritmul de conversie este:
1. Se atribuie ctului valoarea numrului c n.
2. Se calculeaz restul mpririi numrului la valoarea q (r n mod q) o cifr a
numrului i se afieaz (primul rest este cifra cea mai puin semnificativ).
3. Se evalueaz c ctul mpririi numrului la q. Dac cq, se revine la pasul 2, adic

G
se reia execuia subprogramului, atribuind parametrului de intrare valoarea n div q.
Dac c<q, se termin procesul repetitiv i ctul obinut va fi ultima cifr (cifra cea mai

DA
semnificativ).
Tiprirea cifrelor obinute se face n ordinea invers a extragerii (la fel ca i n cazul funciei
recursive, prin care se afia inversul unui ir de caractere). nseamn c, la fiecare apel al
funciei, cifra obinut prin calcularea restului se va pstra de fiecare dat n cte o imagine

PE
a variabilei de memorie folosit n funcia recursiv variabila cifra. Tiprirea cifrelor se
va face n ordinea invers a obinerii lor, deoarece prima cifr care se va tipri va fi cea
corespunztoare ultimului apel, iar ultima cifr care se va tipri va fi cea corespunztoare
primului apel:
I
#include <iostream.h>
void conversie(int n, int q)
{int cifra; cifra=n%q;

if (n>=q) conversie(n/q,q);
cout<<cifra;}
IC

void main()
{int n,q; cout<<"numarul= "; cin>>n; cout<<"baza= "; cin>>q;
conversie(n,q);}
CT

Artai cum se execut funcia recursiv conversie(25,3). Scriei o


Tem funcie recursiv prin care convertii n baza 10 un numr b scris n baza
q (1<q<10).
DA

1.2.5. Implementarea recursiv a algoritmilor pentru


prelucrarea tablourilor de memorie
DI

Prelucrarea unui vector printr-o funcie recursiv f se poate face ncepnd cu primul
element (i=0) i terminnd cu ultimul element (i=n-1), sau invers, ncepnd cu ultimul
element (i=n-1) i terminnd cu primul element (i=0):
RA

condiie de terminare
apel: f(0) f(i+1) i=n-1

i=0 f(i-1) apel: f(n-1)


ITU

condiie de terminare
ED

60 Tehnici de programare
Exemplul 1

IC
Se citesc i se afieaz elementele ntregi ale unui vector. Cele dou funcii recursive: pen-
tru citirea valorii elementelor de la tastatur citeste() i pentru afiarea valorii ele-

OG
mentelor vectorului scrie() pot ncepe cu primul element din vector i se termin cu
ultimul element:
#include <iostream.h>
int n,a[100];

G
void citeste(int i)
{if(i!=n-1) citeste(i+1);
cout<<i<<": "; cin>>a[i];}

DA
void scrie(int i)
{if(i!=n-1) scrie(i+1);
cout<<a[i]<<" ";}
void main()

PE
{cout<<"n= "; cin>>n; citeste(0); scrie(0);}
sau pot ncepe cu ultimul element din vector i se termin cu primul element:
#include <iostream.h>
int n,a[100];
I
void citeste(int i)
{if(i!=0) citeste(i-1);
cout<<i<<": "; cin>>a[i];}

void scrie(int i)
{if(i!=0) scrie(i-1);
IC

cout<<a[i]<<" ";}
void main()
{cout<<"n= "; cin>>n; citeste(n-1); scrie(n-1);}
CT

Exemplul 2
S se verifice dac exist, ntr-un vector true dac x (a1, a2, ..., an)
cu n elemente ntregi, cel puin un ele- gasit(x,i) =
DA

ment cu valoarea ntreag x. Fie vectorul false dac x(a1, a2, ..., an)
a=(a1,a2,...,an). Funcia iterativ
gasit(x,i) este definit alturat. Din algoritmul iterativ se observ c funcia gasit are
valoarea true fie dac elementul curent are valorea x, fie dac cel puin unul dintre elemen-
DI

tele anterior testate are valoarea x. Funcia recursiv poate fi definit n mai multe moduri.
Varianta 1 se evalueaz funcia gasit(x,n-1):
#include <iostream.h> x=a0 pentru i=0
int a[100];
RA

gasit(x,i) =
int gasit(int x,int i) (x=ai) or gasit(x,i-1) pentru 1 i n-1
{if(i==0) return x==a[0];
else return ((x==a[i])||gasit(x,i-1));}
void main()
ITU

{int x,i,n; cout<<"n= "; cin>>n; cout<<"x= "; cin>>x;


for(i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
if(gasit(x,n-1)) cout<<"s-a gasit elementul"<<x;
else cout<<"nu s-a gasit elementul"<<x;}
ED

Informatic 61
De exemplu, pentru n=5, x=2 i a=(1,1,2,2,3), evaluarea funciei se face astfel:

IC
gasit(2,4) = (2=3) or gasit(2,3) = false or ((2=2) or gsit(2,2)) = false or true or
((2=2) or gsit(2,1)) = false or true or true or (2=1) or gsit(2,0)) = false or true or true or false or (2=1)

OG
= false or true or true or false or false = true
Varianta 2 se evalueaz funcia gasit(x,0):
#include <iostream.h> x=an-1 pentru i=n-1
int a[100]; gasit(x,i) =

G
int gasit(int x,int i) (x=ai) or gasit(x,i+1) pentru 0 i n-2
{if(i==n-1) return x==a[n-1];

DA
else return (x==a[i])||gasit(x,i+1);}
void main()
{int x,i,n;
cout<<"n= "; cin>>n;

PE
for(i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
cout<<"x= "; cin>>x;
if(gasit(x,0)) cout<<"s-a gasit elementul"<<x;
else cout<<"nu s-a gasit elementul"<<x;}
Varianta 3 Din evaluarea funciei gasit(2,4) se observ c valoarea funciei s-a
I
aflat dup al doilea apel al funciei i restul apelurilor au fost inutile. nseamn c, imediat
ce s-a gsit un element cu valoarea x, funcia nu trebuie s se mai autoapeleze, i se
atribuie funciei valoarea logic true. Pentru a evita ns apelarea la infinit a funciei n

cazul n care nici un element din


vector nu are valoarea x, se va folosi o false pentru in
IC

condiie suplimentar (i>=n). Funcia gasit(x,i) = true pentru x=ai i i<n


recursiv este definit alturat i se va gasit(x,i+1) pentru xai i i<n
evalua funcia gasit(x,0):
CT

#include <iostream.h>
int a[100];
int gasit(int x,int i)
{if(i>=n) return 0;
DA

else if (x==a[i]) return 1;


else return gasit(x,i+1);}
void main()
{int x,i,n; cout<<"n= "; cin>>n; cout<<"x= "; cin>>x;
DI

for(i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}


if(gasit(x,0)) cout<<"s-a gasit elementul"<<x;
else cout<<"nu s-a gasit elementul"<<x;}
RA

Exemplul 3
true ai > 0
S se verifice dac exist, ntr-un vector cu n elemente ntregi, pozitiv(i) =
cel puin un element pozitiv. Fie vectorul a=(a1,a2,...,an). false ai 0
Funcia iterativ pozitiv(i) este definit alturat. Din
ITU

definiia iterativ se observ c funcia pozitiv are valoarea true fie dac elementul
curent este pozitiv, fie dac cel puin unul dintre elementele anterior testate este pozitiv.
Altfel spus, se evalueaz toate funciile pozitiv(i), i dac cel puin una dintre aceste
funcii are valoarea true, atunci exist cel puin un element cu valoare pozitiv. Funcia
ED

recursiv poate fi definit n urmtoarele variante.



62 Tehnici de programare
Varianta 1 se evalueaz funcia pozitiv(n-1):

IC
#include <iostream.h> a0 > 0 pentru i=0
int a[100],n; pozitiv(i) =

OG
int pozitiv(int i) (ai >0) or pozitiv(i-1) pentru 1 i n-1
{if(i==0) return a[0]>0;
else return (a[i]>0)||pozitiv(i-1);}
void main()
{int i; cout<<"n= "; cin>>n;

G
for(i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
if(pozitiv(n-1)) cout<<"S-a gasit cel putin un element pozitiv";

DA
else cout<<"Nu s-a gasit nici un element pozitiv";}
Varianta 2 se evalueaz func-
an-1 > 0 pentru i=n-1
ia pozitiv(0):
pozitiv(i) =
#include <iostream.h> (ai >0) or pozitiv(i+1) pentru 0 i n-2

PE
int a[100],n;
int pozitiv(int i)
{if(i==n-1) return a[n-1]>0;
else return ((a[i]>0)||pozitiv(i+1));}
I
void main()
{int i; cout<<"n= "; cin>>n;
for(i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
if(pozitiv(0)) cout<<"S-a gasit cel putin un element pozitiv";

else cout<<"Nu s-a gasit nici un element pozitiv";}


IC

Varianta 3 i n cazul celor dou vari-


false pentru i>n
ante definite anterior pentru funcia recur-
pozitiv(i) = true pentru ai > 0
siv se vor face multe autoapeluri inutile.
pozitiv(i+1) pentru ai <= 0
CT

Ar trebui ca, imediat ce s-a gsit un ele-


ment pozitiv, s nu se mai apeleze recursiv funcia i s i se atribuie valoarea true. Pentru a
evita ns apelarea la infinit a funciei, i n acest caz se va folosi o condiie suplimentar
(i<=n). Funcia recursiv este definit alturat. Se evalueaz funcia pozitiv(0)
DA

#include <iostream.h>
int a[100],n;
int pozitiv(int i)
{if(i>=n) return 0;
DI

else if (a[i]>0) return 1;


else return pozitiv(i+1);}
void main()
RA

{int i; cout<<"n= "; cin>>n;


for(i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
if(pozitiv(0)) cout<<"S-a gasit cel putin un element pozitiv";
else cout<<"Nu s-a gasit nici un element pozitiv";}
ITU

Exemplul 4
S se calculeze numrul de apariii ale unui gasit(x,i-1) dac ai x
element precizat, x, ntr-un vector cu n elemen- gasit(x,i) =
te. Fie vectorul a=(a1,a2,...,an). Funcia gasit(x,i-1)+1 dac ai = x
iterativ gasit(x,i) este definit alturat.
ED

Informatic 63
Din algoritmul iterativ se observ c funciei gasit i se incrementeaz valoarea dac

IC
elementul curent are valoarea x. Funciei i se va atribui valoarea 0 dac primul element
comparat nu are valoarea x, sau valoarea 1 dac primul element comparat are valoarea x.

OG
Mai cunoatei c, n limbajul C++, valorii logice false i corespunde valoarea numeric 0,
iar valorii logice true, valoarea numeric 1. Notm cu num (x=ai) valoarea numeric
asociat valorii logice a operatorului relaional. Funcia recursiv poate fi definit n dou
variante, n funcie de elementul din vector care se compar primul cu valoarea x.

G
Varianta 1 se evalueaz funcia num(x=a0) pentru i=0
gasit(x,n-1). gasit(x,i) =

DA
#include <iostream.h> num(x=ai) + gasit(x,i-1) pentru 1 i n-1
int a[100],n;
int gasit(int x,int i)
{if (i==0) return x==a[0];

PE
else return (x==a[i])+gasit(x,i-1);}
void main()
{int i,x; cout<<"n= "; cin>>n; cout<<"x= "; cin>>x;
for (i=0;i<n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
cout<<"S-au gasit "<<gasit(x,n)<<"elemente";}
I
Varianta 2 se evalueaz funcia num(x=an-1) pentru i=n-1
gasit(x,0). gasit(x,i) =
#include <iostream.h> num(x=ai) + gasit(x,i-1) pentru 0 i n-2

int a[100],n;
int gasit(int x,int i)
IC

{if (i==n-1) return x==a[n-1];


else return (x==a[i])+gasit(x,i+1);}
void main()
CT

{int i,x; cout<<"n= "; cin>>n; cout<<"x= "; cin>>x;


for (i=1;i<=n;i++) {cout<<"a["<<i<<"]= "; cin>>a[i];}
cout<<"S-au gasit "<<gasit(x,0)<<"elemente"; }
DA

Exemplul 5
-1 pentru s>d
S se caute, ntr-un vector ordonat,
m+1 pentru am=x
cu n elemente ntregi, elementul cu
gasit(s,d,x,a) = gasit(s,m+1,a.x) pentru am >x
valoarea ntreag x, i s se afieze
gasit(m-1,d,a,x) pentru x>am
DI

poziia n care a fost gsit. Dac nu se


gsete elementul, funcia va furniza valoarea -1. Fie vectorul a=(a1,a2,...,an).
Pentru cutarea elementului cu valoarea precizat se va folosi algoritmul de cutare binar,
unde s i d sunt indicele din stnga, respectiv din dreapta, ai subvectorului n care se
RA

continu cutarea, iar m este indicele elementului din mijloc: m=(s+d)/2. Funcia recursiv
gasit(s,d,a,x) este definit alturat. Se evalueaz funcia gasit(0,n-1,a,x).
#include <iostream.h>
ITU

int gasit(int s,int d,int a[],int x)


{int m=(s+d)/2;
if(s>d) return -1;
else if (a[m]==x) return m+1;
else if (a[m]>x) return gasit(s,m-1,a,x);
ED

else return gasit(m+1,d,a,x);}



64 Tehnici de programare

IC
void citeste (int a[], int &n)
{int i; cout<<"n= "; cin>>n;
for (i=0;i<n;i++) {cout<<"a("<<i+1<<")= ";cin>>a[i];}}

OG
void main()
{int x,n,a[20],poz; cout<<"x= "; cin>>x;
citeste(a,n); poz=gasit(0,n-1,a,x);
if (poz==-1) cout<<"Nu exista elementul";
else cout<<"s-a gasit in pozitia "<<poz; }

G
Exemplul 6

DA
S se sorteze cresctor un vector cu n numere reale. Pentru sortare s-a folosit metoda
seleciei directe. Funcia recursiv este sort(a,i,j,n), unde a este vectorul, i i j indicii
folosii de metoda de sortare i n lungimea logic a vectorului. Cu indicele i se parcurge
vectorul de la primul element pn la penultimul (indicele i ia valori de la 0 pn la n-2), iar

PE
cu indicele j se parcurge vectorul de la elementul urmtor elementului cu indicele i pn la
ultimul (indicele ia valori de la i+1 pn la n-1). Se evalueaz funcia sort(a,0,1,n).
#include <iostream.h>
void citeste(float a[],int n)
{for (int i=0; i<n;i++) {cout<<"a("<<i+1<<")= ";cin>>a[i];}}
I
void scrie(float a[],int n)
{for (int i=0; i<n;i++) cout<<a[i]<<" ";}
void sort(float a[],int i,int j,int n)

{float aux;
if (i!=n-2 || j!=n-1)
IC

{if (a[j]<a[i]) {aux=a[i]; a[i]=a[j]; a[j]=aux;}


if (j!=n-1) sort(a,i,j+1,n);
else sort(a,i+1,i+2,n);}}
CT

void main()
{int n; float a[50]; cout<<"n= "; cin>>n;
citeste (a,n); sort(a,0,1,n); scrie(a,n);}
1. Pentru un vector cu elemente ntregi, scriei un subprogram recursiv,
DA

Tem care calculeaz:


a. suma elementelor vectorului;
b. suma elementelor pozitive din vector;
c. media aritmetic a elementelor vectorului;
DI

d. media aritmetic a elementelor pozitive din vector.


2. Scriei un subprogram recursiv care s inverseze elementele unui vector n el nsui.
3. Scriei un subprogram recursiv care s sorteze cresctor elementele unui vector,
RA

folosind metoda bulelor.

1.2.6. Recursivitatea n cascad


ITU

Se definete irul lui Fibonacci, prin funcia 0 pentru n=0


fibo:NN: fibo(n) = 1 pentru n=1
fibo(n-1)+fibo(n-2) pentru n>1

Algoritmul folosit poate fi descris astfel:


ED

Informatic 65

IC
fibo(0) 0
fibo(1) 1
iterativ fibo(2) fibo(0)+fibo(1) recursiv

OG
.....................
fibo(n) fibo(n-2)+fibo(n-1)

Programul care folosete algoritmul recursiv pentru calcularea termenului de ordinul n al

G
irului lui Fibonacci execut autoapelul de dou ori n cazul general al soluiei:
#include <iostream.h>

DA
int fibo(int n)
{if (n<=1) return n;
else return fibo(n-1)+fibo(n-2);}
void main()

PE
{int n; cout<<"n= "; cin>>n;
cout<<"Termenul "<<n<<" al sirului lui Fibonacci este ";
cout <<fibo(n);}
fibo(4) fibo(3) fibo(2) fibo(1)=1
+
I
Adncimea recursivitii pen- 3 2 1
tru apelul fibo(4) este 9. Dac + + fibo(0)=0
notm cu ar(n) adncimea fibo(1) =1
recursivitii pentru apelul fibo(2) fibo(1) =1

fibo(n), observm c: 1 +
fibo(0) =0
IC

ar(1) = ar(0) = 1 ar(5) = 1 + ar(4) + ar(3) = 1+9+5 = 15


ar(2) = 1 + ar(1) + ar(0) = 1+1+1 = 3 ar(6) = 1 + ar(5) + ar(4) = 1+15+9 = 25
CT

ar(3) = 1 + ar(2) + ar(1) = 1+3+1 = 5 ar(7) = 1 + ar(6) + ar(5) = 1+25+15 = 41


ar(4) = 1 + ar(3) + ar(2) = 1+5+3 = 9 ......................................
ar(n) = 1 + ar(n-1) + ar(n-2)
DA

Scriei un program prin care calculai adncimea recursivitii pentru


Tem apelul fibo(n). Calculai adncimea recursivitii pentru urmtoarele
apeluri: fibo(10), fibo(15), fibo(20), fibo(25), fibo(30), fibo(40), fibo(50). Ce
constatai?
DI

Observaie:
Acest tip de recursivitate se numete recursivitate n cascad i este un exemplu n care
programul iterativ este mult mai eficient dect programul recursiv. Ca s se poat executa
RA

fibo(n) trebuie s se cunoasc valoarea returnat de fibo(n-1) i fibo(n-2).


Aceasta nseamn c mai nti se calculeaz valoarea lui fibo(n-1), dup care se reia
calculul pentru valoarea lui fibo(n-2), rezervndu-se cte o zon n stiv pentru fiecare
apel n care se salveaz contextul funciei. Implementarea recursiv este ineficient pentru
ITU

valori mari ale lui n. Pentru exemplificare, se pot executa ambele versiuni (cea recursiv i
cea iterativ), pentru n=100.
a pentru n=0
Pentru a reduce adncimea recursivitii pro- fibo(n,a,b) =
gramului care calculeaz termenul n al irului fibo(n-1,b,a+b) pentru n>=1
ED

lui Fibonacci, se pornete de la observaia c



66 Tehnici de programare
termenul n este egal cu suma dintre termenul predecesor (a) i termenul antepredecesor (b),

IC
obinndu-se definiia recursiv alturat. Termenul n al irului lui Fibonacci se va calcula prin
evaluarea funciei fibo(n,0,1) unde, pentru primul apel, a i b au valoarea 0 i respectiv 1,

OG
corespunztoare primilor doi termeni ai irului. De exemplu, dac n=4, funcia se calculeaz
astfel: fibo(4,0,1) = fibo(3,1,1) = fibo(2,1,2) = fibo(1,2,3) = fibo(0,3,5) = 3
1. Care este adncimea recursivitii pentru apelul fibo(9)? Scriei
Tem un program n care implementai algoritmul recursiv definit mai sus.

G
Executai cele dou programe care implementeaz algoritmii
recursivi, pentru n=50, i comparai timpii de execuie.

DA
2. Scriei un subprogram recursiv care s verifice dac dou numere a i b citite de la
tastatur sunt termeni consecutivi ai irului lui Fibonacci.
Un alt exemplu de recursivitate n cascad este algoritmul pentru rezolvarea urmtoarei
probleme. Fie an, bn, cn trei iruri, cu n0, definite astfel:

PE
1 pentru n=0 4 pentru n=0
a(n) = 3 pentru n=1 b(n) = 2 pentru n=1
2a(n-1)-a(n-2) pentru n>1 2b(n-2)-b(n-1) pentru n>1
I
i c(n) = a(n) + b(n).
Urmtorul program calculeaz termenul c(n), n fiind introdus de la tastatur.
#include <iostream.h>

int a(int n)
{if(!n) return 1;
IC

else if (n==1) return 3;


else return 2*a(n-1)-a(n-2);}
int b(int n)
CT

{if (!n) return 4;


else if (n==1) return 2;
else return 2*b(n-2)-b(n-1);}
void main()
DA

{int n; cout<<"n= "; cin>>n; cout<<"c("<<n<<")= "<<a(n)+b(n);}


Care este adncimea recursivitii pentru apelul c(4)? Dar pentru apelul
Tem c(7)? Scriei un program prin care calculai adncimea recursivitii
DI

pentru apelul c(n). Scriei o funcie recursiv mai eficient, prin care s
reducei adncimea recursivitii.

1.2.7. Recursivitatea direct i indirect


RA

n funcie de procesele care se autoapeleaz, exist dou tipuri de recursivitate:


 recursivitatea direct
void A()
 recursivitatea indirect ..........
ITU

{
Recursivitatea direct. n acest tip de recursivitate, exist un singur ..........
proces, A, care i genereaz singur existena, pe baza unor condiii. A();
Astfel, dac n corpul unui subprogram A se ntlnete un apel al ace- ..........
luiai subprogram A, nseamn c subprogramul este direct recursiv. }
ED

Informatic 67
Recursivitatea indirect. n acest tip de recursivitate,

IC
void B();
exist dou procese, A i B, care i genereaz reciproc void A();
apariia. Astfel, dac n corpul unui subprogram A se void main(){.....}
void A()

OG
ntlnete un apel al subprogramului B, care la rndul su
apeleaz subprogramul A, nseamn c subprogramele {
sunt indirect recursive. n acest caz, trebuie s fie folosit............
obligatoriu declararea prin prototip a subprogramelor. B();
............

G
Exemplul 1 };
S se afieze termenul n din urmtoarele iruri: void B()
{

DA
an = an-1 + bn-1 ............
2 2
bn = (bn-1) - (an-1) A();
Numrul n i primii termeni, a0 i b0, se citesc de la tasta- ............
tur. Pentru n=2, a(0)=1 i b(0)=2, calculul funciilor a(2) }

PE
i b(2) se desfoar astfel:
a(1) a(0) = 1 2 2 2
a(2) b(2) [b(1)] [b(0)] = 2 = 4
6 3 + 2
0 3 =9
b(0) = 2 2 2
[a(0)] = 1 = 1
+
I
2 2
[b(0)] = 2 = 4 2
b(1) [a(1)] a(0) = 1
2
3
2 2 3 =9 +
[a(0)] = 1 = 1 b(0) = 2

#include <iostream.h>
IC

#include <math.h>
double an(int, float, float); //prototipul funciei an()
double bn(int, float, float); //prototipul funciei bn()
CT

void main()
{int n; double a,b;
cout<<"n= ";cin>>n; cout<<"a= ";cin>>a; cout<<"b= ";cin>>b;
cout<<"a("<<n<<")= "<<an(n,a,b)<<endl;
DA

cout<<"b("<<n<<")= "<<bn(n,a,b);}
double an(int n, float a, float b)
{if(!n) return a+b;
else return an(n-1,a,b)+bn(n-1,a,b);}
DI

double bn(int n, float a, float b)


{if (!n) return b*b-a*a;
else return pow(bn(n-1,a,b),2)-pow(an(n-1,a,b),2);}
RA

Exemplul 2
Se tie c un cioban are o oaie. Dup un an oaia face o mielu. Dup un an, mielua devi-
ne mioar. Dup un an, mioara devine oaie. Cte oi, mioare i mielue are ciobanul dup n
ani, presupunnd c nu moare nici un animal i c fiecare oaie face n fiecare an cte o
ITU

mielu?
n tabelul urmtor se poate observa evoluia animalelor pe parcursul anilor, considern-
du-se ca an de referin anul 0:
ED

68 Tehnici de programare

IC
anul 0 1 2 3 4 5 6 7 8 9 10
oi 1 1 1 2 3 4 6 9 13 19 28
mielue 0 1 1 1 2 3 4 6 9 13 19

OG
mioare 0 0 1 1 1 2 3 4 6 9 13
Se observ c, ntr-un an, numrul de oi este egal cu numrul de oi, plus numrul de mioa-
re din anul precedent, numrul de mioare este egal cu numrul de mielue din anul
precedent, iar numrul de mielue este egal cu numrul de oi din anul precedent. Se vor

G
folosi urmtoarele funcii: x pentru numrul de 1 pentru n=0
mielue, y pentru numrul de mioare, i z pentru z(n) =
numrul de oi. Aceste funcii sunt indirect recursive.

DA
z(n-1)+y(n-1) pentru n>0
Ele sunt definite alturat.
#include <iostream.h> 0 pentru n=0 0 pentru n=0
int x(int n); x(n) = y(n) =

PE
int y(int n); z(n-1) pentru n>0 x(n-1) pentru n>0
int z(int n);
void main()
{int n; cout<<"ani= "; cin>>n;
cout<<"Mielute= "<<x(n)<<endl; cout<<"Mioare= "<<y(n)<<endl;
I
cout<<"oi= "<<z(n);}
int x(int n) {if (n==0) return 0; else return z(n-1);}
int y(int n) {if (n==0) return 0; else return x(n-1);}
int z(int n) {if (n==0) return 1; else return z(n-1)+y(n-1);}

Afiai termenul n din urmtoarele iruri de medii aritmetico - geometrice


IC

Tem (irurile lui Gauss) numrul n i primii termeni a0 i b0 se citesc de la


tastatur (a0, b0>0): an = (an-1 + bn-1)/2 i
bn = SQRT(an-1 bn-1)
CT

Pentru rezolvarea acestei probleme, scriei dou programe: ntr-un program, implementai
algoritmul iterativ i n cellalt program, algoritmul recursiv. Artai cum se execut
programul recursiv pentru n=2, a0=4 i b0=4.
DA

1.2.8. Avantajele i dezavantajele recursivitii


Din exemplele prezentate se observ c, pentru orice algoritm recursiv folosit pentru
rezolvarea unei probleme, exist un algoritm iterativ echivalent, i invers. Problema care se
DI

pune este pe care dintre cei doi algoritmi i vei alege pentru a rezolva o problem.
Exemplul 1
x-1 pentru x12
S se calculeze valorile funciei Manna Pnuell, definit
f(x) =
RA

alturat. Definiia funciei este recursiv, i implementa-


f(f(x+2)) pentru x<12
rea ei printr-un subprogram recursiv este foarte simpl.
#include <iostream.h>
int mp(int n)
ITU

{if (n>=12) return n-1; else return mp(mp(n+2));}


void main()
{int n; cout<<"n= "; cin>>n; cout<<mp(n);}
De exemplu, dac n=8, funcia se calculeaz astfel:
ED

Informatic 69
f(8) = f(f(8+2)) = f(f(10)) = f(f(f(10+2))) = f(f(f(12))) = f(f(12-1)) = f(f(11)) = f(f(f(11+2))) = f(f(f(13))) = f(f(13-

IC
1)) = f(f(12)) = f(12-1) = f(11) = f(f(11+2)) = f(f(13)) = f(13-1) = f(12) = 12-1 = 11
iar, dac n=20, funcia se calculeaz astfel: f(20) = 20-1= 19

OG
Pentru a rezolva aceast problem cu ajutorul unui algoritm iterativ, va trebui s folosim o
structur de date de tip stiv, care va fi prezentat ulterior.

Scriei un program care implementeaz algoritmul recursiv pentru


Tem calcularea valorii funciei Ackermann definit alturat (ack: NN N)

G
De exemplu, dac m=2 i n=1, funcia se calculeaz astfel:
ack(2,1) = ack(1,ack(2,0)) = n+1 pentru m=0

DA
ack(1,ack(1,1)) = ack(1, ack(0, ack(m,n) = ack(m-1,1) pentru n=0
ack(1,0))) = ack(m-1, ack(m, n-1) pentru m,n0
= ack(1, ack(0, ack(0,1))) = = ack(1,
ack(0,2)) = ack(1,3) = ack(0, ack(1,2)) =

PE
= ack(0, ack(0, ack(1,1))) = ack(0, ack(0, ack(0, ack(1,0)))) = ack(0, ack(0, ack(0, ack(0,1)))) = =
ack(0, ack(0, ack(1,12))) = ack(0, ack(0,3)) = ack(0, 4) = 5
Exemplul 2
Fiind dat nN, n1, s se genereze toate permutrile mulimii {1, 2, 3, ..., n}.
I
Elementele unei permutri se genereaz n vectorul p. Pentru generarea tuturor per-
mutrilor vom folosi urmtorul algoritm:
Pas 1. Se genereaz permutarea de 1 element: {1 }.

Pas 2. Pornind de la permutarea de 1 element, se genereaz cele 2 permutri de 2 ele-


mente, astfel: atribuim celui de al doilea element valoarea 2, obinnd permutarea
IC

{1, 2}, i apoi interschimbm al doilea element cu primul element, obinnd permu-
tarea {2, 1}.
.......................................................................................................................................
CT

Pas n. Avnd generat o permutare cu n-1 elemente {a1, a2, ..., an-1} a mulimii {1, 2, 3, ...,
n-1}, obinem n permutri ale mulimii {1, 2, 3, ..., n-1, n} astfel:
Pas n.1. Atribuim elementului an valoarea n.
Pas n.2. Se interschimb pe rnd elementul an cu toate elementele a1, obinn-
DA

du-se cte o permutare cu n elemente.


1 2 3
Generarea permutrilor este un
proces recursiv n care o permu- 1 2 1 3 2
DI

tare cu n elemente se genereaz


pornind de la o permutare cu n-1 3 2 1
elemente, prin adugarea unui 1
nou element i interschimbarea
RA

2 1 3
valorii adugate cu toate elemen-
tele permutrii cu n-1 elemente.
2 1 2 3 1
#include <iostream.h>
ITU

unsigned n,p[10]; 3 1 2
void afiseaza ()
{for (int i=1; i<=n;i++) cout<<p[i]<<" "; cout<<endl;}
void permut(unsigned i)
ED

{unsigned j,aux;

70 Tehnici de programare

IC
if (i==n+1) afiseaza();
else {p[i]=i; for (j=1;j<=i;j++)
{aux=p[i]; p[i]=p[j]; p[j]=aux; permut(i+1);

OG
aux=p[i]; p[i]=p[j]; p[j]=aux;}}}
void main() {cout<<"n= "; cin>>n; permut(1);}

Artai cum se execut programul pentru n=4. Scriei un program prin


Tem care s implementai o soluie iterativ pentru aceast problem.

G
Exemplul 2

DA
S se genereze toate partiiile numrului natural n. O partiie a unui numr natural este o
mulime de numere naturale a cror sum este egal cu numrul n. Dou partiii sunt
diferite dac difer fie prin valori, fie prin ordinea lor. De exemplu, numrul 3 poate fi
descompus astfel: 3 = 1+1+1 = 1+2 = 2+1, i partiiile numrului 3 sunt P1 = {1, 1, 1}, P2 =

PE
{1, 2} i P3 = {2, 1}.
Partiiile numrului se genereaz n vectorul part, care se parcurge cu indicele i. Primul
termen al partiiei se genereaz n variabila j. Generarea partiiilor unui numr poate fi
descris prin urmtorul algoritm:
I
Pas 1. Se iniializeaz primul termen al partiiei j=1.
Pas 2. Se genereaz primul termen j al partiiei Pi.
Pas 3. Se revine la Pas2 pentru a genera o partiie a numrului rmas, n-j.

Pas 4. Dac numrul rmas, n-j, devine 0, se termin generarea partiiei Pi i se afieaz
partiia; altfel, se revine la Pas3.
IC

Pas 5. Se incrementeaz cu 1 primul termen al partiiei (j=j+1). Dac j>n, se termin


generarea tuturor partiiilor; altfel, se revine la Pas2.
Generarea partiiei Pi a numrului n (Pas3) poate fi descris printr-un proces recursiv, care
CT

const n generarea tuturor partiiilor numrului rmas, n-j.


#include <iostream.h>
unsigned n,part[50];
DA

void scrie(unsigned m)
{cout<<"n= "<<part[0];
for(unsigned i=1;i<m;i++) cout<<" + "<<part[i];
cout<<endl;}
DI

void partitie(unsigned i,unsigned n)


{for (unsigned j=1;j<=n;j++)
{part[i]=j; if (j<n) partitie(i+1,n-j);
RA

else scrie(i+1);}}
void main()
{cout<<"n= "; cin>>n; partitie(0,n);}
ITU

Artai cum se execut programul pentru n=4. Scriei un program prin


Tem care s implementai o soluie iterativ pentru aceast problem.
ED

Informatic 71
Observaii

IC
1. Din exemplele prezentate rezult c soluiile recursive sunt mult mai clare, mai scurte i
mai uor de urmrit. Soluia recursiv este mult mai avantajoas dect cea iterativ, n

OG
urmtoarele cazuri:
 soluiile problemei sunt definite recursiv;
 cerinele problemei sunt formulate recursiv.
n unele cazuri este foarte greu de definit o soluie iterativ, cum este cazul algoritmilor
cu recursivitate indirect, i atunci se prefer algoritmul recursiv.

G
2. Fiecare apel al unui subprogram recurent nseamn nc o zon de memorie rezervat
pentru execuia subprogramului (variabilele locale i instruciunile). Pentru o adncime

DA
mare a recursivitii, algoritmii recursivi nu mai sunt eficieni, deoarece timpul de
execuie crete, din cauza timpilor necesari pentru mecanismul de apel i pentru admi-
nistrarea stivei de sistem.
Alegerea unuia dintre cei doi algoritmi iterativ sau recursiv pentru rezolvarea unei

PE
probleme, depinde de programator, n funcie de avantajele i dezavantajele fiecruia.

I
Rspundei:
1. Care este valoarea returnat de funcia urmtoare, la apelul f(10)? Dar la apelul
f(100)? Ce realizeaz aceast funcie?

int f(int n) {if(n==0) return 0; else return f(n-1)+n;}


2. Care este valoarea returnat de funcia urmtoare, la apelul f(10)? Dar la apelul
IC

f(100)? Ce realizeaz aceast funcie?


int f(int n) {if(n<=0) return n; else return f(n-2)+n;}
3. Care este valoarea returnat de funcia urmtoare, la apelul f(5)? Ce realizeaz
CT

aceast funcie?
int f(int n) {if(n<=0) return 1; else return 2*f(n-1);}
4. Care este valoarea returnat de funcia urmtoare, la apelul f(5)? Dar la apelul f(25)?
DA

Ce realizeaz aceast funcie?


int f(int n) {if(n<=1) return 0; else return f(n-1)+ 2*n;}
5. Care este valoarea returnat de funcia urmtoare, la apelul f(10)? Dar la apelul
f(10)? Ce realizeaz aceast funcie?
DI

int f(int n)
{if(n==0) return 0;
else if(n%2==0) return f(n-1)+n; else return f(n-1)-n;}
RA

6. Care este valoarea returnat de funcia urmtoare, la apelul f(3,5)? Ce realizeaz


aceast funcie?
int f(int a,int b)
{if (b==1) return a; else return a+f(a,b-1);}
ITU

7. Care este valoarea returnat de funcia urmtoare, la apelul f(1536,2)? Ce realizeaz


aceast funcie?
int f(int n,int i)
{if (n<=i) return 1;
ED

else if(n%i==0) return 1+f(n/i,i); else return f(n,i+1);}



72 Tehnici de programare
8. Ce se va afia n urma execuiei urmtorului program, dac se citete de la tastatur 5?

IC
#include <iostream.h>
void f(int n, int i)

OG
{if(n>=1) {if (n%2==0) f(n-1,i); else f(n-1,i-1);
cout<<i<<" ";}
void main() {int n,i; cout<<"n= "; cin>>n; f(2*n,n); }
9. Ce se va afia n urma execuiei urmtorului program, dac se citete de la tastatur 10?

G
#include <iostream.h>
#include <iomanip.h>

DA
void f(int n,int i, int j)
{if (i!=n+1){cout<<"* ";
if (j==i) {cout<<endl; f(n,i+1,1);} else f(n,i,j+1);}}
void main() {int n; cout<<"n=";cin>>n; f(n,1,1);}

PE
10. Ce se va afia n urma execuiei urmtorului program, dac se citete de la tastatur 5?
#include <iostream.h>
#include <iomanip.h>
void tr(int i,int j,int n)
{if (i<=n) if(j<=i) {cout<<setw(3)<<j; tr(i,j+1,n);}
I
else {cout<<endl; tr(i+1,1,n);}}
void main() {int n; cout<<"n= "; cin>>n; tr(1,1,n);}
11. Ce se va afia n urma execuiei urmtorului program, dac se citete de la tastatur

3550? Dar dac se citete 2125? Dar dac se citete 1280? Ce realizeaz acest
program?
IC

#include <iostream.h>
int term(int n,int i)
CT

{if (i<=n) return term(n,2*i); else return i/2;}


void scrie(int n)
{if (n>5) scrie(n-term(n,5));
if (n<=5) {if (n!=0) cout<<n<<" ";}
DA

else cout<<term(n,5)<<" ";}


void main() {int n; cout<<"n= "; cin>>n; scrie(n);}
12. Fie a i n dou numere naturale. Urmtoarele 5 vari-
ante de funcii matematice definesc recursiv algoritmul a) 1 pentru n=0
n
DI

n a =
pentru calculul lui a . Implementai aceti algoritmi n-1
recursivi cu ajutorul subprogramelor. a a pentru n>0

b) 1 pentru n=0 c) 1 pentru n=0


RA

a pentru n=1 a pentru n=1


n n/2 n 2 n-2
a = (aa) pentru n par a = a a pentru n par
(n-1)/2 n-1
a (aa) pentru n impar aa pentru n impar
ITU

e) 1 pentru n=0
d) 1 pentru n=0 a pentru n=1
n n/2 2 n n/2 n/2
a = (a ) pentru n par a = a a pentru n par
n-1 (n-1)/2 (n-1)/2
aa
ED

pentru n impar a (a a ) pentru n impar



Informatic 73
Dac antetul subprogramului recursiv este:

IC
unsigned long p(unsigned a, unsigned n)
calculai, pentru fiecare dintre cele cinci exemple, adncimea recursivitii, pentru

OG
apelul p(2,10). Precizai care variant este mai eficient.
13. Implementai n limbajul de programare funciile recursive, folosind modelul urmtor,
care calculeaz i adncimea recursivitii. Executai programele i comparai valorile
afiate de program cu cele calculate la problema 12.

G
#include <iostream.h>
int f(int a, int n, int &q) //varianta a
{q++; if(n==0) return 1; else return a*f1(a,n-1,q); }

DA
void main()
{int a,n,q=0; cout<<"a="; cin>>a; cout<<"n=";cin>>n;
cout<<a<<"**"<<n<<"="<<f(a,n,q)<<endl;
cout<<"Adancimea recursivitatii= "<<q<<endl;}

PE
Adevrat sau Fals:
1. Funcia urmtoare returneaz, la apelul f(5), valoarea 11:
int f(int n)
{if (n<=1) return n; else return f(n-1)+2*f(n-2);}
I
2. Funcia urmtoare returneaz, la apelul numar(0), numrul de apariii ale unui
element precizat, x, ntr-un vector a, de numere ntregi, cu n elemente.
int numar(int i)

{if (i==n-1) return a[n-1]==x; else return a[i]==x)+numar(i+1);}


IC

Alegei:
1. Cu ce expresie trebuie completat secvena lips din funcia urmtoare, pentru ca
f(x) s returneze modulul numrului real x?
CT

float f(float x) {if (...) return x; else return f(-x);}


a. x>0 b. x>=0 c. x<0 d. x<=0
2. Cu ce expresie trebuie completat secvena lips din funcia urmtoare, pentru ca
DA

f(a,b) s returneze cel mai mare divizor comun a dou numere naturale, a i b,
folosind algoritmul lui Euclid?
float f(float a, float b)
{if (b==0) return a; else return f(...);}
DI

a. a,a/b b. b,a/b c. a,a%b d. b,a%b


3. Cu ce expresie trebuie completat secvena lips din funcia urmtoare, pentru ca
f(n,sqrt(n)) s determine dac un numr natural n este prim (dac este prim,
funcia returneaz rezultatul 1)?
RA

int f(int n, int i)


{if (i==1) return 1; else return ...;}
a. n/i!=0 && prim(n,i-1) b. n%i!=0 && prim(n,i-1)
ITU

c. n/i!=0 && prim(n,i+1) d. n%i!=0 && prim(n,i+1)


4. Cu ce expresie trebuie completat secvena lips din funcia urmtoare, pentru ca,
prin apelul f(n,q), un numr natural n, scris n baza 10, s se afieze ca numr
scris n baza q?
ED

74 Tehnici de programare

IC
void f(int n, int q)
{int cifra=n%q;
if (n>=q) f(...); cout<<cifra;}

OG
a. q/n,q b. q%n,q c. n/q,q d. n%q,q
5. Rezultatul furnizat de apelul f(9,51) este:
int f(int a, int b);
{if (a>b) return 0; else return 1+f(a,b-a);}

G
a. 1 b. 6 c. 5 d. 4
6. Funcia de la problema precedent furnizeaz:

DA
a. restul mpririi lui a la b b. ctul mpririi lui a la b
c. restul mpririi lui b la a d. ctul mpririi lui b la a
7. Cu ce expresie trebuie completat secvena lips din funcia urmtoare, pentru ca
este(n-1) s testeze dac o valoare dat, x, exist ntr-un vector a, de numere ntregi,

PE
cu n elemente (dac valoarea este gsit n vector, funcia returneaz rezultatul 1)?
int este(int i)
{if (...) return 0;
else if (a[i]==x) return 1; else return este(i-1);}
a. i==0 b. i==n-1 c. i<0 d. i>=n
I
8. Cu ce expresie trebuie completat secvena lips din funcia urmtoare, pentru ca
este(0) s testeze dac ntr-un vector a, de numere ntregi, cu n elemente, exist
cel puin un numr pozitiv (dac exist, funcia returneaz rezultatul 1)?

int este(int i)
IC

{if (...) return 0;


else if (a[i]>x) return 1; else return este(i+1);}
a. i==0 b. i==n-1 c. i<0 d. i>=n
CT

9. Programul urmtor va afia pe ecran:


int a [20]={1,2,3,4,5,6,7,8,9,10};
int f(int i, int j);
{if (i>j) return 0;
DA

else if (a==b) return a[i];


else return f(i,(i+j)/2) + f((i+j)/2+1,j);}
void main() {cout<<f(2,7); }
a. 27 b. 35 c. 33 d. 37
DI

10. Pentru funcia recursiv alturat stabilii care din-


int f(int i)
tre urmtoarele expresii are valoarea 11: {if (i<1) return 1;
a. 1+f(4) b. f(5) c. f(6) d. f(10)+1 else return 2+f(i-1);}
RA

(Bacalaureat Sesiunea iunie - iulie 2004)


11. Pentru a afia configuraia de asteriscuri de mai void proc(int i, int j)
jos cu ajutorul subprogramului recursiv proc, se {cout<<*;
utilizeaz apelul: if (i>1)
ITU

*** if (j>1) proc(i,j-1);


** else {cout<<endl;
* proc(i-1,i-1);}}
a. proc(4,3) b. proc(4,4) c. proc(3,2) d. proc(3,3)
ED

(Bacalaureat Sesiunea iunie - iulie 2004)



Informatic 75
12. Pentru definiia alturat a subprogramului

IC
void sk(unsigned int x)
sk, stabilii cte asteriscuri se afieaz la {unsigned int x;
apelul sk(6): for(i=1;i<=x/2;i++) sk(i);

OG
a. 4 b. 2 c. un numr impar d. 6 cout<<*;}
(Bacalaureat Simulare 2004)
13. Funcia recursiv suma trebuie definit astfel long suma(long i)
nct apelul suma(n) s returneze suma {if (i==0) return 0;

G
ptratelor perfecte mai mici sau egale cu n. else {long j=sqrt(i);
Care este expresia cu care trebuie comple- return ...;}}
tat definiia funciei?

DA
a. j*j+suma(j*j-1) b. j+suma(j*j-1)
c. j*j+suma(j) d. j*j+suma(j-1)
(Bacalaureat Sesiunea iunie - iulie 2003)

PE
14. Funcia prim(int i) returneaz valoa- int max(int i)
rea 1 dac i este numr prim i valoarea {//1 nu este numar prim
0 n caz contrar. Funcia recursiv max if (i<2) return 0;
trebuie definit astfel nct apelul else if (prim(i)) return i;
else return ...;}
max(n) s returneze cel mai mare
I
numr prim mai mic sau egal cu n sau valoarea 0 n caz c nu exist un astfel de
numr. Care este expresia cu care trebuie completat definiia funciei?
a. i-1 b. 1+max(i-1) c. prim(i-1) d. max(i-1)

(Bacalaureat Sesiunea special 2003)


Miniproiecte:
IC

Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:


a. implementarea iterativ i recursiv a subprogramelor;
CT

b. explicarea noiunilor teoretice folosite pentru realizarea subprogramelor recursive;


c. avantajele i dezavantajele fiecrei implementri.
1. Scriei un subprogram care s calculeze combinri de n luate cte k C(n.k)
definite prin funciile recursive:
DA

 C(n,k) = C(n-1,k)+ C(n-1,k-1), cu C(n,0) = C(n,n) = 1 i C(n,1) = n


 C(n,k) =((n-k+1)/k)*C(n,k-1), cu C(n,0) = 1
Calculai, pentru fiecare dintre subprogramele recursive, adncimea recursivitii,
pentru C(5,2). Care dintre implementri este mai eficient?
DI

2. Se citete de la tastatur un numr natural n. Scriei un subprogram care genereaz


i afieaz toate permutrile circulare ale mulimii X= {1, 2, 3, ..., n}.
3. Scriei un subprogram care s calculeze valoarea unui polinom de gradul n, cu
RA

coeficieni ntregi, ntr-un punct real x. Gradul polinomului, coeficienii lui i valoarea
lui x se citesc de la tastatur.
4. Se citesc trei numere ntregi, a, b i c, care reprezint coeficienii unei ecuaii de gradul
2, i un numr natural n. S se calculeze Sn=x1n+x2n, unde x1 i x2 sunt rdcinile
ITU

ecuaiei. Suma se calculeaz fr a se rezolva ecuaia de gradul 2.


5. Scriei un program care s afieze termenul n din urmtoarele iruri, cu a0 = b0 = 1 :
an = an-1 + bn-1
bn = an-1 - bn-1
Calculai adncimea recursivitii pentru apelurile a(10), b(10), a(11), b(11),
ED

a(n) i b(n).

76 Tehnici de programare
6. S se verifice dac un numr n este superprim. Un numr este superprim dac

IC
toate prefixele sale sunt numere superprime (de exemplu, numrul 171 este
superprim, deoarece toate prefixele sale 1, 17 i 171 sunt numere prime). Vor fi

OG
implementate recursiv att subprogramul care testeaz dac un numr este prim, ct
i subprogramul care extrage toate prefixele numrului.
7. S se genereze toate numerele superprime dintr-un interval [a,b] (valorile pentru a
i b se citesc de la tastatur).
8. S se genereze toate numerele binare cu n cifre care au m cifre de 0 i restul cifrelor

G
1. Valorile pentru n i m se citesc de la tastatur. Combinaiile posibile de m cifre de 0
i n-m cifre de 1 se vor genera recursiv. Din mulimea de combinaii posibile se vor

DA
alege numai acelea care pot forma un numr cu n cifre.
9. S se genereze toate submulimile mulimii {1, 2, 3, ..., n}. Mulimile generate sunt
Ak = {ak1, ak2, ak3, ..., aki}, cu i care poate lua valori de la 1 la n, i ak1<ak2<ak3< ... <aki. De
exemplu, pentru n=3 submulimile sunt: {1}, {1, 2}, {1, 3}, {1, 2, 3}, {2}, {2, 3} i {3}.

PE
Indicaie. Elementele submulimii Ak se genereaz n vectorul a, care se parcurge cu
indicele i. Elementul curent al unei submulimi se genereaz n variabila j. Generarea
submulimii Ak ncepe cu alegerea primului element, ak1, i generarea apoi a submulimii {ak2,
ak3, ..., aki}. Pentru generarea acestei submulimi, se procedeaz ca i pentru submulimea Ak.
Aadar, generarea submulimilor poate fi descris printr-un proces recursiv: se alege pe rnd
I
o valoare j pentru ak1 ncepnd cu prima valoare (1) pn la ultima valoare (n). Pentru
fiecare valoare aleas pentru j, se obine o mulime cu un element. Pornind de la fiecare
dintre aceste submulimi, se genereaz recursiv noi submulimi, prin adugarea a cte unui

nou element, ncepnd cu elementul cu valoarea j+1. Generarea recursiv a acestui grup de
submulimi se termin atunci cnd s-a adugat elementul cu valoarea n.
IC

*
10. S se genereze partiiile mulimii X= {1, 2, 3, ..., n}, cu nN . O partiie a mulimii X se
formeaz prin descompunerea mulimii ntr-o reuniune de mulimi disjuncte: X = X1
*
X2 ... Xi, unde iN i i n. Mulimile Xi au proprietile:
CT

*
 XiX, pentru i, iN , i n, i
*
 Xj Xk = , pentru j i k N , j i, k i i jk.
Indicaie. Din definiia partiiei unei mulimi rezult c un element k se poate gsi numai
DA

ntr-o submulime Xi. Partiiile pot fi codificate ntr-un vector p, ale crui elemente pk
reprezint indicele i al submulimii Xj din care face parte elementul k. Elementul 1 apare
ntotdeauna numai n X1, elementul 2 apare ntotdeauna numai n X1 i X2, ..., elementul k
apare ntotdeauna numai n X1,
partiiile mulimii X= {1, 2, 3} vectorul p
DI

X2, ... i Xk. Generarea unei partiii


nseamn de fapt generarea unui p1 p2 p3
set de valori pentru vectorul p. De {1, 2, 3} X= X1 1 1 1
exemplu, pentru X= {1, 2, 3} {1, 2}{ 3} X= X1 X2 1 1 2
RA

partiiile sunt cele prezentate n {1, 3}{ 2} X= X1 X2 1 2 1


tabelul alturat. {1}{2, 3} X= X1 X2 1 2 2
{1}{2}{3} X= X1 X2 X3 1 2 3
ITU
ED

Informatic 77

IC
1.3. Analiza algoritmilor

OG
Prin analiza unui algoritm se identific resursele necesare pentru executarea
algoritmului: timpul de execuie i memoria.
Analiza algoritmilor este necesar atunci cnd exist mai muli algoritmi pentru rezolvarea
aceleiai probleme i trebuie ales algoritmul cel mai eficient.

G
Eficiena unui algoritm este evaluat prin timpul necesar pentru executarea
algoritmului.

DA
Pentru a compara din punct de vedere al eficienei doi algoritmi care rezolv aceeai
problem, se folosete aceeai dimensiune a datelor de intrare n (acelai numr de
valori pentru datele de intrare).

PE
Timpul de execuie al algoritmului se exprim prin numrul de operaii de baz
executate n funcie de dimensiunea datelor de intrare: T(n).
Pentru a compara doi algoritmi din punct de vedere al timpului de execuie, trebuie s se stabi-
leasc unitatea de msur care se va folosi, adic operaia de baz executat n cadrul algorit-
I
milor, dup care, se numr de cte ori se execut operaia de baz n cazul fiecrui algoritm.

Operaia de baz este o operaie elementar sau o succesiune de operaii


elementare a cror execuie nu depinde de valorile datelor de intrare.

Exist algoritmi la care timpul de execuie depinde de distribuia datelor de intrare. S


IC

considerm doi algoritmi de sortare a unui vector cu n elemente algoritmul de sortare


prin metoda seleciei directe i algoritmul de sortare prin metoda bulelor i ca operaie
de baz comparaia. Dac, n cazul primului algoritm, timpul de execuie nu depinde de
CT

distribuia datelor de intrare (modul n care sunt aranjate elementele vectorului nainte de
n (n 1)
sortarea lui), el fiind T(n) = , n cazul celui de al doilea algoritm, timpul de exe-
2
cuie depinde de distribuia datelor de intrare (numrul de execuii ale structurii repetitive
DA

while depinde de modul n care sunt aranjate elementele vectorului nainte de sortare). n
cazul n care numrul de execuii ale operaiilor elementare depinde de distribuia datelor
de intrare, pentru analiza algoritmului se folosesc:
 timpul maxim de execuie timpul de execuie pentru cazul cel mai nefavorabil de
DI

distribuie a datelor de intrare; n cazul sortrii prin metoda bulelor, cazul cel mai
nefavorabil este atunci cnd elementele vectorului sunt aranjate n ordine invers
dect aceea cerut de criteriul de sortare;
 timpul mediu de execuie media timpilor de execuie pentru fiecare caz de distri-
RA

buie a datelor de intrare.


Deoarece, n analiza eficienei unui algoritm, se urmrete comportamentul lui pentru o
dimensiune mare a datelor de intrare, pentru a compara doi algoritmi, din punct de vedere
ITU

al eficienei, este suficient s se ia n considerare numai factorul care determin timpul de


execuie i care este denumit ordinul de complexitate.
Ordinul de complexitate al unui algoritm l reprezint timpul de execuie estimat
prin ordinul de mrime al numrului de execuii ale operaiei de baz: O(f(n)), unde
ED

f(n) reprezint termenul determinant al timpului de execuie, T(n).



78 Tehnici de programare
De exemplu, dac, pentru algoritmul de sortare prin metoda seleciei directe, timpul de

IC
2
execuie este T(n )= n (n 1) = n n , ordinul de complexitate al algoritmului este O(n ),
2
2 2 2

OG
deoarece n calcularea lui se ia n considerare numai factorul determinant din timpul de
execuie.
n funcie de ordinul de complexitate, exist urmtoarele tipuri de algoritmi:
Ordin de Tipul algoritmului

G
complexitate
O(n) Algoritm liniar.

DA
m Algoritm polinomial. Dac m=2, algoritmul este ptratic, iar dac
O(n )
m=3, algoritmul este cubic.
n n
Algoritm exponenial. De exemplu, 2 , 3 etc. Algoritmul de tip O(n!)
n
O(k ) este tot de tip exponenial, deoarece:
n-1

PE
1234...n > 222...2 = 2 .
O(logn) Algoritm logaritmic.
O(nlogn) Algoritm liniar logaritmic.
De exemplu, algoritmul de sortare prin metoda seleciei directe este un algoritm ptratic.
I
Ordinul de complexitate este determinat de structurile repetitive care se execut cu muli-
mea de valori pentru datele de intrare. n cazul structurilor repetitive imbricate, ordinul de
complexitate este dat de produsul dintre numrul de repetiii ale fiecrei structuri repetitive.

Structura repetitiv Numrul de execuii ale Tipul


corpului structurii algoritmului
IC

for (i=1;i<=n;i=i+k) {....} f(n)=n/k O(n)=n Liniar


for (i=1;i<=n;i=i*k) {....} f(n)= logkn O(n)= logn Logaritmic
for (i=n;i>=n;i=i/k) {....} f(n)= logkn O(n)= logn Logaritmic
CT

for (i=n;i<=n;i=i+p) {....} f(n)=(n/p)*(n/q) = n2/(p*q) Polinomial


for (j=n; j<=n;j=j+q) {....} O(n)= n2 ptratic
for (i=n;i<=n;i=i++) {....} f(n)=1+2+3+ ... +n =(n*(n+1))/2 Polinomial
for (j=i; j<=n;j=j++) {....} O(n)= n2 ptratic
DA

Determinai complexitatea urmtorilor algoritmi i precizai tipul algoritmului.


Tem Pentru fiecare algoritm se va considera dimensiunea datelor de intrare n.
a. determinarea valorii minime dintr-un ir de numere;
DI

b. inserarea unui element ntr-un vector, dup un element cu valoare precizat;


c. tergerea dintr-un vector a unui element cu valoare precizat;
d. stabilirea dac un ir de numere conine numai numere distincte;
e. sortarea unui vector folosind metoda bulelor;
RA

f. cutarea unui element cu valoare precizat, ntr-un vector nesortat;


g. cutarea unui element cu valoare precizat, ntr-un vector sortat;
h. determinarea tuturor permutrilor unei mulimi de numere.
ITU
ED

Informatic 79

IC
1.4. Metode de construire a algoritmilor
n funcie de procesul de calcul necesar pentru rezolvarea unei probleme, exist urmtoarele
clase de probleme:

OG
Clase de probleme

Probleme de enumerare Probleme de decizie Probleme de optimizare

G
prin care se gsesc toate prin care se precizeaz dac prin care se identific soluia
soluiile posibile exist, sau nu, cel puin o optim, din mulimea de

DA
soluie soluii posibile

Generarea tuturor permutrilor unei mulimi de numere este o problem de enumerare, cuta-
rea unei valori precizate ntr-un ir de numere este o problem de decizie, iar gsirea moda-

PE
litii de plat a unei sume s cu un numr minim de bancnote de valori date este o problem de
optimizare.
Pentru rezolvarea unei aceleiai probleme se pot folosi mai multe metode de construire a
algoritmilor. Ai nvat deja c, pentru rezolvarea unei aceleiai probleme, putei folosi un:
 algoritm iterativ;
I
 algoritm recursiv.
Soluiile recursive sunt mult mai clare, mai scurte i mai uor de urmrit. Alegerea

algoritmului recursiv n locul celui iterativ este mai avantajoas n cazul n care soluiile
problemei sunt definite recursiv sau dac cerinele problemei sunt formulate recursiv.
IC

Timpul de execuie al unui algoritm recursiv este dat de (1) pentru n=0
o formul recursiv. De exemplu, pentru algoritmul de T(n) =
calculare a sumei primelor n numere naturale, funcia (1)+T(n-1) pentru n0
CT

pentru timpul de execuie este prezentat alturat, unde


(1) reprezint timpul de execuie al unei operaii elementare de atribuire a unei valori
sumei. Rezult c T(n)=(n+1)(1), iar ordinul de complexitate al algoritmului este O(n),
la fel ca i cel al algoritmului iterativ. n cazul implementrii recursive, fiecare apel al unui
DA

subprogram recurent nseamn nc o zon de memorie rezervat pentru execuia sub-


programului (variabilele locale i instruciunile). Din aceast cauz, n alegerea ntre un
algoritm iterativ i un algoritm recursiv trebuie inut cont nu numai de ordinul de complexi-
tate, dar i de faptul c, pentru o adncime mare a recursivitii, algoritmii recursivi nu
DI

mai sunt eficieni, deoarece timpul de execuie crete, din cauza timpilor necesari pentru
mecanismul de apel i pentru administrarea stivei de sistem.
Vei nva noi metode de construire a algoritmilor care v ofer avantajul c prezint
RA

fiecare o metod general de rezolvare care se poate aplica unei clase de probleme:
 metoda backtracking;
 metoda divide et impera.
Fiecare dintre aceste metode de construire a algoritmilor se poate folosi pentru anumite clase
ITU

de probleme, iar n cazul n care pentru o aceeai clas de probleme se pot folosi mai
multe metode de construire a algoritmilor, criteriul de alegere va fi eficiena algoritmului.
ED

80 Tehnici de programare

IC
1.5. Metoda backtracking
1.5.1. Descrierea metodei backtracking

OG
Metoda backtracking se poate folosi pentru problemele n care trebuie s se genereze toate
soluiile, o soluie a problemei putnd fi dat de un vector:
S = {x1, x2, , xn}
ale crui elemente aparin, fiecare, unor mulimi finite Ai (xiAi), iar asupra elementelor

G
unei soluii exist anumite restricii, specifice problemei care trebuie rezolvat, numite
condiii interne. Mulimile Ai sunt mulimi ale cror elemente sunt n relaii bine stabilite.

DA
Mulimile Ai pot s coincid sau nu. Pentru a gsi toate soluiile unei astfel de probleme
folosind o metod clasic de rezolvare, se execut urmtorul algoritm:
PAS1. Se genereaz toate elementele produsului cartezian A1 x A2 x A3 x x An.
PAS2. Se verific fiecare element al produsului cartezian, dac ndeplinete condiiile

PE
interne impuse ca s fie soluie a problemei.

Scop: identificarea problemelor pentru care trebuie enumerate toate soluiile, fiecare
I
soluie fiind format din n elemente xi, care aparin fiecare unor mulimi finite Ai i care
trebuie s respecte anumite condiii interne.
Enunul problemei 1: S se genereze toate permutrile mulimii {1, 2, 3}.

Cerina este de a enumera toate posibilitile de generare a 3 numere naturale din muli-
mea {1,2,3}, astfel nct numerele generate s fie distincte (condiia intern a soluiei). O
IC

soluie a acestei probleme va fi un vector cu 3 elemente, S = {x1,x2,x3}, n care elementul


xi reprezint numrul care se va gsi, n permutare, pe poziia i, iar mulimea Ai reprezint
mulimea numerelor din care se va alege un numr pentru poziia i. n acest exemplu
CT

mulimile Ai coincid. Ele au aceleai 3 elemente, fiecare element reprezentnd un numr.


Ai = {1, 2, 3} = A
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 x A2 x A3 = A x A x A = A3, adic mulimea:
DA

{(1,1,1), (1,1,2), (1,1,3), (1,2,1), , (3,3,2), (3,3,3)}


dup care, se va verifica fiecare element al mulimii dac este o soluie a problemei,
adic dac cele trei numere dintr-o soluie sunt distincte. Soluiile obinute sunt:
DI

{(1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1)}


Enunul problemei 2: S se genereze toate aranjamentele de 2 elemente ale mulimii {1, 2, 3}.
Cerina este de a enumera toate posibilitile de generare a 2 numere naturale, din
RA

mulimea {1,2,3}, astfel nct numerele generate s fie distincte (condiia intern a solu-
iei). O soluie a acestei probleme va fi un vector cu 2 elemente, S = {x1,x2}, n care
elementul xi reprezint numrul care se va gsi, n aranjament, pe poziia i, iar mulimea Ai
reprezint mulimea numerelor din care se va alege un numr pentru poziia i. i n acest
ITU

exemplu, mulimile Ai coincid. Ele au aceleai 3 elemente, fiecare element reprezentnd un


numr. Ai = {1, 2, 3} = A
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 x A2 = A x A = A2, adic mulimea:
{(1,1), (1, 2), (1,3), (2,1), , (3,2), (3,3)}
ED

Informatic 81
dup care se va verifica fiecare element al mulimii, dac este o soluie a problemei,

IC
adic dac cele dou numere dintr-o soluie sunt distincte. Soluiile obinute sunt:
{(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)}

OG
Enunul problemei 3: S se genereze toate combinrile de 2 elemente ale mulimii {1, 2, 3}.
Cerina este de a enumera toate posibilitile de generare a 2 numere naturale din muli-
mea {1,2,3}, astfel nct numerele generate s fie distincte (condiia intern a soluiei),
iar soluiile obinute s fie distincte. Dou soluii sunt considerate distincte dac nu conin

G
aceleai numere. O soluie a acestei probleme va fi un vector cu 2 elemente, S = {x1,x2},
n care elementul xi reprezint numrul care se va gsi n combinare pe poziia i, iar muli-
mea Ai reprezint mulimea numerelor din care se va alege un numr pentru poziia i. i n

DA
acest exemplu, mulimile Ai coincid. Ele au aceleai 3 elemente, fiecare element repre-
zentnd un numr. Ai = {1, 2, 3} = A
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 x A2 = A x A = A2, adic mulimea:

PE
{(1,1), (1, 2), (1,3), (2,1), , (3,2), (3,3)}
dup care, se va verifica fiecare element al mulimii, dac este o soluie a problemei,
adic dac cele dou numere dintr-o soluie sunt distincte i dac soluia obinut este
distinct de soluiile obinute anterior. Soluiile obinute sunt: {(1,2), (1,3), (2,3)}
I
Enunul problemei 4: S se genereze toate permutrile mulimii {1,2,3,4} care ndeplinesc
condiia c 1 nu este vecin cu 3, i 2 nu este vecin cu 4.
Cerina este de a enumera toate posibilitile de generare a 4 numere naturale, din

mulimea {1,2,3,4}, astfel nct numerele generate s fie distincte, iar 1 s nu se nvecineze
cu 3, i 2 s nu se nvecineze cu 4 (condiia intern a soluiei). O soluie a acestei proble-
IC

me va fi un vector cu 4 elemente, S = {x1,x2,x3,x4}, n care elementul xi reprezint numrul


care se va gsi n permutare pe poziia i, iar mulimea Ai reprezint mulimea numerelor din
care se va alege un numr pentru poziia i. n acest exemplu, mulimile Ai coincid. Ele au
CT

aceleai 4 elemente, fiecare element reprezentnd un numr: Ai = {1, 2, 3, 4} = A


Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele
produsului cartezian A1 x A2 x A3 x A4 = A x A x A x A = A4, adic mulimea:
DA

{(1,1,1,1), (1,1,1,2), (1,1,1,3), (1,1,1,4), , (4,4,4,3), (4,4,4,4)}


dup care se va verifica fiecare element al mulimii, dac este o soluie a problemei,
adic dac cele patru numere dintr-o soluie sunt distincte, i dac 1 nu se nvecineaz
cu 3, iar 2 cu 4. Soluiile obinute sunt:
DI

{(1,2,3,4), (1,4,3,2), (2,1,4,3), (2,3,4,1), (3,2,1,4), (3,4,1,2), (4,1,2,3), (4,3,2,1)}


Enunul problemei 5: S se aranjeze, pe tabla de ah, opt dame care nu se atac ntre
ele (problema celor 8 dame).
RA

Cerina este de a enumera toate posibilitile de aranjare a 8 dame, pe o tabl de ah cu


dimensiunea 8x8 (8 linii i 8 coloane), astfel nct toate cele 8 dame s nu se atace ntre ele
(condiia intern a soluiei). Deoarece nu se pot aranja dou dame pe aceeai coloan (s-ar
ataca ntre ele), nseamn c pe fiecare coloan a tablei de ah se va pune o dam. O soluie
ITU

a acestei probleme va fi un vector cu 8 elemente, S = {x1,x2,x3,x4,x5,x6,x7,x8}, n care


elementul xi reprezint numrul liniei pe care se va pune dama n coloana i, iar mulimea Ai
reprezint mulimea liniilor pe care se poate aranja dama din coloana i. i n acest caz
mulimile Ai coincid. Ele au aceleai opt elemente, fiecare element reprezentnd un numr
de linie: Ai = {1, 2, 3, 4, 5, 6, 7, 8} = A
ED

82 Tehnici de programare
Dac s-ar rezolva clasic aceast problem, ar nsemna s se genereze toate elementele

IC
produsului cartezian A1 x A2 x A3 x ... x A8 = A x A x A x x A = A8, adic mulimea:
{(1,1,1,1,1,1,1,1), (1,1,1,1,1,1,1,2), (1,1,1,1,1,1,1,3), ,(8,8,8,8,8,8,8,7), (8,8,8,8,8,8,8,8)}

OG
dup care se va verifica fiecare element al mulimii, dac este o soluie a problemei, adi-
c dac cele opt numere dintr-o soluie pot reprezenta coloanele pe care pot fi aranjate
damele, pe fiecare linie, astfel nct s nu se atace ntre ele. Soluiile obinute sunt:
{(1,5,8,6,3,7,2,4), (1,6,8,3,7,4,2,5), (1,7,4,6,8,2,5,3), , (8,3,1,6,2,5,7,4),
(8,4,1,3,6,2,7,5)}

G
Observaie. Metoda clasic de rezolvare a acestui tip de probleme necesit foarte multe
operaii din partea calculatorului, pentru a verifica fiecare element al produsului cartezian.

DA
Presupunnd (pentru simplificare) c fiecare mulime Ai are m elemente, atunci algoritmul de
generare a elementelor produsului cartezian are complexitatea O(card(A1) card(A2)
n
card(An)) = Q(m m m m) = O(m ). Considernd c algoritmul prin care se verific
dac un element al produsului cartezian este o soluie a problemei (respect condiia intern

PE
a soluiei) are complexitatea O(p), atunci complexitatea algoritmului de rezolvare a
n
problemei va fi O(pm ). De exemplu, n algoritmul de generare a permutrilor, complexitatea
algoritmului de verificare a condiiei interne este dat de complexitatea algoritmului prin care se
verific dac numerele dintr-un ir sunt distincte. n acest algoritm, se parcurge irul de m
numere i, pentru fiecare numr din ir, se parcurge din nou irul, pentru a verifica dac
I
acel numr mai exist n ir. Complexitatea algoritmului este dat de cele dou structuri
2 2
for imbricate: O(m ) p = m .
Metoda recomandat pentru acest gen de probleme este metoda backtracking sau meto-

da cutrii cu revenire, prin care se reduce volumul operaiilor de gsire a tuturor soluiilor.
IC

Metoda backtracking construiete progresiv vectorul soluiei, pornind de la


primul element i adugnd la vector urmtoarele elemente cu revenire la
elementul anterior din vector n caz de insucces. Elementul care trebuie adugat
CT

se caut n mulime, printre elementele care respect condiiile interne.


Prin metoda backtracking se obin toate soluiile problemei, dac ele exist. Pentru
exemplificarea modului n care sunt construite soluiile, considerm problema generrii
DA

permutrilor mulimii {1, 2, 3, , n} (A1=A2= =An=A={1, 2, 3, , n}).


PAS1. Se alege primul element al soluiei ca fiind primul element din mulimea A. n
exemplu, x1=1, adic primul numr din permutare este 1.
PAS2. Se caut al doilea element al soluiei (x2). Pentru a-l gsi, se parcurg pe rnd ele-
DI

mentele mulimii A i, pentru fiecare element i al mulimii, se verific dac respect


condiiile interne. Cutarea continu pn cnd se gsete primul element din
mulimea A care ndeplinete condiia intern, dup care se oprete. n exemplu, se
caut numrul de pe a doua poziie a permutrii, verificndu-se dac al doilea numr
RA

din permutare este diferit de primul numr (se parcurg primele dou elemente ale
mulimii A). Se gsete elementul x2=2, dup care procesul de cutare se oprete.
PAS3. Se caut al treilea element al soluiei (x3). Cutarea va folosi acelai algoritm de
la Pasul 2. n exemplu, se caut numrul din poziia a treia din permutare. Se
ITU

gsete elementul x3=3.


PAS4. Presupunnd c s-au gsit primele k elemente ale soluiei, x1, x2, x3, , xk, se
trece la cutarea celui de al k+1-lea element al soluiei, xk+1. Cutarea se va face
astfel: se atribuie, pe rnd, lui xk+1, elementele mulimii A, pn se gsete
ED

primul element i care ndeplinete condiia intern. n exemplu, condiia intern



Informatic 83
este ca numrul din poziia k+1 a permutrii s nu fie egal cu nici unul dintre

IC
numerele din poziiile anterioare lui k+1. Pot s apar dou situaii:
a. Exist un element i, n mulimea A, astfel nct xk+1 = i s fie element al soluiei

OG
problemei. n acest caz, se atribuie elementului xk+1 al soluiei valoarea i, dup
care se verific dac s-a gsit soluia problemei. n exemplu, presupunem c pe
nivelul k+1 s-a gsit numrul 4. Se verific dac s-au generat toate cele n
elemente ale mulimii S, adic dac s-au gsit numere pentru toate cele n poziii
din permutare (k=n). Dac s-a gsit soluia problemei, atunci se afieaz soluia;

G
altfel, se caut urmtorul element al soluiei, relundu-se operaiile de la Pasul 4.
b. S-au parcurs toate elementele mulimii A i nu s-a gsit nici un element i care s
fie elementul xk+1 al soluiei problemei. nseamn c trebuie s revenim la

DA
elementul k al soluiei xk. Aadar, se consider generate primele k-1 elemente ale
soluiei: x1, x2, , xk-1 i, pentru elementul xk al soluiei, se reia cutarea cu
urmtorul element din mulimea A, adic se reiau operaiile de la Pasul 4 pentru

PE
elementul xk al soluiei, ns nu cu primul element din mulimea A, ci cu elementul
din muli-mea A care se gsete imediat dup cel care a fost atribuit anterior pentru
elemen-tul xk al soluiei. n exemplu, lund n considerare modul n care au fost
generate primele k numere ale permutrii, n poziia k+1 orice numr s-ar alege, el
mai exist pe una dintre cele k poziii anterioare i se revine la elementul k, care
I
presupu-nem c are valoarea 3. Se genereaz n aceast poziie urmtorul numr
din muli-mea A (4) i se verific dac el nu mai exist pe primele k-1 poziii ale
permutrii, iar dac exist, se genereaz urmtorul element din mulimea A (5)
.a.m.d.

PAS5. Algoritmul se ncheie dup ce au fost parcurse toate elementele mulimii A pentru
elementul x1 al soluiei. n exemplu, algoritmul se ncheie dup ce s-au atribuit,
IC

pe rnd, valorile 1, 2, , n, elementului de pe prima poziie a permutrii.


Generarea tuturor permutrilor mulimii {1, 2, 3}
1 2 3 3 12 2 3
CT

12 2 2 2 3 3 3 3 1
1 1 1 1 1 1 1 1 2 2

1 2 3 3 1 1 23
DA

1 1 1 23 3 3 3 1
2 2 2 2 2 2 2 3 3

12 2 3 1 1 23 Au fost parcurse
DI

1 1 1 2 2 2 2 3 toate elementele
mulimii A, pen-
3 3 3 3 3 3 3
tru elementul x1 al soluiei.
RA

Observaie. n metoda backtracking, dac s-a gsit elementul xk al soluiei, elementului


xk+1 al soluiei i se atribuie o valoare numai dac mai exist o valoare care s ndepli-
neasc condiia de continuare a construirii soluiei adic dac, prin atribuirea acelei
valori, se poate ajunge la o soluie final pentru care condiiile interne sunt ndeplinite.
ITU

Desenai diagramele pentru generarea prin metoda backtracking a:


Tem a. tuturor aranjamentelor de 2 elemente ale mulimii {1, 2, 3};
b. tuturor combinrilor de 2 elemente ale mulimii {1, 2, 3};
c. tuturor permutrilor mulimii {1,2,3,4} care ndeplinesc condiia c 1 nu este vecin cu 3, i 2
nu este vecin cu 4.
ED

84 Tehnici de programare
Algoritmul metodei backtracking poate fi generalizat pentru orice problem care ndepli-

IC
nete urmtoarele condiii:
1. Soluia problemei poate fi pus sub forma unui vector S = {x1, x2, , xn}, ale crui
elemente xi aparin, fiecare, unei mulimi Ai, astfel: x1A1, x2A2, , xnAn.

OG
2. Mulimile Ai sunt finite iar elementele lor sunt numere ntregi i se gsesc ntr-o
ordine bine stabilit.
Algoritmul backtracking este urmtorul:
PAS1. Se alege primul element al soluiei S: x1Ai.

G
PAS2. Ct timp nu au fost parcurse toate elementele mulimii A1 (nu au fost gsite toate
soluiile) execut:

DA
PAS3. Pentru fiecare element al soluiei execut:
PAS4. Se presupune c s-au gsit primele k elemente ale soluiei (x1, x2, , xk)
aparinnd mulimilor A1, A2, A3, , Ak, i se trece la cutarea celui de al
k+1-lea element al soluiei, xk+1, printre elementele mulimii Ak+1. Cutarea

PE
se va face astfel: se atribuie, pe rnd, lui xk+1, elementele mulimii Ak+1,
pn se gsete primul element care ndeplinete condiia de continuare.
PAS5. Dac exist un element ai, n mulimea Ak+1, astfel nct xk+1 = ai s
aparin soluiei problemei, atunci se atribuie elementului xk+1 valoa-
I
rea ai i se trece la Pasul 7; altfel, se trece la Pasul 6.
PAS6. Deoarece s-au parcurs toate elementele mulimii Ak+1 i nu s-a gsit
nici un element ai care s ndeplineasc condiia de continuare, se
revine la elementul xk i se consider generate primele k-1 elemente

ale soluiei, x1, x2, , xk-1, i pentru elementul xk se reia cutarea cu


urmtorul element din mulimea Ak, adic se reiau operaiile de la
IC

Pasul 4, pentru elementul xk al soluiei, ns nu cu primul element din


mulimea Ak ci cu elementul din mulimea Ak care se gsete imediat
dup cel care a fost atribuit anterior elementului xk.
CT

PAS7. Se verific dac s-a gsit soluia problemei, adic dac s-au gsit
toate elementele mulimii S. Dac s-a gsit soluia problemei, atunci
se afieaz soluia; altfel, se trece la cutarea urmtorului element al
soluiei, relundu-se operaiile de la Pasul 4.
DA

1.5.2. Implementarea metodei backtracking


Pentru implementarea metodei se folosesc urmtoarele structuri de date i subprograme.
DI

Date i structuri de date


Pentru a memora elementele xk ale soluiei se folosete o structur de date de tip vector.
Pentru indicele elementului care se adaug la soluie se folosete variabila k. Cnd s-a gsit
RA

elementul xk al soluiei, se trece la pasul urmtor, prin incrementarea indicelui cu 1 (k++),


pentru a cuta elementul xk+1 al soluiei, iar pentru a reveni la elementul xk-1 al soluiei se
decrementeaz indicele cu 1 (k--). Iniial, vectorul va avea dimensiunea 1 (kmin=1),
corespunztoare poziiei de pornire, i va conine valoarea primului element al soluiei. Pentru
ITU

elementul xk al soluiei se va atribui o valoare din mulimea Ak care poate fi un element al


soluiei: s[k]=a[i]. Dup parcurgerea complet a mulimilor Ak, vectorul va avea dimensiunea
n (kmax=n), corespunztoare numrului de elemente ale soluiei. Indicele vectorului va fi iniial
1, la gsirea unei soluii va avea valoarea n, iar la terminarea algoritmului indicele va avea
ED

valoarea 0. Ne putem nchipui vectorul soluie ca o construcie pe vertical, n care fiecare



Informatic 85
element k al soluiei reprezint un nivel k care se adaug la aceast construcie. Soluia se

IC
construiete de la nivelul 1 pn la nivelul n.
Se mai folosesc urmtoarele variabile de memorie:

OG
 as pentru a ti dac pentru elementul xk al soluiei mai exist un succesor, adic dac mai
exist un element n mulimea Ak care ar putea fi elementul xk al soluiei (este o variabil
logic ce are valoarea 1 true, dac exist succesor; altfel, are valoarea 0 false);
 ev pentru a ti dac succesorul gsit respect condiia de continuare i poate fi
elementul xk al soluiei (este o variabil logic ce are valoarea 1 true, dac

G
succesorul este element al soluiei; altfel, are valoarea 0 false) i
 n pentru dimensiunea soluiei (numrul de elemente ale soluiei, n cazul

DA
problemelor n care toate soluiile au acelai numr de elemente).
int s[100]; //s=vectorul soluie
int n,k,ev,as; //k=indicele vectorului soluie

PE
Pentru simplificarea implementrii, toate aceste date i structuri de date sunt declarate
globale deoarece valoarea indicelui elementului care se adaug la soluie se va transmite
mai uor ntre subprograme ca variabil global.
Subprograme
I
Algoritmul va fi implementat prin:
 un subprogram, care va fi acelai pentru toi algoritmii de rezolvare prin metoda back-
tracking (parte fix) i care descrie strategia general backtracking i
 subprograme care au aceeai semnificaie pentru toi algoritmii, dar al cror coninut

difer de la o problem la alta, depinznd de condiiile interne ale soluiei.


Semnificaia subprogramelor folosite este (se va considera ca exemplu generarea per-
IC

mutrilor mulimii {1, 2, 3, , n}):


 Subprogramul init (funcie procedural). Se iniializeaz elementul care urmeaz s
CT

se adauge la soluie (elementul de pe nivelul k). Acest element se iniializeaz cu o


valoare care nu face parte din mulimea Ak considerat, urmnd ca n urmtorul pas al
algoritmului s se atribuie acestui element prima valoare din mulimea Ak. n exemplu,
elementul k al vectorului se va iniializa cu valoarea 0 (s[k]=0), urmnd ca la pasul
DA

urmtor s i se atribuie ca valoare 1, adic primul numr din mulimea {1, 2, 3, ..., n}.
void init()
{s[k]=0;}
 Subprogramul succesor (funcie operand). Verific dac mai exist n mulimea Ak
DI

un element pentru nivelul k al soluiei (un succesor). Dac mai exist un succesor, se
trece la urmtorul element din mulimea Ak, iar funcia va returna valoarea 1 (true).
Dac nu mai exist un succesor, funcia va returna valoarea 0 (false). Valoarea
returnat de funcie se va atribui variabilei as. Iniial, valoarea variabilei de memorie
RA

as este 1 (true) se presupune c mai exist un succesor. n exemplu, subprogramul


succesor va verifica dac pentru poziia k din permutare mai exist un numr. Dac
numrul i din poziia k este mai mic dect n, poziiei k i se va atribui numrul urmtor,
i+1, i funcia va returna valoarea 1 (true), iar dac numrul din poziia k este n,
ITU

nseamn c pe aceast poziie din permutare nu mai poate fi pus nici un numr i
funcia va returna valoarea 0 (false).
int succesor()
{if (s[k]<n) {s[k]++; return 1;}
ED

else return 0;}



86 Tehnici de programare
 Subprogramul valid (funcie operand). Verific dac valoarea atribuit elementului

IC
xk al soluiei ndeplinete condiia de continuare, adic poate fi considerat c face
parte din soluia problemei (dac succesorul gsit este element al soluiei). Dac este

OG
ndeplinit condiia (se evalueaz expresia prin care este descris condiia), funcia va
returna valoarea 1 (true); altfel, va returna valoarea 0 (false). Valoarea returnat de
funcie se va atribui variabilei ev. Iniial, valoarea variabilei de memorie ev este 0
(false) se presupune c succesorul gsit nu este elementul k al soluiei. n exemplu,
subprogramul valid va verifica dac numrul din poziia k nu mai exist n cele k-1

G
poziii anterioare. Dac numrul nu ndeplinete aceast condiie, funcia va returna
valoarea 0 (false).

DA
int valid()
{for (int i=1;i<k;i++)
if (s[i]==s[k]) return 0;
return 1;}

PE
 Subprogramul solutie (funcie operand). Verific dac s-au obinut toate elementele
soluiei. n exemplu, subprogramul solutie va verifica dac au fost gsite toate cele n
elemente ale soluiei, adic dac s-au gsit soluii de aranjare n permutare pentru
toate cele n numere. Dac s-a gsit soluia, subprogramul ntoarce valoarea 1 (true);
I
altfel, ntoarce valoarea 0 (false).
int solutie()
{return k==n;}
 Subprogramul tipar (funcie procedural). Afieaz elementele soluiei. De obicei,

afiarea soluiei const n afiarea valorilor din vectorul soluie.


IC

void tipar()
{for (int i=1;i<=n;i++) cout<<s[i]<<" ";
cout<<endl;}
CT

Numrul de ordine al Elementele soluiei


elementelor soluiei
n an1 an2 anj anm xn
DA

.. Parcurgerea elementelor se face cu .


.. subprogramul succesor .
DI

i ai1 ai2 aij aim xi


.. k=k+1 . k=k-1
a21 a22 a2j a2m x2
RA

2
1 a11 a12 a1j a1m x1
1 2 j . m
ITU

Numrul de ordine al elementelor din mulimea Ak Vectorul s: s[k]


Subprogramul valid verific dac este element al soluiei
Subprogramul fix poate fi implementat iterativ sau recursiv.
ED

Informatic 87
Implementarea iterativ

IC
void bt() //partea fix a algoritmului
{k=1; //se iniializeaz indicele primului element al soluiei

OG
init(); //se iniializeaz primul element al soluiei
while (k>0) //ct timp mai exist valori n mulimea A1
//pentru primul nivel al soluiei
{as=1; ev=0;
while(as && !ev) // ct timp are succesor i nu s-a gsit

G
// elementul k al soluiei
{as=succesor(); // se caut succesor

DA
if(as) // dac are succesor, atunci
ev=valid();} // se verific dac este element al soluiei
// se iese din structura repetitiv while dac nu mai exist
// succesor sau dac s-a gsit elementul soluiei

PE
if(as) // dac are succesor, atunci
if (solutie()) //dac s-au obinut toate elementele soluiei,
tipar(); // atunci se afieaz elementele soluiei__
else {k++; // altfel, se trece la urmtorul nivel al soluiei
init();} // i se iniializeaz elementul
I
// urmtor al soluiei
else k--;}} // altfel se revine la nivelul anterior al soluiei
void main() { ... bt(); ... }

Implementarea recursiv Prelucrrile care se fac pentru nivelul k al soluiei se fac i


pentru nivelul k+1 al soluiei i aceste prelucrri pot fi apelate pentru elementul k+1 al
IC

soluiei, iar trecerea de la elementul k al soluiei la elementul k+1 al soluiei se face prin
apelul recursiv al acestor prelucrri. n algoritmul backtracking implementat iterativ
CT

revenirea la nivelul k-1 trebuie s se fac atunci cnd pe nivelul k al soluiei nu se


gsete o valoare care s ndeplineasc condiiile interne. n cazul implementrii
recursive, condiia de baz este ca pentru nivelul k s nu se gseasc o valoare care s
ndeplineasc condiiile interne. Cnd se ajunge la condiia de baz, nceteaz apelul
DA

recursiv i se revine la subprogramul apelant, adic la subprogramul n care se


prelucreaz nivelul k-1 al soluiei, iar n vector se vor regsi valorile prelucrate anterior n
acest subprogram. Deoarece apelul recursiv se face n funcie de valoarea indicelui
elementului k al soluiei, aceast valoare se va transmite ntre subprograme prin
DI

intermediul parametrilor de comunicaie.


void bt(int k) //partea fix a algoritmului
{init(k); //se iniializeaz elementul k al vectorului soluie
RA

while(succesor(k))
//ct timp se gsete succesor pentru elementul k al soluiei
if(valid(k)) dac succesorul este element al soluiei
if(solutie(k)) //dac s-au obinut toate elementele soluiei
ITU

tipar(k); // atunci se afieaz elementele soluiei_


else bt(k+1); //altfel se apeleaz subprogramul pentru a gsi
} //elementul k+1 al soluiei
void main() { ... bt(1); ... }
ED

88 Tehnici de programare
Complexitatea algoritmului metodei backtracking

IC
Dac fiecare soluie are n elemente i fiecare mulime Ai din care se alege un element al
soluiei are m elemente, atunci complexitatea algoritmului metodei backtracking este

OG
n
O(card(A1) card(A2) card(An)) = Q(m m m m) = O(m ). Dac numrul de
elemente ale mulimilor Ai este diferit i notm cu:
mmin= min(card(A1), card(A2), , card(An))
mmax= max(card(A1), card(A2), , card(An))
n

G
atunci complexitatea algoritmului va fi cuprins ntre o complexitate minim O(mmin ) i o
n
complexitate maxim O(mmax ). Rezult c algoritmul metodei backtracking este un
algoritm exponenial. Avnd o complexitate exponenial, metoda backtracking se reco-

DA
mand numai dac nu se cunoate un algoritm mai eficient.

1.5.3. Probleme rezolvabile prin metoda backtracking

PE
Metoda backtracking este recomandat n cazul problemelor care au urmtoarele
caracteristici:
 se cere gsirea tuturor soluiilor posibile;
 nu se cunoate un algoritm mai eficient.
Alte exemple de probleme clasice care se pot rezolva folosind metoda backtracking:
I
 generarea tuturor elementelor unui produs cartezian;
 generarea tuturor partiiilor unui numr natural;
 generarea tuturor partiiilor unei mulimi;

 generarea tuturor funciilor surjective;


 generarea tuturor funciilor injective;
IC

 generarea tuturor posibilitilor de plat a unei sume cu bancnote de valori date.


1.5.3.1. Generarea permutrilor
CT

Prin asamblarea subprogramelor definite anterior, programul pentru generarea tuturor


permutrilor muimii {1, 2, 3, , n} va fi:
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
DA

int n,k,ev,as,s[100]; int n, s[100];


void init() void init(int k)
{s[k]=0;} {s[k]=0;}
int succesor() int succesor(int k)
DI

{if (s[k]<n) {if (s[k]<n)


{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1; return 1;}
else return 0;} else return 0;}
RA

int valid() int valid(int k)


{for(int i=1;i<k;i++) {for(int i=1;i<k;i++)
if (s[k]==s[i]) return 0; if (s[k]==s[i]) return 0;
return 1;} return 1;}
ITU

int solutie() int solutie(int k)


{return k==n;} {return k==n;}
void tipar() void tipar()
{for(int i=1;i<=n;i++) {for(int i=1;i<=n;i++)
cout<<s[i]<<" "; cout<<s[i]<<" ";
ED

cout<<endl;} cout<<endl;}

Informatic 89

IC
void bt() void bt(int k)
{k=1; {init(k);
init(); while(succesor(k))

OG
while (k>0) if(valid(k))
{as=1; ev=0; if(solutie(k)) tipar();
while(as && !ev) else bt(k+1);}
{as=succesor(); void main()
if(as) ev=valid();} {cout<<"n= "; cin>>n;

G
if(as) bt(1);}
if (solutie()) tipar();

DA
else {k++; init();}
else k--;}}
void main()
{cout<<"n= "; cin>>n;

PE
bt();}
Algoritmul de generare a permutrilor poate fi folosit i n alte probleme. De exemplu, s se
genereze toate permutrile mulimii {1, 2, 3, , n} n care nu apar numere consecutive.
Aceast problem face parte din clasa de probleme de generare a permutrilor cu condiie
I
soluia conine o condiie intern suplimentar fa de cea impus de permutare. n acest
exemplu, condiia suplimentar de continuare a construirii soluiei este ca numrul ales pentru
nivelul k al soluiei s nu difere printr-o unitate de numrul care se gsete pe nivelul k-1 al
soluiei. Modificarea apare n subprogramul valid():

int valid()
IC

{ if (k>1 && abs(s[k]-s[k-1])==1) return 0;


for (int i=1;i<k;i++)if (s[i]==s[k]) return 0;
return 1;}
CT

Scriei urmtoarele programe, n care s folosii metoda backtracking


Tem pentru generarea tuturor permutrilor.
1. S se genereze toate permutrile unei mulimi de numere oarecare.
Numerele se memoreaz ntr-un vector. (Indicaie. Se permut indicii elementelor din
DA

vectorul v i vectorul soluie, s, conine indicii elementelor din vectorul v. n subpro-


gramul tipar() se afieaz elementele v[s[i]]).
2. S se genereze toate funciile bijective f:AB, unde card(A)=card(B)=n.
3. S se genereze toate posibilitile de aranjare, pe o tabl de ah cu dimensiunea nn, a
DI

n ture care s nu se atace ntre ele. Deoarece tura se poate deplasa numai pe linia sau
pe coloana pe care a fost plasat, turele se pot ataca ntre ele pe linie i pe coloan.
Indicaie. Se observ c fiecare tur trebuie s fie plasat singur pe o coloan, ca
RA

s nu se atace ntre ele. Soluia problemei este dat de mulimea cu n elemente {x1,
x2, , xn}, care se memoreaz n vector. Elementul soluiei, xk, reprezint numrul
liniei n care se aaz tura din coloana k i se memoreaz pe nivelul k din vectorul s.
Deoarece dou ture nu pot fi aezate pe aceeai linie, vectorul trebuie s conin
ITU

elemente distincte. Problema se reduce la generarea permutrilor mulimii {1,2,3,,n}.


Interpretarea soluiei este: fiecare tur se plaseaz n coloana k, pe linia s[k].
4. S se genereze toate permutrile mulimii {1, 2, 3, , n}, n care dou numere vecine nu
trebuie s fie ambele pare sau ambele impare. Indicaie. n subprogramul valid() se
mai verific i condiia, suplimentar, de vecintate.
ED

90 Tehnici de programare

IC
int valid()
{if (k>1 && (s[k-1]%2==0 && s[k]%2==0)||
(s[k-1]%2==1 && s[k]%2==1)) return 0;

OG
for (int i=1;i<k;i++)
if (s[i]==s[k]) return 0;
return 1;}
5. S se genereze toate permutrile mulimii {1, 3, 5, , 2n+1}. Indicaie. Soluia are n
elemente. n subprogramul init() elementul de pe nivelul curent al soluiei se

G
iniializeaz cu valoarea -1, iar n subprogramul succesor() se modific modul de
determinare a succesorului.

DA
int succesor()
{if (s[k]<2*n+1) {s[k]= s[k]+2; return 1;}
else return 0;}
6. S se genereze toate permutrile unei mulimi de numere oarecare, astfel nct cea mai

PE
mic i cea mai mare valoare s-i pstreze poziiile iniiale.
7. ntr-un ir sunt aranjate n persoane. S se genereze toate posibilitile de rearanjare n
ir a acestor persoane, astfel nct fiecare persoan din ir:
a. s nu aib n faa sa aceeai persoan pe care a avut-o n irul iniial;
b. s nu aib aceiai vecini ca n irul iniial;
I
c. s nu aib n faa sa persoanele pe care le-a avut n irul iniial.
d. s fie desprit de vecinii pe care i-a avut n irul iniial de una sau cel mult p
persoane; valoarea pentru p se citete de la tastatur.

1.5.3.2. Generarea produsului cartezian


IC

Se genereaz toate elementele produsului cartezian A1 x A2 x A3 x x An, unde Ai={1,


2, , ni}.
O soluie a problemei va fi un element al produsului cartezian i va fi format din n
CT

elemente. Un element xk al soluiei poate fi orice element din mulimea Ak (nu exist
condiii interne). Numrul de elemente ale fiecrei mulimi Ai va fi memorat ntr-un
vector m, cu lungimea logic n, unde m[i]=ni. Fa de algoritmul pentru generarea per-
mutrilor, apar urmtoarele diferene:
DA

 Deoarece fiecare mulime Ak are un numr diferit de elemente, elementul k al soluiei


are succesor dac numrul i de pe acest nivel este mai mic dect m[k].
 Deoarece nu exist condiii interne, nu exist restricii nici pentru condiia de
continuare i subprogramul valid() va furniza valoarea 1.
DI

Implementarea iterativ Implementarea recursiv


#include<iostream.h> #include<iostream.h>
int n,k,ev,as,s[100]; int n,s[100];
RA

void init() void init(int k)


{s[k]=0;} {s[k]=0;}
int succesor() int succesor(int k)
{if (s[k]<m[k]) {if (s[k]<m[k])
ITU

{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1; return 1;}


else return 0;} else return 0;}
int valid() int valid(int k)
{return 1;} {return 1;}
int solutie() int solutie(int k)
ED

{return k==n;} {return k==n;}



Informatic 91

IC
void tipar() void tipar()
{for(int i=1;i<=n;i++) {for(int i=1;i<=n;i++)
cout<<s[i]<<" "; cout<<s[i]<<" ";

OG
cout<<endl;} cout<<endl;}
void bt() void bt(int k)
{k=1; init(); {init(k);
while (k>0) while(succesor(k))
{as=1; ev=0; if(valid(k))

G
while(as && !ev) if(solutie(k)) tipar();
{as=succesor(); else bt(k+1);}

DA
if(as) ev=valid();} void main()
if(as) {cout<<"n= "; cin>>n;
if (solutie()) tipar(); for(int i=1;i<=n;i++)
else {k++; init();} {cout<<"Nr. de elemente multimea "

PE
else k--;}} <<i<<" ";
void main() cin>>m[i];}
{cout<<"n= "; cin>>n; bt(1);}
for(int i=1;i<=n;i++)
{cout<<"Nr. de elemente multimea "
I
<<i<<" ";
cin>>m[i];}
bt();}

Algoritmul de generare a produsului cartezian poate fi folosit i n alte probleme. De exemplu,


pentru generarea tuturor submulimilor unei mulimi.
IC

O submulime este format din elemente ale mulimii A. Submulimile Vectorul


Pentru simplificarea algoritmului, vom considera mulimea {}= 000
A={1,2,3,,n}. Considerm mulimea B={0,1}. Pentru con-
CT

{3} 001
struirea submulimilor, pentru fiecare submulime se definete {2} 010
funcia f:AB, astfel: dac elementul i din mulimea A {2, 3} 011
aparine submulimii, atunci f(i)=1; altfel, f(i)=0. Problema se {1} 100
n
reduce la generarea produsului cartezian B . Soluia va fi
DA

{1,3} 101
memorat n vector i va avea n elemente, fiecare element k {1,2} 110
al soluiei avnd valoarea 0 sau 1, cu semnificaia c elemen- {1,2,3} 111
tul k din mulimea A aparine, respectiv nu aparine
submulimii. Alturat sunt prezentate toate submulimile mulimii {1,2,3} i coninutul
DI

vectorului soluie, pentru fiecare dintre ele.


Fa de programul anterior, apar urmtoarele modificri:
 Deoarece mulimile produsului cartezian sunt identice (B={0,1}), s-au modificat: sub-
RA

programul init() iniializarea nivelului k al soluiei se face cu valoarea -1 , cu 1


mai mic dect 0 i subprogramul succesor() elementul are succesor numai
dac este mai mic dect ultimul element din mulime, 1.
 n subprogramul de afiare a soluiei, va fi afiat numrul nivelului i pentru care, n
ITU

vector, se memoreaz valoarea 1.


Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
int n,k,ev,as,s[100]; int n,s[100];
void init() void init (int k)
ED

92 Tehnici de programare

IC
{s[k]=-1;} {s[k]=0;}
int succesor() int succesor(int k)
{if (s[k]<1) {if (s[k]<s[k-1]+1)

OG
{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1;return 1;}
else return 0;} else return 0;}
int valid() int valid()
{return 1;} {return 1;}
int solutie() int solutie(int k)

G
{return k==n;} {return k==n;}
void tipar () void tipar()

DA
{int i,x=0; cout<<"{"; {int i,x=0; cout<<"{";
for (i=1;i<=n;i++) for (i=1;i<=n;i++)
if (s[i]==1) if (s[i]==1)
{cout<<i<<","; x=1;} {cout<<i<<","; x=1;}

PE
if (x) cout<<'\b'; if (x) cout<<'\b';
cout<<"}"<<endl;} cout<<"}"<<endl;}
void bt() cout<<endl;}
{//partea fix a algoritmului} void bt(int k)
void main() {//partea fix a algoritmului}
I
{cout<<"n= "; cin>>n; void main()
bt();} {cout<<"n= "; cin>>n;
bt(1);}

Observaie. Caracterul escape


IC

'\b' este caracterul Backspace


(terge ultimul caracter din ir)
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
CT

Tem generarea produsului cartezian.


1. ntr-un restaurant, un meniu este format din trei feluri de mncare.
Exist patru preparate culinare pentru felul unu, cinci preparate culinare pentru felul doi
DA

i trei preparate culinare pentru felul 3. S se genereze toate meniurile care se pot
forma cu aceste preparate culinare.
2. Pentru o mulime oarecare A, cu n elemente, s se genereze toate submulimile care au
suma elementelor egal cu s. Numrul de elemente ale mulimii, elementele mulimii A
i valoarea pentru suma s se citesc de la tastatur.
DI

3. S se afieze toate numerele cu n cifre (1n10) care au proprietatea c sunt formate


numai din cifre pare, n ordine descresctoare.
4. S se afieze toate numerele formate din cifre distincte, cu proprietatea c suma
RA

cifrelor este S. Valoarea variabilei S se citete de la tastatur.


5. S se afieze toate secvenele de n litere (n numr natural par, citit de la tastatur)
din mulimea {A,B,C,D}, secvene care se construiesc astfel: nu se aeaz dou litere
identice una lng alta i trebuie s se foloseasc exact n/2 litere A.
ITU

6. S se rezolve, n mulimea numerelor naturale, ecuaia 4x+3y+2xy=48. Indicaie. Soluia


are 2 elemente: x i y. Ele pot lua valori n intervalul [0,16]. Limita inferioar a intervalului
este 0, pentru c numerele sunt naturale. Limita superioar s-a determinat considernd
pe rnd situaiile limit, x=0 i y=0. Considerm mulimea A={0,2,3,,16}. Problema se
ED

Informatic 93
reduce la generarea produsului cartezian cu condiie AA soluia conine o condiie

IC
intern suplimentar: elementele ei trebuie s verifice ecuaia.
7. Se citesc n cifre distincte i un numr natural x. S se genereze toate numerele care se

OG
pot forma cu aceste cifre, i sunt mai mici dect numrul x. De exemplu, pentru cifrele 0,
1 i 3 i numrul x=157, se genereaz 1, 3, 10, 11, 13, 30, 31, 33, 100, 101, 103, 110,
111, 113, 130, 131, 133. Indicaie. Se calculeaz m, numrul de cifre ale numrului x.
p
Pentru mulimea A, format din cele n cifre, se genereaz produsele carteziene A , cu
1pm. Elementele produsului cartezian sunt cifrele numrului care se formeaz.

G
Pentru ca un element al produsului cartezian s fie soluie, trebuie ca primul element s
fie diferit de 0 (cifra cea mai semnificativ din numr nu trebuie s fie 0), iar numrul

DA
format cu m cifre s fie mai mic dect numrul x.
8. S se genereze toate numerele naturale, cu cel mult n cifre (n10), care sunt formate
numai din cifre pare, n ordine strict cresctoare.
9. S se genereze toate numerele naturale, cu n cifre, care conin p cifre k. Valorile pentru

PE
n, p i k se citesc de la tastatur.
10. Se citete un numr natural n. S se genereze toate numerele naturale care
reprezentate n baza 2 au acelai numr de cifre de 0 i acelai numr de cifre de 1 ca
i reprezentarea n baza 2 a numrului n.
11. Pe un bilet exist 12 poziii care pot fi perforate, aranjate pe 4 linii i 3 coloane. S se gene-
I
reze toate posibilitile de perforare a celor 12 poziii, astfel nct s nu existe dou poziii
alturate neperforate. Indicaie. Considerm mulimea A, format din 12 elemente, fiecare
element reprezentnd o poziie care poate fi perforat, i mulimea B={0,1}. Se definete

funcia f:AB, astfel: dac poziia i este perforat, atunci f(i)=1; altfel, f(i)=0. Problema se
12
reduce la generarea produsului cartezian B soluia conine o condiie intern
IC

suplimentar: poziia k, care se adaug, nu trebuie s fie neperforat (nu trebuie s aib
valoarea 0) dac poziia k-1 sau poziia k-3 este neperforat (are valoarea 0).
CT

1.5.3.3. Generarea aranjamentelor


Se genereaz toate aranjamentele de m elemente ale mulimii {1, 2, 3, , n}.
O soluie a problemei va fi un aranjament i va avea m elemente. Fa de algoritmul
DA

pentru generarea permutrilor, se modific doar condiia prin care se verific dac s-au
obinut toate elementele soluiei.
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
DI

int n,m,k,ev,as,s[100]; int n,m,s[100];


void init() void init(int k)
{s[k]=0;} {s[k]=0;}
int succesor() int succesor(int k)
RA

{if (s[k]<n) {if (s[k]<n)


{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1; return 1;}
else return 0;} else return 0;}
int valid() int valid(int k)
ITU

{for(int i=1;i<k;i++) {for(int i=1;i<k;i++)


if (s[k]==s[i]) return 0; if (s[k]==s[i]) return 0;
return 1;} return 1;}
int solutie() int solutie(int k)
ED

{return k==m;} {return k==m;}



94 Tehnici de programare

IC
void tipar() void tipar()
{for(int i=1;i<=m;i++) {for(int i=1;i<=m;i++)
cout<<s[i]<<" "; cout<<s[i]<<" ";

OG
cout<<endl;} cout<<endl;}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
void main() void main()
{cout<<"n= "; cin>>n; {cout<<"n= "; cin>>n;

G
cout<<"m= "; cin>>m; cout<<"m= "; cin>>m;
bt();} bt(1);}

DA
Algoritmul de generare a aranjamentelor poate fi folosit i n alte probleme. De exemplu, pentru
generarea tuturor funciilor injective. Soluia Afiarea
Se genereaz toate funciile injective f:AB, unde card(A)=m 12 x 12

PE
i card(B)=n. Pentru simplificarea algoritmului, vom considera f(x) 12
mulimile A={1,2,3,,m} i B={1,2,3,,n}. O soluie este
13 x 12
format din m elemente. Elementul k al soluiei reprezint va-
f(x) 13
loarea funciei: f(k). Deoarece valoarea funciei f(k) aparine
mulimii B, n vectorul soluie se vor genera numere din muli- 21 x 12
I
mea {1,2,3,,n}. Din definiia funciei injective, f(i)f(j), pentru f(x) 21
orice ij. Rezult c, pentru ca funcia s fie injectiv, trebuie 23 x 12
ca mn. Problema se reduce la generarea tuturor aranjamen- f(x) 23

telor de n elemente luate cte m. Soluiile vor fi afiate sub


forma tabelului de variaie al funciei. De exemplu, dac 31 x 12
f(x) 31
IC

A={1,2} i B={1,2,3}, soluiile i modul n care vor fi afiate sunt


prezentate alturat. 32 x 12
Fa de programul anterior nu se va modifica dect f(x) 32
CT

subprogramul de afiare a soluiilor tipar().


...
void tipar()
{int i; cout<<" x | ";
DA

for (i=1;i<=m;i++) cout<<i<<" "; cout<<endl;


for (i=1;i<=m;i++) cout<<"-----"; cout<<endl<<"f(x)| ";
for (i=1;i<=m;i++) cout<<s[i]<<" "; cout<<endl<<endl;}
...
void main()
DI

{cout<<"numarul de elemente ale multimii A= "; cin>>m;


cout<<"numarul de elemente ale multimii B= "; cin>>n; bt();}
Scriei urmtoarele programe, n care s folosii metoda backtracking
RA

Tem pentru generarea tuturor aranjamentelor.


1. S se genereze toate posibilitile de aranjare pe m scaune a n per-
soane (mn). Valorile pentru n i m i numele persoanelor se citesc dintr-un fiier text.
2. Se citesc de la tastatur n cifre distincte. S se genereze toate numerele de m cifre
ITU

(mn) care se pot forma cu aceste cifre i care conin toate cele n cifre.
3. S se genereze toate anagramele unui cuvnt, din care se elimin p litere oarecare.
Valoarea minim a numrului p este 1, iar valoarea maxim este cu 1 mai mic dect
lungimea cuvntului. Se citesc de la tastatur literele cuvntului i valoarea numrului p.
ED

Informatic 95
4. Se citesc de la tastatur n caractere distincte. S se genereze toate cuvintele de m

IC
litere (mn) care se pot forma cu aceste caractere i care conin toate cele n caractere.
5. Se citete un numr n care are m cifre. S se genereze toate numerele, cu cel mult m

OG
cifre, care se pot forma cu cifrele numrului iniial.
6. Dintr-o mulime de n persoane, aranjate ntr-un ir, se elimin p persoane. S se genereze
toate posibilitile de aranjare ntr-un ir a persoanelor rmase, astfel nct fiecare persoan
s nu aib aceiai vecini ca n irul iniial. Valorile pentru n i p se citesc de la tastatur.
7. S se genereze toate aranjamentele de m numere ale unei mulimi de n numere oarecare,

G
astfel nct suma elementelor generate s fie egal cu S. Numrul de elemente ale mulimii,
n, elementele mulimii, valoarile pentru m i pentru suma S se citesc de la tastatur.

DA
8. S se genereze toate drapelele cu trei culori care se pot forma cu ase culori: alb, gal-
ben, rou, verde, albastru i negru care au n mijloc culoarea alb, verde sau rou.
Indicaie. Soluia are 3 elemente, un element al soluiei fiind indicele din vector al unei
culori. Se genereaz aranjamente cu condiie de 6 obiecte luate cte 3 soluia conine o

PE
condiie intern suplimentar fa de cea impus de aranjamente: elementul 2 al soluiei
trebuie s fie indicele culorii alb, verde sau rou.
9. Se consider n cuburi. Fiecare cub i are latura Li i culoarea ci. S se construiasc toate
turnurile stabile formate cu m cuburi, astfel nct dou cuburi vecine n turn s nu aib
aceeai culoare. Valorile pentru n i m i atributele celor n cuburi se citesc de la tastatur.
I
Indicaie. Informaiile despre cuburi se memoreaz n doi vectori (unul pentru lungimile
laturilor, iar cellalt pentru culori) cu n elemente. Soluia are m elemente. Un element al
soluiei este indicele din vector al unui cub. Se genereaz aranjamente cu condiie de n

obiecte luate cte m soluia conine o condiie intern suplimentar fa de cea impus
de aranjamente: cubul k, care se adaug la turn, trebuie s aib latura mai mic dect a
IC

cubului k-1 i culoarea diferit de acesta.

1.5.3.4. Generarea combinrilor


CT

Se genereaz toate combinrile de m elemente ale mulimii {1, 2, 3, , n}.


O soluie a problemei va fi o combinare i va avea m elemente. Fa de algoritmul pentru
generarea aranjamentelor, apare o condiie suplimentar: aceea ca soluiile obinute s fie
DA

distincte, adic dou soluii s nu conin aceleai numere. Pentru aceasta, se va aduga o
condiie de continuare suplimentar: valoarea de pe nivelul k trebuie s fie strict mai
mare dect oricare dintre valorile de pe nivelele inferioare. Altfel spus, elementele soluiei
trebuie s fie ordonate: s[1]<s[2]< ... <s[k-1]<s[k]. Condiia de continuare este ndeplinit
DI

dac elementul de pe nivelul k va avea o valoare strict mai mare dect valoarea elemen-
tului de pe nivelul k-1 (se iniializeaz cu o valoare egal cu cea a elementului de pe nivelul
k-1) i o valoare mai mic dect n-m+k (se caut succesorul pn la valoarea n-m+k).
Implementarea iterativ Implementarea recursiv
RA

#include<iostream.h> #include<iostream.h>
int n,m,k,ev,as,s[100]; int n,m,s[100];
void init() void init(int k)
{if (k==1) s[k]=0; { if (k==1) s[k]=0;
ITU

else s[k]=s[k-1];} else s[k]=s[k-1];}


int succesor() int succesor(int k)
{if (s[k]<n-m+k) {if (s[k]<n-m+k)
{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1; return 1;}
ED

else return 0;} else return 0;}



96 Tehnici de programare

IC
int valid() int valid()
{return 1;} {return 1;}
int solutie() int solutie(int k)

OG
{return k==m;} {return k==m;}
void tipar() void tipar()
{for(int i=1;i<=m;i++) {for(int i=1;i<=m;i++)
cout<<s[i]<<" "; cout<<s[i]<<" ";
cout<<endl;} cout<<endl;}

G
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}

DA
void main() void main()
{cout<<"n= "; cin>>n; {cout<<"n= "; cin>>n;
cout<<"m= "; cin>>m; bt();} cout<<"m= "; cin>>m;
bt(1);}

PE
Algoritmul de generare a combinrilor poate fi folosit n problemele de generare a tuturor
posibilitilor de a forma din n obiecte grupuri de m obiecte, care s aib anumite
proprieti. De exemplu, din n obiecte trebuie s se distribuie unei persoane m obiecte,
care s conin obligatoriu obiectul p i s nu conin obiectul q. S se genereze toate
posibilitile de a forma grupuri de m astfel de obiecte. Pentru simplificare, vom considera
I
mulimea obiectelor ca fiind {1, 2, 3, , n}. Valorile pentru numrul de obiecte, n, numrul
de obiecte din grup, m, i indicii obiectelor p i q se citesc de la tastatur.
Deoarece obiectul p face parte obligatoriu din grupul de obiecte, el va fi memorat ca prim

element al soluiei (s[1]=p), iar subprogramul bt() va genera numai urmtoarele m-1
elemente ale soluiei. Se modific i condiia de continuare a construirii soluiei (subpro-
IC

gramul valid()), deoarece obiectele p i q nu pot fi elemente ale soluiei.


#include<iostream.h>
int n,m,p,q,k,ev,as,s[100];
CT

void init() {//la fel ca n exemplul anterior}


int succesor() {//la fel ca n exemplul anterior}
int valid()
{return s[k]!=p && s[k]!=q;}
DA

int solutie() {//la fel ca n exemplul anterior}


void tipar() {//la fel ca n exemplul anterior}
void bt()
{k=2;init();
DI

while (k>1)
//la fel ca n exemplul anterior}
void main()
RA

{cout<<"n= "; cin>>n; cout<<"m= "; cin>>m;


cout<<"p= "; cin>>p; cout<<"q= "; cin>>q;
s[1]=p; bt();}
Scriei urmtoarele programe, n care s folosii metoda backtracking pentru
ITU

Tem generarea tuturor combinrilor.


1. S se genereze toate grupurile, de p persoane, care se pot forma din
n persoane. Informaiile se citesc dintr-un fiier text unde, pe primul rnd, sunt scrise
valorile pentru p i n, desprite printr-un spaiu, iar pe urmtoarele rnduri, numele
ED

persoanelor, cte un nume pe un rnd.



Informatic 97
2. Dou persoane i mpart n obiecte, astfel: prima persoan ia m obiecte, iar cealalt

IC
persoan restul obiectelor. S se genereze toate posibilitile de distribuire a celor n
obiecte ntre cele dou persoane.

OG
3. Dou persoane i mpart n obiecte. Fiecare obiect are o valoare vi. S se genereze
toate posibilitile de distribuire a celor n obiecte, ntre cele dou persoane, astfel nct
fiecare persoan s primeasc obiecte care s aib aceeai valoare total.
4. S se genereze toate numerele binare de n cifre care au m cifre de 0. Indicaie. O
soluie este format din m elemente, un element fiind poziia din numr n care se poate

G
gsi cifra 0 exceptnd prima poziie.
5. Din n obiecte date, s se genereze toate grupurile de m obiecte care ndeplinesc

DA
urmtoarele condiii:
a. conin exact p obiecte precizate;
b. nu conin nici unul din p obiecte precizate;
c. conin numai un obiect din p obiecte precizate;

PE
d. conin cel puin un obiect din p obiecte precizate;
e. conin exact q obiecte din p obiecte precizate;
f. conin exact q obiecte din p obiecte precizate i nu conin r obiecte precizate;
g. conin exact q obiecte din p obiecte precizate i nu conin s obiecte, din r obiecte
precizate.
I
1.5.3.5. Generarea tuturor partiiilor unui numr natural
O partiie a unui numr natural nenul, n, este o descompunere a nu-

4=1+1+1+1 (m=4)
mrului n n sum de m numere naturale nenule. Soluiile care nu 4=1+1+2 (m=3)
difer dect prin ordinea termenilor nu sunt considerate distincte.
IC

4=1+3 (m=2)
Alturat, sunt prezentate toate partiiile numrului 4. 4=2+2 (m=2)
O soluie a problemei va fi format din m elemente, a cror sum este 4=4 (m=1)
CT

egal cu numrul n. Elementele soluiei reprezint termenii unei descompuneri. Numrul de


elemente ale unei soluii (m) este egal cu valoarea indicelui k atunci cnd s-a obinut
soluia. Soluia se obine atunci cnd suma elementelor din vector este egal cu n. Altfel
spus, soluia se obine atunci cnd suma S=s[1]+s[2]+ ... +s[k-1]+s[k] are valoarea n.
DA

Pentru a evita repetarea aceleiai descompuneri, valoarea de pe nivelul k trebuie s fie mai
mare sau egal cu oricare dintre valorile de pe nivelele inferioare. Altfel spus, elementele
soluiei trebuie s fie ordonate: s[1]s[2] ... s[k-1]s[k]. Aceast condiie este
ndeplinit dac elementul de pe nivelul k va avea o valoare mai mare sau egal cu
DI

valoarea elementului de pe nivelul k-1 (se iniializeaz cu o valoare mai mic cu 1 dect
cea a elementului de pe nivelul k-1) i o valoare mai mic dect diferena dintre numrul n
i suma termenilor descompunerii gsii pn la nivelul k, S=s[1]+s[2]+ ... +s[k-1].
RA

Condiia de continuare este ca suma termenilor generai, S, s fie mai mic sau egal
cu n (Sn), o soluie complet obinndu-se atunci cnd S=n. Iniial, suma S are valoarea
0, i ea trebuie actualizat n permanen. Exist dou cazuri de actualizare:
 Atunci cnd se adaug la soluie un nou termen, acesta se adaug i la sum. Altfel
ITU

spus, dac succesorul gsit poate fi element al soluiei (prin adugarea lui la sum,
aceasta nu va depi valoarea numrului n), atunci el se adaug la sum.
Actualizarea sumei se va face n subprogramul valid() (termenul se adaug la
sum numai dac face parte din descompunere): S+=s[k].
ED

98 Tehnici de programare
 Atunci cnd se coboar la nivelul anterior al soluiei, trebuie sczute din sum dou

IC
valori: valoarea elementului de pe nivelul k i valoarea elementului de pe nivelul
precedent (k-1). Deoarece n soluie se coboar ntotdeauna dup ce s-a obinut o

OG
soluie complet i nu se mai poate gsi un element pentru nivelul k, cu care s se
continue dezvoltarea soluiei scderea din sum a termenului de pe nivelul curent se
va face dup ce se afieaz o soluie complet, n subprogramul tipar(): S-=s[k],
iar scderea din sum a termenului precedent se face n subprogramul succesor(),
atunci cnd nu se gsete succesor pentru elementul de pe nivelul k: S-=s[k-1].

G
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>

DA
int n,S=0,k,ev,as,s[100]; int n,S=0,s[100];
void init () void init (int k)
{if (k==1) s[k]=0; {if (k==1) s[k]=0;
else s[k]=s[k-1]-1;} else s[k]=s[k-1]-1;}

PE
int succesor() int succesor(int k)
{if (s[k]<n-S) {if (s[k]<n-S)
{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1; return 1;}
else {S-=s[k-1]; return 0;}} else {S-=s[k-1]; return 0;}}
int valid()
I
int valid(int k)
{if (S+s[k]<=n) {if (S+s[k]<=n)
{S+=s[k]; return 1;} {S+=s[k]; return 1;}
else return 0;} else return 0;}

int solutie() int solutie(int k)


{return S==n;} {return S==n;}
IC

void tipar() void tipar(int k)


{for(int i=1;<k;i++) {for(int i=1;<k;i++)
cout<<s[i]<<"+ "; cout<<s[i]<<"+ ";
CT

cout<<s[k]<<endl; cout<<s[k]<<endl;
S-=s[k];} S-=s[k];}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
DA

void main() void main()


{cout<<"n= "; cin>>n; bt();} {cout<<"n= "; cin>>n;
bt(1);}
DI

Algoritmul de generare a tuturor partiiilor unui numr natural poate fi folosit i n alte
probleme. De exemplu, generarea tuturor posibilitilor de plat a unei sume cu
bancnote de valori date.
Problema se reduce la generarea tuturor partiiilor unui numr 25 = 5+5+5+5+5 (m=5)
RA

natural nenul, suma, o partiie fiind o descompunere a num- 25 = 5+5+5+10 (m=4)


rului suma n sum de m numere naturale nenule, cu valori 25 = 5+10+10 (m=3)
aparinnd mulimii A={a1,a2, ,an}. Alturat, sunt prezentate
toate partiiile sumei 25, pentru bancnote cu valori aparinnd mulimii A={5,10}.
ITU

Fa de problema anterioar, apar urmtoarele modificri:


 Deoarece suma suma se descompune n valori precizate, aparinnd mulimii A,
aceste valori se memoreaz n vectorul a, care are lungimea logic n (numrul de
valori ale bancnotelor).
ED

Informatic 99
 Un element al soluiei este indicele valorii bancnotei din vectorul a, adic un element

IC
din mulimea {1,2, , n}.
 O soluie a problemei va fi format din m elemente, alese astfel nct suma valorilor

OG
bancnotelor corespunztoare lor s fie egal cu numrul suma. Altfel spus, soluia se
obine atunci cnd suma S=a[s[1]]+a[s[2]]+ ... + a[s[k-1]]+ a[s[k]] are valoarea suma.
 Condiia de continuare este ca suma valorilor termenilor generai, S, s fie mai mic
sau egal cu suma (Ssuma), o soluie complet obinndu-se atunci cnd S=suma.
Atunci cnd se adaug la soluie un nou element, se adun la sum valoarea

G
bancnotei cu indicele k: S+=a[s[k]], iar cnd se coboar la nivelul anterior al
soluiei, se scade din sum valoarea bancnotei cu indicele k: S-=a[s[k]] i

DA
valoarea bancnotei cu indicele k-1: S+=a[s[k-1]].
 Deoarece este posibil ca, pentru anumite valori ale sumei suma i ale valorilor
bancnotelor, s nu existe nici o soluie, se folosete variabila de tip logic este, care
are valoarea 1 (true), dac exist cel puin o soluie, i 0 (false) n caz contrar.

PE
#include<iostream.h>
int n,k,ev,as,S=0,suma,este=0,a[10], s[100];
void init ()
{if (k==1) s[k]=0;
else s[k]=s[k-1]-1;}
I
int succesor()
{if (s[k]<n) {s[k]=s[k]+1; return 1;}
else {S-=a[s[k-1]]; return 0;}}

int valid()
{if (S+a[s[k]]<=suma) {S+=a[s[k]]; return 1;}
IC

else return 0;}


int solutie()
{return S==suma;}
CT

void tipar()
{int i,j,p,este=1;
for (i=1;i<=n;i++)
{for(j=1,p=0;j<=k;j++) if (i==s[j]) p++;
DA

if (p!=0) cout<<p<<"*"<<a[i]<<" + ";}


cout<<'\b'<<'\b'<<" "<<endl; s-=a[s[k]];}
void bt() //partea fix a algoritmului
{ ... }
DI

void main()
{cout<<"n= "; cin>>n;
for (int i=1;i<=n;i++)
RA

{cout<<"Valoare bancnota "<<i<<": "; cin>>a[i];}


cout<<"suma= "; cin>>suma; bt();
if (!este) cout<<"Imposibil"; }
Scriei urmtoarele programe, n care s folosii metoda backtracking
ITU

Tem pentru generarea tuturor partiiilor unui numr natural.


1. S se genereze toate descompunerile unui numr natural, n, n
numere naturale distincte.
2. S se genereze toate descompunerile unui numr natural n n numere prime.
3. S se genereze toate descompunerile unui numr natural n n sum de 3 i 5.
ED

100 Tehnici de programare
4. O bar are lungimea L. Se consider n repere de lungimi diferite. S se genereze toate

IC
posibilitile de a tia bara dup reperele existente, fr s rmn rest la tiere, un
reper putnd fi folosit de mai multe ori. Se citesc dintr-un fiier text, de pe primul rnd,

OG
lungimea barei L i numrul de repere n, i de pe urmtorul rnd reperele. Numerele
de pe un rnd sunt separate prin spaiu.
5. S se gseasc modalitatea de plat a unei sume cu un numr minim de bancnote cu
valori date.

G
1.5.3.6. Generarea tuturor partiiilor unei mulimi

DA
O partiie a unei mulimi A este format din mulimile nevide disjuncte Ai, a cror reuniune
m
este mulimea A: U A i = A i A i I A j = , pentru orice i,j = 1m.
i =1

Pentru simplificarea algoritmului vom considera mulimea A={1,2,3, Partiiile Vectorul

PE
,n}. O partiie va fi format din m mulimi, cu 1mn. Soluia va fi {1, 2, 3} 111
memorat n vector i va avea n elemente, fiecare element k al {1, 2} {3} 112
soluiei reprezentnd mulimea i (1in) creia i aparine elementul {1, 3} {2 } 121
k din mulimea care se partiioneaz: s[k]=i nseamn c elementul {1} {2, 3 } 122
{1} {2} {3 } 123
I
k din mulimea A face parte din mulimea i a partiiei. n cadrul unei
partiii nu intereseaz ordinea n care apar elementele mulimii A. Cel mai mare numr care
va fi generat n vector reprezint numrul de mulimi m n care a fost descompus mulimea
A. n plus, numerele generate trebuie s aparin unei mulimi de numere consecutive care

ncepe cu 1, deoarece partiia nu conine mulimi vide. Alturat sunt prezentate toate partiiile
mulimii {1,2,3} i coninutul vectorului pentru fiecare dintre ele. n exemplu, nu exist soluia 1
IC

3 3, deoarece aceste valori nu aparin unei mulimi de numere consecutive (nu se poate ca un
element din mulimea A s aparin mulimii A1 i alte dou elemente mulimii A3, deoarece
CT

ar nsemna c mulimea A2 este vid).


Condiia de continuare este asigurat prin modul n care este ales succesorul s[k]k,
ceea ce nseamn c elementul k din mulimea A nu poate aparine dect unei partiii al crei
numr este mai mic sau cel mult egal cu numrul de ordine al elementului. Altfel spus, dac
DA

pn la nivelul k numrul maxim atribuit pentru o partiie este i, acest numr reprezentnd
numrul de mulimi ale partiiei care exist n soluia parial, pe nivelul k+1 elementul poate
avea una dintre urmtoarele valori:
 Orice valoare de la 1 la i, ceea ce nseamn c elementul k+1 din mulimea A se
DI

adaug la una dintre mulimile care exist deja.


 Valoarea i+1, ceea ce nseamn c elementul k+1 din mulimea A va genera o nou
mulime n partiie.
RA

Implementarea iterativ Implementarea recursiv


#include<iostream.h> #include<iostream.h>
int n,k,ev,as,s[100]; int n,s[100];
void init() void init (int k)
ITU

{s[k]=0;} {s[k]=0;}
int succesor() int succesor(int k)
{if (s[k]<s[k-1]+1) {if (s[k]<s[k-1]+1)
{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1;return 1;}
else return 0;} else return 0;}
ED

Informatic 101

IC
int valid() int valid()
{return 1;} {return 1;}
int solutie() int solutie(int k)

OG
{return k==n;} {return k==n;}
void tipar() void tipar()
{int i,j,max=st[1]; {int i,j,max=s[1];
for(i=2;i<=n;i++) for(i=2;i<=n;i++)
if (s[i]>max) max=s[i]; if (s[i]>max) max=s[i];

G
for (i=1;i<=max;i++) for (i=1;i<=max;i++)
{cout<<"{"; {cout<<"{";

DA
for (j=1;j<=n;j++) for (j=1;j<=n;j++)
if (s[j]==i) cout<<j<<","; if (s[j]==i) cout<<j<<",";
cout<<'\b'<<"} ";} cout<<'\b'<<"} ";}
cout<<endl;} cout<<endl;}

PE
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
void main() void main()
{cout<<"n= "; cin>>n; bt();} {cout<<"n= "; cin>>n; bt(1);}
I
Scriei urmtoarele programe, n care s folosii metoda backtracking
Tem pentru generarea tuturor partiiilor unei mulimi. Se consider mulimea A,
cu n numere ntregi. Valorile pentru n i m i cele pentru elementele
mulimii A se citesc de la tastatur.

1. S se genereze toate partiiile mulimii A formate din dou submulimi, care au suma
elementelor egale.
IC

2. S se genereze toate partiiile mulimii A formate din m submulimi.


3. S se genereze toate partiiile mulimii A formate din submulimi care au acelai numr
de elemente.
CT

Soluia Afiarea
112 x 123
1.5.3.7. Generarea tuturor funciilor surjective f(x) 1 1 2
Se genereaz toate funciile surjective f:AB, unde card(A)=m i 121 x 123
DA

card(B)=n. Pentru simplificarea algoritmului vom considera muli- f(x) 1 2 1


mile A={1,2,3,,m} i B={1,2,3,,n}. O soluie este format din m
elemente. Elementul k al soluiei reprezint valoarea funciei: f(k). 122 x 123
Deoarece valoarea funciei f(k) aparine mulimii B, n vector se vor f(x) 1 2 2
DI

genera numere din mulimea {1,2,3,,n}. Din definiia funciei 211 x 123
surjective, trebuie ca, pentru orice jB, s existe iA, astfel nct f(x) 2 1 1
f(i)=j. Rezult c, pentru ca funcia s fie surjectiv, trebuie ca
221 x 123
nm. Problema se reduce la generarea n vectorul soluie a tuturor
RA

m f(x) 2 2 1
elementelor produsului cartezian B , din care vor fi considerate
soluii numai cele care conin toate elementele din mulimea B. 212 x 123
Soluiile vor fi afiate sub forma tabelului de variaie al funciei. f(x) 2 1 2
ITU

De exemplu, dac A={1,2,3} i B={1,2}, soluiile i modul n care vor fi 221 x 123
afiate sunt prezentate alturat. f(x) 2 2 1
Condiia de continuare este asigurat prin modul n care este ales
succesorul ca element din mulimea B, singurul caz special fiind al elementului care se
adaug pe ultimul nivel din vectorul soluie (m). Prin adugarea acestui element trebuie ca n
ED

102 Tehnici de programare
vector s existe toate elementele mulimii B. Aceast condiie este verificat prin funcia

IC
surjectiva() care furnizeaz un rezultat logic: 1 (true), dac n vector exist toate cele n
elemente ale mulimii B, i 0 (false) n caz contrar.

OG
Implementarea iterativ Implementarea recursiv
#include<iostream.h> #include<iostream.h>
int n,m,k,ev,as,s[100]; int n,m,s[100];
int surjectiva() int surjectiva()
{int i,j,x; {int i,j,x;

G
for (j=1;j<=n;j++) for (j=1;j<=n;j++)
{for (i=1,x=0;i<=m && !x;i++) {for (i=1,x=0;i<=m && !x;i++)

DA
if (st[i]==j) x=1; if (s[i]==j) x=1;
if (!x) return 0;} if (!x) return 0;}
return 1;} void init (int k)
void init() {s[k]=0;} {{s[k]=0;}

PE
int succesor() int succesor(int k)
{if (s[k]<s[k-1]+1) {if (s[k]<s[k-1]+1)
{s[k]=s[k]+1; return 1;} {s[k]=s[k]+1;return 1;}
else return 0;} else return 0;}
int valid() int valid(int k)
I
{if (k==m) {if (k==m)
if (!surjectiva()) return 0; if (!surjectiva()) return 0;
return 1;} return 1;}

int solutie() int solutie(int k)


{return k==m;} {return k==n;}
IC

void tipar() void tipar()


{int i; cout<<" x | "; { int i; cout<<" x | ";
for (i=1;i<=m;i++) cout<<i<<" "; for (i=1;i<=m;i++) cout<<i<<" ";
CT

cout<<endl; cout<<endl;
for (i=1;i<=m;i++) cout<<"-----"; for (i=1;i<=m;i++) cout<<"-----";
cout<<endl<<"f(x)| "; cout<<endl<<"f(x)| ";
for (i=1;i<=m;i++) cout<<s[i]<<" "; for (i=1;i<=m;i++) cout<<s[i]<<" ";
DA

cout<<endl<<endl;} cout<<endl<<endl;}
void bt() void bt(int k)
{//partea fix a algoritmului} {//partea fix a algoritmului}
void main() void main()
DI

{cout<<"elemente multimea A= "; {cout<<"elemente multimea A= ";


cin>>m; cin>>m;
cout<<"elemente multimea B= "; cout<<"elemente multimea B= ";
cin>>n; bt();} cin>>n; bt(1);}
RA

Scriei urmtoarele programe, n care s folosii metoda backtracking


Tem pentru generarea tuturor funciilor surjective.
1. Se citesc de la tastatur n cifre distincte. S se genereze toate nu-
ITU

merele de m cifre (nm) care se pot forma cu aceste cifre i care conin toate cele n cifre.
2. Se citesc de la tastatur n caractere distincte. S se genereze toate cuvintele de m carac-
tere (nm) care se pot forma cu aceste caractere i care conin toate cele n caractere.
ED

Informatic 103
3. Profesorul de informatic a pregtit m teme pentru proiecte, pe care trebuie s le

IC
repartizeze celor n elevi din clas (mn), astfel nct nici o tem de proiect s nu rmn
nerepartizat. S se genereze toate soluiile de repartizare a temelor pentru proiect.

OG
4. S se genereze toate construciile corecte de n paranteze ( i ) n fiind un numr par
citit de la tastatur. De exemplu, pentru n=6 construciile (())() i ()(()) sunt corecte, iar
construcia ())(() nu este corect. Indicaie. Se genereaz funciile surjective f:AB,
unde A={1,2,3,,n} = mulimea poziiilor ocupate de paranteze, i B= {0,1} = mulimea
parantezelor (=0 i )=1 care ndeplinesc urmtoarele condiii:

G
 f(1)=0 i f(n)=1 (expresia ncepe cu parantez deschis i se termin cu o parantez
nchis).

DA
 Numrul de valori 0 ale funciei i numrul de valori 1 ale funciei sunt egale cu n/2
(numrul de paranteze deschise este egal cu numrul de paranteze nchise).
 n timpul construirii soluiei nu trebuie ca numrul de valori 1 ale funciei s fie mai mare
dect numrul de valori 0 generate pn la acel moment (numrul de paranteze nchise

PE
este ntotdeauna cel mult egal cu numrul de paranteze deschise).

1.5.3.8. Problema celor n dame


Se genereaz toate posibilitile de aranjare, pe o tabl de 8 
I
ah, cu dimensiunea nn, a n dame, care s nu se atace 7 
ntre ele. Damele se pot ataca ntre ele pe linie, pe coloa- 6 
n i pe diagonal. 5 
4 

Se observ c fiecare dam trebuie s fie plasat singur


pe o coloan, ca s nu se atace ntre ele. Soluia pro- 3 
IC

blemei este dat de mulimea cu n elemente {x1, x2, , n}, 2 


care se memoreaz n vector. Elementul soluiei, xk, 1 
reprezint numrul liniei n care se aaz dama din coloa- 1 2 3 4 5 6 7 8
CT

na k i se memoreaz pe nivelul k al vectorului s. De


exemplu, pentru n=8, o soluie este S={4,8,1,5,7,2,6,3} i damele sunt aranjate pe tabla
de ah ca n figura alturat.
Date fiind coordonatele i i j de pe tabla de C
DA

ah ale poziiei unei dame care a fost i+p, k


aezat anterior (linia i este memorat pe
nivelul j n vector i=st[j]), ca ea s nu atace
dama care urmeaz s fie pus n coloana k A B
DI

trebuie s fie ndeplinite urmtoarele condiii i,j i,k


interne:
 Dama din coloana k nu trebuie s se
RA

gseasc pe linia i.
 Dama din coloana k nu trebuie s se g- i-p, k
seasc pe diagonala cu dama din coloana
j, adic triunghiul dreptunghic ABC nu tre-buie s fie isoscel. Pentru ca triunghiul ABC
ITU

s nu fie isoscel, condiia pe care trebuie s o ndeplineasc dama din coloana k se


poate exprima astfel: oricare ar fi j<k, xj xk i |xk xj| kj.
Aceste condiii interne ale soluiei trebuie s se regseasc n condiia de continuare a
soluiei, care se verific n subprogramul valid(): s[j]s[k] i abs(s[k]s[j])kj pentru
orice jk.
ED

104 Tehnici de programare
#include<iostream.h>

IC
#include<math.h>
int n,k,ev,as,s=0,suma,este=0,a[10],s[100];
void init() {s[k]=0;}

OG
int succesor()
{if (s[k]<n) {s[k]=s[k]+1; return 1;}
else return 0;}
int valid()
{for(int i=1;i<k;i++)

G
if (s[k]==s[i] || abs(s[k]-s[i])==k-i) return 0;
return 1;}

DA
int solutie()
{return k==n;}
void tipar()
{for(int i=1;i<=n;i++) cout<<s[i]<<" "; cout<<endl;}
void bt() { ... } //partea fixa a algoritmului

PE
void main()
{cout<<"n= "; cin>>n; bt();}
S se genereze toate posibilitile de aranjare, pe o tabl de ah, cu
Tem dimensiunea nn, a n nebuni, care s nu se atace ntre ei. Nebunul se
I
poate deplasa numai pe diagonal.

1.6. Metoda Divide et Impera



IC

1.6.1. Descrierea metodei Divide et Impera


Metoda Divide et Impera se poate folosi pentru problemele care pot fi descompuse n
CT

subprobleme similare cu problema iniial (care se rezolv prin aceeai metod) i care
prelucreaz mulimi de date de dimensiuni mai mici, independente unele de altele (care
folosesc mulimi de date de intrare disjuncte).
DA

Scop: identificarea problemelor care pot fi descompuse n subprobleme similare care


folosesc mulimi de date de intrare disjuncte.
Enunul problemei 1: S se calculeze suma elementelor dintr-un vector v care conine
DI

numere ntregi.
Mulimea datelor de intrare o reprezint cele n elemente ale vectorului v. Ele pot fi divizate
n cte dou submulimi disjuncte, prin divizarea mulimii indicilor n dou submulimi.
RA

Mulimea iniial a indicilor este determinat de primul indice (s) i de ultimul indice (d), iar
intervalul indicilor care se divizeaz este [s,d]. El se divizeaz n dou submulimi disjuncte,
[s,m] i [m+1,d], unde m este indicele din mijlocul intervalului: m=(s+d)/2. Astfel, problema
iniial este descompus n dou subprobleme, fiecare dintre ele constnd n calcularea
sumei numerelor dintr-o submulime de elemente (care corespunde unui subinterval al
ITU

indicilor). Descompunerea continu pn cnd fiecare submulime conine un singur


element i se poate calcula suma, obinndu-se soluia subproblemei.
ED

Informatic 105

IC
Enunul problemei 2: S se calculeze suma 12+23+ ... +n(n+1).
Mulimea datelor de intrare o reprezint primele n numere naturale. Mulimea iniial este
determinat de primul numr (s=1) i de ultimul numr (d=n), iar intervalul care se divizea-

OG
z este [s,d]. El se divizeaz n dou submulimi disjuncte, [s,m] i [m+1,d], unde m este
numrul din mijlocul intervalului: m=(s+d)/2. Astfel, problema iniial este descompus n
dou subprobleme, fiecare dintre ele constnd n calcularea sumei produselor dintre dou
numere consecutive dintr-o submulime de elemente (care corespunde unui subinterval al

G
numerelor). Descompunerea continu pn cnd fiecare submulime conine un singur
element i se poate calcula produsul, care se va aduga la sum, pentru a obine soluia
subproblemei.

DA
Enunul problemei 3: S se genereze termenul n al irului lui Fibonacci.
irul lui Fibonacci este definit recursiv: f1=1, f2=1 i fn= fn-2+ fn-1, pentru n3. Problema
determinrii termenului n al irului lui Fibonacci se poate descompune n dou subpro-

PE
bleme: determinarea termenului n-1 i determinarea termenului n-2. Descompu-
nerea continu pn cnd trebuie determinai termenii f1 i f2, a cror valoare este
cunoscut.

Metoda Divide et Impera se bazeaz pe descompunerea unei probleme n


I
subprobleme similare, prin intermediul unui proces recursiv. Procesul recursiv de
descompunere a unei subprobleme n alte subprobleme continu pn se obine
o subproblem cu rezolvarea imediat (cazul de baz), dup care se compun

soluiile subproblemelor pn se obine soluia problemei iniale.


Paii algoritmului sunt:
IC

PAS1. Se descompune problema n subprobleme similare problemei iniiale, de dimen-


siuni mai mici, independente unele de altele (care folosesc mulimi de date de
intrare disjuncte di).
CT

PAS2. Dac subproblema permite rezolvarea imediat (corespunde cazului de baz),


atunci se rezolv, obinndu-se soluia s; altfel, se revine la Pas1.
PAS3. Se combin soluiile subproblemelor (si) n care a fost descompus o subproble-
DA

m, pn cnd se obine soluia problemei iniiale.

1.6.2. Implementarea metodei Divide et Impera


Deoarece subproblemele n care se descompune problema sunt similare cu problema
DI

iniial, algoritmul divide et impera poate fi implementat recursiv. Subprogramul recursiv


divide_et_impera(d,s), unde d reprezint dimensiunea subproblemei (corespunde mulimii
datelor de intrare), iar s soluia subproblemei, poate fi descris n pseudocod astfel:
RA

divide_et impera(d,s)
nceput
dac dimensiunea d corespunde unui caz de baz
atunci se determin soluia s a problemei;
ITU

altfel
pentru i=1,n execut
se determin dimensiunea d i a subproblemei P i;
se determin soluia s i a problemei P i prin
apelul divide et impera(d i,s i);
ED

sfrit_pentru;

106 Tehnici de programare

IC
se combin soluiile s 1, s 2, s 3, ..., s n;
sfrit_dac;
sfrit;

OG
Implementarea acestui algoritm n limbajul C++ se face astfel:
/*declaraii globale pentru datele de intrare, ce vor fi divizate n sub-
mulimi disjuncte pentru subproblemele n care se descompune problema*/
void divizeaza(<parametri: submulimile>)
{//se divizeaz mulimea de date de intrare n submulimi disjuncte d i}

G
void combina(<parametri: soluiile s i care se combin>)
{//se combin soluiile obinute s i}

DA
void dei(<parametri: mulimea de date d i soluia s>)
{//declaraii de variabile locale
if (<este caz de baz>) {//se obine soluia corespunztoare subproblemei}
else

PE
{divizeaza(<parametri: k submulimi>);
for (i=1;i=k;i++)
dei(<parametri: mulimea de date d i i soluia s i>);
combina(<parametri: soluiile s i>);}}
void main()
I
{//declaraii de variabile locale
//se citesc datele de intrare ale problemei mulimea d
dei(<parametri: mulimea de date d i soluia s>);

//se afieaz soluia problemei s}


Exemplul 1. S se calculeze suma elementelor pare dintr-un vector v care conine
IC

numere ntregi. Numrul de elemente ale vectorului (n) i elementele lui se citesc de la
tastatur.
s=1 1 2 3 4 5 d=5
CT

5 10 15 20 25
m=(1+5)/2=3
z=z12345= z123+ z45=10+20=30
DA

1 2 3 4 5
s=1 5 10 15 d=3 s=4 20 25 d=5
m=(1+3)/2=2 m=(4+5)/2=4
DI

z123= z12+ z45= z4+ z5=20+0=20


z3=10+0=10
1 2 3 4 5
s=1 5 10 d=2 15 20 25
RA

m=(1+2)/2=1 s=d=3 s=d=4 s=d=5


z12= z1+ z2=0+10=10 z3=0 z4=20 z5=0

1 2
ITU

s=d=1 5 10 s=d=2
z1=0 z2=10
Implementarea metodei divide et impera n acest exemplu se face astfel:
ED

Informatic 107
 Subprogramul divizeaza() Numrul de subprobleme n care se descompune

IC
problema este 2 (k=2). Mulimea datelor de intrare este divizat n dou submulimi
disjuncte, prin divizarea mulimii indicilor n dou submulimi disjuncte de indici, adic

OG
mulimea indicilor [s,d] (unde s este primul indice, iar d ultimul indice) este divizat n
dou submulimi disjuncte, [s,m] i [m+1,d], unde m este indicele din mijlocul interva-
lului: m=(s+d)/2. n subprogram, procesul de divizare const n determinarea mijlocului
intervalului m.
 Subprogramul combina() Combinarea soluiei nseamn adunarea celor dou sume

G
obinute prin rezolvarea celor dou subprobleme. n subprogram sunt combinate cele
dou valori obinute din prelucrarea celor dou intervale, adic se adun cele dou

DA
valori x i y, obinndu-se soluia z.
 Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd sub-
mulimea conine un singur element (se poate calcula suma, obinndu-se soluia subpro-
blemei). Dac s-a terminat procesul recursiv (prin procesul de divizare, cele dou capete

PE
ale intervalului au ajuns s fie identice) atunci se prelucreaz cazul de baz (se
calculeaz suma n variabila z, corespunztoare soluiei, astfel: dac numrul v[s] este
par, atunci suma va fi chiar numrul; altfel, are valoarea 0); altfel, se apeleaz subpro-
gramul pentru divizarea intervalului, se apeleaz subprogramul dei() pentru primul
interval, se apeleaz subprogramul dei() pentru al doilea interval i se combin cele
I
dou rezultate.
#include<iostream.h>
int v[100],n;

void divizeaza(int s,int d,int &m)


{m=(s+d)/2;}
IC

void combina(int x,int y,int &z)


{z=x+y;}
void dei(int s,int d,int &z)
CT

{int m,x1,x2;
if (d==s)
if (v[s]%2==0) z=v[s]; else z=0;
else
DA

{divizeaza(s,d,m); dei(s,m,x1); dei(m+1,d,x2); combina(x1,x2,z);}}


void main()
{int i,z; cout<<"n= ";cin>>n;
for(i=1;i<=n;i++) {cout<<"v["<<i<<"]="; cin>>v[i];}
DI

dei(1,n,z); cout<<"suma= "<<z;}


Exemplul 2: S se calculeze suma 12+23+ ... +n(n+1).
Implementarea metodei divide et impera n acest exemplu se face astfel:
RA

 Subprogramul divizeaza() Numrul de subprobleme n care se descompune


problema este 2 (k=2). Mulimea datelor de intrare este divizat n dou submulimi dis-
juncte, prin divizarea mulimii primelor n numere naturale n dou submulimi disjuncte,
adic mulimea [s,d] (unde s este primul numr din mulime, iar d ultimul numr din
ITU

mulime) este divizat n dou submulimi disjuncte, [s,m] i [m+1,d], unde m este
numrul din mijlocul intervalului: m=(s+d)/2. n subprogram, procesul de divizare const
n determinarea mijlocului intervalului, m.
 Subprogramul combina() Combinarea soluiei nseamn adunarea celor dou sume
ED

obinute prin rezolvarea celor dou subprobleme. n subprogram sunt combinate cele

108 Tehnici de programare
dou valori obinute din cele dou intervale (se adun cele dou valori, x i y)

IC
obinndu-se soluia z.
 Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd

OG
submulimea conine un singur element (se poate calcula termenul sumei produsul
celor dou numere consecutive obinndu-se soluia subproblemei). Dac s-a terminat
procesul recursiv (prin procesul de divizare, cele dou capete ale intervalului au ajuns
s fie identice), atunci se prelucreaz cazul de baz (se calculeaz produsul, n
variabila z, corespunztoare soluiei); altfel, se apeleaz subprogramul pentru divizarea

G
intervalului, se apeleaz subprogramul dei() pentru primul interval, se apeleaz
subprogramul dei() pentru al doilea interval i se combin cele dou rezultate.

DA
s=1 1 2 3 4 5 d=5
m=(1+5)/2=3
z=z12345= z123+ z45=20+50=70

PE
s=1 1 2 3 d=3 s=4 4 5 d=5
m=(1+3)/2=2 m=(4+5)/2=4
z123= z12+ z3=8+12=20I z45= z4+ z5=20+30=50

s=1 1 2 d=2 3 4 5
m=(1+2)/2=1 s=d=3 s=d=4 s=d=5
z12= z1+ z2=2+6=8 z3=34=12 z4=45=20 z5=56=30

s=d=1 1 2 s=d=2
IC

z1=12=2 z2=23=6
#include<iostream.h>
int n;
CT

void divizeaza(int s,int d,int &m)


{m=(s+d)/2;}
void combina(int x,int y,int &z)
{z=x+y;}
DA

void dei(int s,int d,int &z)


{int m,x1,x2;
if (d==s) z=s*(s+1);
else {divizeaza(s,d,m); dei(s,m,x1); dei(m+1,d,x2); combina(x1,x2,z);}}
DI

void main()
{int z; cout<<"n= ";cin>>n; dei(1,n,z); cout<<"suma ="<<z; }
Exemplul 3: S se calculeze termenul n al irului lui Fibonacci.
RA

Implementarea metodei divide et impera n acest exemplu se face astfel:


 Subprogramul divizeaza() Numrul de subprobleme n care se descompune
problema este 2 (k=2): determinarea termenului n-1 i determinarea termenului n-2.
ITU

Descompunerea se face implicit, prin parametrul cu care se apeleaz subprogramul


dei() i subprogramul de divizare nu mai este necesar.
 Subprogramul combina() Combinarea soluiei nseamn adunarea celor doi termeni
ai irului (x1 i x2) obinndu-se soluia z.
 Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd s-a ajuns
ED

la un termen direct calculabil. Dac s-a terminat procesul recursiv (prin procesul de divizare

Informatic 109
s-a ajuns la termenul f1 sau f2), atunci se prelucreaz cazul de baz; altfel, se apeleaz

IC
subprogramul dei() pentru primul termen al descompunerii, se apeleaz subprogramul

OG
f(2) =1
f(3)
f(4) z=1+1=2 f(1) =1
f(5) z=2+1=3 f(2) =1
z=3+2=5

G
f(2) =1
f(3)

DA
z=1+1=2 f(1) =1

f(6) f(2) =1
z=5+3=8 f(3)

PE
f(4) z=1+1=2 f(1) =1
z=2+1=3 f(2) =1
dei()pentru al doilea termen al descompunerii i se combin cele dou rezultate.
I
#include<iostream.h>
int n;
void combina(int x1,int x2,int &z)
{z=x1+x2;}

void dei(int n,int &z)


{int x1,x2;
IC

if (n==1 || n==2) z=1;


else {dei(n-1,x1); dei(n-2,x2); combina(x1,x2,z);}}
void main()
CT

{int z; cout<<"n= "; cin>>n; dei(n,z); cout<<z;}


n acest exemplu, problema a fost descompus n probleme care nu
Atenie sunt independente unele de altele i, n apelurile recursive, aceeai
DA

subproblem este rezolvat de mai multe ori: f(4), f(3), f(2), f(1).
Pentru acest tip de problem nu se recomand metoda divide et impera deoarece nu este
eficient. Pentru a calcula termenul fn trebuie s se calculeze termenii fn-1 i fn-2. Dar n
calculul termenului fn-1 reapare calculul termenului fn-2, iar n calculul ambilor termeni apare
DI

calculul termenului fn-3. .a.m.d. n acest caz, se recomand algoritmul iterativ, n care se
calculeaz pe rnd termenii f3, f4, , fn, pornind de la termenii f1=f2=1. Formula de recuren
este: fi = fi-1+fi-2, pentru 3in. Deoarece termenul fi nu depinde dect de doi termeni, fi-1 i
fi-2, nu este necesar s se memoreze ntregul ir de termeni, ci, pentru fiecare subproblem i,
RA

numai termenii obinui n subproblemele i-1 i i-2.


Exemplul 4: S se determine, simultan, valoarea minim i valoarea maxim dintr-un
vector v care conine numere ntregi. Numrul de elemente ale vectorului (n) i elementele
ITU

lui se citesc de la tastatur.


Implementarea metodei divide et impera n acest exemplu se face astfel:
 Subprogramul divizeaza() Numrul de subprobleme n care se descompune
problema este 2 (k=2). Divizarea mulimii datelor de intrare se face la fel ca la exemplul
pentru calcularea sumei elementelor unui vector i subprogramele sunt identice.
ED

110 Tehnici de programare
 Subprogramul combina() Combinarea soluiei nseamn determinarea minimului (z1)

IC
i a maximului (z2) dintre cele dou valori minime (x1 i y1), respectiv maxime (x2 i y2)
obinute prin rezolvarea celor dou subprobleme. n subprogram sunt combinate cele

OG
dou perechi de valori obinute din cele dou intervale. Dac x1>y1, atunci minimul
(z1) este y1; altfel, este x1. Dac x2>y2, atunci maximul (z2) este x2; altfel, este y2.
 Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd
submulimea conine un singur element (se pot calcula minimul i maximul; att minimul
ct i maximul vor avea valoarea elementului). Dac s-a terminat procesul recursiv (prin

G
procesul de divizare, cele dou capete ale intervalului au ajuns s fie identice), atunci
se prelucreaz cazul de baz (se calculeaz minimul i maximul, n variabilele z1 i z2

DA
corespunztoare soluiei); altfel, se apeleaz subprogramul pentru divizarea interva-
lului, se apeleaz subprogramul dei() pentru primul interval, se apeleaz subpro-
gramul dei() pentru al doilea interval i se combin cele dou rezultate.
#include<iostream.h>

PE
int v[100],n;
void divizeaza(int s,int d,int &m)
{m=(s+d)/2;}
void combina(int x1,int y1,int &z1,int x2,int y2,int &z2)
{if (x1>y1) z1=y1; else z1=x1;
I
if (x2>y2) z2=x2; else z2=y2;}
void dei(int s,int d,int &z1, int &z2) //z1 minim, z2 maxim
{int m,x1,x2,y1,y2;

if (d==s) z1=z2=v[s];
else {divizeaza(s,d,m);
IC

dei(s,m,x1,x2); //x1 minim, x2 maxim


dei(m+1,d,y1,y2); //y1 minim, y2 maxim
combina(x1,y1,z1,x2,y2,z2);}}
CT

void main()
{int i,z1,z2; cout<<"n= ";cin>>n;
for(i=1;i<=n;i++) {cout<<"v["<<i<<"]="; cin>>v[i];}
dei(1,n,z1,z2);
DA

cout<<"minimul ="<<z1<<endl<<"maximul ="<<z2<<endl;}


Exemplul 5: S se calculeze suma a dou polinoame. Gradele celor dou polinoame, n
i m, i coeficienii celor dou polinoame se citesc de la tastatur. Coeficienii celor dou
DI

polinoame se memoreaz n vectorii p i q, iar coeficienii polinomului sum se memoreaz


n vectorul r.
Implementarea metodei divide et impera n acest exemplu se face astfel:
 Subprogramul divizeaza() Numrul de subprobleme n care se descompune
RA

problema este 2 (k=2). Deoarece exist dou mulimi de date de intrare (vectorii p i q,
care memoreaz coeficienii celor dou polinoame), se va lua ca reper mulimea cu cele
mai multe elemente. Mulimea datelor de intrare este divizat n dou submulimi dis-
juncte, prin divizarea mulimii indicilor n dou submulimi disjuncte de indici, adic muli-
ITU

mea indicilor [s,d] (unde s este primul indice, iar d este ultimul indice d=maxim(n,m)+1)
este divizat n dou submulimi disjuncte [s,mijl] i [mijl+1,d], unde mijl este indicele
din mijlocul intervalului: mijl=(s+d)/2. Procesul de divizare este identic cu cel de la
exemplele anterioare.
ED

Informatic 111
 Subprogramul combina() Deoarece n cazul de baz se determin unul dintre coe-

IC
ficienii polinomului sum, care se scrie direct n vectorul r, acest subprogram nu mai
este necesar.
 Subprogramul dei() O subproblem corespunde cazului de baz atunci cnd submul-

OG
imea conine un singur element (se poate calcula coeficientul polinomului sum). Dac
s-a terminat procesul recursiv (prin procesul de divizare, cele dou capete ale intervalului
au ajuns s fie identice), atunci se prelucreaz cazul de baz prin care se calculeaz
coeficientul polinomului sum pentru acel indice (dac termenul care se calculeaz are

G
indicele mai mic dect gradul minim al polinoamelor, atunci el este egal cu suma coefi-
cienilor celor dou polinoame; altfel, dac polinomul p are gradul mai mic dect al polino-

DA
mului q, atunci el este egal cu coeficientul polinomului q; altfel, el este egal cu coeficientul
polinomului p); altfel, se apeleaz subprogramul pentru divizarea intervalului, se apelea-
z subprogramul dei() pentru primul interval i apoi pentru al doilea interval.
#include<iostream.h>

PE
int p[10],q[10],r[10],n,m;
int maxim(int x,int y)
{if (x>y) return x; else return y;}
int minim(int x,int y)
{if (x>y) return y; else return x;}
I
void divizeaza(int s,int d,int &mijl)
{mijl=(s+d)/2;}
void dei(int s,int d)

{int mijl;
if (d==s)
IC

if (d<=minim(n,m)) r[d]=p[d]+q[d];
else if(n<m) r[d]=q[d];
else r[d]=p[d];
CT

else {divizeaza(s,d,mijl); dei(s,mijl); dei(mijl+1,d);}}


void main()
{int i; cout<<"n= ";cin>>n; cout<<"m= ";cin>>m;
for(i=1;i<=n+1;i++) {cout<<"p("<<i-1<<")= "; cin>>p[i];}
DA

for(i=1;i<=m+1;i++) {cout<<"q("<<i-1<<")= "; cin>>q[i];}


dei(1,maxim(n,m)+1);
for(i=maxim(n,m)+1;i>=1;i--)
if (r[i]!=0)
DI

{if (r[i]!=1) {cout<<r[i]; if (i!=1) cout<<"*";}


if (i>2) cout<<"x^"<<i-1; else if (i==2) cout<<"x";
if (i!=1) cout<<" + ";}}
RA

1. Programul urmtor afieaz n ordine invers elementele unui


Tem vector. Explicai cum a fost folosit metoda divide et impera pentru
a rezolva problema.
#include<iostream.h>
ITU

int v[100],n;
void divizeaza(int s,int d,int &m) {m=(s+d)/2;}
void dei(int s,int d)
{int m;
if (d==s) cout<<v[s]<<" ";
ED

112 Tehnici de programare

IC
else {divizeaza(s,d,m); dei(m+1,d); dei(s,m);}}
void main()
{int i; cout<<"n= ";cin>>n;

OG
for(i=1;i<=n;i++) {cout<<"a("<<i<<")= "; cin>>v[i];}
dei(1,n);}
2. Determinai ce calculeaz programul urmtor. Explicai cum a fost folosit metoda
divide et impera pentru a rezolva problema.
#include<iostream.h>

G
int n;
void divizeaza(int s,int d,int &m) {m=(s+d)/2;}

DA
void combina(int x,int y,int &z) {z=x+y;}
void dei(int s,int d,int &z)
{int m,x1,x2;
if (d==s) {if(s%2==0) z=-s*5; else z=s*5;}

PE
else
{divizeaza(s,d,m); dei(s,m,x1); dei(m+1,d,x2); combina(x1,x2,z);}}
void main()
{int z; dei(1,20,z); cout<<"suma = "<<z;}
I
Scriei urmtoarele programe, n care s folosii metoda divide et impera.
Tem Valorile pentru datele de intrare se citesc de la tastatur.
1. S se calculeze n!.
2. S se calculeze simultan produsul i suma a n numere memorate ntr-un vector.

3. S se calculeze suma 1+12+123+...+123...n.


4. S se numere elementele pare dintr-un vector.
IC

5. S se verifice dac un vector conine numai numere pozitive sau numai numere negative.
6. S se calculeze c.m.m.d.c. a n numere memorate ntr-un vector.
CT

7. S se determine numrul de apariii ale unei valori x ntr-un vector.


8. S se calculeze valoarea unui polinom P(x), ntr-un punct x precizat.
Complexitatea algoritmului Divide et Impera
DA

Metoda divide et impera se bazeaz pe rezolvarea recursiv a subproblemelor n care


este divizat problema iniial.
Atunci cnd un algoritm conine un apel recursiv, timpul su de execuie este dat de o formul
recursiv care calculeaz timpul de execuie al algoritmului, pentru o dimensiune n a datelor
DI

de intrare, cu ajutorul timpilor de execuie pentru dimensiuni mai mici. Timpul de execuie al
unui algoritm care folosete metoda divide et impera se bazeaz pe calculul timpilor de
execuie ai celor trei etape de rezolvare a problemei. Dac:
 problema iniial se divizeaz n a subprobleme, pentru care dimensiunea datelor de
RA

intrare reprezint 1/b din dimensiunea problemei iniiale;


 timpul de execuie al problemei iniiale este T(n);
 timpul necesar pentru a divide problema n subprobleme este D(n);
 timpul necesar pentru combinarea soluiilor subproblemelor pentru a obine soluia
ITU

problemei este C(n);


 timpul necesar pentru rezolvarea cazului (1) pentru cazul de baz
de baz este (1); T(n) =
atunci se obine funcia pentru timpul de aT(n/b)+D(n)+C(n) n caz contrar
ED

execuie care este prezentat alturat.



Informatic 113
De exemplu, pentru a calcula suma elementelor unui vector cu n elemente, problema se

IC
descompune n dou subprobleme (a=2) i dimensiunea datelor de intrare pentru o subpro-
blem reprezint jumtate din dimensiunea datelor iniiale (b=2). Pentru divizarea problemei

OG
n subprobleme, se calculeaz mijlocul intervalului de indici, i O(D(n))=(1)). Pentru
combinarea celor dou soluii ale fiecrei subprobleme adun cele dou valori i
k
O(C(n))=(1). Considerm c n=2 . Rezult c:
k k-1 k-1 2
T(n)=T(2 )+2(1) = 2(T(2 )+2(1))+2(1 )= 2(T(2 )+2 (1) =
k-2 2 2 k-2 3
2(2T(2 )+2(1))+2 (1)=2 T(2 )+2 (1) = ... =

G
k 0 k+1 k k+1 k
2 T(2 )+2 (1) = 2 (1)+2 (1) = 2 3 = n3.
Ordinul de complexitate al algoritmului este O(n). Algoritmul iterativ pentru rezolvarea

DA
acestei probleme are ordinul de complexitate O(n).
Observaie. Pentru acest gen de probleme, metoda iterativ este mai eficient. Rezolvarea
acestui tip de probleme cu ajutorul metodei divide et impera a avut numai un rol scolastic,

PE
pentru nelegerea metodei i a implementrii ei.
Metoda divide et impera se recomand n urmtoarele cazuri:
 algoritmul obinut este mai eficient dect algoritmul clasic (iterativ) de exemplu, algo-
ritmul de cutare ntr-un vector sortat i algoritmii pentru sortarea unui vector;
 rezolvarea problemei prin divizarea ei n subprobleme este mai simpl dect rezol-
I
varea clasic (iterativ) de exemplu, problema turnurilor din Hanoi.

1.6.3. Cutarea binar


S se caute ntr-un ir de numere ntregi ordonate strict cresctor (sau varianta strict
IC

descresctor) poziia n care se gsete, n ir, o valoare x citit de la tastatur. Dac


valoarea nu se gsete n ir, s se afieze un mesaj de informare.
Algoritmul de cutare secvenial ntr-un vector are ordinul de complexitate O(n). Pornind
CT

de la faptul c vectorul este un vector particular (este ordonat strict cresctor sau strict
descresctor) se poate folosi metoda divide et impera. Pentru un vector ordonat strict
cresctor, paii algoritmului sunt:
PAS1. Se divizeaz vectorul v n doi subvectori, prin divizarea mulimii indicilor [s,d] (unde
DA

s este indicele primului element, iar d indicele ultimului element), n dou submulimi
disjuncte, [s,m-1] i [m+1,d], unde m este indicele din mijlocul intervalului: m=(s+d)/2.
PAS2. Dac elementul situat pe poziia din mijloc (v[m]) are valoarea x, atunci proble-
ma este rezolvat i poziia este m; altfel, dac elementul din mijlocul
DI

vectorului este mai mic dect valoarea x, atunci cutarea se face printre
elementele cu indicii n mulimea [s,m]; altfel, cutarea se face printre
elementele cu indicii din mulimea [m+1,d]. Pasul 2 se execut pn cnd se
gsete elementul sau pn cnd vectorul nu mai poate fi mprit n subvectori.
RA

#include<iostream.h>
int v[100],n,x;
void divizeaza(int s,int d,int &m)
ITU

{m=(s+d)/2;}
void cauta(int s,int d,int &z)
{int m;
if (d>s){divizeaza(s,d,m);
if (v[m]==x) z=m;
ED

114 Tehnici de programare

IC
else if (x>v[m]) cauta(m+1,d,z);
else cauta(s,m-1,z);}}
void main()

OG
{int i,z=0; cout<<"n= ";cin>>n; cout<<"x= ";cin>>x;
for(i=1;i<=n;i++) {cout<<"v["<<i<<"]="; cin>>v[i];}
cauta(1,n,z);
if(z==0) cout<<"nu exista elementul "<<x<<" in vector";
else cout<<"exista pe pozitia "<<z;}

G
Complexitatea algoritmului de cutare binar. Pentru divizarea problemei n subproble-
me, se calculeaz mijlocul intervalului de indici i O(D(n))=(1). Deoarece cutarea se face

DA
numai ntr-unul dintre cei doi subvectori (problema iniial se rezolv prin rezolvarea
uneia dintre cele dou subprobleme) i a=1, formula recurent a timpului de execuie
k
este T(n)= T(n/2)+(1). Considerm c n=2 (k=log2n). Rezult c:
k k-1 k-1
T(n)=T(2 )+(1) = (T(2 ) +(1)) +(1)= T(2 )+2(1)) = ... =

PE
0
T(2 )+(k+1)(1) = (1)+ (k+1)(1) = (k+2)(1)= log2n (1).
Ordinul de complexitate al algoritmului este O(log2n).
Aplicarea algoritmului de cutare binar
I
Exemplu. S se determine cu o precizie de 4 zecimale rdcina real din intervalul [0,1]
3
a ecuaiei x +x-1=0.
S-a identificat pentru aceast ecuaie o rdcin n intervalul [0,1] i ne propunem s locali-
zm aceast rdcin n limitele unei precizii de 4 zecimale, printr-o valoare x. Pentru cuta-

rea valorii x, se va folosi metoda biseciei care const n reducerea intervalului de cutare
prin njumtirea repetat i selectarea subintervalului n care se gsete rdcina. Intervalul
IC

[s,d] este mprit n dou subintervale, [s,m] i [m,d], unde m=(s+d)/2. Cutarea rdcinii
3
se va face n subintervalul n care funcia f(x)=x +x-1 i schimb semnul, astfel: dac
CT

f(s)*f(m)<0, atunci cutarea continu n intervalul [s,m]; altfel, cutarea continu n sub-
intervalul [m,d]. Procesul recursiv este ntrerupt cnd se ajunge la intervalul [s,d] pentru care
d-s<r, unde r este eroarea acceptat pentru o precizie de 4 zecimale i are valoarea 0,0001.
#include<iostream.h>
DA

#include<iosmanip.h>
const float r=0.0001;
float f(float x)
{return x*x*x+x-1;}
DI

void divizeaza(float s,float d,float &m)


{m=(s+d)/2;}
void radacina(float s,float d,float &z)
{float m;
RA

if (d-s<r) z=(s+d)/2;
else
{divizeaza(s,d,m);
if (f(s)*f(m)<0) radacina(s,m,z);
ITU

else radacina(m,d,z);}}
void main()
{float z=0; radacina(0,1,z); cout<<"radacina= "<<z<<endl;
cout<<"f(x)= "<<setiosflags(ios::fixed)<<f(z); }
ED

Informatic 115
1. S se caute ntr-un ir de numere ntregi, n care mai nti se

IC
Tem gsesc numerele pare i apoi numerele impare poziia n care se
gsete, n ir, o valoare x citit de la tastatur.

OG
2. S se calculeze radicalul de ordinul 2 din numrul a, cu o aproximaie de 4 zecimale,
fr a folosi funcia matematic de sistem sqrt(). S se compare rezultatul obinut cu
rezultatul furnizat de funcia matematic de sistem. Indicaie. Pornind de la ecuaia
2
x -a=0 se va identifica intervalul n care se gsete soluia i apoi se va localiza cu o
precizie de 4 zecimale rdcina real din acest interval.

G
3. S se calculeze partea ntreag a radicalului de ordinul 3 din numrul a, fr a folosi
funcia matematic de sistem.

DA
1.6.4. Sortarea prin interclasare (MergeSort)
Algoritmul de interclasare se execut pe doi vectori ordonai dup acelai criteriu, pentru a

PE
obine un al treilea vector, care s conin elementele primilor doi vectori, ordonate dup
acelai criteriu. Algoritmul de sortare prin interclasare se bazeaz pe observaia c orice
vector care conine un singur element este un vector sortat. Algoritmul de interclasare se
poate folosi pentru sortarea unui vector, folosind metoda divide et impera, astfel:
PAS1. Se descompune problema n subprobleme
I
10 8 7 9 5
similare, prin mprirea vectorului n doi sub-
vectori avnd mulimea indicilor [s,m] i
[m+1,d], unde m este indicele din mijlocul 10 8 7 9 5

intervalului: m=(s+d)/2.
PAS2. Dac subvectorul conine un singur element,
10 8 7 9 5
IC

atunci se consider sortat (corespunde ca-


zului de baz); altfel, se continu descom-
punerea lui n subvectorii care au mulimea 10 8
CT

indicilor [s,m] i mulimea indicilor [m+1,d].


PAS3. Se combin soluiile celor dou subpro-
bleme prin interclasarea celor doi vectori 8 10
sortai, obinndu-se un vector sortat.
DA

Vectorul care se sorteaz este x. Prin subprogramul


interclaseaza() se realizeaz combinarea soluii- 7 8 10 5 9
lor, prin interclasarea subvectorului x, care are muli-
mea indicilor [s,m], cu subvectorul x, care are muli- 5 7 8 9 10
DI

mea indicilor [m+1,d], n vectorul auxiliar v, dup care


vectorul v se copiaz n vectorul x care are mulimea indicilor [s,d].
#include<iostream.h>
RA

int x[100],n;
void divizeaza(int s,int d,int &m)
{m=(s+d)/2;}
void interclaseaza(int s,int d,int m)
ITU

{int i=s,j=m+1,k=1,v[100];
while (i<=m && j<=d)
{if (x[i]<x[j]) {v[k]=x[i]; i++;}
else {v[k]=x[j]; j++;}
k++;}
ED

if (i<=m) while (i<=m) {v[k]=x[i]; i++; k++;}



116 Tehnici de programare

IC
else while (j<=d) {v[k]=x[j]; j++; k++;}
for (k=1,i=s;i<=d;k++,i++) x[i]=v[k];}
void MergeSort(int s,int d)

OG
{int m;
if (s<d) {divizeaza(s,d,m);
MergeSort(s,m);
MergeSort(m+1,d);
interclaseaza(s,d,m);}}

G
void main()
{int i; cout<<"n= ";cin>>n;

DA
for(i=1;i<=n;i++) {cout<<"x["<<i<<"]= ";cin>>x[i];}
MergeSort(1,n);
cout<<"vectorul sortat"<<endl;
for(i=1;i<=n;i++) cout<<x[i]<<" ";}

PE
Complexitatea algoritmului de sortare prin interclasare. Pentru divizarea problemei n
subprobleme, se calculeaz mijlocul intervalului de indici i O(D(n))=(1)). Pentru combi-
narea soluiilor, se execut interclasarea a doi vectori i O(D(n))=O(n). Timpul de
k
execuie este T(n)= 2T(n/2)+n. Considernd c n=2 , rezult:
I
k k k-1 k-1 k k-1 k k
T(n)=T(2 )+2 = 2(T(2 )+ 2 ) +2 = 2T(2 ) +2 +2 = ... =
k-2 k-2 k k 2 k-2 k-2 k k k k
22(T(2 )+ 2 ) +2 +2 = 2 (T(2 )+ 2 ) +2 +2 +2 = k2 = log2n n.
Ordinul de complexitate al algoritmului este O(nlog2n).

1.6.5. Sortarea rapid (QuickSort)


IC

Prin aceast metod de sortare se execut urmtoarele operaii prin care sunt rearanjate
elementele din cadrul vectorului:
CT

X1 X2 X3 Xi-1 Xi Xi+1 Xn-1 Xn


DA

Pivotul Vectorul iniial

 Primul element din vector, numit pivot, este mutat n cadrul vectorului pe poziia pe
DI

care trebuie s se gseasc n vectorul sortat.


 Toate elementele mai mici dect el vor fi mutate n vector n faa sa.
 Toate elementele mai mari dect el vor fi mutate n vector dup el.
RA

Xs Xs+1 Xs+2 Xm-1 Xm Xm+1 Xd-1 Xd

Subvectorul din stnga pivotului Subvectorul din dreapta pivotului


(elemente mai mici dect pivotul) Pivotul (elemente mai mari dect pivotul)
ITU

De exemplu, dac vectorul conine elementele {3, 4, 1, 5, 2}, dup executarea operaiilor
precizate vectorul va fi {2, 1, 3, 5, 4}.
Folosind metoda divide et impera problema iniial va fi descompus n subprobleme astfel:
ED

PAS1. Se rearanjeaz vectorul, determinndu-se poziia n care va fi mutat pivotul (m).



Informatic 117
PAS2. Problema iniial (sortarea vectorului iniial) se descompune n dou subprobleme,

IC
prin descompunerea vectorului n doi subvectori: vectorul din stnga pivotului i
vectorul din dreapta pivotului care vor fi sortai prin aceeai metod. Aceti sub-

OG
vectori, la rndul lor, vor fi i ei rearanjai i mprii de pivot n doi subvectori etc.
PAS3. Procesul de descompunere n subprobleme va continua pn cnd, prin descom-
punerea vectorului n subvectori, se vor obine vectori care conin un singur element.
Subprogramele specifice algoritmului Divide et Impera vor avea urmtoarea semnificaie:
 n subprogramul divizeaza() se va rearanja vectorul i se va determina poziia pivotului

G
xm , care va fi folosit pentru divizarea vectorului n doi subvectori: [xs, xm-1] i [xm+1, xd].
 Subprogramul combina() nu mai este necesar, deoarece combinarea soluiilor se

DA
face prin rearanjarea elementelor n vector.
n subprogramul divizeaza() vectorul se parcurge de la ambele capete ctre poziia n
care trebuie mutat pivotul. Se vor folosi doi indici: i pentru parcurgerea vectorului de la
nceputul lui ctre poziia pivotului (i se va incrementa) i j pentru parcurgerea vectorului

PE
de la sfritul lui ctre poziia pivotului (j se va decrementa). Cei doi indici vor fi iniializai cu
capetele vectorului (i=s, respectiv j=d) i se vor deplasa pn cnd se ntlnesc, adic att
timp ct i<j. n momentul n care cei doi indici s-au ntlnit nseamn c operaiile de
rearanjare a vectorului s-au terminat i pivotul a fost adus n poziia corespunztoare lui n
I
vectorul sortat. Aceast poziie este i (sau j) i va fi poziia m de divizare a vectorului.
n exemplele urmtoare sunt prezentate dou versiuni pentru subprogramul divizeaza():
Versiunea 1. Se folosesc variabilele logice: pi, pentru parcurgerea cu indicele i, i pj,

pentru parcurgerea cu indicele j: Ele au valoarea: 1 se parcurge vectorul cu acel indice i


0 nu se parcurge vectorul cu acel indice; cele dou valori sunt complementare.
IC

#include<iostream.h>
int x[100],n;
void schimb(int &a, int &b)
CT

{int aux=a; a=b; b=aux;}


void divizeaza(int s,int d,int &m)
{int i=s,j=d,pi=0,pj=1;
// pivotul fiind pe pozitia s, parcurgerea incepe cu indicele j
DA

while (i<j)
{if (x[i]>x[j]) {schimb(v[i],v[j]); schimb(pi,pj);}
i=i+pi; j=j-pj;}
m=i;}
DI

void QuickSort(int s,int d)


{int m;
if (s<d) {divizeaza(s,d,m);
RA

QuickSort(s,m-1);
QuickSort(m+1,d);}}
void main()
{int i; cout<<"n= ";cin>>n;
ITU

for(i=1;i<=n;i++) {cout<<"x["<<i<<"]= ";cin>>x[i];}


QuickSort(1,n);
cout<<"vectorul sortat"<<endl;
for(i=1;i<=n;i++) cout<<x[i]<<" ";}
ED

118 Tehnici de programare
i j

IC
Cei doi indici i i j sunt iniializai cu extremitile
vectorului (i=1; j=5) i parcurgerea ncepe cu indicele j 1 2 3 4 5
(pi=0; pj=1) 3 4 1 5 2
i j

OG
Se compar pivotul (3) cu ultimul element (2). Deoarece
pivotul este mai mic, cele dou valori se interschimb 1 2 3 4 5
i se schimb i modul de parcurgere (pi=1; pj=0 2 4 1 5 3
avanseaz indicele i).
Se compar elementul din poziia i (4) cu elementul din i j

G
poziia j (3). Deoarece 4 este mai mare dect 3, cele 1 2 3 4 5
dou valori se interschimb i se schimb i modul de 2 3 1 5 4

DA
parcurgere (pi=0; pj=1 avanseaz indicele j).
Se compar elementul din poziia i (3) cu elementul din i j
poziia j (5). Deoarece 3 este mai mic dect 5, cele dou 1 2 3 4 5
valori nu se interschimb i se pstreaz modul de 2 3 1 5 4

PE
parcurgere (pi=0; pj=1 avanseaz indicele j).
Se compar elementul din poziia i (3) cu elementul din po- ij
ziia j (1). 3 fiind mai mare dect 1, cele dou valori se in- 1 2 3 4 5
terschimb i se schimb i modul de parcurgere (avan- 2 1 3 5 4
seaz indicele i). Cei doi indici sunt egali.
I
Versiunea 2:
void divizeaza(int s,int d,int &m)
{int pivot=v[s],i=s,j=d;

while (i<j) {while(v[i]<pivot) i++;


while(v[j]>pivot) j--;
IC

if (i<j) schimb(v[i],v[j]);}
m=i;}
i j
CT

Iniial, cei doi indici i i j sunt iniializai cu extremitile


vectorului (i=1; j=5) i pivotul are valoarea 3. 1 2 3 4 5
3 4 1 5 2
Elementul din poziia i (3) nu este mai mic dect pivotul; i j
DA

indicele i nu avanseaz (i=1). Elementul din poziia j (2) 1 2 3 4 5


nu este mai mare dect pivotul; indicele j nu avanseaz 2 4 1 5 3
(j=5). Valorile din poziiile i i j se interschimb.
Elementul din poziia i (2) este mai mic dect pivotul; i j
DI

indicele i avanseaz pn la primul element mai mare 1 2 3 4 5


dect pivotul (i=2). Elementul din poziia j (3) nu este mai 2 3 1 5 4
mare dect pivotul; indicele j (j=5) nu avanseaz. Valorile
din poziiile i i j se interschimb.
RA

Elementul din poziia i (3) nu este mai mic dect pivotul; i j


indicele i nu avanseaz (i=2). Elementul din poziia j (4) 1 2 3 4 5
este mai mare dect pivotul; indicele j avanseaz pn la 2 1 3 5 4
primul element mai mic dect pivotul (j=3). Valorile din
ITU

poziiile i i j se interschimb.
Elementul din poziia i (1) este mai mic dect pivotul; indi- j i
cele i avanseaz la primul element mai mare dect pivotul 1 2 3 4 5
(i=4). Elementul din poziia j (3) nu este mai mare dect 2 1 3 5 4
pivotul; indicele j nu avanseaz (j=3). Indicele i este mai
mare dect indicele j.
ED

Informatic 119
Observaie. n ambele cazuri, algoritmul continu cu divizarea vectorului n subvectorii cu

IC
indicii [1,2] i [4,5] i rearanjarea elementelor n cei doi subvectori.
Complexitatea algoritmului de sortare rapid. Pentru divizarea problemei n subpro-

OG
bleme se calculeaz mijlocul intervalului de indici i O(D(n))=(1)). Pentru combinarea
soluiilor se parcurge vectorul, cu ajutorul celor doi indici, de la primul element pn la
ultimul element, i O(D(n))=O(n(1))=O(n). Timpul de execuie este T(n)= 2T(n/2)+n.
k
Considernd c n=2 , rezult:
k k k-1 k-1 k k-1 k k

G
T(n)=T(2 )+2 = 2(T(2 )+ 2 ) +2 = 2T(2 ) +2 +2 = ... =
k-2 k-2 k k 2 k-2 k-2 k k k k
22(T(2 )+ 2 ) +2 +2 = 2 (T(2 )+ 2 ) +2 +2 +2 = k2 = log2n n.

DA
Ordinul de complexitate al algoritmului este O(nlog2n).
Observaie. n comparaie cu algoritmii de sortare prin metoda seleciei directe i prin metoda
2
bulelor, care au ordinul de complexitate O(n ), algoritmii de sortare care folosesc strategia
divide et impera sunt mai eficieni.

PE
1. S se rearanjeze elementele unui vector astfel nct n vector s se
gseasc mai nti numerele impare i apoi numerele pare. Se vor
Tem realiza dou versiuni ale programului, cte una pentru fiecare
metod de sortare care folosete strategia divide et impera.
I
2. ntr-un fiier text sunt scrise urmtoarele informaii: pe primul rnd numrul de elevi din clas
n, iar pe urmtoarele n rnduri, pentru fiecare elev, mediile semestriale la disciplina
informatic. n cadrul unui rnd, mediile sunt separate prin spaiu. Fiecare elev se identific
prin numrul de ordine la citirea din fiier. S se scrie un program care s realizeze urmtoa-

rele cerine. Fiecare cerin va fi rezolvat printr-un subprogram. Ordonarea elementelor


vectorului i cutarea unui elev se vor face folosind algoritmii cei mai eficieni.
IC

a. Se citesc datele din fiierul text i se calculeaz media anual a fiecrui elev.
b. Pentru identificatorul unui elev, citit de la tastatur, se afieaz mediile semestriale
i media anual.
CT

c. Se rearanjeaz elevii n ordinea cresctoare a mediilor i se afieaz mediile


fiecrui elev.
d. Se scriu informaiile obinute n urma prelucrrilor ntr-un alt fiier text.
DA

1.6.6. Problema turnurilor din Hanoi


Pe trei tije, notate cu A, B i C, se pot monta discuri perforate, de diferite dimensiuni.
Iniial, pe tija A (tija surs) sunt aezate unele peste altele n discuri, n ordinea descres-
DI

ctoare a diametrelor, iar celelalte tije sunt goale. S se afieze toate mutrile care
trebuie fcute ca discurile de pe tija A s fie aranjate pe tija B (tija destinaie) n aceeai
ordine n care erau pe tija A, folosind tija C ca tij de manevr. O mutare nu se poate
face dect cu un disc i el nu poate fi aezat pe o tij dect peste un disc cu diametrul
RA

mai mare. S analizm mutrile care trebuie fcute pentru n=3:


 Se mut discul de pe tija A pe tija B (1).
 Se mut discul de pe tija A pe tija C (2).
 Se mut discul de pe tija B pe tija C (3).
ITU

n discuri

 Se mut discul de pe tija A pe tija B (4).


 Se mut discul de pe tija C pe tija A (5).
 Se mut discul de pe tija C pe tija B (6).
 Se mut discul de pe tija A pe tija B (7).
ED

120 Tehnici de programare

IC
B B
1

OG
A

C C
3

G
Mut primele 2
discuri pe tija de
2

DA
manevr
B B
4

PE
A A

C I C

Mut discul cu
diametrul maxim
pe tija destinaie

B B
7
IC

A A
CT

C 6 C

Mut cele dou


DA

discuri pe tija
5 destinaie
Folosind metoda Divide et Impera problema iniial va fi descompus n subprobleme astfel:
PAS1. Se mut primele n-1 discuri de pe tija surs pe tija de manevr.
DI

PAS2. Se mut discul cu diametrul cel mai mare de pe tija surs pe tija destinaie.
PAS3. Se mut cele n-1 discuri de pe tija de manevr pe tija destinaie.
#include<iostream.h>
RA

void hanoi(int n, char a, char b, char c)


{if (n==1) cout<<"Mutarea: "<<a<<"->"<<b<<endl;
else
{hanoi(n-1,a,c,b);
ITU

cout<<"Mutarea: "<<a<<"->"<<b<<endl;
hanoi(n-1,c,b,a);}}
void main()
{int n; char a='A',b='B',c='C'; cout<<"n= "; cin>>n;
hanoi(n,a,b,c);}
ED

Informatic 121
ntr-un parc cu o suprafa dreptunghiular care are coordonatele colului

IC
Tem din stnga sus (X1,Y1) i ale colului din dreapta jos (X2,Y2) se gsesc n
copaci. Poziia fiecrui copac pe teren este dat de coordonatele (xi,yi). n

OG
parc, trebuie amenajat un teren de joac pentru copii, de form dreptunghiular, cu laturile
paralele cu laturile parcului. S se determine dreptunghiul cu arie maxim pe care se poate
amenaja terenul de joac fr s se taie nici un copac. Indicaie. Considernd c un copac i
mparte dreptunghiul iniial n patru dreptunghiuri cu laturile paralele cu dreptunghiul iniial,
problema se descompune n patru subprobleme, fiecare subproblem rezolvnd cazul unuia

G
dintre cele patru dreptunghiuri, care au coordonatele colurilor ((X1,Y1); (xi, Y2)), ((xi, Y1);
(X2,Y2)), ((X1,Y1); (X2,yi)) i ((X1, yi); (X2,Y2)). La cazul de baz se ajunge atunci cnd

DA
dreptunghiul nu conine nici un copac. Pentru fiecare dreptunghi care nu conine nici un
copac, se calculeaz aria i se memoreaz coordonatele colurilor. Din combinarea soluiilor
obinute se identific dreptunghiul care are aria cea mai mare.

PE
Adevrat sau Fals:
1. n algoritmul metodei backtracking, iniializarea elementului k al soluiei se face cnd
I
se revine de pe nivelul k+1 la nivelul k.
2. Algoritmul metodei backtracking se ncheie dac s-au testat toate valorile posibile
pentru primul element al soluiei.
3. n algoritmul backtracking, dup gsirea unei soluii, se revine la nivelul anterior al

soluiei.
4. n algoritmul backtracking, trecerea de la nivelul k la nivelul k-1 al soluiei se face
IC

dup ce s-au gsit toate valorile posibile pentru nivelul k.


5. n algoritmul backtracking, iniializarea nivelului k al soluiei se face cu valoarea de pe
nivelul anterior al soluiei.
CT

6. n algoritmul backtracking, dac s-a trecut la nivelul k al soluiei nseamn c s-au


gsit primele k-1 elemente ale soluiei.
7. n algoritmul backtracking, trecerea la nivelul k+1 al soluiei se face dup ce au fost
testate toate valorile posibile pentru nivelul k al soluiei.
DA

8. n implementarea recursiv a metodei backtracking, revenirea din autoapel este


echivalent cu revenirea la nivelul anterior al soluiei, din varianta iterativ.
9. n implementarea recursiv a metodei backtracking, autoapelul este echivalent cu
trecerea la nivelul urmtor al soluiei din varianta iterativ.
DI

10. Divide et impera este metoda prin care problema iniial se descompune n subpro-
bleme care nu sunt independente.
11. Prin metoda divide et impera se gsete soluia optim a problemei.
RA

Alegei:
1. Algoritmul care implementeaz metoda backtracking este:
a. polinomial b. logaritmic c. exponenial d. liniar logaritmic
ITU

2. Algoritmul care implementeaz metoda sortrii rapide este:


a. liniar b. logaritmic c. ptratic d. liniar logaritmic
3. Algoritmul care implementeaz metoda cutrii binare este:
a. liniar b. logaritmic c. ptratic d. liniar logaritmic
ED

122 Tehnici de programare
4. Se utilizeaz metoda backtracking pentru generarea anagramelor cuvntului masca.

IC
S se precizeze cuvntul precedent i cuvntul urmtor secvenei camas, camsa,
caams:

OG
a. csaam i casma b. csama i casma c. csaam i casma d. csaam i caasm
5. Se utilizeaz metoda backtracking pentru generarea tuturor numerelor care se pot
forma cu cifrele 0, 2, 4 i 8. S se precizeze numrul precedent i numrul urmtor
secvenei 2840 4028 4082:
a. 2480 i 4280 b. 2804 i 4280 c. 2804 i 4208 d. 2480 i 4280

G
6. Se utilizeaz metoda backtracking pentru generarea irului de opt paranteze rotunde,
astfel nct ele s formeze o succesiune corect. S se precizeze irul de paranteze

DA
precedent i irul de paranteze urmtor secvenei (()(())) (()()()) (()())():
a. ((()())) i ()((())) b. ((()))() i ()((())) c. ((()))() i (())(()) d. ((()())) i (())(())
7. Se utilizeaz metoda backtracking pentru generarea submulimilor mulimii {1,2,3}.

PE
S se precizeze submulimea precedent i submulimea urmtoare secvenei de
submulimi {1} {1,3} {1,2} :
a. {} i {2,3} b. {} i {2} c. {2,3} i {1,2,3} d. {} i {3}
8. Dac se utilizeaz metoda backtracking pentru a genera toate permutrile de 5
obiecte i primele 4 permutri generate sunt: 5 4 3 2 1, 5 4 3 1 2, 5 4 2 3 1, 5 4 2 1 3,
I
atunci a cincea permutare este:
a. 5 4 3 2 1 b. 5 3 4 2 1 c. 5 4 1 2 3 d. 5 4 1 3 2
(Bacalaureat Sesiunea special 2003)

9. Se cere determinarea tuturor modalitilor de planificare n zile diferite a 4 probe


(rezisten, aruncarea suliei, srituri, tir) n oricare dintre cele 7 zile din sptmn.
IC

Problema este echivalent cu:


a. generarea combinrilor de 4 obiecte luate cte 7
b. generarea aranjamentelor de 4 obiecte luate cte 7
CT

c. generarea combinrior de 7 obiecte luate cte 4


d. generarea aranjamentelor de 7 obiecte luate cte 4
(Bacalaureat Sesiunea special 2003)
10. Generarea tuturor irurilor de 3 elemente, fiecare element putnd fi oricare numr din
DA

mulimea {1,2,3,4,5,6}, se realizeaz cu ajutorul unui algoritm echivalent cu algoritmul


de generare a:
a. aranjamentelor b. permutrilor c. combinrilor d. produsului cartezian
(Bacalaureat Sesiunea special 2003)
DI

11. Se cere determinarea tuturor modalitilor distincte de aezare n linie a tuturor celor
n sportivi aflai la o festivitate de premiere. Problema este echivalent cu generarea:
a. partiiilor unei mulimi de n obiecte b. aranjamentelor de n obiecte luate cte 1
c. permutrilor de n obiecte d. submulimilor unei mulimi cu n obiecte
RA

(Bacalaureat Sesiunea iunie-iulie 2003)


12. Se cere determinarea tuturor numerelor formate cu cifre aflate n ordine strict
cresctoare, cifre alese dintr-o mulime cu k cifre distincte date. De exemplu, pentru
ITU

cifrele alese din mulimea {1,5,2} se obin numerele 1, 2, 12, 5, 15, 25, 125 (nu
neaprat n aceast ordine). Problema este echivalent cu generarea:
a. partiiilor unei mulimi b. aranjamentelor de 10 obiecte luate cte k
c. permutrilor de k obiecte d. submulimilor nevide ale unei mulimi
(Bacalaureat Sesiunea august 2003)
ED

Informatic 123
13. Cineva dorete s obin i s prelucreze toate numerele formate din trei cifre din

IC
irul 2, 9, 4 i le genereaz exact n ordinea 222, 229, 224, 292, 299, 294, 242, 249,
244, 922, 929, 924, 992, 999, 994, 942, 949, 944, 422, 429, 424, 492, 499, 494, 442,

OG
449, 444. Dac dorete s obin prin acelai procedeu numerele formate din 4 cifre,
atunci dup numrul 4944 va urma:
a. 4949 b. 9222 c. 4422 d. 4924
(Bacalaureat Simulare2004)
14. Un elev folosete metoda backtracking pentru a genera submulimile mulimii

G
{1,2,5,6,9}. Cte soluii (submulimi) care obligatoriu conin elementul 2 i nu conin
elementul 6 a generat?

DA
a. 7 b. 16 c. 6 d. 8
(Bacalaureat Sesiunea special 2004)
15. Pentru a determina toate modalitile de a scrie pe 9 ca sum de numere naturale
nenule distincte (abstracie fcnd de ordinea termenilor), un elev folosete metoda

PE
backtracking genernd, n aceast ordine, toate soluiile: 1+2+6, 1+3+5, 1+8, 2+3+4,
2+7, 3+6 i 4+5. Aplicnd exact aceeai metod, el determin soluiile pentru
scrierea lui 12. Cte soluii de forma 3+ exist?
a. 7 b. 1 c. 2 d. 4
I
(Bacalaureat Sesiunea iunie-iulie 2004)
16. Pentru problema anterioar, care este a opta soluie determinat?
a. 2+3+7 b. 3+4+5 c. 1+5+6 d. 1+11
(Bacalaureat Sesiunea iunie-iulie 2004)

17. Pentru problema anterioar, stabilii care este soluia cu proprietatea c imediat dup
IC

ea este generat soluia 3+4+5?


a. 3+4+6 b. 2+3+7 c. 2+10 d. 4+8
(Bacalaureat Sesiunea iunie-iulie 2004)
CT

18. Se genereaz toate permutrile distincte de 4 obiecte, numerotate de la 1 la 4, avnd


proprietatea c 1 nu este vecin cu 3 (1 nu se afl imediat dup 3 i nici 3 imediat
dup 1) i 2 nu este vecin cu 4. Cte astfel de permutri se genereaz?
a. 12 b. 24 c. 6 d. 8
DA

(Bacalaureat Sesiunea august 2004)


19. Se genereaz toate submulimile formate din dou elemente ale mulimii {5,6,7,8}, n
ordinea: 5 6, 5 7, 5 8, 6 7, 6 8, i 7 8. Dac se utilizeaz exact aceeai metod pentru
a genera submulimile de trei elemente ale mulimii {2,3,4,5,6}, atunci penultima mul-
DI

ime generat este:


a. 3 4 5 b. 3 5 6 c. 4 5 6 d. 2 5 6
(Bacalaureat Simulare 2006)
RA

Miniproiecte:
Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:
a. rezolvarea problemei prin implementarea metodei backtracking sau divide et
impera;
ITU

b. explicarea noiunilor teoretice folosite pentru realizarea programului;


c. justificarea metodei alese.
1. O eav cu lungimea L trebuie s se confecioneze din n buci de eav, fiecare
bucat avnd lungimea ai. O bucat de eav nu poate fi tiat. S se gseasc, dac
ED

exist, soluia de a obine eava de lungime L prin sudarea unor buci de eav de

124 Tehnici de programare
lungimea ai. Se citesc, dintr-un fiier text, de pe primul rnd, lungimea evii L, i

IC
numrul de buci de eav n, i, de pe urmtorul rnd, lungimile fiecrei buci de
eav. Numerele de pe un rnd sunt separate prin spaiu.

OG
2. O bar are lungimea L. Se consider n repere de lungimi diferite. S se genereze toate
posibilitile de a tia bara dup reperele existente, fr s rmn rest la tiere, i
fiecare reper s fie folosit cel puin o dat. Se citesc, dintr-un fiier text de pe primul
rnd, lungimea barei L, i numrul de repere n, i de pe urmtorul rnd, reperele.
Numerele de pe un rnd sunt separate prin spaiu.

G
3. S se genereze toate posibilitile de plat a unei sume cu bancnote cu valori date,
pentru fiecare valoare de bancnot avnd la dispoziie un anumit numr de bancnote.

DA
4. Se dau n paralelipipede, avnd fiecare dimensiunile ai, bi i ci. S se construiasc un turn
de nlime maxim, prin suprapunerea acestor paralelipipede. Un paralelipiped poate fi
aezat pe orice fa. Un paralelipiped poate fi aranjat peste un alt paralelipiped numai

PE
dac faa lui nu depete faa paralelipipedului pe care este pus.
5. S se determine numrul de partiii distincte ale unui numr natural n. 4
Indicaie. Se descompune numrul n n dou numere, n1 i n2, dup 3+1 2+2
care fiecare numr nou obinut se descompune n alte dou numere.
Procesul de descompunere continu pn cnd n1<n2. Numrul de 2+1
I
partiii este egal cu numrul de descompuneri obinute. 1 1
6. ntr-un vector sunt memorate mai multe numere ntegi. S se plieze
repetat vectorul, pn cnd rmne un singur element, i s se afieze valoarea acestui

element. Plierea unui vector nseamn suprapunerea unei jumti (numit donatoare)
peste cealalt jumtate (numit receptoare). Dac numrul de elemente ale vectorului
IC

este impar, elementul din mijloc se elimin. De exemplu, pentru vectorul {1,2,3,4,5,6,7},
considernd prima jumtate ca fiind cea receptoare, vectorul obinut dup prima pliere
este {5,6,7}.
CT

7. ntr-un restaurant un meniu este format din trei feluri de mncare. Exist patru preparate
culinare pentru felul unu, cinci preparate culinare pentru felul doi i trei preparate culi-
nare pentru felul 3. Fiecare preparat culinar are un pre i un numr de calorii. S se
genereze toate meniurile pe care le poate comanda o persoan, care s nu depeasc
DA

suma s i numrul de calorii c. Datele se citesc dintr-un fiier text, astfel: de pe primul
rnd, suma s i numrul de calorii, de pe rndul urmtor, n ordine, preul fiecrui pre-
parat culinar, i, de pe ultimul rnd, n aceeai ordine, caloriile fiecrui preparat culinar.
DI

8. Dou persoane i mpart n obiecte, astfel: prima persoan ia m obiecte, iar cealalt
persoan restul obiectelor. Fiecare obiect are o valoare vi. S se genereze toate
posibilitile de distribuire a celor n obiecte ntre cele dou persoane astfel nct
fiecare persoan s primeasc obiecte care s aib aceeai valoare total.
RA

9. Se citesc de la tastatur un numr natural n (0<n10) i apoi n numere naturale: a1,


a2, a3, ..., an. S se afieze toate posibilitile de a intercala, ntre toate cele n numere
operatorii + i - , astfel nct, evalund de la stnga la dreapta expresia obinut, la
fiecare pas, rezultatul obinut s fie strict pozitiv.
ITU
ED

IC
2. Implementarea

OG
structurilor de date
2.1. Datele prelucrate de algoritmi

G
Ai aflat deja c orice rezolvare de problem ncepe prin definirea datelor, continu cu

DA
prelucrarea lor (de exemplu, atribuirea de valori sau efectuarea unor calcule numerice) i
se termin fie cu afiarea valorii lor, fie cu stocarea lor pe un mediu de memorare, n
vederea unei prelucrri ulterioare. Aadar:

PE
Datele sunt iruri de bii care sunt prelucrate de calculator.

Data este o resurs la dispoziia programatorului. Orice limbaj de programare permite folo-
sirea mai multor tipuri de date. Indiferent de tipul de date ales, reprezentarea sa n memoria
calculatorului (fie intern, fie extern) se face printr-un ir de bii. Pentru a realiza aceast
I
reprezentare, sunt implementai algoritmi de codificare ce asigur corespondena dintre
tipul de dat i irul de bii, att la scrierea datelor, ct i la citirea lor. Tipul de dat ales de
ctre programator influeneaz calitatea programului, deoarece el determin dimensiunea
zonei de memorie alocate, algoritmul de codificare i operatorii admii pentru prelucrare.

Datele pot fi clasificate folosind mai multe criterii:


IC

criteriul naturii (tipului) datelor


CT

Date de tip ntreg Date de tip real


n limbajul C++ sunt implementate mai multe n limbajul C++ sunt implementate mai multe
subtipuri ntregi de date: subtipuri reale de date: float (4 octei), double
 Tipuri de date ntregi pozitive: unsigned
DA

(8 octei), long double (10 octei).


char (1 octet), unsigned int (2 octei),
unsigned long (4 octei);
 Tipuri de date ntregi cu semn: char (1 Date de tip logic (boolean).
octet), int (2 octei), long (4 octei); n limbajul C++ nu este implementat tipul logic;
DI

pentru evaluarea unei operaii logice se folosesc


valorile numerice 1 sau diferit de 0 (true) i 0
Date de tip caracter
(false).
n limbajul C++ este implementat tipul char.
RA

Tipul datelor determin modul n care sunt reprezentate datele n memoria intern i
operatorii permii pentru prelucrarea acestor date. Pentru fiecare tip de dat, sunt
implementai algoritmi pentru ncrcarea valorii datei n zona de memorie, algoritmi pentru
ITU

adresarea zonei de memorie alocate, algoritmi pentru extragerea valorii datei din zona de
memorie alocat etc. De exemplu, tipurile unsigned char i unsigned int se folosesc
amndou pentru reprezentarea numerelor ntregi pozitive. Numai c, tipul unsigned
char se memoreaz ntr-un octet i permite memorarea unor valori pozitive cuprinse ntre
0 i 255 (255=28-1), iar tipul unsigned int se memoreaz n doi octei (cea mai frecven-
ED

t implementare a limbajului C++ pe microcalculatoare) i permite memorarea unor valori



126 Implementarea structurilor de date
16
pozitive cuprinse ntre 0 i 65535 (65535=2 -1). Tipul int se reprezint pe 2 octei, prin

IC
mrime i semn (folosindu-se primul bit pentru semn, iar urmtorii 15 bii pentru reprezen-
tarea n binar a numrului). Acest tip poate fi folosit pentru reprezentarea numerelor ntregi
15

OG
cu semn care au o valoare cuprins ntre -32768...32767 (32767=2 -1). Tipul float se
reprezint pe 4 octei n virgul mobil, prin reprezentarea exponentului i a mantisei
(folosindu-se primul bit pentru semnul numrului, urmtorul bit pentru semnul exponentului,
7 bii pentru exponent i 23 de bii pentru mantis). Acest tip poate fi folosit pentru
38 38
reprezentarea numerelor reale cu 7 cifre semnificative, n domeniul -10 ...10 .

G
Se poate testa lungimea n octei a fiecrui tip de dat folosind
operatorul sizeof(). Acesta furnizeaz numrul de octei folosii pentru

DA
memorarea unei date, precizat printr-o expresie sau prin tipul datei.

Sintaxa operatorului este: sizeof(<tip>), unde <tip> este tipul datei care se testeaz, sau
sizeof(<expresie>), unde <expresie> este o expresie care se evalueaz.

PE
Exemple:
 operatorul sizeof(int) va furniza rezultatul 2, deoarece reprezentarea acestui tip de
dat se face pe 2 octei.
 considernd declaraiile int a; float b; operatorul sizeof(a+b); va furniza
I
rezultatul 4, deoarece rezultatul obinut n urma evalurii expresiei este de tip float i
reprezentarea sa necesit 4 octei.
Pe lng aceste tipuri de date, n limbajul C++ mai sunt implementate (Anexa 1):
 tipul pointer i

 tipul referin.
IC

Analiza datelor se poate face n trei moduri:


 Conceptual (la nivelul algoritmului pentru rezolvarea problemei). De exemplu, o dat n
este un numr ntreg pozitiv, cu valori cuprinse ntre 0 i 40000.
CT

 Logic (la nivelul implementrii n limbajul de programare). De exemplu, pentru data n se


alege tipul unsigned int, care este o dat numeric de tip ntreg cu valori pozitive, ce
poate lua valori de la 0 la 65535 i care permite aplicarea operatorilor aritmetici i
relaionali. La nivelul limbajului de programare, este necesar s fie implementai diferii
DA

algoritmi, care s permit folosirea acestui tip de dat: algoritmi de ncrcare a valorii
datei n zona de memorie, algoritmi de adresare a zonei de memorie alocate, algoritmi
de extragere a valorii din zona de memorie etc.
 Fizic (la nivelul reprezentrii ei n memoria intern corespunztor modului de implemen-
DI

tare n limbajul de programare). De exemplu, data de tip unsigned int este repre-
zentat pe doi octei de memorie, prin codificarea n binar a valorii numerice.
Memoria intern a calculatorului este organizat sub forma unor locaii de dimensiunea
RA

unui octet, numerotate consecutiv, pornind de la 0. Aceste numere, exprimate n hexaze-


cimal, se numesc adrese de memorie. Locaiile de memorie pot fi manipulate individual
sau n grupuri contigue. O dat manipulat de program prin intermediul unei variabile de
memorie este caracterizat de mai multe atribute, pe care le primete n momentul n
ITU

care este declarat n program.


Exemplu: Prin urmtoarea declarare a unei date n program:
unsigned int a=100;
data va primi urmtoarele atribute:
ED

Informatic 127
 Numele. Este identificatorul folosit pentru referirea datei n cadrul programului. n

IC
exemplu, a.
 Adresa. Este adresa de memorie intern la care se aloc spaiu datei respective,

OG
pentru a stoca valoarea datei. n exemplu, adr (un numr binar care reprezint adre-
sa unui octet de memorie). Atribuirea adresei este fcut de sistem, n funcie de
locaiile cu dimensiunea de 2 octei libere din zona de lucru alocat programului.
 Valoarea. Este coninutul, la un moment dat, al zonei de memorie rezervat datei. n
exemplu, 100.

G
 Tipul. Determin: domeniul de definiie intern al datei (mulimea n care poate lua valori
data), operatorii care pot fi aplicai pe acea dat i modul n care data este reprezentat

DA
n memoria intern (metoda de codificare n binar a valorii datei). n exemplu, tipul este
unsigned int i determin: domeniul de definiie intern al datei (intervalul [0,
65535]), operatorii care pot fi aplicai pe acea dat (operatorii permii de tipul numeric
aritmetici, relaionali, logici, logici pe bii etc.) i modul n care data este reprezentat n

PE
memoria intern (reprezentarea prin conversia numrului din zecimal n binar).
 Lungimea. Este dimensiunea zonei de memorie alocate datei i se msoar n octei.
Ea depinde de modul de reprezentare intern a tipului de dat. n exemplu, 2 octei
(datei i se aloc un grup contiguu de 2 octei).
I
2 octei valoarea datei

a = nume dat 0000000001100100


adr = adresa zonei de memorie adr+2


IC

Memoria intern

n urma declarrii datelor ntr-un program, sistemul de operare i construiete o tabel prin
CT

care stabilete corespondena dintre numele datei, adresa la care se memoreaz data i
lungimea zonei de memorie alocat. Pentru exemplul precedent, se va memora n tabel:
numele a, adresa adr i lungimea 2. Atunci cnd se va cere printr-o instruciune din program
s se afieze valoarea acestei date, sistemul va cuta n tabel identificatorul a. Dac l
DA

gsete, va citi coninutul zonei de memorie care ncepe de la adresa adr i are lungimea de
2 octei, l va converti din modul de reprezentare intern n modul de reprezentare extern i
va afia valoarea obinut n urma conversiei, la dispozitivul desemnat pentru afiarea ei.
Dac nu gsete acest identificator, sistemul va afia un mesaj de eroare prin care va preciza
DI

c nu exist aceast dat. Pentru a putea manipula o dat, sistemul trebuie s identifice
zona de memorie n care este stocat. Identificarea acestei zone se poate face att prin
numele datei (a), ct i prin adresa la care este memorat (adr).
RA

1. Declarai dou variabile de memorie: una de tip numeric ntreg i


Tem una de tip numeric real.
2. Declarai dou variabile: una de tip numeric i una de tip caracter.
3. Enumerai, pentru fiecare tip de dat, subtipurile implementate. Artai modul n care pot
ITU

fi declarate i precizai spaiul de memorie alocat fiecrui subtip i domeniul de valori.


4. Analizai data de tip char (reprezentare n memoria intern, ncadrare n criteriile pre-
zentate, operatori permii etc.).
ED

128 Implementarea structurilor de date

IC
criteriul variabilitii

OG
Constante Variabile
Sunt date a cror valoare nu se modific n Sunt date a cror valoare se modific n
timpul execuiei programului. ntr-un program pot timpul execuiei programului, cnd pot avea
fi folosite constante simbolice. Acestea sunt o valoare iniial, mai multe valori interme-

G
constante care au fost puse n coresponden diare i o valoare final. Identificarea lor n
cu un identificator, iar n program se va folosi cadrul programului se face printr-un nume
identificatorul. n limbajul C++, definirea con- care li se atribuie la nceputul programului,

DA
stantelor simbolice se face cu declaraia const. atunci cnd li se stabilete i tipul.

Se recomand folosirea constantelor simbolice n urmtoarele cazuri:


 valoarea datei rmne constant pe o perioad de timp, dup care se poate modifica

PE
(de exemplu, ntr-un program pentru calcularea salariilor, impozitul se poate modifica
dup o anumit perioad de timp i, folosind constante simbolice, se poate face mult
mai uor modificarea n programul surs),
 data este o constant matematic (de exemplu, constanta ) sau
 o dat constant este folosit n mai multe locuri n program.
I
Observaii:
1. Un caracter delimitat de apostrofuri este diferit de un caracter delimitat de ghilimele (de
exemplu, 'a' este diferit de "a"). Primul este o constant de tip char (o dat elementar),

iar al doilea este o structur de date de tip ir de caractere ce conine un singur caracter.
IC

2. Exist constante simbolice de sistem (definite n bibliotecile limbajului) pe care le putei


folosi n programe: MAXINT (cea mai mare valoare de tip int ntreg); MAXSHORT
(cea mai mare valoare de tip short ntreg scurt); MAXLONG (cea mai mare valoare
CT

de tip long ntreg lung); MAXFLOAT, respectiv MINFLOAT (cea mai mare valoare,
respectiv cea mai mic valoarea de tip float real simpl precizie); MAXDOUBLE,
respectiv MINDOUBLE (cea mai mare valoare, respectiv cea mai mic valoarea de tip
double real dubl precizie); i M_PI pentru numrul .
DA

1. Declarai dou constante: una de tip numeric ntreg i una de tip


Tem numeric real.
2. Care este valoarea urmtorului numr, exprimat n notaie
DI

tiinific: 7.54E5? Dar a numrului -1.354e-6? Ce fel de constante sunt acestea:


simbolice sau literale?

criteriul compunerii
RA

Date simple sau date Date compuse sau structuri de date.


elementare. Sunt colecii de date ntre care exist anumite relaii
Sunt date independente unele de (relaii structurale). Fiecare component a structurii are
ITU

altele, din punct de vedere al o anumit poziie n cadrul structurii. Pentru fiecare tip
reprezentrii lor n memorie: de structur de date, n limbajul de programare trebuie
localizarea unei date pe suportul s fie definii algoritmi de localizare a componentelor n
de memorare nu se face n funcie cadrul structurii de date. ntre componentele structurii
de locaia unei alte date pe suport. exist i legturi de coninut, adic ntregul ansamblu de
ED

date din colecie poate caracteriza un obiect, o


persoan, un fenomen, un proces.

Informatic 129
Ai studiat structurile de date implementate la nivel fizic n limbajul C++:

IC
 tabloul de memorie cu o dimensiune (vectorul) i
 fiierul.

OG
Tabloul de memorie este o structur de date omogen, intern i temporar, iar fiierul este
structur de date omogen, extern i permanent. Pentru rezolvarea unor probleme, nu
sunt suficiente numai aceste structuri de date. Limbajul C++ mai permite i folosirea
urmtoarelor structuri fizice de date:
 tabloul de memorie cu dou dimensiuni (matricea);

G
 irul de caractere i
 nregistrarea.

DA
1. Structurii de date a, declarat cu double a[10];, i se aloc un
Tem spaiu de memorare continuu, ncepnd de la adresa 200. La ce
adres se va gsi data a[4]?

PE
2. Analizai, din punct de vedere al modului n care se ncadreaz n criteriile prezenta-
te, urmtoarele tipuri de date.
const int MAXIM=1000, VZ[3]={0};
const float PI=3.14;
typedef unsigned char byte;
I
typedef enum {False,True} boolean;
int a, b[10]; float c, d[2]; char x; byte y; boolean Z;
a) Cte date au fost definite? Enumerai-le!

b) Cte variabile de memorie au fost definite? Enumerai-le!


c) Cte date structurate au fost definite? Enumerai-le!
IC

2.2. Tabloul de memorie bidimensional (matricea)


CT

Organizarea n structuri de date a datelor prelucrate de algoritmi simplific multe dintre


operaiile de prelucrare. Atunci cnd organizai datele ntr-o structur de date, trebuie s
identificai modul n care putei avea acces la ele i operaiile pe care le putei executa cu
datele din colecie. Procesul de organizare a datelor n colecii este un proces care se
DA

desfoar pe trei niveluri care interacioneaz ntre ele, pornind de la nivelul conceptual:

nivel conceptual
(nivelul la care se dezvolt imaginea mental a structurii de date: modul
DI

n care trebuie organizate datele i relaiile care exist ntre ele)

nivel logic
RA

(nivelul la care se alege un model de implementare a structurii


conceptuale)
ITU

nivel fizic
(nivelul la care sunt stocate datele n memoria calculatorului i care implic
anumite caracteristici ale operaiilor de accesare i de prelucrare a datelor din
colecie, n funcie de modul n care sunt memorate datele i de algoritmii
implementai n limbaj pentru accesarea, citirea i scrierea datelor n memorie)
ED

130 Implementarea structurilor de date

IC
Scop: exemplificarea modului n care, pentru a rezolva problema, alegei organizarea

OG
datelor ntr-o structur de date de tip tablou de memorie.
Enunul problemei 1. O firm de transport are un parc de 10 maini, cu capaciti de
transport diferite. Trebuie s se determine cte dintre aceste maini au cea mai mare
capacitate de transport.

G
Pentru rezolvarea problemei, trebuie stabilit structura de date care se va folosi:
 La nivel conceptual capacitile de transport ale mainilor reprezint un ir de

DA
numere ntregi, aranjate ntr-o ordine aleatorie, n care trebuie cutat numrul cel mai
mare i de cte ori apare n ir.
20 40 50 30 20 40 50 40 30 40
 La nivel logic implementarea permis de limbajul C++ a unei colecii de date omogene

PE
este vectorul, fiecare numr ntreg fiind un element al structurii. Pentru rezolvarea proble-
mei se vor folosi urmtorii algoritmi: algoritmul pentru parcurgerea vectorului la memo-
rarea numerelor, algoritmul pentru determinarea valorii maxime dintr-un ir de numere i
algoritmul de cutare n vector a elementelor cu o valoare precizat (valoarea maxim).
I
int a[10];
 La nivel fizic numerele vor fi memorate ntr-o zon continu de memorie intern, fiecrui
numr alocndu-i-se acelai spaiu pentru memorare. Identificarea unui element al
structurii se face prin numrul su de ordine (indicele).

20 40 50 30 20 40 50 40 30 40
IC

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
Dac se dorete pstrarea datelor memorate (capacitile de transport ale mainilor din
parcul auto) pentru prelucrarea lor ulterior, se vor salva ntr-un fiier text, de unde vor fi
CT

restaurate n memoria intern ntr-un vector, la fiecare prelucrare (execuie a programului).


Observaie. n structura de date folosit (vectorul), ntre elementele structurii exist o
relaie de ordine n care fiecare element are un succesor i un predecesor. Acest tip de
DA

structur este o structur liniar.

a1 a2 ... ai-1 ai ai+1 ... an


DI

a1 = primul element ai = element an = ultimul element


(nu are predecesor) succesorul su este ai+1 (nu are succesor)
predecesorul su este ai-1
RA

Enunul problemei 2. Sunt cinci contoare pentru enegia electric, ce se citesc trimestrial, i
se nregistreaz ntr-un tabel consumul trimestrial (n mii de kWh). Trebuie s se determine:
media consumului trimestrial pe un singur contor i pe toate contoarele, cel mai mare consum
trimestrial, cel mai mic consum trimestrial, contorul cu cel mai mic consum i contorul cu cel
ITU

mai mare consum.


Pentru rezolvarea problemei, trebuie stabilit structura de date care se va folosi:
 La nivel conceptual contoarele sunt organizate ntr-un tabel cu patru linii i cinci
coloane n care sunt memorate numere ntregi. Tabelul va avea 4 linii, corespunztoare
celor 4 trimestre, i 5 coloane, corespunztoare celor cinci contoare.
ED

Informatic 131
 La nivel logic implementarea permis de limbajul C++ a unei colecii de date omogene

IC
este tabloul de memorie. Pentru rezolvarea problemei se vor folosi urmtorii algoritmi:
algoritmul pentru parcurgerea tabloului de memorie, pentru memorarea numerelor,

OG
algoritmul pentru determinarea mediei aritmetice i algoritmii de determinare a valorii
minime, respectiv maxime. Dac pentru reprezentarea datelor s-ar folosi tabloul de memorie
cu o singur dimensiune (vectorul), algoritmii de prelucrare ar fi foarte complicai. Soluia, n
acest caz, este un tablou bidimensional (matrice) cu patru linii i cinci coloane. Identificarea
unui element din tablou se va face de data aceasta nu printr-un numr de ordine, ci prin

G
numrul liniei i numrul coloanei. Dac numele tabloului bidimensional este b, elementul
b2,3 este elementul din linia 2 i coloana 3 i, n exemplu, are valoarea 32.

DA
 La nivel fizic memoria intern nu are o structur matriceal. Ea este format din
locaii de memorare care au adrese consecutive. Din aceast cauz, structura
dreptunghiular a tabelului trebuie simulat. Spaiul de memorare alocat tabelului va fi
o zon continu, de 40 de octei, n care se vor memora datele din tabel, linie cu linie.

PE
Numrul de ordine m al elementului din linia i i coloana j dintr-un tablou cu n coloane
este: m = n(i-1)+j

contoarele
Memoria intern
I
1 2 3 4 5 linia 1 linia 2 linia 4
trimestrele

1 43 56 53 34 23
2 34 47 32 38 29 43 56 ... 23 34 47 ... 15 36 ... 25

3 25 34 27 32 15 50 ....... adresele elementelor ....... 88


4 36 43 38 42 25
IC

elementul din linia 2 i coloana 3


i n cazul acestui exemplu, dac se dorete pstrarea datelor memorate (valorile
CT

consumului trimestrial al fiecrui contor) pentru prelucrarea lor ulterior, se vor salva
ntr-un fiier text, de unde vor fi restaurate n memoria intern ntr-un tablou
bidimensional, la fiecare prelucrare (execuie a programului).
DA

Rezolvai cele dou probleme folosind structura de date de tipul tablou de


Tem memorie cu o dimensiune.

Observaie. Metoda de memorare a elementelor tabloului, n ordine, unul dup altul, ntr-o
DI

zon continu de memorie, n locaii cu aceeai dimensiune, este folosit pentru identifi-
carea elementelor structurii i se realizeaz printr-un ansamblu de indici. Numrul de indici
(k) folosit pentru identificarea elementelor determin dimensiunea tabloului. Astfel:
 pentru k=1, structura este un tablou unidimensional numit i vector;
RA

 pentru k=2, structura este un tablou bidimensional numit i matrice.


n primul exemplu, s-a folosit un tablou de memorie cu numele a, cu o singur dimensiune
i cu 10 elemente. n al doilea exemplu, s-a folosit tabloul cu numele b, cu dou
dimensiuni, cu 4 elemente pe o dimensiune (4 linii) i 5 elemente pe cealalt dimensiune
ITU

(5 coloane). n cel de al doilea caz, tabloul are tot 20 de elemente. Chiar dac, din punct
de vedere al memoriei interne, spaiul de memorare alocat este tot sub forma unui bloc
continuu de 20, respectiv 40 de octei, cele dou tipuri de tablouri (cu o dimensiune sau cu
dou dimensiuni) difer ntre ele prin modul n care pot fi identificate elementele structurii.
Identificarea unui element al tabloului se face prin numele tabloului i valorile indicilor dup
ED

132 Implementarea structurilor de date
toate dimensiunile. De exemplu, a6 nseamn elementul 6 din tabloul a, iar b2,4 nseamn

IC
elementul de pe linia 2 i coloana 4 din tabloul b.
ntr-o matrice cu m linii i n coloane, numrul de ordine al elementului de pe linia nl i din

OG
coloana nc este:
 Dac nregistrarea n memorie se face linie cu linie: nr ord l=(nl1)n+nc.
 Dac nregistrarea n memorie se face coloan cu coloan: nr ord c=(nc1)m+nl.
Dac matricea se nregistreaz ncepnd de la adresa adr, iar un element ocup o zon

G
de memorie cu dimensiunea dim, adresa la care se gsete elementul care are numrul de
ordine nr_ord este egal cu adr+dim(nr_ord1).

DA
O structur de date care, la nivel conceptual, are imaginea unui tabel care conine date
de acelai tip, se implementeaz la nivel logic cu ajutorul unui tablou bidimensional.

2.2.1. Implementarea tabloului bidimensional n C++

PE
Declararea unui tablou de memorie de tip matrice (cu dou dimensiuni) se face prin
instruciunea:
<tip_dat> <nume> [<nr_1>] [<nr_2>];
unde <tip_dat> precizeaz tipul elementelor matricei, <nume> este identificatorul
I
matricei, iar <nr_1> i <nr_2> sunt dou constante ntregi care specific numrul de
elemente ale matricei pentru fiecare dimensiune: <nr_1> numrul de linii, iar <nr_2>
numrul de coloane. De exemplu, prin instruciunile declarative:

int a[2][4];
float b[3][5];
IC

se declar dou matrice: a cu 8 elemente de tip int, care are 2 linii i 4 coloane, i b, cu
15 elemente de tip float, care are 3 linii i 5 coloane.
i la declararea unei matrice se pot atribui valori iniiale elementelor, cu instruciunea:
CT

<tip_dat> <nume> [<nr_1>] [<nr_2>] = {<list_valori>};


unde valorile din list se vor atribui elementelor innd cont de faptul c memorarea lor n
zona alocat matricei se face linie dup linie. De exemplu, prin instruciunea declarativ:
DA

int a[2][4] = {1,2,3,4,5,6,7,8}; sau


int a[2][4] = {{1,2,3,4},{5,6,7,8}};
se declar o matrice a cu 8 elemente de tip int, care are 2 linii i 4 coloane n care s-au
atribuit valori iniiale elementelor.
DI

Pentru prelucrarea datelor memorate ntr-o matrice, referirea la un element al matricei


se face prin construcia:
<nume> [<indice_1>] [<indice_2>]
unde nume este numele matricei, <indice_1> este numrul de ordine al liniei, iar
RA

<indice_2> este numrul de ordine al coloanei.


indicele coloanei j
0 1 2 3
ITU

indicele liniei i 0 1 2 3 4
element = a[i] [j] 1 5 6 7 8
a[1] [2] = 7
ED

Informatic 133
Deoarece adresa matricei este i adresa primului element, iar indicii

IC
reprezint deplasarea elementului fa de adresa matricei, numero-
Atenie tarea indicilor se face pornind de la 0, iar 0<=indice_1<m i

OG
0<=indice_2<n, unde m reprezint numrul de linii, i n numrul de
coloane ale matricei, precizate la declararea ei. n exemplu, a[1][2]
reprezint elementul din linia a 2-a i coloana a 3-a din matricea a, i are valoarea 7.
Tabloul de memorie fiind o structur de date static, la declararea lui

G
i se aloc o zon fix de memorie. Lungimea tabloului de memo-
Atenie
rie reprezint numrul de elemente ale tabloului. La declararea
tabloului, este posibil s nu se cunoasc numrul de elemente care

DA
vor fi prelucrate la fiecare execuie a programului. n prelucrarea tabloului de memorie se
folosesc dou lungimi:
 Lungimea fizic. Reprezint numrul de elemente stabilit la declararea tabloului.
Este numrul maxim de elemente care pot fi stocate n spaiul de memorie rezervat

PE
tabloului. n cazul unei matrice, lungimea fizic este dat de produsul dintre numrul
de linii i numrul de coloane precizate la declararea matricei.
 Lungimea logic. Reprezint numrul de elemente care vor fi prelucrate la execuia
programului. Este mai mic sau cel mult egal cu lungimea fizic (numrul maxim de
I
elemente). Lungimea logic se comunic n timpul execuiei programului (de la
tastatur, sau se citete dintr-un fiier text). n cazul matricei, ea reprezint produsul
dintre numrul de linii i numrul de coloane ale matricei (mn).
Pentru elementul a[i][j], unde i i j reprezint indicele liniei, respectiv al coloanei, se

definesc succesorul elementului i predecesorul lui, astfel:


IC

succ(a[i][j]) = a[i+1][0] dac j=n-1 pred(a[i][j]) = a[i -1][n-1] dac j=0


a[i][j +1] dac jn-1 a[i][j -1] dac j0
CT

Elementul a[0][0] nu are predecesor, iar elementul a[m-1][n-1] nu are succesor.

2.2.2. Algoritmi pentru prelucrarea tablourilor bidimensionale


DA

2.2.2.1. Algoritmi pentru parcurgerea elementelor unei matrice


Parcurgerea elementelor unei matrice se poate face:
 de la primul element pn la ultimul element, sau
DI

 de la ultimul element pn la primul element.


Secvena de instruciuni pentru parcurgerea elementelor unei matrice de la primul
element la ultimul element este:
RA

int i,j,m,n,a[10][10];
// se declar variabilele i i j pentru indicele elementului,
// i - numrul liniei i j - numrul coloanei
// m i n pentru lungimea logic a matricei (m - numrul de
// linii i n - numrul de coloane) i a pentru o matrice cu
ITU

// lungimea fizic de 10 linii i 10 coloane.


cout<<"n= "; cin>>m; // se citete numrul de linii ale matricei
cout<<"m= "; cin>>n; // se citete numrul de coloane ale matricei
for (i=0;i<m;i++) // se parcurg liniile matricei
for (j=0;j<n;j++) //se parcurg coloanele matricei de pe o linie
ED

.....; //instruciunea pentru prelucrarea elementului a[i][j]



134 Implementarea structurilor de date
Secvena de instruciuni pentru parcurgerea elementelor unei matrice de la ultimul ele-

IC
ment la primul element este:
int i,j,m,n,a[10][10];

OG
cout<<"m= "; cin>>m; cout<<"n= "; cin>>n;
for (i=m-1;i>=0;i--) // se parcurg liniile matricei
for (j=n-1;j>=0;j--) //se parcurg coloanele matricei de pe o linie
.....; //instruciunea pentru prelucrarea elementului a[i][j]
Exemplul 1 Citirea de la tastatur a valorilor elementelor unei matrice. Secvena de

G
instruciuni este:
int i,j,m,n,a[10][10];

DA
cout<<"m= "; cin>>m; cout<<"n= "; cin>>n;
for (i=0;i<m;i++)
for (j=0;j<n;j++)
{cout<<"a("<<i+1<<","<<j+1<<")= "; cin>>a[i][j];}
..................... //se prelucreaz elementele matricei

PE
Exemplul 2 Afiarea pe ecran a valorilor elementelor unei matrice. Secvena de
instruciuni este:
int i,j,m,n,a[10][10];
..................... //se prelucreaz elementele matricei
I
for (i=0;i<m;i++)
{for (j=0;j<n;j++) cout<<a[i][j]<<" ";
cout<<endl;}

Parcurgerea unei matrice pe contur:


 n sensul acelor de ceasornic (n sens invers trigonometric).
IC

(1) a[0][j] j=0  n-1; j++


CT

(4) a[i][0] i=m-2 1; i-- (2) a[i][n-1] i=1  m-1; i++
DA

(3) a[m-1][j] j=n-2  0; j--


DI

Secvena de instruciuni este:


int i,j,m,n,a[10]10];
RA

..................... //se citesc valorile elementelor matricei


for (j=0;j<n;j++) cout<<a[0][j]<<" ";
for (i=1;i<m;i++) cout<<a[i][n-1]<<" ";
for (j=n-2;j>=0;j--) cout<<a[m-1][j]<<" ";
for (i=m-2;i>0;i--) cout<<a[i][0]<<" ";
ITU
ED

Informatic 135
 n sens trigonometric.

IC
(4) a[0][j] j=n-2 1; j--

OG
(1) a[i][0] i=0 m-1; i++ (3) a[i][n-1] i=m-2 1; i--

G
DA
(2) a[m-1][j] j=1  n-1; j++

PE
Scop: exemplificarea modului n care se aplic algoritmii pentru parcurgerea tablourilor
de memorie bidimensionale.
Enunul problemei 1: S se inverseze coloanele unei matrice cu n linii i m coloane
I
(n10, m10,) cu elementele numere ntregi.
Se folosete algoritmul de inversare a unui vector n el nsui, pentru fiecare linie a matricei.
#include <iostream.h>
void main()

{int n,m,i,j,x,a[10][10];
cout<<"n ="; cin>>n; cout<<"m ="; cin>>m;
IC

for (i=0;i<n;i++)
for (j=0;j<m;j++)
{cout<<"a["<<i+1<<","<<j+1<<"]= "; cin>>a[i][j];}
CT

for (i=0;i<n;i++)
for (j=0;j<m/2;j++)
{x=a[i][j]; a[i][j]=a[i][m-j-1]; a[i][m-j-1]=x;}
for (i=0;i<n;i++)
{for (j=0;j<m;j++)cout<<a[i][j]<<" ";
DA

cout<<endl; }}
Enunul problemei 2: Se citesc de la tastatur elementele de tip ntreg ale unei matrice cu
m linii i n coloane. S se calculeze ntr-un vector suma elementelor din fiecare linie a matri-
cei. Problema se va descompune n subprobleme i fiecare subproblem va fi implemen-
DI

tat cu ajutorul unui subprogram.


Se folosesc subprogramele: cit mat() pentru a citi elementele matricei, suma() pentru
a calcula suma elementelor matricei de pe fiecare linie i afis vec() pentru a afia
RA

elementele vectorului.
#include <iostream.h>
void cit mat(int a[][50] , int &m, int &n)
{cout<<"m= "; cin>>m; cout<<"m= "; cin>>m;
ITU

for (int i=0;i<m;i++)


for (int j=0;j<n;j++)
{cout<<"a["<<i+1<<","<<j+1<<"]= "; cin>>a[i][j];}}
void afis vec(int b[], int m)
ED

{for (int i=0;i<m;i++) cout<<b[i]<<" ";}



136 Implementarea structurilor de date

IC
void suma(int a[][50], int b[], int m, int n)
{int i,j;
for (i=0;i<m;i++) b[i]=0;

OG
for (i=0;i<m;i++)
for (j=0;j<n;j++) b[i]+=a[i][j];}
void main()
{int a[50][50],b[50],m,n;
cit mat(a,m,n); suma(a,b,m,n); afis vec(b,m);}

G
Atunci cnd transmitei o matrice ca parametru, la declararea para-
Atenie

DA
metrului nu trebuie s precizai numrul de rnduri ale matricei, dar
trebuie s precizai numrul de coloane.
Enunul problemei 3: Se citesc de la tastatur elementele unei matrice cu m linii i n
coloane. Elementele matricei sunt de tip ntreg. S se afieze maximul dintre elementele

PE
matricei i poziia primei apariii a acestuia (linia i coloana). Problema se va descompune
n subprobleme i fiecare subproblem va fi implementat cu ajutorul unui subprogram.
Se folosesc urmtoarele subprograme: citeste() pentru a citi elementele matricei i
maxim() pentru a obine informaiile despre valoarea maxim.
I
#include <iostream.h>
void citeste(int a[][50], int &m, int &n)
{cout<<"m= "; cin>>m; cout<<"n= "; cin>>n;

for (int i=0;i<m;i++)


for (int j=0;j<n;j++)
IC

{cout<<"a["<<i+1<<","<<j+1<<"]= "; cin>>a[i][j];}}


void maxim(int a[][50], int m, int n, int &max, int &nl, int &nc)
{max=a[0][0]; nl=0; nc=0;
CT

for (int i=0;i<m;i++)


for (int j=0;j<n;j++)
if (a[i][j]>max) {max=a[i][j]; nl=i; nc=j;}}
void main()
DA

{int a[50][50],m,n,max,nl,nc; citeste(a,m,n);


maxim(a,m,n,max,nl,nc);
cout<<"maximul este "<<max<<"si apare prima data "<<endl;
cout<<" in linia "<<nl+1<<" si coloana "<<nc+1<<endl;}
DI

Enunul problemei 4: Se consider o matrice a cu m linii i n coloane, cu elemente


numere reale. Valorile pentru m i n i pentru elementele matricei se citesc dintr-un fiier
text, unde sunt scrise astfel: pe primul rnd valorile pentru m i n, iar pe urmtoarele m
RA

rnduri, cte n elemente de pe fiecare linie a matricei. Numerele sunt separate prin
spaiu. S se bordeze matricea cu coloana n+1, ale crei elemente a[i][n+1] au ca
valoare media aritmetic a celor n elemente din linia i, i cu linia m+1, ale crei elemente
a[m+1][j] au ca valoare media aritmetic a celor n elemente din coloana j. S se scrie
ITU

ntr-un fiier text matricea obinut. Problema se va descompune n subprobleme i


fiecare subproblem va fi implementat cu ajutorul unui subprogram.
Se folosesc urmtoarele subprograme: citeste() pentru a citi matricea iniial din fiierul
text, bordeaza() pentru a borda matricea i scrie() pentru a scrie ntr-un fiier text
ED

matricea obinut.

Informatic 137

IC
#include <fstream.h>
fstream f1("mat1.txt",ios::in),f2("mat2.txt",ios::out);
void citeste(float a[][10], int &m, int &n)

OG
{f1>>m>>n;
for (int i=0;i<m;i++)
for (int j=0;j<n;j++) f1>>a[i][j];
f1.close();}

G
void scrie(float a[][10], int m, int n)
{f2<<m<<" "<<n<<endl;

DA
for (int i=0;i<m;i++)
{for (int j=0;j<n;j++) f2<<a[i][j]<<" ";
f2<<endl;}
f2.close();}

PE
void bordeaza(float a[][10], int &m, int &n)
{int i,j; float s;
for (i=0;i<m;i++)
{for (j=0,s=0;j<n;j++) s+=a[i][j];
a[i][n]=s/n;}
I
n++;
for (i=0;i<n;i++)
{for (j=0,s=0;j<m;j++) s+=a[j][i];

a[m][i]=s/m;}
m++;}
IC

void main()
{int n,m; float a[10][10];
CT

citeste(a,m,n); bordeaza(a,m,n); scrie(a,m,n); }


Enunul problemei 4: Se consider o matrice a cu m linii i n coloane, cu elemente
numere reale. Valorile pentru m i n i pentru elementele matricei se citesc de la tasta-
tur. S se calculeze suma elementelor pare din matrice, folosind o funcie recursiv.
DA

Funcia recursiv este suma(i,j,n,a), unde a este matricea, i i j indicii folosii pentru
a identifica un element al matricei i n numrul de coloane. Cu indicele i se parcurg liniile
de la ultima pn la prima (indicele i ia valori de la m-1 pn la 0), iar cu indicele j se
parcurg coloanele de la ultima pn la prima (indicele j ia valori de la n-1 pn la 0). Se
DI

evalueaz funcia suma(m-1,n-1,n,a).


#include <iostream.h>
void citeste (int a[][20], int &m, int &n)
RA

{int i,j; cout<<"m= "; cin>>m; cout<<"n= "; cin>>n;


for (i=0;i<m;i++)
for (j=0;j<n;j++)
{cout<<"a("<<i+1<<","<<j+1<<")= "; cin>>a[i][j];}}
ITU

int suma(int i,int j,int n, int a[][20])


{if(i==0 && j==0)
if (a[0][0]%2==0) return a[0][0];
else return 0;
ED

138 Implementarea structurilor de date

IC
else if (a[i][j]%2==0)
if (j==0) return a[i][j]+suma(i-1,n-1,n,a);
else return a[i][j]+suma(i,j-1,n,a);

OG
else
if (j==0) return suma(i-1,n-1,n,a);
else return suma(i,j-1,n,a);}
void main()

G
{int m,n,a[20][20]; citeste(a,m,n);
cout<<"suma este "<<suma(m-1,n-1,n,a)<<endl;}

DA
1. S se verifice c o matrice ptrat cu m linii i n coloane (m i n i
Tem elementele matricei se citesc dintr-un fiier text) este matricea zero
(matricea care are toate elementele egale cu 0).
2. S se afieze elementele de pe conturul matricei, parcurgerea lor fcndu-se n sens

PE
trigonometric.
3. Pentru o valoare n (numr natural de cel mult o cifr) citit de la 1 1 1 1
tastatur se cere s se scrie un program care construiete n 1 2 2 1
memorie o matrice de n linii i n coloane format numai din elemente 1 2 2 1
de 1 i 2, elementele aflate pe cele 4 margini ale tabloului fiind egale 1 1 1 1
I
cu 1, cele din interior fiind egale cu 2. Elementele matricei se scriu pe ecran, pe linii,
ca n exemplul urmtor. Pentru n=4, se afieaz matricea prezentat alturat.
(Bacalaureat Simulare 2006)

Urmtoarele probleme se vor descompune n subprobleme i fiecare subproblem va fi


implementat cu ajutorul unui subprogram.
IC

4. Se consider o matrice a cu m linii i n coloane, cu elemente numere reale. Valorile


pentru n i m i elementele matricei se citesc de la tastatur. S se afieze numrul
CT

liniei i numrul coloanei pe care suma elementelor este maxim.


5. Se consider o matrice a cu m linii i n coloane, cu elemente numere reale. Valorile
pentru m i n i elementele matricei se citesc de la tastatur. Se mai citesc de la
tastatur dou numere ntregi, p (1pn) i q (1qn). S se interschimbe coloanele p
DA

i q ale matricei. S se afieze matricea obinut.


6. Se consider o matrice a cu m linii i n coloane, cu elemente numere reale. Valorile
pentru n i m i elementele matricei se citesc dintr-un fiier text. Se citesc de la
tastatur dou numere ntregi, p (1pm) i q (1qm). S se interschimbe liniile p i
DI

q ale matricei. S se afieze matricea obinut.


7. Se consider o matrice a cu m linii i n coloane, cu elemente numere reale. Valorile
pentru n i m i elementele matricei se citesc dintr-un fiier text. Se citesc de la
tastatur dou numere ntregi, p (1pm) i q (1qn). S se elimine din matrice linia
RA

p i coloana q. S se scrie ntr-un fiier matricea obinut.


8. Se citesc de la tastatur dou numere naturale, m i n, care reprezint dimensiunile
unei matrice cu numere ntregi, i elementele matricei. Afiai liniile i coloanele
matricei care au numai numere pare.
ITU

9. Se citesc de la tastatur dou numere naturale, m i n, care reprezint dimensiunile


unei matrice cu numere ntregi, i elementele matricei. Afiai liniile i coloanele
matricei care au elementele aranjate cresctor.
ED

Informatic 139
10. Pentru o matrice cu n linii i m coloane, scriei un subprogram recursiv care s inver-

IC
seze linia p cu linia q i un subprogram recursiv care s inverseze coloana x cu
coloana y.

OG
11.Se consider o matrice a cu numere ntregi, cu dimensiunea m linii i n coloane, i un
vector b, cu mn elemente. Se citesc dintr-un fiier text cele dou numere, m i n, i
elementele matricei. S se copieze n vectorul b elementele matricei a, parcurse:
a. linie cu linie,
b. coloan cu coloan,

G
c. n spiral (pornind de la elementul a[0][0] n sens invers trigonometric).
12.Se consider o matrice a cu numere ntregi, cu dimensiunea m linii i n coloane.

DA
Folosind metoda divide et impera:
a. s se interschimbe coloana p cu coloana q (p i q se citesc de la tastatur);
b. s se determine simultan valoarea minim i valoarea maxim din matrice.

PE
2.2.2.2. Algoritmi pentru prelucrarea matricelor ptrate
O matrice ptrat este o matrice n care numrul liniilor este egal cu numrul coloanelor.
Lungimea logic a unei matrice ptrate este nn (unde n = numrul de linii i de coloa-
ne). Ea este mprit n zone, de cele dou diagonale:
I
 diagonala principal;
 diagonala secundar.
Diagonala principal:

paralela k cu diagonala (1) deasupra diagonalei


IC

sub diagonal a[i][j]: i=0  n-2; j=i+1  n-1;


k=1  n-2; i-j=k
(1)
a[i][i-k]: i=k  n-1; Elementele de pe diagonal:
CT

a[i][i]  i=j
(2) sub diagonal
(2) paralela k cu diagonala
a[i][j]: i=1  n-1; j=0  i-1;
deasupra diagonalei
DA

k=1  n-2; j-i=k


a[j-k][j]: j=k  n-1;

Diagonala secundar:
DI

(1) deasupra diagonalei


a[i][j]: i=0  n-2; j=0  n-i-2; paralela k cu diagonala
sub diagonal
RA

k=1  n-2; i+j=n+k-1


(1) a[i][n-i+k-1]: i=k  n-1;
paralela k cu diagonala
deasupra diagonalei Elementele de pe diagonal:
ITU

k=1  n-2; i+j=n-k-1 a[i][n-1-i]  i+j=n-1


a[i][n-i-k-1]: i=0  n-k-1; (2)
(2) sub diagonal
a[i][j]: i=1  n-1; j=n-i  n-1;
ED

140 Implementarea structurilor de date
Cele dou diagonale mpart matricea ptrat n patru regiuni: Nord, Vest, Sud i Est:

IC
(N) i=0  n/2-1 (jumtatea superioar)
j=i+1  n-2-i (peste diagonala principal i peste

OG
diagonala secundar)

(V) jumtatea superioar (i<n/2) (E) jumtatea superioar (i<n/2)


i=1  n/2-1; j=0  i-1; N i=1  n/2-1; j=n-i  n-1;

G
(sub diagonala principal) (sub diagonala secundar)
V E

DA
(V) jumtatea inferioar (in/2) (E) jumtatea inferioar (in/2)
i= n/2  n-2; j=0  n-i-2; S i= n/2  n-2; j=i+1  n-1;
(peste diagonala secundar) (peste diagonala principal)

(S) i= n/2+1  n-1 (jumtatea inferioar)

PE
j=i+1  n-2-i (sub diagonala principal i sub diagonala
secundar)

(nn 2n)/4 dac n par


I
Numrul de elemente dintr-o regiune (k) este: k=
(nn 2n +1)/4 dac n impar

Matrice speciale (sunt matrice care au anumite proprieti, n funcie de valorile elemen-

telor). Pentru a se face economie de memorie, aceste matrice pot fi memorate ca vectori.
IC

 Matrice ptrat simetric fa de diagonal. Dac este simetric fa de diagonala


principal (a[i][j] = a[j][i]), se vor memora n vectorul b numai elementele de pe diagonala
principal i cele de deasupra diagonalei principale: b[k] = a[i][j], unde i=0  n-1 i j=i
CT

 n-1. Dac este simetric fa de diagonala secundar (a[i][j] = a[n-i-1]n-j-1j]), se vor


memora n vectorul b numai elementele de pe diagonala secundar i cele de deasupra
diagonalei principale: b[k] = a[i][j], unde i=0  n-1 i j=0  n-i-1. Numrul de elemente
ale vectorului b va fi: n(n+1)/2.
DA

 Matrice simetric fa de axe. Dac este simetric fa de axa vertical (a[i][j] =


a[i][n-j-1]), se vor memora n vectorul b numai elementele de pe axa vertical (numai
dac numrul de coloane este impar) i cele de la dreapta axei verticale: b[k] = a[i][j], unde
i=0  m-1 i j=0  n/2 (pentru n par) sau j=0  n/2-1 (pentru n impar). Numrul de
DI

elemente ale vectorului b va fi: m(n/2+1) pentru n par, respectiv mn/2, pentru n impar.
Dac este simetric fa de axa orizontal (a[i][j] = a[m-i-1][j]), se vor memora n vectorul b
numai elementele de pe axa orizontal (numai dac numrul de linii este impar) i cele de
deasupra axei orizontale: b[k] = a[i][j], unde i=0  m/2 (pentru n par) sau i=0  m/2-1
RA

(pentru m impar) i j=0  n-1. Numrul de elemente ale vectorului b va fi: n(m/2+1)
pentru m par, respectiv nm/2, pentru m impar.
 Matrice ptrat diagonal. Toate elementele care nu se gsesc pe diagonala principa-
ITU

l, respectiv secundar, au valoarea 0. Se vor memora n vectorul b numai elementele


de pe diagonala principal, respectiv secundar: b[k] = a[i][i], respectiv b[k] = a[i][n-i-1],
unde i=0  n-1. Numrul de elemente ale vectorului b va fi: n.
ED

Informatic 141
 Matrice ptrat triunghiular. Toate elementele care se gsesc deasupra sau sub o

IC
diagonal au valoarea 0. Se va memora la fel ca o matrice ptrat simetric fa de
acea diagonal.

OG
Scop: exemplificarea modului n care se aplic algoritmii pentru prelucrarea matricelor
ptrate.

G
Enunul problemei 1: S se calculeze suma elementelor de pe diagonala principal a
unei matrice ptrate, de dimensiune n (n10). Elementele matricei sunt numere ntregi.

DA
Elementele de pe diagonala principal au cei doi indici egali (numrul liniei este egal cu
numrul coloanei).
#include <iostream.h>

PE
void main()
{int n,i,j,s=0,a[10][10];
cout<<"n ="; cin>>n;
for (i=0;i<n;i++) //se parcurge matricea pentru creare
for (j=0;j<n;j++)
{cout<<"a["<<i+1<<","<<j+1<<"]= "; cin>>a[i][j];}
I
for (i=0;i<n;i++) s+=a[i][i]; //se parcurge diagonala principal
cout<<"suma= "<<s;}
Enunul problemei 2: S se verifice dac o matrice ptrat de dimensiune n (n10) are

urmtoarea proprietate: elementele de pe diagonala secundar au valoarea 1, iar restul


elementelor au valoarea 0. Elementele matricei sunt numere ntregi.
IC

Elementele de pe diagonala secundar au suma indicilor egal cu n-1 (i+j=n-1). Se va


folosi o variabil x, care va avea valoarea 1 dac matricea are proprietatea specificat
(valoarea logic True), i valoarea 0 dac matricea nu are proprietatea specificat
CT

(valoarea logic False). Variabila x se iniializeaz cu 1 (presupunem c matricea are


proprietatea specificat). Deoarece, pentru a determina proprietatea matricei, nu trebuie
parcurse toate elementele, n cazul n care se gsete un element care nu ndeplinete
condiia din proprietate, parcurgerea matricei se va face cu o instruciune while. Se vor
DA

parcurge coloanele unei linii prin incrementarea indicelui j, dup care se va trece la linia
urmtoare, prin incrementarea indicelui i i iniializarea cu 0 a indicelui j.
#include <iostream.h>
void main()
DI

{int n,i,j,x=1,a[10][10];
cout<<"n ="; cin>>n;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
RA

{cout<<"a["<<i+1<<","<<j+1<<"]= "; cin>>a[i][j];}


i=0; j=0;
while (i<n && x)
{if (i+j==n-1)
{if (a[i][j]!=1) x=0;}
ITU

else
if (a[i][j]!=0) x=0;
if (j==n-1){j=0; i++;}
else j++;}
if (x) cout<<"Matricea are proprietatile specificate";
else cout<<"Matricea nu are proprietatile specificate"; }
ED

142 Implementarea structurilor de date
Urmtoarele probleme se vor descompune n subprobleme i fiecare

IC
Tem subproblem va fi implementat cu ajutorul unui subprogram.
1. Se citete de la tastatur un numr natural n care reprezint

OG
dimensiunea unei matrice ptrate cu numere ntregi. Elementele matricei se citesc de
la tastatur. Afiai suma elementelor de pe cele dou diagonale.
2. S se verifice dac o matrice ptrat cu dimensiunea nn este:
a. simetric fa de axa orizontal,

G
b. simetric fa de axa vertical,
c. simetric fa de diagonala principal,

DA
d. simetric fa de diagonala secundar.
3. Se consider o matrice ptrat cu dimensiunea nn i un vector cu n elemente.
Numrul n i elementele matricei i ale vectorului se citesc de la tastatur. S se
verifice dac elementele vectorului formeaz o linie sau o coloan a matricei. n caz

PE
afirmativ, s se afieze un mesaj n care s se precizeze numrul liniei i/sau al
coloanei.
4. S se genereze toate matricele binare ptrate de dimensiune n care au un singur
element de 1 pe linie i un singur element de 1 pe coloan. O matrice binar este o
matrice ale crei elemente au valoarea 0 sau 1. Indicaie. Soluia are n elemente.
I
Elementul soluiei xk reprezint numrul coloanei de pe linia k pe care se gsete
elementul cu valoarea 1.
5. Se consider o matrice ptrat a cu numere ntregi, cu dimensiunea n. Folosind

metoda divide et impera:


a. s se interschimbe linia p cu coloana q (p i q se citesc de la tastatur);
IC

b. s se interschimbe diagonala principal cu diagonala secundar.


CT

Rspundei:
1. Se consider o matrice cu 3 linii i 5 coloane. Artai cum
1 2 3 4 5
DA

vor fi aranjate n memorie elementele matricei dac ele


5 4 3 2 1
sunt nregistrate n ordinea liniilor. Artai cum vor fi
1 3 5 2 4
aranjate i n cazul n care ar fi nregistrate n ordinea
coloanelor. Ce constatai? Cum vor fi aranjate n memorie elementele acestei matrice
DI

dac va fi implementat n limbajul C++?


2. Construii o structur de date de tip tabel, n care s nregistrai notele elevilor din
clas pe semestrul 1, la disciplina Informatic.
3. Dac elementele unei matrice cu 5 linii i 8 coloane sunt nregistrate n ordinea
RA

liniilor, ncepnd de la adresa de memorie 100, care este adresa elementului din linia
4 i coloana 5? Datele memorate n matrice sunt de tip int.
4. Dac elementele unei matrice cu m linii i n coloane sunt nregistrate n memoria
intern n ordinea coloanelor, care este formula prin care calculai numrul de ordine
ITU

al elementului din linia i i coloana j?


5. Cum se declar un vector cu 10 elemente de tip ntreg care s aib valoarea iniial 0?
6. Gsii greelile din urmtoarele instruciuni declarative:
const int DIM=10;
ED

int n, a[n][n], b[dim][dim], B[10][10], c[10,20];



Informatic 143
7. Care este succesorul elementului a[i][j] al matricei definit prin instruciunea de-

IC
clarativ int a[4][5];? Dar predecesorul su?
8. Fie matricea cu 3 linii i 5 coloane de tip int n care se nregistreaz, coloan cu

OG
coloan, primele 15 numere naturale pare (a[0][0]=2; a[1][0]=4; ..., a[0][1]=8; etc.).
Elementele matricei a se copiaz, n ordine, linie cu linie, n vectorul b care are 15
elemente de tip int. Ce valoare are elementul b[5]?

Adevrat sau Fals:

G
1. Tabloul de memorie este o structur de date extern.
2. Tabloul de memorie se creeaz ntr-o zon continu de memorie intern.

DA
3. Tabloul de memorie este ntotdeauna o structur de date temporar.
4. Tabloul de memorie de tip matrice nu este o structur de date liniar.
5. Pentru indicii unei matrice se pot folosi numere reale.
6. Cu declaraiile urmtoare, se poate folosi variabila x, pentru a memora 15 numere ntregi:

PE
typedef int vec int[3];_
vec int x[5];
7. Pentru variabila x definit anterior, este corect atribuirea: x[2] = {1,2,3};.
8. Cu declaraiile urmtoare, se obin tablourile de memorie x i y, echivalente din punct
I
de vedere al implementrii:
typedef int vec int[3];
vec int x[5];
int y[5][3];

9. Cu declaraia int x[3][5],y[5][3]; se obin tablourile de memorie x i y,


echivalente din punct de vedere al implementrii:
IC

10. Cu declaraia int x[15],y[5][3]; se obin tablourile de memorie x i y,


echivalente din punct de vedere al implementrii:
11. n matricea ptrat a, cu n linii i n coloane, elementul a[n-2][n-2] aparine
CT

diagonalei principale.
12. n matricea ptrat a, cu n linii i n coloane, elementul a[n-2][3] aparine
diagonalei secundare.
DA

13. n matricea ptrat a, cu 10 linii i 10 coloane, elementul a[3][2] se gsete


deasupra diagonalei principale.
14. n matricea ptrat a, cu 10 linii i 10 coloane, elementul a[3][2] se gsete sub
diagonala secundar.
DI

15. Secvena urmtoare de program calculeaz minimul elementelor de pe diagonala


principal a unei matrice ptrate a, de dimensiune nn:
int n,i,x,a[50][50];
................
RA

for (i=1;i<n;i++)
if (a[i][i]<a[0][0])
{x=a[i][i]; a[i][i]=a[0][0]; a[0][0]=x;}_
Alegei:
ITU

1. Se consider urmtoarea matrice, stocat n memoria intern a calculatorului n


ordinea coloanelor. Elementul cu numrul de ordine 5 este:
a b c d e a) e
f g h i j b) g
k l m n o c) h
ED

144 Implementarea structurilor de date
2. Se consider urmtoarea matrice, cu numele alfa, stocat n memoria intern a

IC
calculatorului n ordinea liniilor. Elementul alfa(2,3) are valoarea:
1 2 3 4 5 a) 12

OG
6 7 8 9 10 b) 8
11 12 13 14 15 c) 6
3. Care dintre urmtoarele secvene de instruciuni determin, n variabila ntreag s,
suma elementelor de sub diagonala secundar a unei matrice ptrate a, cu numere
ntregi, cu dimensiunea nn ?

G
a) s=0; c) s=0;

DA
for (i=0;i<n;i++) for (i=0;i<n;i++)
for (j=i+1;j<n;i++) for (j=0;j<=i-1;i++)
s+=a[i][j]; s+=a[i][n-j-1];
b) s=0; d) s=0;

PE
for (i=0;i<n;i++) for (i=1;i<n;i++)
for (j=i;j<n;i++) for (j=1;j<=i;i++)
s+=a[i][j]; s+=a[i][n-j];
4. Secvena urmtoare de program realizeaz:
int n,i,x,p,q,a[20][20];
I
................
for (i=0;i<n;i++)
{x=a[i][q]; a[i][q]=a[i][p]; a[i][p]=x}
a. sortarea elementelor de pe linia i folosind metoda selectrii directe;

b. interschimbarea coloanei p cu coloana q;


c. interschimbarea liniei p cu linia q;
IC

d. sortarea elementelor de pe linia i folosind metoda bulelor.

Miniproiecte:
CT

Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:


a. descompunerea problemei n subprobleme i rezolvarea fiecrei subproble-
me cu ajutorul unui subprogram.
DA

b. explicarea algoritmilor folosii pentru realizarea subprogramelor;


c. citirea matricelor dintr-un fiier text;
d. alte dou exemple de probleme cu aplicare practic, n care, pentru implemen-
tarea datelor, se vor folosi tablouri bidimensionale, i rezolvarea acestor
DI

probleme. Exemplu. Se nregistreaz ntr-un tabel cheltuielile lunare cu utilitile


(electricitate, ap, gaze, telefon, cablu TV etc.) pe perioada unui an. Trebuie s se
determine: media consumului anual i trimestrial, pe fiecare tip de cheltuial i pentru
cheltuielile totale, luna cu cele mai multe cheltuieli i luna cu cele mai puine cheltuieli.
RA

1. Gsii metoda adecvat prin care s memorai coordonatele carteziene n spaiu (xi,
yi, zi) a n vectori, astfel nct s putei implementa un algoritm ct mai eficient care s
afieze vectorii perpendiculari (vectorii al cror produs scalar este 0). Afiai vectorii
perpendiculari.
ITU

Pentru urmtoarele probleme, se consider o matrice ptrat cu elemente numere ntregi


cu dimensiunea nn.
ED

Informatic 145
2. S se afieze:

IC
a. suma elementelor situate deasupra diagonalei principale;
b. simetrica matricei fa de diagonala secundar;

OG
c. descresctor, elementele de pe diagonala principal, folosind metoda seleciei
directe.
3. S se afieze:
a. suma elementelor situate sub diagonala secundar;
b. simetrica matricei fa de diagonala principal;

G
c. cresctor, elementele de pe diagonala secundar, folosind metoda bulelor.
4. S se afieze:

DA
a. suma elementelor situate sub diagonala principal;
b. simetrica matricei fa de axa orizontal care trece prin centrul matricei;
c. cresctor, elementele de pe linia p, folosind metoda sortrii prin interclasare (p se
citete de la tastatur).

PE
5. S se afieze:
a. suma elementelor situate deasupra diagonalei secundare;
b. simetrica matricei fa de axa vertical care trece prin centrul matricei;
c. descresctor, elementele de pe coloana q, folosind metoda sortrii rapide (q se
I
citete de la tastatur).
6. S se afieze:
a. elementele situate deasupra diagonalei principale;

b. suma elementelor pare din regiunea Vest a matricei;


c. descresctor, elementele de pe diagonala secundar, folosind metoda bulelor.
IC

7. S se afieze:
a. elementele situate sub diagonala secundar;
b. media aritmetic a elementelor din regiunea Nord a matricei;
CT

c. cresctor, elementele de pe linia p, folosind metoda sortrii rapide (p se citete


de la tastatur).
8. S se afieze:
a. elementele situate sub diagonala principal;
DA

b. produsul elementelor impare din regiunea Est a matricei;


c. cresctor, elementele de pe diagonala secundar, folosind metoda seleciei
directe.
DI

9. S se afieze:
a. elementele situate deasupra diagonalei secundare;
b. numrul de elemente, care au ultima cifr divizibil cu 3, din regiunea Sud a
matricei;
RA

c. descresctor, elementele de pe coloana q, folosind metoda sortrii prin


interclasare (q se citete de la tastatur).
ITU
ED

146 Implementarea structurilor de date

IC
2.3. irul de caractere

OG
Un cuvnt, o propoziie, o fraz, un paragraf, un text reprezint o mulime ordonat de
caractere care poate avea o lungime variabil.

irul de caractere este o structur de date care este format dintr-o mulime ordona-
t de caractere, n care fiecare caracter se identific prin poziia sa n cadrul mulimii.

G
2.3.1. Implementarea irului de caractere n C++

DA
n limbajul C++, implementarea irurilor de caractere se face sub forma unui tablou unidi-
mensional (vector) ale crui elemente sunt de tip caracter, fiecare caracter fiind repre-
zentat prin codul su ASCII.

PE
Ai aflat c, n general, vectorii au dou lungimi: o lungime fizic (care reprezint numrul
maxim de elemente pe care le poate avea vectorul i corespunde locaiilor de memorie
rezervate n urma declarrii lui) i o lungime logic (numrul de elemente folosite din
vector, la o execuie a programului). i n cazul unui vector de caractere exist o lungime
I
fizic i o lungime logic a vectorului. Ceea ce deosebete un vector de caractere de
vectorii cu alte tipuri de elemente este posibilitatea de a marca sfritul logic al vectorului
prin folosirea caracterului NULL specificat prin constanta caracter '\0' (care are codul
ASCII 0). Acest caracter se adaug la sfritul caracterelor memorate n vector, ca un

terminator. De exemplu, prin instruciunea:


char sir[256];
IC

se creeaz un ir de caractere n care vor putea fi memorate maxim 255 de caractere,


deoarece un element al vectorului se va folosi pentru a memora caracterul NULL. Astfel,
CT

dac n acest vector se memoreaz irul de caractere "Buna ziua", coninutul zonei de
memorie alocate irului de caractere va fi:
256 de octei lungimea fizic a vectorului de caractere sir
DA

10 octei folosii lungimea logic a vectorului de caractere

B u n a z i u a \0
DI

sir[0] sir[1] sir[8] sir[9] cei 246 de octei


nefolosii
Memoria intern
RA

ntr-un ir de caractere, ordinea acestora este esenial, fiecrui caracter putnd s i se


asocieze un numr care reprezint poziia caracterului n cadrul irului, iar fiecare caracter
din ir poate fi identificat, ca i n cadrul unui vector, prin poziia sa n cadrul irului:
sir[i]. Astfel, n irul declarat anterior, sir[3] reprezint caracterul din poziia 4,
ITU

numrarea poziiilor ncepnd de la 0, adic al patrulea caracter al irului: a.


Vectorul de caractere trebuie declarat cu un caracter mai mult
Atenie (caracterul '\0') dect cel mai mare ir de caractere pe care l
poate conine. De exemplu, o mulime ordonat de maxim 20 de
ED

caractere va putea fi descris astfel: char sir[21]; .



Informatic 147
n exemplul anterior a fost declarat un ir de caractere preciznd lungimea sa maxim.

IC
Putei s iniializai un ir de caractere la declararea lui, atribuindu-i o constant de tip ir
de caractere. O constant de tip ir de caractere este o succesiune de caractere deli-

OG
mitat de ghilimele.
char sir[256]="Buna ziua";
Prin aceast instruciune s-a declarat un ir de caractere cu lungimea maxim de 256 de
caractere (pentru care s-au rezervat 256 de octei) din care au fost ocupate numai 10
caractere: nou pentru irul de caractere "Buna ziua" i unul pentru caracterul NULL

G
care este adugat automat de ctre compilator. Dac se iniializeaz la declarare un
ir de caractere, poziiile neocupate din ir vor fi completate cu caracterul NULL.

DA
Exemplu:
char sir[20]="Buna ziua"; int i;
for (i=0;i<20;i++)

PE
if (sir[i]==NULL) cout<<'0'; else cout<<sir[i];
/* se afieaz Buna ziua00000000000 */
Dac se iniializeaz irul de caractere, nu mai este obligatoriu s se precizeze lungimea
maxim a irului, aceasta fiind calculat de ctre compilator. De exemplu, prin instruciunea:
char sir[]="Buna ziua";
I
s-a declarat un ir de caractere pentru care compilatorul va rezerva numrul de octei
necesari pentru memorarea constantei ir de caractere (9 octei) i a caracterului NULL
(1 octet), adic 10 octei.

Dup ce ai declarat un ir de caractere nu mai putei s-i atribuii o


Atenie constant de tip ir de caractere. Numele irului de caractere este
IC

numele unui tablou de memorie, deci o constant de tip adres:


char sir[20]; sir="Buna ziua";
CT

/* Eroare! valoarea unei constante nu poate fi modificat*/


O constant de tip ir de caractere, chiar dac va conine un singur
Atenie caracter, este diferit de o constant de tip caracter, datorit modului
diferit de stocare n memoria intern. n acelai mod, un ir de carac-
DA

tere, chiar dac va conine un singur caracter, este diferit de o dat elementar de tip char:

a a \0 A A \0
DI

'a' "a" char x='A' char y[ ]="A"


Memoria intern Memoria intern
Pentru a insera caracterul ghilimele ntr-o constant de tip ir de caractere, folosii
RA

secvena escape \". Astfel, pentru a afia pe ecran textul Acesta este un
"Exemplu" folosii instruciunea: cout<<"Acesta este un \"Exemplu\""; .
Lungimea unui ir de caractere reprezint numrul de caractere din ir,
ITU

mai puin caracterul NULL.


De exemplu, lungimea irului de caractere declarat prin instruciunea urmtoare este 9,
chiar dac se vor rezerva 10 octei pentru memorarea lui:
char sir[]="Buna ziua";
ED

148 Implementarea structurilor de date

IC
irul vid sau irul nul este irul care are lungimea 0.
De exemplu, putei s iniializai un ir de caractere la declararea lui ca ir nul, astfel:
char sir[256]="";

OG
n cadrul programului, putei s iniializai un ir de caractere ca ir nul atribuind primei
poziii din ir valoarea NULL printr-una dintre urmtoarele instruciuni de atribuire:
sir[0]=NULL; sir[0]=0; sir[0]='\0';

G
Operaiile de atribuire sir[0]="";; sir[0]=''; sau sir[0]='0';
Atenie nu pot fi folosite pentru iniializarea unui ir vid. Primele dou vor
produce eroare la compilare, deoarece nu se poate atribui unui

DA
element care este de tip char o constant de tip ir de caractere, respectiv nu exist un
caracter ASCII care s fie precizat prin constanta ''. n cel de al treilea caz, primul carac-
ter din ir va fi caracterul cifra 0, iar lungimea irului va fi determinat de existena unui
caracter NULL n cadrul irului.

PE
Declarai trei iruri de caractere pe care le iniializai astfel nct s aib
Tem lungimea 10, 1 i respectiv 0.
I
2.3.2. Citirea i scrierea irurilor de caractere
Citirea i scrierea irurilor de caractere se poate face:
 la nivel de element al structurii caracterul;

 la nivel de structur irul de caractere.


Exemplul 1 Se citete i se afieaz un ir de caractere. Citirea se face caracter cu
IC

caracter, pn la apsarea tastei Enter (reprezentarea codului ASCII al caracterului Enter


se face prin secvena escape '\n'). Afiarea se face caracter cu caracter, pn la ntlnirea
caracterului NULL care marcheaz sfritul irului de caractere. Citirea se face cu format,
CT

folosind manipulatorul care permite citirea caracterelor albe.


#include <iostream.h>
#include <stdlib.h>
DA

#include <iomanip.h>
void main()
{char sir[256]; int i=0;
cin>>resetiosflags(ios::skipws)>>sir[i];
DI

while (sir[i]!='\n') {i++; cin>>resetiosflags(ios::skipws)>>sir[i];}


sir[i+1]=0; //se adaug caracterul NULL
for (i=0;sir[i]!=NULL;i++) cout<<sir[i];}
Observaie:
RA

n cazul n care citirea unui ir de caractere se face caracter cu caracter, trebuie adugat
caracterul NULL la sfritul irului de caractere.
Exemplul 2 Se scriu ntr-un ir de caractere literele alfabetului latin: aAbBcC...zZ i apoi
ITU

se afieaz liter cu liter.


#include <iostream.h>
#include <stdlib.h>
void main()
ED

{char sir[256]; int i,j;



Informatic 149

IC
for (i=0,j=0;j<26;j++) {sir[i]='a'+j; sir[i+1]='A'+j; i+=2;}
sir[i+1]=NULL; //se adaug caracterul NULL
for (i=0;sir[i]!=NULL;i++) cout<<sir[i];}

OG
1. Scriei secvena de instruciuni prin care atribuii unui ir de
Tem caractere valoarea "0123...89abc...zABC...Z98...3210" i afiai apoi
acest ir, caracter cu caracter.
2. S se afieze toate anagramele unui cuvnt citit de la tastatur.

G
Exemplul 3 Se citete i se afieaz un ir de caractere, operaiile executndu-se la
nivelul structurii de date.

DA
#include <iostream.h>
void main() {char sir[256]; cin>>sir; cout<<sir;}
Observaii:
1. Acest mod de citire i scriere a irurilor de caractere este mult mai simplu, deoarece

PE
caracterul NULL este adugat automat de ctre compilator.
2. Primul caracter scris n irul de caractere va fi primul caracter citit de la tastatur care
nu este un caracter alb. Operaia de citire de la tastatur se va termina la ntlnirea
unui caracter alb (de exemplu, spaiu sau apsarea tastei Enter). Dezavantajul
acestei metode l reprezint faptul c nu pot fi citite de la tastatur caracterele albe,
I
cum este de exemplu spaiu (nu poate fi citit un text care conine mai multe cuvinte).
Astfel, dac se introduce de la tastatur n variabila de memorie sir irul de caractere
alfabeta (caracterul simbolizeaz un spaiu), pe ecran se va afia alfa.

Pentru a elimina acest dezavantaj, se poate folosi funcia get() cu urmtoarele forme,
care difer prin parametrii folosii:
IC

Forma 1 (cu parametri):


cin.get(sir,nr,ch);
CT

Parametrii funciei sunt: sir de tip ir de caractere, nr de tip ntreg i ch de tip caracter,
ultimul fiind opional. Efectul acestei funcii este urmtorul: se citesc de la tastatur mai
multe caractere, inclusiv caracterele albe, care vor fi scrise n variabila sir, pn cnd
se produce unul dintre urmtoarele evenimente:
DA

 au fost citite maxim nr-1 caractere;


 a fost ntlnit caracterul ch care are rolul de delimitator el nu va fi scris n variabi-
la sir i nu va fi nlturat din fluxul de intrare; dac nu este precizat acest parame-
tru, se consider implicit caracterul '\n' (linie nou) generat la apsarea tastei Enter.
DI

Exemplu:
char sir[256]; cin.get(sir,5); cout<<sir;
Se scriu n variabila sir maxim 4 caractere introduse de la tastatur. De exemplu, dac
RA

introducei de la tastatur Calculator Enter, se va afia Calc, iar dac introducei An


Enter, se va afia An.
Exemplu:
char sir[256]; cin.get(sir,9,'#'); cout<<sir;
ITU

Se scriu n variabila sir caracterele introduse pn la ntlnirea caracterului #, dar nu


mai mult de 8 caractere. De exemplu, dac introducei de la tastatur alfa#beta Enter,
se va afia alfa, iar dac introducei alfa beta Enter, se va afia alfa bet.
Forma 2 (fr parametri):
ED

cin.get();

150 Implementarea structurilor de date
Aceast funcie nu are nici un parametru i furnizeaz urmtorul caracter din fluxul de date

IC
sub forma unei valori ntregi. Ea este folosit, dup o funcie cin.get() cu parametri,
pentru a descrca din fluxul de date ultimul caracter citit (delimitatorul), care ar mpiedica

OG
efectuarea unei a doua operaii de citire de la tastatur, dac funcia cin.get(), cu care
se face a doua citire, folosete acelai caracter ca delimitator. De obicei, ntr-un program, n
fluxurile de date de la tastatur, se folosete ca delimitator pentru operaiile de citire
caracterul linie nou, generat prin apsarea tastei Enter. Dac acest caracter rmne n
flux dup prima operaie de citire, iar a doua operaie de citire folosete acelai delimitator,

G
primul caracter care va fi interpretat de cea de a doua operaie de citire va fi caracterul linie
nou care, fiind delimitator, va determina terminarea operaiei de citire de la tastatur.

DA
Exemplu:
char sir1[256], sir2[256];
cin.get(sir1,5); cin.get(); cin.get(sir2,5);
cout<<sir1<<sir2;

PE
De exemplu, dac introducei de la tastatur alfa beta gama delta Enter, se va afia
alfabeta, alfa fiind valoarea variabilei sir1, iar beta, valoarea variabilei sir2. Dar, dac
introducei a1 Enter a2 Enter, se va afia a1a2, a1 fiind valoarea variabilei sir1, iar a2,
valoarea variabilei sir2. Dac eliminai din secven instruciunea cin.get(); i
I
introducei aceleai date, n primul caz se va afia alfa bet, alfa fiind valoarea variabilei
sir1, iar bet, valoarea variabilei sir2, iar n al doilea caz, dup ce vei introduce de la
tastatur a1 Enter se va afia a1, a1 fiind valoarea variabilei sir1, iar variabila sir2 nu va
conine nimic, deoarece primul caracter citit pentru aceast variabil va fi caracterul linie

nou, care va determina terminarea operaiei de citire.


IC

Considernd urmtoarea secven de instruciuni, precizai ce se va


Tem afia dac se va citi de la tastatur alfa beta gama Enter? Dar dac se
citete alfa#beta gama Enter? Dar dac se citete alfa Enter
CT

betaEnter? Ce se va ntmpla dac din secven se va elimina instruciunea cin.get(); i


vei relua cele trei variante de introducere a datelor?
char sir1[256], sir2[256];
cin.get(sir1,5); cin.get(); cin.get(sir2,5,'#');
DA

cout<<sir1<<sir2;

irurile de caractere i pointerii


irurile de caractere pot fi manipulate prin intermediul unei variabile de tip pointer ctre
DI

tipul char.
char *p,*q;
p="Ana are mere."; cout<<p; //afieaz Ana are mere.
RA

q=p+2; cout<<q; //afieaz a are mere.


cout<<q-p; //afieaz 2
Din aceast cauz, un ir de caractere poate fi declarat ca un pointer ctre tipul char,
cum este de exemplu declaraia irului de caractere sir din exemplul urmtor:
ITU

char *sir="ala bala portocala",*p;


cout<<strlen(sir)<<" "<<sir<<endl; //afieaz 18 ala bala portocala
sir++; cout<<strlen(sir)<<" "<<sir<<endl;
//afieaz 17 la bala portocala
ED

p=sir; p+=3; cout<<strlen(p)<<" "<<p; //afieaz 14 bala portocala



Informatic 151
De exemplu, declararea unui ir de caractere cu char *sir="abcd" poate fi folosit n

IC
locul declaraiei char sir[]="abcd".
Cele dou declaraii au urmtoarele caracteristici comune:

OG
1. n ambele cazuri, sir reprezint o adres i, pe acest identificator, se pot aplica
urmtorii operatori folosii pentru tipul de dat pointer:
 operatorul de indirectare * (*sir) care furnizeaz coninutul variabilei de la adresa
indicat: n primul caz, caracterul memorat n octetul de la adresa indicat de

G
pointerul sir, iar n al doilea caz caracterul memorat n primul element al vectorului;
 operatorul aritmetic pentru adunarea unei constante + (sir+1) care furnizeaz o

DA
adres: n primul caz, caracterul memorat n octetul care urmeaz celui indicat de
pointerul sir, iar n al doilea caz caracterul memorat n al doilea element al
vectorului;
 operatorul aritmetic pentru scderea a doi pointeri - (sir1-sir2) care furnizeaz

PE
n ambele exemple numrul de elemente dintre cele dou adrese de memorie;
 operatorul indice [ ]: sir[i] *(sir+i).
2. n ambele cazuri, se poate folosi instruciunea cout<<sir; pentru a afia coninu-
tul irului de caractere. Aceast instruciune afieaz ceea ce este stocat de la adre-
sa memorat n pointerul sir, respectiv de la adresa simbolic sir, pn la
I
ntlnirea caracterului NULL.
Deosebirile dintre cele dou declaraii sunt:
char sir[]="abcd" char *sir="abcd"

semnificaia Este numele simbolic al unei Este numele unui pointer ctre tipul
identificatorului constante de tip adres: valoarea sa char, adic numele unei variabile de
IC

sir nu se poate modifica. tip adres


alocarea Se aloc efectiv 5 octei, ncepnd de Compilatorul aloc 5 octei pentru
memoriei la adresa simbolic sir, pentru cele 5 constanta de tip ir de caractere "abcd"
CT

interne componente ale vectorului de caractere i creeaz o variabil de memorie de tip


(irul de caractere). pointer care conine adresa primului
caracter din ir.
operatori Deoarece sir este o constant, nu se Deoarece sir este o variabil, se pot
DA

pot aplica pe identificatorul sir ope- aplica pe identificatorul sir operatorii de


ratorii de incrementare i decremen- incrementare i decrementare i i se
tare i nici nu i se poate modifica poate modifica valoarea prin operaia
valoarea prin operaia de atribuire. de atribuire.
DI

citirea de la cin.get(sir,100) citete de la cin.get(*sir) citete de la


tastatur tastatur un ir de maxim 100 de tastatur un caracter care va fi scris la
caractere care va fi scris n memorie adresa memorat n pointerul sir.
ncepnd de la adresa simbolic sir.
RA

2.3.3. Algoritmi pentru prelucrarea irurilor de caractere


Prelucrarea irurilor de caractere se poate face prin mai multe metode:
ITU

1. prin parcurgerea caracterelor din ir ca elemente ale unui vector de caractere:


 folosind indicii sau
 folosind pointerii;
2. folosind funciile de sistem implementate n bibliotecile limbajului; fiierul antet n
ED

care sunt definite cele mai multe dintre aceste funcii este fiierul <string.h>.

152 Implementarea structurilor de date
Exemplu Se afieaz lungimea unui ir de caractere.

IC
#include <iostream.h>
#include <stdlib.h>

OG
void main()
{char sir[256]; int i;
cout<<"Introduceti sirul de caractere"<<endl; cin.get(sir,100);
for (i=0;sir[i]!=NULL;i++); //sau for(i=0;sir[i];i++);
cout<<"Lungimea sirului de caractere este "<<i;}

G
Aceeai problem se poate rezolva innd cont c parcurgerea unui vector se poate face
i cu ajutorul pointerilor. Folosind un pointer p ctre elementele irului, se parcurge irul

DA
de la prima poziie pn la sfritul lui, prin aplicarea operatorului de incrementare pe
pointer. Lungimea irului se obine fcnd diferena dintre adresa memorat n pointerul p
i adresa primului element din ir.
#include <iostream.h>

PE
void main()
{char sir[256],*p;
cout<<"Introduceti sirul de caractere"<<endl; cin.get(sir,100);
for (p=sir;*p!=0;p++); //sau for (p=sir;*p;p++);
I
cout<<"Lungimea sirului de caractere este "<<p-sir;}
Rezolvarea acestei probleme este i mai simpl dac se folosete funcia sistem strlen()
care are sintaxa: strlen(sir):

#include <iostream.h>
#include <string.h>
IC

void main()
{char sir[256];
cout<<"Introduceti sirul de caractere"<<endl; cin.get(sir,100);
CT

cout<<"Lungimea sirului de caractere este "<<strlen(sir);}

irurile de caractere i subprogramele


a. Subprogramele utilizator
DA

Transmiterea unui parametru de tip ir de caractere se poate face fie folosind pointeri,
fie folosind vectorii de caractere. De exemplu, urmtoarele dou anteturi de funcii transmit
ca parametri dou iruri de caractere, i sunt echivalente:
a. void copiaza(char sir1[], char sir2[])
DI

b. void copiaza(char *sir1, char *sir2)


Urmtoarele patru exemple de funcii realizeaz aceeai operaie: copiaz un ir de carac-
tere n alt ir de caractere:
RA

char *copiaza(char *d, char *s) void copiaza(char *d, char *s)
{char *p=d; {while (*s) *d++=*s++;
while (*s) *d++=*s++; *d=*s;}
ITU

*d=*s; void main()


return p;} {char a[256]="alfabet",b[256];
void main() copiaza(b,a); cout<<b;}
{char a[256]="alfabet",b[256];
copiaza(b,a); cout<<b;}
ED

Informatic 153

IC
char *copiaza(char d[], char s[]) void copiaza(char d[], char s[])
{char *p=d; {for (int i=0; s[i]!=NULL;i++)
for (int i=0; s[i]!=NULL;i++) d[i]=s[i];

OG
d[i]=s[i]; d[i]=s[i];}
di]=s[i]; void main()
return p;} {char a[256]="alfabet",b[256];
void main() copiaza(b,a); cout<<b;}
{char a[256]="alfabet",b[256];

G
copiaza(b,a); cout<<b;}
Observaie. Spre deosebire de vectorii numerici, n cazul irurilor de caractere nu trebuie

DA
s precizai lungimea logic, aceasta fiind determinat de poziia caracterului NULL.
Scriei un subprogram care s testeze dac un text citit de la tastatur
Tem este un cuvnt (condiia ca s fie cuvnt este s conin numai litere).

PE
a. Subprogramele de sistem
Pentru a putea folosi o funcie de sistem trebuie s tii s interpretai prototipul funciei
pe care vi-l pune la dispoziie autodocumentarea (help-ul) limbajului de programare.
I
Exemplul 1 Funcia strcpy()din fiierul antet string.h copiaz irul de caractere
surs src n irul de caractere destinaie dest, precizate prin parametri. Ea are proto-
tipul:

char *strcpy(char *dest, const char *src);


Interpretai prototipul funciei astfel:
IC

 Rezultatul funciei este de tip adresa unui ir de caractere pointer ctre tipul char.
 Funcia are doi parametri de tip ir de caractere (precizai prin pointeri ctre tipul char).
 Cuvntul cheie const care precede cel de al doilea parametru precizeaz faptul c
CT

subprogramul nu trebuie s modifice cel de al doilea ir de caractere. Dac funcia ar


ncerca s modifice acest parametru, compilatorul va semnala o eroare.
Exemplul 2 Funcia ecvt()din fiierul antet stdlib.h furnizeaz, prin numele ei, un ir de
DA

caractere n care a fost convertit un numr real value. irul de caractere are lungimea
ndig. Poziia punctului zecimal este dec, iar semnul este sign. Ea are prototipul:
char *ecvt(double value, int ndig, int *dec, int *sign);
Interpretai prototipul funciei, astfel:
DI

 Rezultatul funciei este de tip ir de caractere pointer ctre tipul char.


 Funcia are patru parametri: unul de tip real pentru value double, unul de tip ntreg
pentru lungimea irului de caractere ndig int, unul de tip adres ctre ntreg pentru
RA

poziia punctului zecimal ndig *int i unul de tip adres ctre ntreg pentru semnul
numrului sign *int.
 Parametrii dec i sign sunt parametri de ieire. Ei se transmit prin valoare, folosind
adrese de memorie (pointeri ctre ntreg).
ITU

Algoritmii pentru prelucrarea irurilor de caractere pot fi grupai astfel:


1. prelucrarea a dou iruri de caractere;
2. prelucrarea unui ir de caractere;
3. prelucrarea subirurilor de caractere;
4. conversii ntre tipul ir de caractere i tipuri numerice.
ED

154 Implementarea structurilor de date
2.3.3.1. Prelucrarea a dou iruri de caractere

IC
Pentru prelucrarea a dou iruri de caractere putei folosi urmtoarele operaii:
 copierea unui ir de caractere ntr-un alt ir de caractere;

OG
 concatenarea a dou iruri de caractere;
 compararea a dou iruri de caractere.
Copierea unui ir de caractere ntr-un alt ir de caractere
Se transfer coninutul unui ir de caractere (irul surs) ntr-un alt ir de caractere

G
(irul destinaie). Putei s folosii urmtoarele funcii de sistem (parametrii funciilor
sunt: s1 irul surs, s2 irul destinaie i n numrul de caractere care se copiaz):

DA
Funcia Sintaxa apelului Realizeaz
strcpy() strcpy(s2,s1) Sunt copiate din irul surs s1 n irul destinaie s2 toate
caracterele, inclusiv caracterul NULL. Funcia furnizeaz ca

PE
rezultat un pointer care indic adresa irului destinaie.
strncpy() strncpy(s2,s1,n) Sunt copiate din irul surs s1 n irul destinaie s2 maxim n
caractere, ncepnd cu primul caracter. Dac lungimea irului
surs este mai mic dect n, va fi copiat i caracterul NULL
funcia fiind echivalent cu strcpy(); altfel, irul destinaie nu
I
va fi terminat cu caracterul NULL. Funcia furnizeaz ca rezultat
un pointer care indic adresa irului destinaie.
Exemplu:

#include <iostream.h>
#include <string.h>
IC

void main()
{char sir1[256], sir2[256];
cout<<"Sirul de caractere care se copiaz"<<endl; cin.get(sir1,100);
CT

strcpy(sir2,sir1); cout<<sir2;}
Dac vrei s atribuii unei variabile de tip ir de caractere sir o
Atenie constant de tip ir de caractere const_sir, folosii funcia
strcpy() astfel: strcpy(sir,const_sir). Urmtoarele sec-
DA

vene de program sunt echivalente:

char sir[256]="alfa"; char sir[256];


.....................
DI

secvena 1 strcpy(sir,"alfa");
secvena 2
RA

Scriei trei variante de programe (folosind cele trei metode de prelucrare


Tem a irurilor de caractere) prin care copiai ntr-un ir de caractere primele
n caractere dintr-un al doilea ir de caractere. n cazul n care nu folosii
funcia de sistem, implementarea se va face cu ajutorul subprogramelor. Cele dou iruri
ITU

de caractere i numrul de caractere n se transmit ca parametri. n programul principal se


citesc de la tastatur irul de caractere din care se copiaz i numrul de caractere care
se copiaz i se afieaz irul de caractere obinut.
ED

Informatic 155
Concatenarea a dou iruri de caractere

IC
Se adaug la sfritul unui ir de caractere (irul destinaie) coninutul unui alt ir de
caractere (irul surs). Putei s folosii urmtoarele funcii de sistem (parametrii funciilor

OG
sunt: s2 irul surs, s1 irul destinaie i n numrul de caractere care se adaug).
Ambele funcii furnizeaz ca rezultat un pointer care indic adresa irului destinaie.
Funcia Sintaxa apelului Realizeaz
strcat() strcat(s1,s2) Sunt adugate din irul surs s2 n irul destinaie s1 toate

G
caracterele, inclusiv caracterul NULL
strncat () strncat(s1,s2,n) Sunt adugate din irul surs s2 n irul destinaie s1

DA
maxim n caractere, ncepnd cu primul caracter. Funcia
adaug la sfritul caracterelor adugate caracterul NULL.
n cazul n care n este mai mare dect lungimea irului
surs, se va aduga tot irul surs, dar nu i alte caractere.

PE
Exemplu
#include <iostream.h>
#include <string.h>
void main()
I
{char sir1[256], sir2[256];
cout<<"Primul sir de caractere "; cin.get(sir1,100); cin.get();
cout<<"Al doilea sir de caractere "; cin.get(sir2,100);
strcat(sir1,sir2); cout<<sir1;}

Scriei trei variante de program (folosind cele trei metode de prelucrare


Tem
IC

a irurilor de caractere) prin care concatenai la un ir de caractere


primele n caractere din cel de al doilea ir de caractere. n cazul n care
nu folosii funcia de sistem, implementarea se va face cu ajutorul subprogramelor. Cele
CT

dou iruri de caractere i numrul de caractere n se transmit ca parametri. n programul


principal se citesc de la tastatur irurile de caractere care se concateneaz i numrul
de caractere n i se afieaz irul de caractere obinut.
n prelucrrile prin care adugai sau copiai un ir de caractere
DA

Atenie surs la un ir de caractere destinaie trebuie s avei grij s nu


depii locaiile de memorie rezervate irului destinaie,
deoarece este posibil ca sistemul de operare s nu sesizeze aceast eroare i s scrie n
zona rezervat altor variabile de memorie.
DI

Urmrii instruciunile urmtorului program. Ce ar trebui s afieze?


Tem Executai programul. Ce constatai? Explicai de ce au fost afiate
aceste valori pentru rezultate.
RA

#include <iostream.h>
#include <string.h>
void main()
{char sir1[4]="alfa",sir2[4]; cout<<sir1<<" "<<&sir1<<" "<<&sir2<<endl;
ITU

strcpy(sir2,"alfabet"); cout<<sir1<<" "<<sir2;}


Observaie: Funciile prin care se scriu caractere ntr-un ir destinaie (copierea unui ir
i concatenarea a dou iruri) adaug caracterul NULL la sfritul irului destinaie,
degrevnd programatorul de aceast sarcin.
ED

156 Implementarea structurilor de date
Compararea a dou iruri de caractere

IC
Compararea a dou iruri de caractere se face prin compararea codului ASCII al
caracterelor din aceeai poziie a fiecrui ir. Dac cele dou iruri nu au aceeai

OG
lungime, irul cu lungime mai mic este completat la sfrit, pn la egalarea lungimilor,
cu caracterul NULL care are codul ASCII 0. Operaia de comparare ncepe cu prima
poziie din ir i continu cu urmtoarele poziii numai dac poziiile anterioare sunt
identice n ambele iruri. De exemplu, irul de caractere Idee este mai mare dect irul
de caractere IDei deoarece, n poziia a doua, caracterele din cele dou iruri nu mai sunt

G
identice, iar codul ASCII al caracterului d este mai mare dect codul ASCII al caracterului
D. Operaia de comparare se oprete dup cel de al doilea caracter i nu mai conteaz

DA
codurile caracterelor din poziia patru, care sunt diferite pentru e i pentru i.
Putei s folosii urmtoarele funcii de sistem (toate funciile furnizeaz un rezultat de tip
int; parametrii funciilor sunt: s1 i s2 irurile de caractere care se compar i n

PE
numrul de caractere care se compar):
Funcia Sintaxa apelului Realizeaz
strcmp() strcmp(s1,s2) Compar cele dou iruri de caractere. Dac sunt
identice, rezultatul este 0. Dac s1 este mai mare dect
s2, rezultatul este pozitiv. Dac s1 este mai mic dect
I
s2, rezultatul este negativ.
stricmp() stricmp(s1,s2) Compar cele dou iruri de caractere la fel ca i
funcia strcmp(), dar fr s fac diferena ntre litere-

le mari i literele mici.


strncmp() strncmp(s1,s2,n) Compar primele n caractere din cele dou iruri de
IC

caractere, furniznd rezultatul la fel ca i funcia


strcmp().
strncmpi () strncmpi (s1,s2,n) Compar cele dou iruri de caractere la fel ca i
CT

funcia strncmp(), dar fr s fac diferena ntre lite-


rele mari i literele mici.
1. Scriei trei variante de program (folosind cele trei metode de prelu-
Tem crare a irurilor de caractere) prin care comparai dou iruri de
DA

caractere. n cazul n care nu folosii funcia de sistem, implemen-


tarea se va face cu ajutorul subprogramelor. Cele dou iruri de caractere se transmit
ca parametri. n programul principal se citesc de la tastatur irurile de caractere care
se compar i se afieaz rezultatul comparaiei.
DI

2. Precizai rezultatul furnizat de urmtoarele funcii: strcmp("ab","a"), strcmp("ab","abc"),


strcmp("ab","Ab"), stricmp("Abcd","Abcd"), stricmp("abcd","Abcd"), stricmp("ab","Abc"),
strncmpi("abcd","Abcd",2), strncmpi("abc","Abc",4), strcmp("ab","Ab"), stricmp("ab","Ab"),
RA

strcmp("ab","A"), stricmp("a","A"), strcmp("abc","abc"), strncmp("abc","abcd",3).


3. Se citesc de la tastatur dou iruri de caractere s1 i s2. Scriei un subprogram recur-
siv care s compare cele dou iruri de caractere i care va furniza urmtoarele valori:
-1 dac s1 este mai mic dect s2, 0 dac sunt egale i +1 dac s1 este mai mare dect
ITU

s2. Folosii subprogramul recursiv pentru a compara cele dou iruri de caractere.
Compararea a dou iruri de caractere este util atunci cnd trebuie s ordonai
alfabetic o mulime de iruri de caractere (de exemplu, o mulime de cuvinte). Pentru
rezolvarea acestui gen de probleme vei forma un vector cu elemente iruri de caractere
ED

i vei aplica pe acest vector unul dintre algoritmii de sortare nvai.



Informatic 157

IC
Scop: exemplificarea modului n care putei folosi funciile care prelucreaz dou iruri de
caractere.

OG
Enunul problemei: S se ordoneze alfabetic o mulime de n cuvinte citite de la tastatur.
Se consider c un cuvnt poate avea maxim 25 de caractere, iar mulimea maxim 50 de
cuvinte. Mulimea de cuvinte va fi implementat printr-o matrice de caractere cu 50 de linii i
25 de coloane char sir[50][25], care poate fi considerat ca un vector ale crui

G
elemente sunt iruri de caractere: primul indice precizeaz numrul de iruri de caractere
memorate n vector, iar al doilea indice, lungimea maxim a fiecrui ir de caractere.

DA
Aadar, matricea fiind un vector de cuvinte, fiecare linie a matricei sir[i] va memora
un cuvnt (un ir de caractere cu maxim 25 de caractere) din mulimea de cuvinte. Se va
folosi pentru sortarea cuvintelor metoda seleciei directe. Variabila intermediar aux prin
intermediul creia se face interschimbarea ntre cele dou elemente ale vectorului de

PE
cuvinte este de tip ir de caractere cu maxim 25 de caractere.
#include <iostream.h>
#include <string.h>
void main()
I
{char sir[50][25],aux[25]; int n,i,j;
cout<<"Numarul de cuvinte= "; cin>>n; cin.get();
for (i=0;i<n;i++)
{cout<<"cuvantul: "; cin.get(sir[i],25); cin.get();}

for (i=0;i<n-1;i++)
for (j=i+1;j<n;j++)
IC

if (strcmp(sir[i],sir[j])>0)
{strcpy(aux,sir[i]); strcpy(sir[i],sir[j]); strcpy(sir[j],aux);}
for (i=0;i<n;i++) cout<<sir[i]<<endl; }
CT

1. Refacei programul anterior folosind sortarea prin metoda bulelor.


Tem 2. Se consider n mulimi de cuvinte Ai, fiecare mulime avnd ni cuvinte.
S se genereze toate textele de n cuvinte care se pot forma cu
DA

cuvintele din aceste mulimi, cuvntul i din text aparinnd mulimii Ai.
3. Se citesc de la tastatur dou iruri de caractere s1 i s2 Scriei un
subprogram recursiv care s verifice dac irul s1 este anagrama irului s2.
DI

Observaie
n marea majoritate a limbajelor de programare, pentru a manipula iruri de caractere, exis-
t implementat un tip special de date. De obicei, prin aceast implementare, irul de carac-
tere poate avea o lungime de maxim 255 de caractere (ocupnd 256 de octei, din care
RA

unul se folosete pentru a memora lungimea irului de caractere). Pe acest tip de dat se
pot aplica operatorul de concatenare, operatorul de atribuire i operatorii relaionali. n lim-
bajul C++ irul de caractere nu este implementat ca un tip de dat i nu pot fi aplicai opera-
torii menionai. Realizarea acestor operaii se poate face folosind funciile de sistem, astfel:
ITU

Operatorul Operaia Funcia


de atribuire s1s2 strcpy(s1,s2)
de concatenare s1+s2 strcat(s1,s2)
relaional s1=s2 sau s1<>s2 sau s1>s2 sau strcmp(s1,s2)
ED

s1<s2 sau s1>=s2 sau s1<=s2



158 Implementarea structurilor de date
2.3.3.2. Prelucrarea unui ir de caractere

IC
Pentru prelucrarea unui ir de caractere putei folosi urmtoarele operaii:
 iniializarea unui ir de caractere cu acelai caracter;

OG
 inversarea coninutului unui ir de caractere;
 transformri ntre literele mari i literele mici din ir;
 cutarea unui caracter ntr-un ir:
gsirea primeia sau a ultimei apariii n ir a caracterului;
furnizarea poziiei primeia sau a ultimei apariii n ir a caracterului;

G
numrarea apariiilor unui caracter ntr-un ir.

DA
Iniializarea unui ir de caractere cu acelai caracter
Prin aceast operaie se atribuie poziiilor dintr-un ir aceeai valoare pe o lungime
comunicat prin program. Vectorul de caractere se parcurge cu ajutorul indicilor:
#include <iostream.h>

PE
void main()
{char sir[256],c; int i,n;
cout<<"Numarul de caractere"; cin>>n;
cout<<"Caracterul de umplere: "; cin>>c;
for (i=0;i<n;i++) sir[i]=c; sir[i]=0; cout<<sir;}
I
n cazul n care irul de caractere are deja o valoare, vechea valoare poate fi modificat
prin nlocuirea tuturor caracterelor cu un acelai caracter:
#include <iostream.h>

void main()
{char sir[256],c; int i; cout<<"Textul: "; cin.get(sir,100);
IC

cout<<"Caracterul de umplere: "; cin>>c;


for (i=0;sir[i];i++) sir[i]=c; sir[i]=0; cout<<sir;}
CT

Rescriei programele anterioare parcurgnd vectorul cu ajutorul


Tem pointerilor.
DA

Putei s folosii urmtoarele funcii de sistem (parametrii funciilor sunt: sir irul de
caractere, ch caracterul i n numrul de caractere). Ambele funcii furnizeaz ca
rezultat un pointer care indic adresa irului.
Funcia Sintaxa apelului Realizeaz
DI

strset() strset(sir,ch) irul sir este parcurs ncepnd cu primul caracter, pn la


sfritul lui, fiecare caracter fiind nlocuit cu caracterul ch, mai
puin caracterul NULL.
RA

strnset() strnset(sir,ch,n) n irul sir sunt parcurse primele n caractere, ncepnd cu


primul caracter, dar nu mai mult dect lungimea irului,
fiecare caracter fiind nlocuit cu caracterul ch. Dac n este
mai mare sau egal cu lungimea irului sir, funcia va avea
acelai efect ca i strset().
ITU

Rescriei programele anterioare folosind funciile de sistem corespun-


Tem ztoare.
ED

Informatic 159
Inversarea coninutului unui ir de caractere

IC
Se inverseaz coninutul unui vector de caractere n el nsui, mai puin caracterul NULL.
Pentru rezolvarea acestei probleme se poate folosi funcia sistem strrev() care are

OG
sintaxa: strrev(sir), unde sir este irul care se inverseaz. Funcia furnizeaz ca
rezultat un pointer care indic adresa irului inversat.
Scriei trei variante de program (folosind cele trei metode de prelucrare a
Tem irurilor de caractere) prin care inversai un ir de caractere citit de la

G
tastatur, n dou variante:
a. ntr-un alt ir de caractere; b. n el nsui.

DA
Transformarea literelor mari n litere mici i invers
Prin aceast operaie, caracterele scrise cu litere mari dintr-un text sunt transformate n
litere mici, i invers, prin modificarea codului ASCII al caracterului. Se va ine cont c,

PE
pentru un caracter liter, diferena dintre codul ASCII al literei mari i codul ASCII al literei
mici este 32. Pentru transformare se mai pot folosi funciile tolower() i toupper() cu
sintaxa: tolower(ch) transform caracterul ch din liter mare n liter mic; altfel, l las
neschimbat, i respectiv toupper(ch) transform caracterul ch din liter mic n liter
mare; altfel, l las neschimbat. Ambele funcii furnizeaz un rezultat de tip char i au
I
nevoie de fiierul antet <ctype.h>. n exemplul urmtor, literele mari din ir sunt transfor-
mate n litere mici, folosind codul ASCII, i apoi literele mici sunt transformate n litere mari
folosind funcia toupper(). Vectorul de caractere se parcurge cu ajutorul pointerului:

#include <iostream.h>
#include <ctype.h>
IC

void main()
{char sir[256],*p; cout<<"sirul de caractere: "; cin.get(sir,100);
//literele mari vor fi transformate n litere mici
CT

for (p=sir;*p;p++) if (*p>='A'&& *p<='Z') *p+=32; cout<<sir<<endl;


//literele mici vor fi transformate n litere mari
for (p=sir;*p;p++) *p=toupper(*p); cout<<sir;}
Rescriei programul anterior parcurgnd vectorul cu ajutorul indicilor;
DA

Tem transformai mai nti literele mici n litere mari folosind codul ASCII i
apoi literele mari n litere mici folosind funcia tolower().
Se mai pot folosi funciile sistem care au parametrul sir irul de caractere care se trans-
DI

form. Ambele funcii furnizeaz ca rezultat un pointer care indic adresa irului transformat.
Funcia Sintaxa apelului Realizeaz
strlwr() strlwr(sir) n irul de caractere sir transform literele mari n litere mici.
RA

Restul caracterelor nu sunt modificate.


strupr() strupr(sir) n irul de caractere sir transform literele mici n litere mari.
Restul caracterelor nu sunt modificate.

Cutarea unui caracter ntr-un ir


ITU

Prin aceast operaie se parcurge irul de caractere pentru a verifica dac exist
caracterul cutat. Se pot folosi funcii sistem care au parametrii: sir irul de caractere
n care se caut, i ch caracterul care se caut. Ambele funcii furnizeaz ca rezultat un
pointer care indic poziia caracterului cutat, dac l-au gsit; altfel, dac nu l-au gsit,
ED

returneaz pointerul caracterului NULL care marcheaz sfritul irului de caractere.



160 Implementarea structurilor de date

IC
Funcia Sintaxa apelului Realizeaz
strchr() strchr(sir,ch) Furnizeaz ca rezultat un pointer ctre prima apariie a carac-
terului ch n irul de caractere sir (cea din extremitatea stng).

OG
strrchr() strrchr(sir,ch) Furnizeaz ca rezultat un pointer ctre ultima apariie a carac-
terului ch n irul de caractere sir (cea din extremitatea dreapt).
Observaie. Parcurgerea irului de caractere se poate face de la nceputul irului de
caractere ctre sfritul lui, gsindu-se astfel prima apariie, sau de la sfritul irului de

G
caractere ctre nceputul su, gsindu-se ultima apariie. De exemplu, n irul de
caractere ala bala portocala prima apariie a caracterului a este n poziia 1 i ultima

DA
apariie a caracterului a este n poziia 18.
Exemplul 1 Se afieaz numrul de apariii ale unui caracter c ntr-un ir de caractere
sir i poziiile n care apare caracterul n ir. Localizarea poziiilor n care se gsete
caracterul se face cu pointerul p.

PE
#include <iostream.h>
#include <string.h>
void main()
{char sir[256],c,*p; int nr=0;
cout<<"Sirul de caractere "; cin.get(sir,100);
I
cout<<"Caracterul cautat "; cin>>c;
cout<<"caracterul "<<c<<" apare in pozitiile:"<<endl;
p=strchr(sir,c); //se caut prima apariie

while (p) //ct timp se gsete caracterul


{cout<<p-sir+1<<" "; nr++; p=strchr(p+1,c);}
IC

/*se caut urmtoarea apariie a caracterului ncepnd cu


poziia imediat urmtoare celei n care a fost gsit */
cout<<endl<<"apare in "<<nr<<" pozitii";}
CT

Exemplul 2 Se determin numrul de apariii ale caracterului c n irul de caractere sir.


Subprogramul numar() numr aceste apariii (c i sir se transmit prin parametri).
#include <iostream.h>
DA

#include <string.h>
int numar(char *s, char c)
{int n=0; s=strchr(s,c);
while (s) {n++; s=strchr(s+1,c);}
DI

return n;}
void main()
{char sir[256],c; cout<<"sirul de caractere= "; cin.get(sir,255);
RA

cout<<"caracterul= "; cin>>c;


cout<<"caracterul "<<c<<" apare in sirul "<<sir;
cout<<" de "<<numar(sir,c)<<" ori";}
Exemplul 3 Se numr cuvintele dintr-un text. Se consider c separarea cuvintelor se
ITU

face printr-un singur spaiu. Pentru aceasta, se folosesc doi pointeri p i q n care se
memoreaz adresa de la care ncepe cuvntul, respectiv adresa la care se termin
cuvntul. Adresa la care se termin cuvntul este adresa la care se gsete primul spaiu
din restul textului. Pointerul q este folosit pentru a ne deplasa n text pe primul spaiu care
urmeaz dup adresa memorat n pointerul p.
ED

Informatic 161

IC
#include <iostream.h>
#include <string.h>
void main()

OG
{char text[256],*p,*q; int nr=1;
cout<<"Textul: "; cin.get(text,256); q=strchr(text,' ');
//n pointerul q se memoreaz adresa primului spaiu
while (q) //ct timp se mai gsete un spaiu n text
{nr++; p=q+1; //pointerul p este poziionat dup spaiul gsit

G
q=strchr(p,' ');}
//n pointerul q se memoreaz adresa primului spaiu gsit

DA
//ncepnd de la adresa memorat n pointerul p
cout<<"S-au gasit "<<nr<<" cuvinte";}
1. Rescriei programul de la Exemplul 2 folosind funcia strrchr().
Tem 2. Rescriei programele anterioare fr s folosii funcii de sistem,

PE
parcurgnd vectorul de caractere cu ajutorul indicilor, respectiv cu
ajutorul pointerilor.
3. Scriei trei variante de programe (folosind cele trei metode de prelucrare a irurilor de
caractere) prin care s afiai prima apariie i ultima apariie a unui caracter c ntr-un
I
ir de caractere sir.
4. Scriei un program care s afieze numrul de apariii ale unui caracter c ntr-un ir de
caractere sir i poziiile n care apare caracterul n ir.
5. Scriei un program care s afieze ordinea n care apar ntr-un ir dou caractere, c1

i c2. Indicaie. Se folosesc doi pointeri, p (pentru localizarea caracterului c1) i q


(pentru localizarea caracterului c2). Stabilirea ordinii de afiare se face prin compa-
IC

rarea celor doi pointeri (a adreselor memorate n pointeri).


6. Scriei un program care s afieze numrul de caractere ntre primele dou apariii,
ntr-un ir de caractere ale unui caracter c precizat. Indicaie. Se folosesc doi pointeri,
CT

p i q, ctre elementele irului. Adresa primei apariii a caracterului c se memoreaz n


pointerul q, iar adresa urmtoarei apariii n pointerul p. Numrul de caractere dintre cele
dou apariii se calculeaz ca diferen dintre adresele memorate n pointerii p i q.
DA

Scop: exemplificarea modului n care putei folosi funciile care prelucreaz un ir de


caractere.
DI

Enunul problemei 1: Se citete de la tastatur un text n care cuvintele sunt separate


printr-un singur spaiu. S se afieze cuvintele din text care sunt palindrom.
Se folosesc urmtoarele iruri de caractere: text pentru a citi textul de la tastatur, cuv
RA

pentru a extrage un cuvnt din text i inv pentru a inversa caracterele cuvntului. Pointerii p
i q se folosesc pentru a memora adresa de la care ncepe cuvntul, respectiv adresa la care
se termin cuvntul. Diferena dintre pointeri (p-q) reprezint numrul de caractere din text
care formeaz un cuvnt, ncepnd de la adresa p.
ITU

#include <iostream.h>
#include <string.h>
void main()
{char text[256],cuv[25],inv[25],*p,*q;
ED

cout<<"Textul: "; cin.get(text,256); p=text; q=strchr(text,' ');



162 Implementarea structurilor de date

IC
while (q)
{*cuv=NULL; //variabila pentru cuvnt se iniializeaz cu irul vid
strncat(cuv,p,q-p); //se obine cuvntul prin concatenarea la
// irul vid cuv a p-q caractere din irul care ncepe la adresa p

OG
strcpy(inv,cuv); //se copiaz cuvntul cuv n irul inv
strrev(inv); //se inverseaz cuvntul (irul de caractere inv)
if (!stricmp(cuv,inv)) cout<<cuv<<endl;
//se compar cele dou iruri de caractere (cuv i inv);

G
//dac sunt egale, se afieaz cuvntul
p=q+1; // pointerul p este poziionat dup spaiul gsit

DA
//n pointerul q se memoreaz adresa primului spaiu gsit
//ncepnd de la adresa memorat n pointerul p
q=strchr(p,' ');}
//se extrage i se prelucreaz ultimul cuvnt:

PE
*cuv=NULL; strncat(cuv,p,q-p); strcpy(inv,cuv); strrev(inv);
if (!stricmp(cuv,inv)) cout<<cuv;}
De ce, pentru a extrage cuvntul, s-a folosit funcia pentru concatena-
Tem rea a dou iruri de caractere strncat(cuv,p,q-p)i nu funcia
I
pentru copierea unui ir de caractere strncpy(cuv,p,q-p)?
Enunul problemei 2: Se citete un cuvnt de la tastatur. S se traduc ntr-o limb
psreasc definit astfel:
 dup fiecare vocal se adaug litera m urmat de vocala respectiv;

 dac ultima liter din cuvnt este o consoan, se adaug la sfritul cuvntului irul
IC

de caractere ala.
Se folosesc irurile de caractere: s1 pentru a citi cuvntul de la tastatur, s2 pentru cuvntul
tradus i v pentru a memora vocalele. Pointerii p i q se folosesc pentru a parcurge cuvntul
CT

citit, respectiv cuvntul tradus. Pentru a testa caracterul curent (de la adresa p) se folosete
funcia strchr() prin care se caut caracterul n irul de vocale. Dac este gsit, la adresa q
se adaug caracterul, litera m i din nou caracterul; altfel, se adaug numai caracterul. Pentru
a verifica dac s-a ajuns la ultimul caracter, se compar diferena dintre adresa caracterului i
DA

adresa de nceput a cuvntului (p-s1) cu lungimea cuvntului, din care se scade ultimul
caracter (strlen(s1)-1) pentru ultimul caracter cele dou valori trebuie s fie egale.
#include <iostream.h>
#include <string.h>
DI

void main()
{char s1[25],s2[75],v[]="aeiou",*p,*q; cout<<"cuvant= ";cin>>s1;
for (p=s1,q=s2;*p;p++,q++)
RA

{if (strchr(v,tolower(*p))) {*q=*p;q++;*q='m';q++;*q=*p;}


else *q=*p;
if (p-s1==strlen(s1)-1)
{q++; *q=0;
ITU

if (!strchr(v,tolower(*p))) strcat(s2,"ala");}}
cout<<s2;}

Refacei cele dou probleme folosind prelucrarea irurilor de caractere


Tem
cu ajutorul indicilor.
ED

Informatic 163
Enunul problemei 3: Se citete un text de la tastatur. S se afieze frecvena de apariie a

IC
literelor n text, fr a se ine cont de diferena dintre litere mari i litere mici.
n irul de caractere text se citete textul care se analizeaz. Vectorul v este un vector de

OG
contoare n care se numr apariia fiecrei litere. El are 26 de elemente, fiecare element
fiind un contor pentru o liter: v[0] pentru litera a, v[1] pentru litera b, v[2] pentru litera
c etc. Elementele vectorului sunt iniializate cu 0. Se parcurge textul i, pentru fiecare liter,
se incrementeaz n vectorul v elementul care i corespunde. Indicele elementului se obine
fcnd diferena dintre liter (text[i]) i 65 codul ASCII al literei A. Fiecare liter din

G
text este tratat ca liter mare prin aplicarea funciei toupper(). Pentru a afia frecvena
de apariie a literelor n text se parcurge vectorul v. Dac elementul curent este diferit de 0,

DA
nseamn c litera asociat lui a aprut n text, i se afieaz litera mic, respectiv litera
mare i numrul de apariii (valoarea elementului v[i]). Litera se afieaz astfel: folosind
operatorul de conversie (char) se convertete codul ASCII al literei obinut prin adunarea
indicelui cu 97 (codul ASCII al literei a), respectiv cu 65 (codul ASCII al literei A).

PE
#include <iostream.h>
#include <string.h>
#include <ctype.h>
void main()
I
{char text[256]; int i,v[26]={0}; cout<<"Textul :"; cin.get(text,255);
for (i=0; i<strlen(text); i++) v[toupper(text[i])-65]++;
for (i=0; i<26; i++)
if (v[i]!=0) {cout<<"Litera "<<(char)(65+i)<<" sau ";

cout<<(char)(97+i)<<" apare de ";


cout<<v[i]<<" ori"<<endl;};
IC

1. Se introduce un text de la tastatur. S se afieze numrul


Tem literelor distincte din text i de cte ori apar ele n text. Se va ine cont
CT

de diferena dintre literele mari i literele mici.


2. Se introduce un text de la tastatur. S se afieze n ordine cresctoare numrul de
apariii ale fiecrei litere n text. Se va preciza litera care are frecvena cea mai mare i
litera care are frecvena cea mai mic. Analiza textului se va face fr s se in cont
DA

de diferena dintre literele mari i literele mici.

2.3.3.3. Prelucrarea subirurilor de caractere


DI

Se definete subirul ca fiind o poriune dintr-un ir identificat prin poziia din


care ncepe (n) i prin lungime (m).

poziia de nceput a subirului = 5


RA

lungimea subirului = 8 caracterul din poziia 20


irul din care
se extrage x x x x x x x x x x x x x x x x x x x x x x x x x x x x
subirul 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
ITU

subirul care se extrage lungimea irului = 28


De exemplu, n irul de caractere untdelemn, caracterul din poziia 5 este l, iar
subirul de ncepe din poziia 3 i are lungimea 2.
ED

164 Implementarea structurilor de date
Pentru prelucrarea subirurilor de caractere putei folosi urmtoarele operaii:

IC
 extragerea unui subir dintr-un ir;
 cutarea unui subir ntr-un ir;
 tergerea unui subir dintr-un ir;

OG
 inserarea unui subir ntr-un ir;
 nlocuirea unui subir cu un alt subir.
Extragerea unui subir dintr-un ir

G
Prin aceast operaie se extrage, prin copiere din irul sir, un subir care ncepe din
poziia n i care are lungimea m. Dac n>strlen(sir), se va extrage irul vid. Dac
m>strlen(sir)-n, se vor extrage numai ultimele strlen(sir)-n caractere din irul

DA
sir. n urma acestei operaii, subirul extras rmne n irul surs.
Exemplul 1 Se extrage subirul sb din irul sir folosind funciile de sistem.
#include <iostream.h>

PE
#include <string.h>
void main()
{char sir[256],sb[50]=""; int n,m;
cout<<"Textul "; cin.get(sir,50);
cout<<"Pozitia din care incepe subsirul "; cin>>n;
I
cout<<"Lungimea subsirului "; cin>>m;
if (n<=strlen(sir))
if (m>strlen(sir)-n) strcat(sb,sir+n-1);

else strncat(sb,sir+n-1,m);
cout<<sb;}
IC

n n
m m
ir ir
CT

'\0' '\0'

strncat(sb,sir+n-1,m) m
DA

sb '\0' sb '\0'

1. Folosind programul, extragei cuvntul car din cuvntul parcare i


DI

Tem cuvntul pa din cuvntul copac.


2. Rescriei programul parcurgnd irurile de caractere cu ajutorul
indicilor, respectiv al pointerilor.
RA

Cutarea unui subir ntr-un ir


Prin aceast operaie se furnizeaz prima poziie din care ncepe n irul sir un subir
sb. Se folosete funcia sistem strstr() care are sintaxa: strstr(sir,sb), unde sir
este irul n care se caut, iar sb este subirul care se caut. Dac gsete subirul,
ITU

funcia furnizeaz ca rezultat un pointer ctre prima apariie a subirului; altfel, furnizeaz
valoarea NULL.
Exemplul 1 Se caut poziia primei apariii a subirului sb n irul sir. Cele dou iruri
au lungimea lg1, respectiv lg2. Pentru executarea operaiei se parcurg irul i subirul de
ED

caractere folosind indicii: i pentru ir i j pentru subir. irul se parcurge de la primul caracter

Informatic 165
pn la caracterul de la care, pn la sfritul irului, sunt mai puine caractere dect

IC
lungimea subirului (nu mai exist caractere suficiente pentru a forma mpreun subirul).
#include <iostream.h>

OG
#include <string.h>
void main()
{char sir[256],sb[11]; int i,j,lg1,lg2;
cout<<"sirul in care se cauta : "; cin.get(sir,255);cin.get();
cout<<"subsirul care se cauta : "; cin.get(sb,10);

G
lg1=strlen(sir); lg2=strlen(sb);
for (i=0;i<lg1-lg2;i++)

DA
{for (j=0;sir[i+j]==sb[j] && j<lg2 ;j++);
if (j==lg2) {cout<<"prima aparitie este in pozitia "<<i+1; i=lg1;}}
if (i!=lg1+1) cout<<"subsirul nu exist n sir";}

PE
Folosind programul, aflai din ce poziie ncepe cuvntul car n cuvntul
Tem
parcare i cuvntul pa din cuvntul copac.

Exemplul 2 Se caut i se numr toate apariiile disjuncte ale subirului sb n irul


sir. Se folosete funcia strstr(). Pointerul p localizeaz poziiile n care se gsete
I
subirul sb. Cutarea subirului sb continu pn cnd nu se mai gsete (pointerul p are
valoarea NULL).
#include <iostream.h>

#include <string.h>
{char sir[256],sb[11],*p,*q; int nr=0;
IC

cout<<"sirul in care se cauta :"; cin.get(sir,255);cin.get();


cout<<"subsirul care se cauta :"; cin.get(sb,10);
p=strstr(sir,sb); cout<<"subsirul apare in pozitiile: ";
CT

while (p) {nr++; cout<<p-sir+1<<" "; p=strstr(p+1,sb);}


cout<<endl<<"de "<<nr<<" ori"; }
1. Folosind programul anterior, aflai din ce poziie ncepe cuvntul car
Tem
DA

n cuvntul parcare i cuvntul pa din cuvntul copac.


2. Se citesc de la tastatur dou iruri de caractere, sir1 i sir2. S
se afieze de cte ori apare irul sir2 n irul sir1 i n ce poziii. Pentru localizarea
i numrarea poziiilor vei folosi un subprogram.
3. Scriei trei variante de programe (folosind cele trei metode de prelucrare a irurilor de
DI

caractere) prin care s afiai prima apariie a subirului sb n irul sir.


4. Scriei dou versiuni pentru un program care afieaz poziia ultimei apariii a unui
subir ntr-un ir o versiune n care parcurgei irul i subirul cu ajutorul indicilor i o
RA

versiune n care parcurgei irul i subirul cu ajutorul pointerilor.


5. Scriei dou versiuni pentru un program care caut toate apariiile disjuncte ale
subirului sb n irul sir, fr a folosi funcia sistem o versiune n care parcurgei
irul i subirul cu ajutorul indicilor i o versiune n care parcurgei irul i subirul cu
ITU

ajutorul pointerilor.

tergerea unui subir dintr-un ir


Prin aceast operaie se terge din irul sir un subir sb. Dup executarea operaiei de
tergere, noua lungime a irului va fi strlen(sir)- strlen(sb).
ED

166 Implementarea structurilor de date
Exemplul 1 Se terge din irul sir un subir care ncepe din poziia n i are lungimea

IC
m. Dac n>strlen(sir), irul va rmne neschimbat. Dac m>strlen(sir)-n, se vor
terge numai ultimele strlen(sir)-n caractere. Pentru executarea operaiei se parcur-

OG
ge irul folosind indicii.
#include <iostream.h>
#include <string.h>
void main()
{char sir[256]; int n,m,i;

G
cout<<"sirul din care se sterge :"; cin.get(sir,255);
cout<<"pozitia din care se sterge :"; cin>>n;

DA
cout<<"numarul de pozitii care se sterg :"; cin>>m;
if (n<strlen(sir))
{if(m>strlen(sir)-n)
for (i=n-1; sir[i+strlen(sir)-n+1]; i++)

PE
sir[i]=sir[i+strlen(sir)-n+1];
else for (i=n-1; sir[i+m]; i++) sir[i]=sir[i+m];
sir[i]=0;}
cout<<sir;}
I
Folosind operaia de tergere a unui subir dintr-un ir, obinei
Tem cuvntul pare din cuvntul parcare.

Exemplul 2 Se terge din irul sir prima apariie a unui subir sb. Pentru executarea

operaiei se folosete funcia strstr() pentru a localiza prima apariie a subirului.


Dac subirul este gsit n ir, va fi ters prin copierea la adresa gsit a poriunii din ir
IC

care urmeaz dup subir.


p p+strlen(sb) p strlen(sb)
sb
CT

ir ir
'\0' '\0'

strlen(sir)
DA

strcpy(p,p+strlen(sb))
DI

#include <iostream.h>
#include <string.h>
void main()
{char sir[256],sb[11],*p;
RA

cout<<"sirul in care se sterge :";cin.get(sir,255); cin.get();


cout<<"subsirul care se sterge :";cin.get(sb,10); p=strstr(sir,sb);
if (p) strcpy(p,p+strlen(sb)); cout<<sir;}
Exemplul 3 Se terg din irul sir toate apariiile unui subir sb. Pentru executarea
ITU

operaiei se folosete funcia strstr() pentru a localiza fiecare apariie a subirului. Cnd
subirul este gsit n ir, va fi ters prin copiere la adresa la care a fost gsit a poriunii
din ir care urmeaz dup subir.
#include <iostream.h>
ED

#include <string.h>

Informatic 167

IC
void main()
{char sir[256],sb[11],*p;
cout<<"sirul in care se sterge :";cin.get(sir,255); cin.get();

OG
cout<<"subsirul care se sterge :"; cin.get(sb,10); p=strstr(sir,sb);
while (p) {strcpy(p,p+strlen(sb));p=strstr(p,sb);}
cout<<sir;}

Inserarea unui subir ntr-un ir

G
Prin aceast operaie se insereaz subirul sb n irul sir n poziia n. Dup executarea
operaiei de inserare, noua lungime a irului va fi strlen(sir)+strlen(sb). Dac

DA
strlen(sir)+strlen(sb)>nmax (nmax fiind lungimea fizic a irului de caractere),
se vor pstra din irul rezultat numai nmax caractere.
Folosind operaia de inserare a unui subir ntr-un ir, obinei cuvntul
Tem parcare din cuvntul pare.

PE
Exemplu Se insereaz subirul sb n irul sir n poziia n, folosind funciile de sistem.
#include <iostream.h>
#include <string.h>
I
void main()
{char sir[256],aux[256],sb[20],*p; int n;
cout<<"sirul in care se insereaza:"; cin.get(sir,255);cin.get();
cout<<"subsirul care se insereaza:"; cin.get(sb,19);

cout<<"pozitia din care se insereaza:"; cin>>n;


p=&sir[n-1]; strcpy(aux,p); strcpy(p,sb); strcpy(p+strlen(sb),aux);
IC

cout<<sir;}
p p
CT

ir ir

'\0' '\0'
strcpy(p,sb)
strcpy(aux,p)
DA

sb '\0'
aux '\0'
strlen(sb)
DI

p p p+strlen(sb)
p+strlen(sb)
ir ir

'\0 '\0' '\0'


RA

strcpy(p+strlen(sb),aux)
sb aux
strlen(sir)+strlen(sb)
aux '\0'
ITU

Refacei programul astfel nct s fie tratat i cazul n care


Tem strlen(sir)+strlen(sb)>nmax (nmax fiind lungimea fizic a irului).
ED

168 Implementarea structurilor de date
nlocuirea, ntr-un ir, a unui subir cu un alt subir

IC
Prin aceast operaie se nlocuiete, n irul sir, subirul sb1 cu subirul sb2. Dup
executarea operaiei de nlocuire, noua lungime a irului va fi strlen(sir)+strlen(sb2)-

OG
strlen(sb1). Dac strlen(sir)+strlen(sb2)-strlen(sb1)>nmax (nmax fiind lungi-
mea fizic a irului de caractere), se vor pstra din irul rezultat numai nmax caractere.
Pentru realizarea operaiei de nlocuire se execut, n ordine, urmtoarele operaii:
 se caut n irul sir subirul sb1;
 se terge subirul sb1 din irul sir;

G
 se insereaz n irul sir subirul sb2 n poziia n care a fost gsit subirul sb1.

DA
Desenai diagrama operaiei de nlocuire a unui subir ntr-un ir folosind
Tem modelele de diagrame de la operaiile: extragerea unui subir dintr-un ir,
tergerea unui subir dintr-un ir i inserarea uni subir ntr-un ir.
Exemplul 1 Se nlocuiete, n irul sb, subirul s1 cu subirul s2, folosind funciile de

PE
sistem. Cele trei iruri de caractere se citesc de la tastatur.
#include <iostream.h>
#include <string.h>
void main()
{char sir[256],aux[256],s1[20],s2[20],*p;
I
cout<<"sirul in care se inlocuieste :"; cin.get(sir,255); cin.get();
cout<<"subsirul care se cauta :"; cin.get(s1,19); cin.get();
cout<<"subsirul cu care se inlocuieste:"; cin.get(s2,19);

p=strstr(sir,s1);
while (p) {strcpy(p,p+strlen(s1)); strcpy(aux,p); strcpy(p,s2);
IC

strcpy(p+strlen(s2),aux); p=strstr(p,s1);}
cout<<sir;}
Modificai programul astfel nct s fie nlocuit numai prima apariie a
CT

Tem subirului s1 n irul sir. Transformai cuvntul sortare n serbare


folosind operaia de nlocuire, ntr-un ir de caractere, a unui subir cu
un alt subir, realizat de acest program.
DA

Exemplul 2 Pentru rezolvarea problemei din exemplul anterior, se folosesc subprogra-


mele: gasit(), pentru a verifica dac s-a mai gsit subirul sb1 n irul sir, sterg()
care terge subirul sb1 din irul sir, i inserez(), care insereaz subirul sb2.
Subprogramul gasit() furnizeaz dou rezultate: unul prin numele su (este de tip logic
DI

i precizeaz dac s-a gsit sau nu s-a gsit subirul) i altul prin parametrul p, care este
de tip pointer i care furnizeaz adresa subirului (n cazul n care s-a gsit) informaia
care se transmite fiind o adres care se poate modifica n interiorul subprogramului,
transferul s-a fcut prin referin.
RA

#include <iostream.h>
#include <stdlib.h>
#include <string.h>
ITU

int gasit(char * &p, char sb[])


{p=strstr(p,sb);
if (p==NULL) return 0; else return 1;}
void sterg(char *p, char sb[])
{strcpy(p,p+strlen(sb));}
ED

Informatic 169

IC
void inserez(char *p, char sb[])
{char aux[256];
strcpy(aux,p); strcpy(p,sb); strcpy(p+strlen(sb),aux);}

OG
void main()
{char sir[256],sb1[20],sb2[20],*p=sir;
cout<<"sirul de caractere= "; cin.get(sir,255); cin.get();
cout<<"subsirul care se cauta= "; cin.get(sb1,19); cin.get();
cout<<"subsirul care se inlocuieste= "; cin.get(sb2,19);

G
while (gasit(p,sb1)) {sterg(p,sb1); inserez(p,sb2);}
cout<<sir;}

DA
Folosind operaiile cu subiruri, realizai urmtoarele transformri de
Tem cuvinte: car caviar
cor color
parcare partajare

PE
covor cotor motor mosor
covor cotor color cosor cosar
cod codare decodare
Alte funcii utile n prelucrarea irurilor de caractere
I
n prelucrarea irurilor de caractere mai putei folosi urmtoarele funcii (s1 i s2
parametrii acestor funcii sunt iruri de caractere):

Funcia Sintaxa apelului Realizeaz


strspn() strspn(s1,s2) Furnizeaz ca rezultat numrul de caractere consecutive din irul
IC

s1 (ncepnd cu primul caracter), care se gsesc printre carac-


terele din irul s2.
strcspn() strcspn(s1,s2) Furnizeaz ca rezultat numrul de caractere consecutive din irul
CT

s1 (ncepnd cu primul caracter), care nu se gsesc printre


caracterele din irul s2.
strpbrk() strpbrk(s1,s2) Furnizeaz ca rezultat un pointer ctre primul caracter din irul
s1 care se gsete i n irul s2. Dac nici un caracter din irul
DA

s1 nu se gsete printre caracterele irului s2, funcia furnizeaz


ca rezultat adresa nul.
strtok() strtok(s1,s2) irul s2 este un ir de caractere care pot fi folosite ca separatori,
iar irul s1 este format din mai multe entiti separate prin unul din-
tre separatorii din irul s2. Funcia nlocuiete separatoril prin
DI

caracterul NULL i furnizeaz ca rezultat un pointer ctre primul


caracter al primei entiti. Pentru a gsi urmtoarea entitate din
irul s1, apelarea funciei se va face cu strtok(NULL,s2).
RA

Exemplu:
#include <iostream.h>
#include <string.h>
#include <stdio.h>
ITU

void main()
{char sir[]="Azi, Ana are mere.",sp[]=",. ",*p;
cout<<strspn("1234567890","1D2C3B")<<endl; //afieaz 3
cout<<strspn("1234567890","2D1C3B")<<endl; //afieaz 3
cout<<strspn("1234567890","ABC")<<endl; //afieaz 0
ED

170 Implementarea structurilor de date

IC
cout<<strcspn("1234567890","ABC457")<<endl; //afieaz 3
cout<<strcspn("1234567890","ABC")<<endl; //afieaz 10
cout<<strcspn("1234567890","025")<<endl; //afieaz 1

OG
p=strpbrk("1234567890","052");
if (p) cout<<"primul caracter este "<<*p<<endl; //afieaz 2
p=strpbrk("1234567890","ABC");
if (p) cout<<"primul caracter este "<<*p<<endl; //nu afieaz
p=strtok(sir,sp); if (p) cout<<p<<endl; //afieaz Azi

G
p=strtok(NULL,sp); if (p) cout<<p<<endl; //afieaz Ana
p=strtok(NULL,sp); if (p) cout<<p<<endl; //afieaz are

DA
p=strtok(NULL,sp); if (p) cout<<p<<endl; //afieaz mere
p=strtok(NULL,sp); if (p) cout<<p<<endl;} //nu afieaz nimic

PE
Scop: exemplificarea modului n care putei folosi funciile ce prelucreaz subiruri de caractere.
Enunul problemei 1: Se citete de la tastatur, ca ir de caractere, codul numeric al unei
persoane. S se afieze urmtoarele informaii: sexul i data de natere ale persoanei.
Codul numeric personal este format din 13 caractere, astfel: saallzzxxxxxx, unde s
I
precizeaz sexul persoanei (1 masculin i 2 feminin), iar aa anul, ll luna i zz ziua
din data de natere. Pentru extragerea informaiilor, trebuie extrase subirurile de
caractere: s1 sexul i s2 anul, s3 luna, s4 ziua datei de natere.

#include <iostream.h>
#include <string.h>
IC

void main()
{char cn[14],s1[2]="",s2[3]="",s3[3]="",s4[3]="";
cout<<"Codul numeric personal este "; cin.get(cn,13);
CT

cout<<"Persoana este de sex ";


if (strcmp(strncat(s1,cn,1),"1")) cout<<"feminin"<<endl;
else cout<<"masculin"<<endl;
strncat(s2,cn+1,2); strncat(s3,cn+3,2); strncat(s4,cn+5,2);
DA

cout<<"si s-a nascut la data "<<s4<<" - "<<s3<<" - "<<s2;}


Enunul problemei 2: Se citete de la tastatur un numr real sub forma unui ir de
caractere. Partea ntreag este separat de partea fracionar prin virgul. S se afieze
DI

partea ntreag i partea zecimal.


Pentru separarea celor dou entiti se folosete funcia strtok():
#include <iostream.h>
RA

#include <string.h>
#include <stdlib.h>
void main()
{char numar[20],*p; cout<<"Numarul: "; cin.get(numar,19);
ITU

p=strtok(numar,","); if (p) cout<<"partea intreaga este "<<p<<endl;


p=strtok(NULL,","); if (p) cout<<"partea fractionara este "<<p<<endl;}
Enunul problemei 3: Se citete un text de la tastatur. Cuvintele sunt separate prin
spaiu sau caracterele: .,!?. S se numere cuvintele din text i s se afieze fiecare
cuvnt pe un rnd.
ED

Informatic 171
Cuvintele sunt entitile din text care vor fi identificate folosind funcia strtok():

IC
#include <iostream.h>
#include <string.h>

OG
#include <stdlib.h>
void main()
{char text[1000],sep[]=" .,!?",*p; int n=0;
cout<<"Textul: "; cin.get(text,999);
p=strtok(text,sep);

G
while (p) {n++; cout<<p<<endl; p=strtok(NULL,sep);}
cout<<"S-au gasit "<<n<<" cuvinte";}

DA
Enunul problemei 4: Se citete un text de la tastatur. S se afieze cte cifre conine textul.
Textul poate fi format din mai multe subiruri care conin numai cifre. Se caut n irul de
caractere fiecare subir cu cifre, folosind funcia strpbrk(), iar cu funcia strspn()

PE
se stabilete lungimea subirului. Lungimea subirului se va aduna la variabila lc n care
se numr cifrele.
#include <iostream.h>
#include <string.h>
void main()
I
{char sir[100], cifre[]="1234567890",*p; int lc=0;
cout<<"textul "; cin.get(sir,99); p=strpbrk(sir,cifre);
while (p) {lc+=strspn(p,cifre); strcpy(p,p+strspn(p,cifre));

p=strpbrk(p,cifre);}
cout<<"Textul contine "<<lc<<" cifre";}
IC

Enunul problemei 5: Se citete de la tastatur un text care se va analiza astfel:


 dac el conine numai cifre, se va afia c este un numr;
 dac el conine numai litere, se va afia c este un cuvnt;
CT

 dac el conine numai cifre i litere, se va afia: numai caractere alfanumerice;


 dac el conine numai semne speciale, se va afia: numai semne speciale;
 dac el conine litere, cifre i semne speciale, se va afia: toate tipurile de caractere.
DA

n irul de caractere sir se citete textul. irul de caractere cifre conine numai caractere cifre,
iar irul de caractere litere numai caractere litere mici. Deoarece prin operaiile de prelucrare
irul de caractere sir se va modifica, lungimea sa se va memora n variabila lg. n variabilele
lc i ll se va memora numrul de cifre din text, respectiv numrul de litere. Folosind funcia
DI

strspn() se determin dac textul este un numr sau un cuvnt, astfel: dac lungimea
subirului din ir care conine numai cifre este egal cu lungimea irului, atunci este numr, iar
dac lungimea subirului din ir care conine numai litere este egal cu lungimea irului, atunci
este cuvnt. Folosind funcia strcspn() se determin dac textul conine numai semne
RA

speciale, astfel: dac lungimea subirului de cifre care nu exist n ir este egal cu numrul de
cifre (10) i dac lungimea subirului de litere care nu exist n ir este egal cu numrul de
litere ale alfabetului (26), atunci textul nu conine cifre i litere. Pentru a determina dac textul
conine numai caractere alfanumerice, se numr literele i cifrele din text. Dac numrul lor
ITU

este egal cu lungimea irului, atunci textul conine numai caractere alfanumerice.
#include <iostream.h>
#include <string.h>
void main()
ED

{char sir[100],cifre[]="1234567890",litere[27],*p;

172 Implementarea structurilor de date

IC
int i,lc=0,ll=0,lg;
cout<<"textul "; cin.get(sir,99); lg=strlen(sir);
for (i=0;i<26;i++) litere[i]='a'+i;

OG
litere[i]=0; //s-au generat literele mici ale alfabetului
if (strspn(sir,cifre)==lg) cout<<"numar";
else if (strspn(strlwr(sir),litere)==lg) cout<<"cuvant";
else if (strcspn(cifre,sir)==10 && strcspn(litere,strlwr(sir))==26)
cout<<"numai semne speciale";

G
else
{p=strpbrk(sir,cifre);

DA
while (p) {lc+=strspn(p,cifre);
strcpy(p,p+strspn(p,cifre));
p=strpbrk(p,cifre);}
p=strpbrk(strlwr(sir),litere);

PE
while (p) {ll+=strspn(strlwr(p),litere);
strcpy(p,p+strspn(p,litere));
p=strpbrk(strlwr(p),litere);}
if (lc+ll==lg) cout<<"numai caractere alfanumerice";
else cout<<"toate tipurile de caractere"; }}
I
Enunul problemei 6: Se citesc de la tastatur dou iruri de caractere. S se numere cte
dintre caracterele primului ir exist i n al doilea ir.
Pentru a gsi fiecare caracter din primul ir (sir1) care exist i n al doilea ir (ir2) se

va folosi funcia strpbrk().


IC

#include <iostream.h>
#include <stdio.h>
void main()
CT

{char s1[100],s2[100],*p; int nr=0;


cout<<"primul text "; cin.get(s1,100); cin.get();
cout<<"al doilea text "; cin.get(s2,100); p=strpbrk(s1,s2);
while (p) {nr++; p++; p=strpbrk(p,s2);}
DA

cout<<"S-au gasit in primul sir "<<nr;


cout<<" caractere care exista si in al doilea sir";}

1. Executai programul de dou ori: o dat pentru sir1="alfabet" i


Tem
DI

sir2="alb" i a doua oar pentru sir2="alfabet" i sir1="alb". Ce


constatai?
2. Se citete un text de la tastatur. Cuvintele se consider separate prin spaiu, virgul
sau punct. Numrai cte cuvinte conine textul.
RA

3. Se citete un text de la tastatur, format dintr-o singur propoziie. Se consider c


separarea cuvintelor se face prin cel puin un spaiu. Afiai numrul de cuvinte din
text, i apoi, fiecare cuvnt, pe cte un rnd. Eliminai din text spaiile suplimentare i
afiai textul.
ITU

4. Se citete de la tastatur un caracter c i apoi se introduce un text, n care separarea


cuvintelor se face prin cel puin un spaiu. S se numere cuvintele care conin
caracterul c. S se afieze cuvintele n care apare acest caracter.
5. Se citesc de la tastatur dou iruri de caractere. S se elimine din fiecare ir
ED

caracterele care sunt comune celor dou iruri.



Informatic 173
6. Se citesc de la tastatur trei iruri de caractere. S se elimine din al treilea ir

IC
caracterele care sunt comune n primele dou iruri.
2.3.3.4. Conversii ntre tipul ir de caractere i tipuri numerice

OG
n multe probleme, datele de tip numeric trebuie transformate n date de tip ir de ca-
ractere pentru a se putea concatena, i invers, datele de tip ir de caractere care conin
numai cifre trebuie transformate n date de tip numeric pentru a se putea aplica asupra lor
operatorii matematici. Pentru aceste operaii de conversie se pot folosi funciile (toate

G
aceste funcii sunt definite n fiierele antet <stdlib.h>) :

DA
atoi(), atol(), _atold(), atof(),
strtol, strtoul, strtod
ir de caractere numr

PE
itoa(), ltoa(), ultoa(),
ecvt(), fcvt()

Conversia unui ir de caractere ntr-un numr


I
Pentru acest tip de conversie se pot folosi funcii de sistem. irul de caractere care se
convertete ar trebui s conin numai caractere folosite pentru reprezentarea unui
numr: cifre, semnul + sau -, iar pentru numerele reale, punctul ca separator ntre partea
ntreag i partea zecimal. De exemplu, irurile de caractere "1234" i "-12.34" conin

numai caractere folosite pentru reprezentarea unui numr, spre deosebire de irul de
caractere "12x4" ce conine litera x care nu este folosit pentru reprezentarea unui
IC

numr. Aceste funcii furnizeaz rezultatul astfel:


 Dac operaia de conversie se poate executa (irul de caractere conine numai
caractere folosite pentru reprezentarea unui numr), funcia va furniza o valoare
CT

numeric format din caracterele irului.


 Dac irul de caractere conine i caractere care nu sunt folosite pentru repre-
zentarea unui numr (de exemplu, irul "12x34"), se va face conversia pn la
DA

ntlnirea acelui caracter (n exemplu, valoarea furnizat va fi 12).


 Dac primul caracter din ir nu este un caracter permis (de exemplu, irul "x123"),
funcia va furniza valoarea 0.

Parametrii acestor funcii pot fi:


DI

 sir este de tip ir de caractere i furnizeaz funciei irul de caractere care se


convertete;
 p este de tip *char (o adres ctre un caracter) i v furnizeaz poziia primului
RA

caracter din ir care nu poate fi convertit;


 b este de tip int i furnizeaz funciei baza de numeraie n care trebuie s
realizeze conversia (de obicei, are valoarea 10 baza de numeraie 10).

Funcie Tip Sintax Realizeaz


ITU

rezultat apel
atoi() int atoi(sir) Convertete irul de caractere sir ntr-o valoare numeric
ntreag.
atol() long atol(sir) Convertete irul de caractere sir ntr-o valoare numeric
ED

ntreag de tip long.



174 Implementarea structurilor de date

IC
Funcie Tip Sintax Realizeaz
rezultat apel
atof() double atof(sir) Convertete irul de caractere sir ntr-o valoare numeric

OG
real n virgul mobil dubl precizie.
_atold() long _atold(sir) Convertete irul de caractere sir ntr-o valoare numeric
double real n virgul mobil dubl precizie, de tip long.
strtol() long strtol(sir,&p,b) Convertete irul de caractere sir ntr-o valoare numeric

G
ntreag de tip long. Funciei i se furnizeaz baza de nu-
meraie prin parametrul b. Funcia furnizeaz poziia pri-
mului caracter care nu poate fi convertit prin parametrul p.

DA
strtoul() unsigned strtol(sir,&p,b) Convertete irul de caractere sir ntr-o valoare numeric
long ntreag fr semn, de tip long. Funciei i se furnizeaz
baza de numeraie prin parametrul b. Funcia furnizeaz
poziia primului caracter care nu poate fi convertit prin

PE
parametrul p.
strtod() double strtod(sir,&p) Convertete irul de caractere sir ntr-o valoare numeric
real n virgul mobil dubl precizie. Funcia furnizeaz
poziia primului caracter care nu poate fi convertit prin
parametrul p.
I
Exemplu:
#include <iostream.h>
#include <stdlib.h>

void main()
{char *sir="123456789",*p;
IC

int n1; long n2; double n3; long double n4;


n1=atoi(sir); n2=atol(sir);
cout<<n1<<" "<<n2<<endl; //afieaz -13035 123456789
CT

strcpy(sir,"12345"); n1=atoi(sir); n2=atol(sir);


cout<<n1<<" "<<n2<<endl; //afieaz 12345 12345
strcpy(sir,"12345.6789");
DA

n1=atoi(sir); n2=atol(sir); n3=atof(sir); n4=_atold(sir);


cout<<n1<<" "<<n2<<" "<<n3<<" "<<n4<<endl;
//afieaz 12345 12345 12345.6789 12345.6789
strcpy(sir,"12Aa"); n2=strtol(sir,&p,16);
DI

if (!*p) cout<<"conversie corecta -> "<<n2<<endl;


else {cout<<"nu s-au putut converti decat primele ";
cout<<p-sir<<" caractere -> "<<n2<<endl; }
//conversie corect -> 4778
RA

n2=strtol(sir,&p,10);
if (!*p) cout<<"conversie corecta -> "<<n2<<endl;
else {cout<<"nu s-au putut converti decat primele ";
cout<<p-sir<<" caractere -> "<<n2<<endl; }}
ITU

//nu s-au putut converti decat primele 2 caractere ->12

n exemplele prezentate, analizai valorile afiate i explicai modul n


Tem
care s-a fcut conversia n fiecare caz.
ED

Informatic 175
Conversia unui numr n ir de caractere

IC
i pentru acest tip de conversie se pot folosi funcii de sistem. Ele furnizeaz ca rezultat
un ir de caractere. Dac funcia convertete un numr ntreg cu semn (funciile itoa()

OG
i ltoa()) i numrul este negativ, semnul minus va fi scris n irul de caractere pe
prima poziie. Dac funcia convertete un numr real (funciile ecvt() i fcvt()),
semnul minus i punctul zecimal nu sunt scrise n irul de caractere; informaiile despre
poziia punctului zecimal i semnul numrului sunt furnizate prin intermediul unor

G
parametri. Toate aceste funcii furnizeaz ca rezultat un pointer ctre irul de caractere n
care este convertit numrul. Parametrii acestor funcii pot fi:
 sir este de tip ir de caractere i v furnizeaz irul de caractere n care este

DA
convertit numrul;
 n este de tip numeric (tipul depinde de funcia folosit pentru conversie) i este
furnizat funciei pentru a fi convertit;
 b este de tip int i furnizeaz funciei baza de numeraie n care trebuie s

PE
realizeze conversia (de obicei, are valoarea 10 baza de numeraie 10).
 m este de tip int i furnizeaz funciei numrul de cifre folosite pentru conversie;
 p este de tip int i furnizeaz poziia punctului zecimal fa de prima poziie din
ir, n cazul valorilor reale;
I
 s este de tip int i v furnizeaz informaii despre semnul numrului n cazul valorilor
reale: dac numrul este negativ, s va avea valoarea 1; altfel, va avea valoarea 0.
Funcie Tip Sintax apel Realizeaz

numr
itoa() int itoa(n,sir,b) Convertete n irul de caractere sir o valoare numeric
IC

ntreag n exprimat n baza de numeraie b.


ltoa() long ltoa(n,sir,b) Convertete n irul de caractere sir o valoare numeric
ntreag de tip long n exprimat n baza de numeraie b.
CT

ultoa() unsigned ultoa(n,sir,b) Convertete n irul de caractere sir o valoare numeric


long ntreag fr semn, de tip long n, exprimat n baza de
numeraie b.
ecvt() double ecvt(n,m,&p, &s) Convertete ntr-un ir de caractere o valoare numeric
DA

real n virgul mobil dubl precizie n. Parametrul m


precizeaz numrul de caractere ale irului; dac
numrul are mai puine cifre dect m, se va completa la
dreapta cu caracterul cifra 0, pn se obin cele m
DI

caractere. Funcia furnizeaz prin numele ei adresa


irului de caractere, prin parametrul p poziia punctului
zecimal i prin parametrul s semnul.
fcvt() double fcvt(n,m,&p, &s) Convertete ntr-un ir de caractere o valoare numeric
RA

real n virgul mobil dubl precizie n, la fel ca funcia


ecvt() cu deosebirea c parametrul m precizeaz
numrul de caractere ale prii zecimale din ir; dac
numrul are mai puine cifre n partea fracionar dect m,
ITU

se va completa la dreapta cu caracterul cifra 0 pn se


obin cele m caractere pentru partea fracionar.
Exemplu:
#include <iostream.h>
#include <stdlib.h>
ED

176 Implementarea structurilor de date

IC
void main()
{char sir[25],*sc; double n; int n1=-12345,m,p,s;
long n2=213456789; unsigned long n3=4223456789;

OG
itoa(n1,sir,10); cout<<n1<<" "<<sir<<endl; //afieaz -12345 -12345
n1=12345; itoa(n1,sir,10); cout<<n1<<" "<<sir<<endl; //12345 12345
ltoa(n2,sir,10); cout<<n2<<" "<<sir<<endl; //213456789 213456789
ultoa(n3,sir,10); cout<<n3<<" "<<sir<<endl; //4223456789 4223456789
n=9.87654; m=10; sc=ecvt(n,m,&p,&s);

G
cout<<sc<<" "<<p<<" "<<s<<endl; //9876540000 1 0
n=-123.456; m=15; sc=ecvt(n,m,&p,&s);

DA
cout<<sc<<" "<<p<<" "<<s<<endl; //123456000000000 3 1
n=9988.76; m=5; sc=ecvt(n,m,&p,&s);
cout<<sc<<" "<<p<<" "<<s<<endl; //99888 4 0
n=987.654; sc=fcvt(n,m,&p,&s);

PE
cout<<sc<<" "<<p<<" "<<s<<endl; //98765400 3 0
n=9.87654; m=10; sc=fcvt(n,m,&p,&s);
cout<<sc<<" "<<p<<" "<<s<<endl; //98765400000 1 0
n=-123.456; m=5; sc=fcvt(n,m,&p,&s);
cout<<sc<<" "<<p<<" "<<s<<endl; //12345600 3 1
I
n=-1.23456; m=10; sc=fcvt(n,m,&p,&s);
cout<<sc<<" "<<p<<" "<<s<<endl; //12345600000 1 1
n=9.87654; m=3; sc=fcvt(n,m,&p,&s);

cout<<sc<<" "<<p<<" "<<s<<endl; } //9877 1 0


1. Folosind operaia de conversie, concatenai vrsta furnizat de
IC

Tem data v, de tip unsigned int, cu irul de caractere "ani".


2. Din exemplele prezentate, stabilii regula folosit de funciile
ecvt() i fcvt() pentru a rotunji numrul convertit n ir de caractere, atunci cnd
CT

numrul poziiilor din ir este mai mic dect numrul de cifre din valoarea numeric.
DA

Scop: exemplificarea modului n care putei folosi funciile care fac conversia ntre valori
numerice i iruri de caractere.
Enunul problemei 1: Se citete de la tastatur un text care poate conine i numere. S
se afieze suma acestor numere, chiar dac fac parte din cuvinte.
DI

Cu funcia strpbrk() se identific fiecare cifr, cu funcia strspn() se extrage din irul
numar subirul de cifre care ncepe cu acea cifr (subir care reprezint un numr), cu
funcia strtoul() se convertete irul de caractere numar ntr-o valoare ntreag care se
RA

adun la suma s, dup care se elimin din irul iniial sir numrul, cu funcia strcpy().
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
ITU

void main()
{char sir[100],numar[10],cifre[]="1234567890",*p,*q,*r;
unsigned long s=0; cout<<"textul "; cin.get(sir,100);
p=strpbrk(sir,cifre);
ED

while (p)

Informatic 177

IC
{strcpy(numar,""); q=p+strspn(p,cifre); strncat(numar,p,q-p);
s+=strtoul(numar,&r,10); strcpy(p,q); p=strpbrk(p,cifre);}
cout<<"suma= "<<s; }

OG
Enunul problemei 2: S se afieze suma a dou numere hexazecimale citite de la tastatur.
Cele dou numere se citesc n irurile de caractere nr1 i nr2. Pentru fiecare numr se
verific dac el poate reprezenta un numr n baza 16, astfel: se convertete irul de
caractere n valoarea numeric n1, respectiv n2, i se verific dac s-a executat corect

G
conversia comparnd lungimea irului nr1, respectiv nr2, cu numrul de caractere care
au fost convertite (p-nr1 sau p-nr2 p fiind un pointer ctre poziia caracterului care nu a

DA
putut fi convertit). Suma celor dou valori numerice n1 i n2 reprezentate n hexazecimal
se convertete, cu funcia ultoa(), n irul de caractere suma care se afieaz.
#include <iostream.h>
#include <string.h>

PE
#include <stdlib.h>
void main()
{char nr1[10],nr2[10],suma[10],*p; unsigned long n1,n2;
cout<<"primul numar "; cin.get(nr1,10); cin.get();
n1=strtoul(nr1,&p,16);
I
while (p-nr1!=strlen(nr1))
{cout<<"primul numar "; cin.get(nr1,10); cin.get();
n1=strtoul(nr1,&p,16);}

cout<<"al doilea numar "; cin.get(nr2,10); cin.get();


n2=strtoul(nr2,&p,16);
IC

while (p-nr2!=strlen(nr2))
{cout<<"al doilea numar "; cin.get(nr2,10); cin.get();
n2=strtoul(nr2,&p,16);}
CT

ultoa(n1+n2,suma,16); cout<<"suma= "<<suma;}


Enunul problemei 3: Se citete un numr real. S se converteasc ntr-un ir de
caractere ce va fi prelucrat astfel nct numrul real s poat fi afiat ntr-un format n
care partea ntreag este separat de partea fracionar prin virgul.
DA

Numrul se citete n variabila nr. n irul nr1 se convertete cu funcia ecvt() valoarea
numeric nr, iar n irul nr2 se obine valoarea numeric prelucrat prin adugarea
semnului minus (dac numrul este negativ), inserarea virgulei ntre partea ntreag i
partea fracionar i eliminarea zerourilor nesemnificative din partea zecimal a numrului.
DI

#include <iostream.h>
#include <string.h>
#include <stdlib.h>
RA

void main()
{char nr1[20],nr2[20]="",*q; double nr; int p,s;
cout<<"numarul "; cin>>nr; strcpy(nr1,ecvt(nr,20,&p,&s));
if (s) strcat(nr2,"-"); // se adaug semnul - dac este cazul
ITU

strncat(nr2,nr1,p); //se concateneaz partea ntreag


strcat(nr2,","); //se concateneaz virgula
q=strchr(nr1+p,'0'); //se caut poziia primului 0 din partea zecimal
strncat(nr2,nr1+p,q-nr1-p); //se concateneaz din partea
cout<<nr2;} //zecimal numai cifrele semnificative
ED

178 Implementarea structurilor de date
Se citesc dou iruri de caractere care conin dou numere

IC
Tem reprezentate n baza 20. Afiai diferena celor dou numere, n: a)
baza 20; b) baza 10.

OG
Rspundei:
1. Ce se va afia n urma execuiei urmtoarei secvene de program:

G
char sir[20]="0123456789",aux[20],sb[3]="ab",*p; int n=4;
p=&sir[n-1]; strcpy(aux,p); strcpy(p+strlen(sb),aux);

DA
strncpy(p,sb,strlen(sb)); cout<<sir;
Ce operaie se execut prin aceast secven de program?
2. Ce se va afia n urma execuiei urmtoarei secvene de program:

PE
char sir[20]="calculator"; cout<<strchr(sir,'l')-sir;
3. Ce se va afia n urma execuiei urmtoarei secvene de program:
char *sir="alfabet",p=sir; p+=2; cout<<p;
4. Ce se va afia n urma execuiei urmtoarei secvene de program:
I
char s1[20]="calculator",s2[10]="lat",*p; p=strstr(s1,s2); cout<<p;
5. Ce se va afia n urma execuiei urmtoarei secvene de program:
char s1[10]="alfa",s2[5]="ALFA";

if(s1==strlwr(s2)) cout<<"siruri egale"; else cout<<"siruri inegale";


6. Ce se va afia n urma execuiei urmtoarei secvene de program:
IC

char sir[20]="12alfa34beta56",*p;
for(p=sir;*p>='0' && *p<=9 && *p; p++); cout<<p;
7. Ce se va afia n urma execuiei urmtoarei secvene de program:
CT

char sir[2][10]={"alfa","beta"};
if(sir[0]<sir[1]) cout<<sir[0]; else cout<<sir[1];
8. Se declar irurile char s1[5],s2[5];. Ce se va afia n urma execuiei urm-
DA

toarei secvene de program, dac irul s1 are valoarea "125", iar irul s2 valoarea
"75". Dar dac irul s1 are valoarea "201", iar irul s2 valoarea "21":
if(strcmp(s1,s2)) cout<<atoi(s1); else cout<<atoi(s2);
9. Ce se va afia n urma execuiei urmtoarei secvene de program:
DI

char *sir[5]={"abcd","defgh","123","ab123",NULL},*p=&sir[0][0];
cout<<*sir[0]<<" "<<*sir[0]++<<" "<<(*sir[0])++<<endl;
cout<<*sir[1]<<" "<<*sir[1]++<<" "<<(*sir[1])++<<endl;
RA

cout<<*sir[2]<<" "<<*sir[2]++<<" "<<(*sir[2])++ <<endl;


cout<<sir[1]<<" "<<sir[2][1]<<" "<<*(p+1)<<" "<<*(p+15);
10. Analizai interfaa procesorului de texte Word. Identificai operaiile specifice pentru prelu-
crarea textelor care au fost rezolvate n acest capitol.
ITU

Adevrat sau Fals:


1. Dac irul s1 este irul vid, instruciunea strcat(s1,s2); este echivalent cu
instruciunea strcpy(s1,s2);.
ED

Informatic 179
2. Dac irul s1 este irul vid, instruciunea strncat(s1,s2,n); este echivalent cu

IC
instruciunea strncpy(s1,s2,n);.
3. Urmtoarea secven de program elimin ultimul spaiu din irul s:

OG
char s[100],*p=s;
while (*p!=' ' && *p) p++;
while (p) strcpy(s,p);
4. Urmtoarea secven de program afieaz "diferite" numai dac irul s1 este diferit
de irul s2 i irul s2 este diferit de irul s3:

G
char s1[10],s2[10],s3[10];
if (strcmp(s1,s2) && strcmp(s2,s3)) cout<<"diferite";

DA
5. Urmtoarea secven de program afieaz portocala:
char sir[]="ala bala portocala",*p=sir;
strcpy(p,strchr(sir,' '));

PE
while (*p){strcpy(sir,p+1); strcpy(p,strchr(sir,' '));}; cout<<sir;

Alegei:
1. Care este declaraia corect pentru un ir de caractere:
a. char *sir; b. char sir[20];
I
c. char *sir[20]; d. char sir[];
2. Care este declaraia corect pentru un ir de caractere care conine cuvntul
"alfabet":

a. char sir[7]="alfabet; b. char sir[10]="alfabet;


c. char sir[]="alfabet; d. char sir[8]="alfabet;
IC

3. Care este declaraia corect pentru un vector care conine 3 iruri de caractere:
a. char sir[3][2]={"ab","12"};
b. char sir[3][3]= {"ab","12"};
CT

c. char sir[3][2]= {"ab","12",NULL};


d. char sir[][3]= {"ab","12",NULL};
4. Funcia prin care inversai caracterele dintr-un ir este:
a. strtok(); b. strpbrk(); c. strfrx(); d. strrev()
DA

5. Care va fi lungimea irului s dup execuia instruciunii:


for(i=0;(char)s[i]<='Z';i++) s[i]=i+65;:
a. 26 b. 25 c. 27; d. necunoscut
DI

6. Care dintre urmtoarele funcii nu face parte din acelai fiier antet:
a. strtod(); b. ecvt() c. strspn(); d. ltoa()
7. Care dintre urmtoarele secvene de instruciuni afieaz toate apariiile disjuncte ale
subirului sb n irul sir, variabila p fiind de tip pointer ctre tipul char i fiind
RA

iniializat cu valoarea sir:


a. while (p) b. while (p)
{p=strstr(sir,sb); {if (p) cout<<p-sir;
ITU

if (p) cout<<p-sir+1; strcpy(sir,p);


strcpy(sir,p);} p=strstr(sir,sb);}
c. while (p) d. while (p)
{p=strstr(p+1,sb); {cout<<p-sir+1;
if (p) cout<<p-sir+1;} p=strstr(p+1,sb);}
ED

180 Implementarea structurilor de date
Miniproiecte:

IC
Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:
a. trei variante de programe (folosind cele trei metode de prelucrare a irurilor de

OG
caractere); n cazul n care nu folosii funcia de sistem, implementarea se va
face cu ajutorul subprogramelor;
b. alte dou exemple de probleme n care se vor folosi subprograme create pentru
rezolvarea problemei iniiale;
c. un subprogram care s simuleze una dintre operaiile realizate de un procesor de

G
texte care se vor identifica n aplicaia Word. (Exemple: deschiderea fiierului text,
salvarea modificrilor n fiier, cutarea i nlocuirea unui ir de caractere, numrarea

DA
unor entiti din text caractere, cuvinte, propoziii, linii de text etc. , transformarea
literei de la nceputul cuvntului n liter mare etc.)
1. Se introduc de la tastatur un cuvnt i un text. Se consider c separarea cuvintelor
n text se face prin cel puin un spaiu. S se tearg un cuvnt precizat din text,

PE
astfel: a) numai prima apariie a cuvntului; b) toate apariiile cuvntului.
2. Se citesc dou cuvinte de la tastatur. S se verifice dac ele au acelai prefix i/sau
acelai sufix. n caz afirmativ, s se afieze prefixul i/sau sufixul. De exemplu,
cuvintele vara i seara au sufixul ara, cuvintele incet i inca au prefixul inc, iar
I
cuvintele derutat i decodat au prefixul de i sufixul at.
3. Se citesc dou cuvinte de la tastatur. S se verifice dac ele sunt anagrame (conin
aceleai litere). Nu se va ine cont de diferena dintre literele mari i literele mici. De

exemplu, cuvintele arta i tara sunt anagrame.


4. Se introduc de la tastatur dou cuvinte i un text. Se consider c separarea
IC

cuvintelor n text se face prin cel puin un spaiu. S se nlocuiasc n text primul
cuvnt cu al doilea cuvnt, astfel:
a) numai prima apariie a cuvntului; b) toate apariiile cuvntului.
CT

5. Se citete de la tastatur un text care conine mai multe propoziii. Propoziiile se


consider separate prin: .,! sau ?. Numrai cte propoziii conine textul i afiai:
a) propoziia cu cele mai puine caractere; b) propoziia cu cele mai multe caractere;
c) propoziia cu cele mai puine cuvinte; d) propoziia cu cele mai multe cuvinte.
DA

6. Se citete de la tastatur un numr natural n i apoi se introduce un text, n care


separarea cuvintelor se face prin cel puin un spaiu. S se numere cuvintele care
conin n caractere. S se afieze numrul de ordine al acestor cuvinte n text (primul
cuvnt sau al cincilea cuvnt etc.).
DI

7. Se introduce de la tastatur un text n care separarea cuvintelor se face prin cel puin
un spaiu. S se afieze cuvntul cel mai scurt i cuvntul cel mai lung precum i
numerele de ordine ale acestor cuvinte.
RA

8. Se introduce un text de la tastatur. S se afieze numrul de vocale i numrul de


consoane din text. Analiza se va face fr s se in cont de diferena dintre literele
mari i literele mici.
9. Se introduce un text de la tastatur. S se afieze numrul de litere din text, numrul
ITU

de cifre i numrul de caractere speciale. Analiza se va face fr s se in cont de


diferena dintre literele mari i literele mici.
10. Se introduce de la tastatur un text n care separarea cuvintelor se face prin cel puin
un spaiu. S se afieze cuvintele care conin o singur consoan, i n rest numai
vocale (de exemplu: apa, oaza, roua etc.).
ED

Informatic 181

IC
2.4. nregistrarea

OG
Pentru prelucrri mai complexe, este nevoie s grupai informaii corelate n colecii de
date numite structuri de date. Ai studiat deja o structur de date: tabloul de memorie.
Acesta permite s grupai mai multe date de acelai tip i s le manipulai ca pe o singur
variabil de memorie.
Pentru a caracteriza un obiect (persoan, fenomen, proces etc.) este necesar o

G
mulime de proprieti pe care o vom numi list de atribute. Lista de atribute definete o
ntreag clas de obiecte. Fiecare obiect din aceast clas de obiecte poate fi apoi

DA
descris prin atribuirea de valori atributelor.

PE
Scop: exemplificarea modului n care putei caracteriza un obiect folosind o list de atribute.
Enunul problemei: S se caracterizeze situaia colar a unui elev dintr-o clas, la o
anumit disciplin, ntr-un semestru.
Obiectul este situaia colar a unui elev la o anumit disciplin. Pentru a caracteriza
acest obiect, sunt necesare urmtoarele atribute: numele i prenumele elevului, notele la
I
acea disciplin i media. Aadar, colecia de atribute caracterizeaz situaia oricrui elev
dintr-o clas, i va defini, la rndul ei, o clas de obiecte. Pentru a descrie situaia colar
a unui anumit elev, trebuie atribuite valori acestor atribute.

Pentru a reprezenta n calculator valorile atributelor pentru aceast list, se pot folosi mai
multe variabile de memorie independente, cu urmtoarele tipuri de date: iruri de
IC

caractere de lungime 20 (pentru nume i prenume), numere ntregi cu valori ntre 1 i 10


(pentru note) i numere reale (pentru medie).
CT

Dac trebuie pstrate informaii despre toi elevii unei clase (spre exemplu, clasa are 25
de elevi), se va alege o structur de date de tip vector (cu 25 de elemente) n care fiecare
element trebuie s conin setul de date (nume, prenume, note i media) care se refer
la un elev, deci care descrie comportamentul unui elev.
DA

Elevul nume prenume nota 1 nota 2 nota 3 media


1 Blaa Ana 9 10 9 9.33
2 Dinu Mihai 10 9 - 9.50
DI


Acest set de date nu este format din date omogene i, prin urmare, nu poate fi reprezentat
printr-o structur de date de tip matrice, n care o linie s conin lista de atribute ale unui
elev, iar o coloan s corespund unui atribut. n acest caz, ar trebui create mai multe
RA

structuri de date de tip tablou de memorie: o structur de date de tip matrice cu elemente
de tip ir de caractere cu lungimea de 20, care conine 25 de linii (cte una pentru fiecare
elev) i dou coloane (una pentru nume i alta pentru prenume), o structur de date de tip
matrice cu elemente de tip unsigned int, care conine 25 de linii (cte una pentru fiecare
ITU

elev) i trei coloane (cte una pentru fiecare not, presupunnd c elevul poate primi
maxim 3 note dac a primit, de exemplu, numai dou note, acestea se vor scrie n
primele dou coloane, iar urmtoarea se va completa cu 0), i un vector cu 25 de elemente
de tip real, pentru medii. n timpul prelucrrii, un elev se va identifica prin numrul de ordine
ED

i, care reprezint numrul liniei n cele dou matrice i numrul elementului n vector.

182 Implementarea structurilor de date
Acest model de reprezentare este foarte greoi din punct de vedere al algoritmilor

IC
de prelucrare. n acest caz, se poate folosi structura de date de tip nregistrare:

nregistrarea este structura de date format dintr-un ansamblu de date neomogene

OG
(date elementare sau structuri de date) ntre care exist o legtur de coninut.
Elementele structurii se numesc cmpuri i pot fi identificate dup un nume.
Folosind o nregistrare, se pot pstra informaii legate ntre ele din punct de vedere al

G
coninutului, care sunt memorate n variabile de memorie de tipuri diferite. Legtura de
coninut sau legtura logic se refer la faptul c, pentru a obine informaii despre obiect,
ntreaga colecie de date trebuie prelucrat mpreun. Fiecare descriere a listei de

DA
atribute specifice unui elev va putea fi reprezentat cu ajutorul unei nregistrri ce conine
cmpurile: nume, prenume, note (trei cmpuri) i media, iar reprezentarea anterioar a
elevilor dintr-o clas va putea fi nlocuit cu o structur de date de tip vector cu 25 de
elemente, ale crui elemente sunt de tip nregistrare.

PE
Cmpul este reprezentarea unui
colecia de cmpuri

Nume Numele cmpului


nregistrarea =

atribut din lista de atribute care este Pren


descriu obiectul. El conine o da- Popescu
t (elementar sau o structur de Tipul cmpului este
I
date) care are legtur logic cu Pren ir de caractere
datele din celelalte cmpuri ale
nregistrrii, cu care formeaz Ana
Valoarea cmpu-
mpreun o entitate de informa-

lui este "Ana"


ie. Fiecare cmp se identific n Cmpul
list printr-un nume. Cmpul este
IC

caracterizat de tipul datei i valoarea datei. De exemplu, n vectorul clasa, numele elevului
este un cmp, prenumele alt cmp, notele alte trei cmpuri, iar media alt cmp. Fiecare cmp
CT

este caracterizat, ca i data, prin nume, tip i valoare. Accesul la elementele structurii se face
prin numele cmpului. Numele cmpurilor pot s apar ntr-o expresie ca operanzi, la fel ca i
numele datelor elementare, tipul operandului fiind determinat de tipul cmpului.
nregistrarea, ca entitate prelucrat de calculator, se identific printr-un nume. De exemplu,
DA

nregistrarea care conine informaii despre elev se poate identifica prin numele elev. Cm-
purile care compun nregistrarea sunt i ele identificate prin nume: nume (numele), pren
(prenumele), nota1, nota2, nota3 (notele) i media (media).
numele nregistrrii elev
DI

numele cmpului nume pren nota1 nota2 nota3 media


tipul cmpului ir de caractere ir de caractere ntreg ntreg ntreg real
pozitiv pozitiv pozitiv
RA

valoarea Blaa Ana 9 10 9 9.33


Identificarea unui cmp al unei nregistrri se va face folosind att numele cmpului, ct i
numele nregistrrii. De exemplu, pentru a identifica cmpul nume din nregistrarea elev
trebuie precizat att numele nregistrrii elev, ct i numele cmpului nume. Prin
ITU

identificatorul elev se va identifica ntreaga nregistrare (ntreg ansamblul de cmpuri).


n clasificarea structurilor de date, nregistrarea poate fi privit ca:
 o structur de date neomogen (elementele sale pot fi de tipuri diferite);
 o structur de date intern (utilizat ca variabil de memorie independent sau ca o com-
ED

ponent a unui tablou de memorie);



Informatic 183
 o structur de date temporar;

IC
 o structur de date cu acces direct (este permis accesul direct la un cmp);
 o structur de date static (la compilare, i se aloc un anumit spaiu de memorie co-
respunztor sumei lungimii tuturor cmpurilor, spaiu care nu mai poate fi modificat n

OG
timpul executrii programului).
Implementarea unei nregistrri se face:
 Din punct de vedere logic. nregistrarea este o structur de date neomogen, cu
elemente care pot fi de tipuri diferite. Localizarea unui element n cadrul structurii se

G
face printr-un nume.
 Din punct de vedere fizic. nregistrrii i se aloc o zon de memorie contigu, de

DA
dimensiune fix, egal cu suma lungimii tuturor cmpurilor. Dimensiunea alocat unui
cmp este determinat de tipul datei memorate n cmp. Localizarea unui cmp se
face prin calcularea adresei cmpului fa de un element de referin (adresa la care
este memorat nregistrarea), innd cont de dimensiunea cmpurilor precedente.

PE
La fel ca i tabloul de memorie, nregistrarea este o structur de date secvenial sau
liniar (componentele structurii sunt aezate n locaii succesive de memorie).
Aadar, nregistrarea este o zon continu de memorie intern creia i se atribuie
un nume i care permite memorarea mai multor date de tipuri diferite. Aceste date
I
pot fi tratate ca un tot unitar sau ca date elementare independente.
structura de date secvenial grupeaz date corelate, care
sunt aezate n locaii succesive n memorie

Tabloul de memorie nregistrarea


IC

grupeaz date omogene grupeaz date neomogene


CT

identificarea unei componente a identificarea unei componente a


structurii se face cu un indice structurii se face dup numele
DA

(poziia componentei n structur) componentei

2.4.1. Implementarea nregistrrii n limbajul C++


DI

2.4.1.1. Declararea variabilei de tip nregistrare


n limbajul C++, pentru a putea crea i manipula o structur de date de tip nregistrare,
trebuie s definii un tip de dat numit structur.
RA

Structura este un tip de dat definit de utilizator care reunete un grup de


variabile, sub acelai nume.
ITU

Forma general a instruciunii prin care putei defini structura este:


struct <nume_structur>
{<tip dat 1> <nume 11>, <nume 12>, ..., <nume 1n>;
<tip dat 2> <nume 21>, <nume 22>, ..., <nume 2n>;
.................................................
ED

<tip dat m> <nume m1>, <nume m2>, ..., <nume mn>; };

184 Implementarea structurilor de date
unde <nume structur> este numele tipului de dat care reunete mai multe variabile

IC
de memorie de tipul <tip dat i>, identificate prin <nume i1>, <nume i2>, ..., <nume
in>. Numele structurii este opional. Variabilele definite n structur se numesc membrii
structurii i corespund cmpurilor nregistrrii. Tipul <tip dat i> poate fi:

OG
 un tip de baz (de exemplu, int, float, char etc.),
 un tip utilizator definit anterior (cu declaraia typedef sau struct ) sau
 un tip utilizator definit chiar n cadrul structurii (tipul tablou de memorie sau tipul
nregistrare).

G
Observaii:
1. Declararea unei structuri se termin cu caracterul ; deoarece este o instruciune.

DA
2. Printr-o instruciune de declarare a unei structuri nu se creeaz o variabil de
memorie, ci un tip de dat utilizator (tipul de dat structurat, sau nregistrare). Pentru
a folosi n program o variabil de memorie de acest tip, ea trebuie declarat:

PE
<nume structur> <nume variabil>;
Pentru a putea manipula o structur de date de tip nregistrare, trebuie s definii:
1. un tip de dat structur prin care descriei colecia de cmpuri ale nregistrrii
(numele i tipul lor) i
2. o variabil de memorie care va avea ca tip de dat numele structurii.
I
Se pot folosi urmtoarele trei variante de declarare a tipului nregistrare i a variabilei de
acest tip:
Varianta 1

struct <nume structur> {<descriere cmpuri nregistrare>};


IC

<nume_structur> <nume variabil>;


Varianta 2
struct <nume_structur>
CT

{<descriere cmpuri nregistrare>} <nume variabil>;


Varianta 3
struct {<descriere cmpuri nregistrare>} <nume variabil>;
DA

Observaie:
n cea de a treia variant, nu s-a atribuit un nume structurii definite. Aceasta nseamn c
nu vei putea s definii ulterior o alt variabil de memorie cu acest tip.
DI

Exemplul 1 Pentru a utiliza o nregistrare n care s memorai datele referitoare la o


persoan (numele, prenumele, adresa, localitatea, judeul i codul potal) vei crea mai nti
un tip de dat structur cu numele adresa i apoi o variabil de memorie adr_pers care
va avea tipul adresa.
RA

struct adresa
{char nume[20], pren[20], adr[40], loc[20], jud[20];
unsigned long cod_p;};
ITU

adresa adr pers;


sau
struct adresa
{char nume[20], pren[20], adr[40], loc[20], jud[20];
unsigned long cod p;} adr pers;
ED

sau

Informatic 185
struct

IC
{char nume[20], pren[20], adr[40], loc[20], jud[20];
unsigned long cod p;} adr pers;
Compilatorul va rezerva variabilei de memorie adr_pers 124 de octei.

OG
nume pren adr loc jud cod_p

20 20 40 20 20 4
octei octei octei octei octei octei

G
124 octei
adr_pers

DA
Exemplul 2 Pentru a utiliza nregistrri n care s memorai coordonatele unui punct
din plan (x i y), vei crea mai nti un tip de dat structur cu numele punct i apoi dou
variabile de memorie, pt1 i pt2, care vor avea tipul punct.

PE
struct punct {int x,y;};
punct pt1,pt2;
sau
struct punct {int x,y;} pt1,pt2;
Compilatorul va rezerva pentru fiecare variabil de memorie de tip punct (pt1 i pt2)
I
cte 4 octei.
x y x y

2 2 2 2
octei octei octei octei
IC

4 octei 4 octei
pt1 pt2
CT

Observaie:
Chiar dac exist dou cmpuri cu acelai nume, cmpurile x, respectiv cmpurile y, ele
nu pot fi confundate deoarece unul aparine nregistrrii pt1, iar cellalt nregistrrii pt2.
DA

Creai o nregistrare care s descrie obiectul triunghi (lista de atribute ale


Tem acestui obiect) i o nregistrare care s descrie obiectul dat calendaris-
tic.
La fel ca i tabloul de memorie, o structur de date de tip nregistrare
DI

Atenie poate fi iniializat la declararea ei, atribuindu-se valori cmpurilor:


struct punct {int x,y;};
punct a={3,4},b={2,5};
RA

S-au definit dou nregistrri de tip punct: a, care are coordonatele x=3 i y=4, respectiv
b, care are coordonatele x=2 i y=5.

2.4.1.2. Accesul la cmpurile nregistrrii


ITU

Pentru prelucrarea datelor dintr-o nregistrare trebuie s avei acces la fiecare cmp al nre-
gistrrii. Pentru a avea acces la un cmp al nregistrrii se folosete operatorul punct (.):
<nume_variabil_nregistrare>.<nume_cmp>
ED

186 Implementarea structurilor de date
Operatorul punct este operatorul de selecie a membrului unei

IC
Atenie structuri i leag numele structurii de numele membrului, adic, n
expresia a.b a trebuie s fie de tip structur, iar b trebuie s fie
de tip membru al acelei structuri. Rezultatul furnizat de expresie este valoarea membrului

OG
selectat. Punctul este un operator binar i are prioritate maxim.
Exemplu Valorile cmpurilor din nregistrarea adr_pers se pot stabili prin atribuirea
unor constante:

G
strcpy(adr_pers.nume,"Popescu"); strcpy(adr_pers.pren,"Vlad");
strcpy(adr_pers.adr,"Str. Rozelor nr. 5");
strcpy(adr_pers.loc,"Eforie Sud"); strcpy(adr_pers.jud,"Constanta");

DA
adr pers.cod_p=123456;
sau prin citirea de la tastatur:
cout<<"Numele "; cin.get(adr pers.nume,20); cin.get();

PE
cout<<"Prenumele "; cin.get(adr pers.pren,20); cin.get();
cout<<"Adresa "; cin.get(adr pers.adr,40); cin.get();
cout<<"Localitatea "; cin.get(adr pers.loc,20); cin.get();
cout<<"Judetul "; cin.get(adr pers.jud,20); cin.get();
cout<<"Codul postal "; cin>>adr pers.cod p;
I
Prin referirea:
<nume_variabil_nregistrare>
se identific ntreaga nregistrare (toate cmpurile nregistrrii).

Observaie. Unei nregistrri (o variabil de memorie de tip structur) i se poate atribui


IC

valoarea unei alte nregistrri de acelai tip.


Exemplu:
struct punct {int x, y;};
CT

punct a,b; a.x=10; a.y=20; b=a;


cout<<b.x<<" "<<b.y; //afieaz 10 20
Observaie. Tipul parametrului unui subprogram poate fi de tip nregistrare deoarece
DA

este un tip definit de utilizator. Condiia este ca tipul nregistrare s fie definit ca variabil
gobal (tipul de dat utilizator trebuie definit naintea subprogramului).
Exemplu:
struct punct {int x, y;};
DI

void afiseaza(punct a) {cout<<a.x<<" "<<a.y;}


void main() {punct a={3,4}; afiseaza(a);}
RA

Scop: exemplificarea modului n care putei folosi structura de date de tip nregistrare
pentru a prelucra datele.
Enunul problemei 1: Se citesc de la tastatur coordonatele a dou puncte din plan a
ITU

i b. S se afieze distana dintre cele dou puncte.


#include <iostream.h>
#include <math.h>
void main()
ED

{struct punct {int x,y;};



Informatic 187
punct a,b;

IC
cout<<"coordonatele punctului a - x: "; cin>>a.x;
cout<<" - y: "; cin>>a.y;
cout<<"coordonatele punctului b - x: "; cin>>b.x;

OG
cout<<" - y: "; cin>>b.y;
cout<<"distanta dintre punctele a si b este ";
cout<<sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)); }
Enunul problemei 2: Se citesc de la tastatur numrtorul i numitorul a dou fracii. S

G
se calculeze suma i produsul celor dou fracii, s se simplifice rezultatele obinute i
apoi s se afieze.

DA
n variabilele f1 i f2 se memoreaz cele dou fracii, n variabila s se calculeaz suma
lor, iar n variabila p se calculeaz produsul lor. Pentru a simplifica fraciile sum i pro-
dus trebuie calculat, pentru fiecare fracie, cel mai mic divizor comun dintre numrtor i
numitor. Pentru calculul lui se folosete funcia cmmdc(). Pentru calculul sumei celor

PE
dou fracii se folosete funcia suma(), iar pentru produsul lor funcia produs().
#include <iostream.h>
struct fractie {int x,y;};
int cmmdc (int a,int b)
I
{while (a!=b) if (a>b) a-=b; else b-=a; return a;}
fractie suma(fractie f1, fractie f2)
{fractie s; int a;
s.x=f1.x*f2.y+f1.y*f2.x; s.y=f1.y*f2.y; a=cmmdc(s.x,s.y); s.x/=a; s.y/=a;

return s;}
IC

fractie produs(fractie f1, fractie f2)


{fractie p; int a;
p.x=f1.x*f2.x; p.y=f1.y*f2.y; a=cmmdc(p.x,p.y); p.x/=a; p.y/=a;
CT

return p;}
void main()
{fractie f1,f2,s,p;
cout<<"prima fractie - numaratorul: "; cin>>f1.x;
DA

cout<<" - numitor: "; cin>>f1.y;


cout<<"a doua fractie - numaratorul: "; cin>>f2.x;
cout<<" - numitor: "; cin>>f2.y;
s=suma(f1,f2); cout<<"suma este "<<s.x<<"/"<<s.y<<endl;
DI

p=produs(f1,f2); cout<<"produsul este "<<p.x<<"/"<<p.y<<endl;}

Se citesc de la tastatur numrtorul i numitorul a dou fracii. S se


Tem compare cele dou fracii i s se afieze fracia care este mai mare.
RA

2.4.2. nregistrri imbricate


ITU

n unele cazuri, unul dintre cmpurile nregistrrii poate s fie i el, la rndul lui, de tip
nregistrare.
Exemplul 1 S considerm o nregistrare care trebuie s conin urmtoarele informaii
despre o persoan: numele, prenumele, data naterii i vrsta. nregistrarea va avea
urmtoarea structur de cmpuri: nume, pren, data_n i varsta. Unul dintre cmpurile
ED

188 Implementarea structurilor de date
nregistrrii (data_n folosit pentru data

IC
naterii) este i el tot de tip nregis- nume pren data_n varsta
trare. n acest caz, trebuie definite
dou nregistrri: una pentru atributele

OG
zi luna an
persoanei i alta pentru atributele datei
de natere. Putei folosi una dintre urmtoarele variante:
Varianta 1 Tipul de dat nregistrare data se declar naintea structurii care
caracterizeaz persoana i care conine cmpul data_n, care este de tipul data:

G
struct data {unsigned zi, luna, an;};
struct persoana

DA
{char nume[20], pren[20];
data data n;
unsigned varsta;};
persoana pers;

PE
Pentru a ne referi la ziua de natere a unei persoane, se va folosi identificatorul:
pers.data n.zi
Varianta 2 Tipul cmpului data_n se declar n structura care caracterizeaz
persoana:
struct persoana
I
{char nume[20], pren[20];
struct {unsigned zi, luna, an;} data n;
unsigned varsta;};

persoana pers;
Pentru a ne referi la ziua de natere a unei persoane, se va folosi identificatorul:
IC

pers.data n.zi
Exemplul 2 S considerm o nregistrare care trebuie s conin urmtoarele informaii
despre o persoan: numele, prenumele, data naterii, data angajrii i salariul. nregistra-
CT

rea va avea urmtoarea structur de cmpuri: nume, pren, data_n, data_a i salariu.
Dou dintre cmpurile nregistrrii (data_n folosit pentru data naterii i data_a folosit pentru
data angajrii) sunt tot de tip nregistrare. n acest caz trebuie definite dou nregistrri: una
DA

pentru atributele persoanei i alta pentru atributele unei date calendaristice care s fie folosit
pentru data naterii i pentru data angajrii. Putei folosi una dintre urmtoarele variante:
nume pren data_n data_a salari
DI

zi luna an zi luna an
Varianta 1 Tipul de dat nregistrare data se declar naintea structurii care
RA

caracterizeaz persoana i care conine cmpul data_n care este de tipul data:
struct data {unsigned zi, luna, an;};
struct persoana
{char nume[20], pren[20];
ITU

data data n, data a;


unsigned long salariu;};
persoana pers;
Pentru a calcula diferena dintre anul angajrii i anul naterii persoanei respective, se va
calcula expresia:
ED

pers.data a.an - pers.data n.an



Informatic 189
Varianta 2 Tipul cmpurilor data_n i data_a se declar n structura care caracterizeaz

IC
persoana:
struct persoana
{char nume[20], pren[20];

OG
struct {unsigned zi, luna, an;} data n, data a;
unsigned varsta;};
persoana pers;
Pentru a calcula diferena dintre anul angajrii i anul naterii persoanei respective, se va

G
calcula expresia:
pers.data a.an - pers.data n.an

DA
Observaie: Dac o structur de date conine n interiorul su una sau mai multe struc-
turi, se spune c acele structuri sunt imbricate. Pentru a identifica un cmp aflat n
interiorul unor astfel de structuri imbricate, se construiete identificatorul pornind din
exterior ctre interior, pn se ajunge la cmp. Astfel, presupunnd c structura S1

PE
conine structura S2, care conine structura S3, i aa mai departe, pn la structura Sn,
iar v1, v2, v3, ..., vn sunt variabile care au tipul de dat al acestor structuri, identificarea
cmpului cmp definit n structura Sn se va face cu expresia:
<v1>.<v2>.<v3>. ... . <vn>.<cmp>
I
Asociativitatea operatorului de selecie a membrului unei
Atenie structuri este de la stnga la dreapta, pentru c n final trebuie
obinut adresa membrului a crui valoare trebuie furnizat. De
aceea este foarte important ordinea n care sunt scrise structurile n expresie.

Creai o nregistrare care s conin urmtoarele informaii despre o per-


IC

Tem soan: numele, prenumele, adresa, locaia domiciliului, locaia naterii,


data naterii i numrul de telefon. nregistrarea va avea urmtoarea
structur de cmpuri: nume, pren, adresa, loc_d, loc_n, data_n i telefon. Cmpul
CT

data_n este de tip nregistrare, ca n exemplul precedent. Cmpul adresa este de tip
nregistrare i conine urmtoarele informaii: strada, numrul, blocul, scara, etajul i
apartamentul. Cmpurile loc_d i loc_n sunt de tip nregistrare i conin urmtoarele
informaii: oraul i judeul. Cmpul telefon este de tip nregistrare i conine urmtoarele
DA

informaii: numrul telefonului fix i numrul telefonului mobil.


DI

Scop: exemplificarea modului n care putei folosi structuri imbricate.


Enunul problemei 1: Se citesc de la tastatur coordonatele a dou coluri ale unui drept-
unghi: colul din stnga sus i colul din dreapta jos. S se calculeze diagonala dreptunghiului.
Dreptunghiul este caracterizat de dou atribute: colul din stnga sus i colul din dreapta
RA

jos (cmpurile st_s i dr_j). Fiecare dintre aceste atribute este caracterizat la rndul su
de dou atribute: coordonatele punctului fa de abscis i ordonat (cmpurile x i y):
st_s dr_j
ITU

x y x y

#include <iostream.h>
ED

#include <math.h>

190 Implementarea structurilor de date
void main()

IC
{struct punct {int x,y;};
struct dreptunghi {punct st s,dr j;} drpt;
cout<<"coordonate colt stanga sus - x: "; cin>>drpt.st s.x;

OG
cout<<" - y: "; cin>>drpt.st s.y;
cout<<"coordonate colt dreapta jos - x: "; cin>>drpt.dr j.x;
cout<<" - y: "; cin>>drpt.dr j.y;;
cout<<"diagonala dreptunghiului este ";

G
cout<<sqrt(pow(drpt.st s.x-drpt.dr j.x,2)+
pow(drpt.st s.y-drpt.dr j.y,2));}

DA
Descrierea datelor prelucrate n program se mai poate face i n varianta urmtoare:
struct dreptunghi
{struct {int x,y;} st s,dr j;};
dreptunghi drpt;

PE
nregistrrii care caracterizeaz dreptunghiul i se poate aduga un nou atribut: diagonala
dreptunghiului:
struct dreptunghi
{struct {int x,y;} st s,dr j;
I
unsigned diag;};
dreptunghi drpt;
calculul mrimii diagonalei dreptunghiului fcndu-se astfel:

drpt.diag = sqrt(pow(drpt.st s.x-drpt.dr j.x,2)+


pow(drpt.st s.y-drpt.dr j.y,2));}
IC

Enunul problemei 2: Se citesc de la tastatur coordonatele a dou segmente care


reprezint laturile unui dreptunghi (limea i lungimea). S i se calculeze diagonala.
CT

lat lung

pt1 pt2 pt1 pt2


DA

x y x y x y x y

Dreptunghiul este caracterizat de dou atribute: segmentul de pe lime i segmentul de


DI

pe lungime (cmpurile lat i lung). Fiecare dintre aceste atribute (segmentele) este
caracterizat la rndul su de dou atribute: punctele de la extremitatea segmentului (pt1
i pt2). Fiecare dintre aceste atribute (punctele) este caracterizat la rndul su de dou
atribute: coordonatele punctului fa de abscis i ordonat (cmpurile x i y).
RA

#include <iostream.h>
#include <math.h>
void main()
{struct punct {int x,y;};
ITU

struct segment {punct pt1,pt2;};


struct dreptunghi {segment lat,lung;};
dreptunghi d; float l1,l2;
cout<<"Latimea - punct 1 - x = "; cin>>d.lat.pt1.x;
ED

cout<<" - y = "; cin>>d.lat.pt1.y;



Informatic 191
cout<<" - punct 2 - x = "; cin>>d.lat.pt2.x;

IC
cout<<" - y = "; cin>>d.lat.pt2.y;
cout<<"Lungimea - punct 1 - x = "; cin>>d.lung.pt1.x;
cout<<" - y = "; cin>>d.lung.pt1.y;

OG
cout<<" - punct 2 - x = "; cin>>d.lung.pt2.x;
cout<<" - y = "; cin>>d.lung.pt2.y;
l1=sqrt(pow(d.lat.pt1.x-d.lat.pt2.x,2)+
pow(d.lat.pt1.y-d.lat.pt2.y,2));

G
l2=sqrt(pow(d.lung.pt1.x-d.lung.pt2.x,2)+
pow(d.lung.pt1.y-d.lung.pt2.y,2));

DA
cout<<sqrt(pow(l1,2)+ pow(l2,2));}
Descrierea datelor prelucrate n program se mai poate face i n varianta urmtoare:
struct dreptunghi
{struct segment

PE
{struct punct {int x,y;} pt1,pt2;} lat,lung;};
dreptunghi d;
nregistrrii care caracterizeaz dreptunghiul i se poate aduga un nou atribut: diagonala
dreptunghiului:
I
struct dreptunghi
{struct segment
{struct punct {int x,y;} pt1,pt2;} lat,lung;
unsigned diag;};

dreptunghi d;
sau
IC

struct dreptunghi
{struct {struct {int x,y;} pt1,pt2;} lat,lung;
unsigned diag;};
CT

dreptunghi d;
calculul mrimii diagonalei dreptunghiului fcndu-se astfel:
d.diag = sqrt(pow(sqrt(pow(d.lat.pt1.x-d.lat.pt2.x,2)+
DA

pow(d.lat.pt1.y-d.lat.pt2.y,2)),2)+
pow(sqrt(pow(d.lung.pt1.x-d.lung.pt2.x,2)+
pow(d.lung.pt1.y-d.lung.pt2.y,2)),2));}
1. Se citesc de la tastatur dou intervale de timp exprimate n ore,
DI

Tem minute i secunde. S se calculeze i s se afieze suma celor


dou intervale de timp.
2. Se citete de la tastatur o dat calendaristic exprimat n zi, lun i an. Se mai
RA

citete i un numr n. S se afieze data care va fi peste n zile. (Indicaie: se va folosi


un vector cu 12 elemente n care se va memora n fiecare element numrul de zile din
luna corespunztoare poziiei din vector, prima lun fiind ianuarie.)
3. Se citesc de la tastatur dou date calendaristice. S se afieze care dat este mai
ITU

recent i diferena n zile dintre cele dou date.


4. ntr-o nregistrare, se pstreaz atributele unui triunghi, care sunt cele 3 segmente ce
reprezint laturile triunghiului din plan. Atributele segmentului sunt punctele de la
extremitile lui (precizate prin coordonatele lor). Afiai dac:
a) mrimile celor trei segmente pot fi mrimile laturilor unui triunghi;
ED

b) cele trei segmente formeaz un triunghi.



192 Implementarea structurilor de date
2.4.3. Tablouri de nregistrri

IC
Pentru a caracteriza situaia colar a unui elev la o anumit disciplin, ntr-un semestru,
trebuie s se defineasc o nregistrare elev, cu urmtoarea structur de cmpuri:

OG
struct elev
{char nume[20], pren[20];
unsigned n1, n2, n3;
float media;};

G
elev a;
Pentru a caracteriza situaia colar a tuturor elevilor dintr-o clas, la o anumit discipli-

DA
n, ntr-un semestru, trebuie s se defineasc un vector clasa, ale crui elemente sunt
de tip nregistrare elev i care va avea attea elemente ci elevi sunt n clas (de
exemplu, 25 de elemente). Elementele vectorului sunt omogene, fiind de acelai tip,
adic nregistrri cu aceeai structur:

PE
clasa[0] clasa[1] ... clasa[i] ... clasa[24

nume pren n1 n2 n3 media


I
Declararea acestui vector se face cu instruciunea:
elev clasa[25];

Identificarea unui cmp (de exemplu, cmpul nume) care conine numele elevului i, din
clas, se face cu expresia:
IC

clasa[i].nume;
Variabila e este de acelai tip cu elementele vectorului clasa, i urmtoarele operaii de
atribuire sunt corecte:
CT

a = clasa[i]; clasa[i] = a;
clasa[i].nume=e.nume; a.nume = clasa[i].nume;
DA

Scop: exemplificarea modului n care putei folosi vectorii cu nregistrri.


Enunul problemei: ntr-o clas sunt maxim 30 de elevi, fiecare elev fiind identificat prin nu-
me i prenume. Elevul poate primi maxim 5 note la o disciplin, pe semestru. Se citesc de la
DI

tastatur: numrul de elevi din clas i, pentru fiecare elev, numele, prenumele i notele.
Dac are mai puin de 5 note, notelor lips li se va atribui valoarea 0, iar n calculul mediei se
vor lua numai notele diferite de 0. S se calculeze i s se afieze mediile elevilor din clas la
RA

acea disciplin.
Se folosesc variabilele s i k pentru a calcula suma notelor unui elev, respectiv numrul
de note diferite de zero.
#include <iostream.h>
ITU

#include <math.h>
void main()
{struct elev {char nume[20],pren[20];
unsigned n1,n2,n3,n4,n5;
ED

float media;};

Informatic 193
elev clasa[30]; int n,i,s,k;

IC
cout<<"nr. de elevi din clasa "; cin>>n;
//se citesc elementele vectorului (cmpurile nregistrrii
//pentru fiecare elev)

OG
for (i=0;i<n;i++)
{cin.get(); cout<<"elevul "<<i+1<<endl;
cout<<"nume "; cin.get(clasa[i].nume,20); cin.get();
cout<<"prenume "; cin.get(clasa[i].pren,20); cin.get();

G
cout<<"nota 1 "; cin>>clasa[i].n1;
cout<<"nota 2 "; cin>>clasa[i].n2;

DA
cout<<"nota 3 "; cin>>clasa[i].n3;
cout<<"nota 4 "; cin>>clasa[i].n4;
cout<<"nota 5 "; cin>>clasa[i].n5;}
for (i=0;i<n;i++) //se calculeaz media pentru fiecare elev

PE
{s=0,k=0;
if (clasa[i].n1!=0) {s+=clasa[i].n1;k++;}
if (clasa[i].n2!=0) {s+=clasa[i].n2;k++;}
if (clasa[i].n3!=0) {s+=clasa[i].n3;k++;}
if (clasa[i].n4!=0) {s+=clasa[i].n4;k++;}
I
if (clasa[i].n5!=0) {s+=clasa[i].n5;k++;}
clasa[i].media=(float)s/k;}
for (i=0;i<n;i++) //se afieaz media fiecrui elev
{cout<<clasa[i].nume<<" "<<clasa[i].pren<<" ";

cout<<clasa[i].media<<endl;} }
IC

Observaie:
Pentru a simplifica algoritmul de prelucrare, notele fiecrui elev pot fi i ele grupate
ntr-un vector, structura vectorului clasa devenind:
CT

clasa[0] clasa[1] ... clasa[i] ... clasa[24


DA

nume pren nota media

nota[0] nota[1] nota[2] nota[3] nota[4]


DI

iar programul:
#include <iostream.h>
#include <math.h>
RA

void main()
{struct elev {char nume[20],pren[20];
unsigned nota[5];
float media;};
ITU

elev clasa[30]; int n,i,j,s,k;


cout<<"nr. de elevi din clasa "; cin>>n;
for (i=0;i<n;i++)
{cin.get(); cout<<"elevul "<<i+1<<endl;
cout<<"nume "; cin.get(clasa[i].nume,20); cin.get();
ED

194 Implementarea structurilor de date
cout<<"prenume "; cin.get(clasa[i].pren,20); cin.get();

IC
for (j=0;j<5;j++) {cout<<"nota "<<j+1<<" ";
cin>>clasa[i].nota[j];}}
for (i=0;i<n;i++)

OG
{s=0,k=0;
for (j=0;j<5;j++)
if (clasa[i].nota[j]!=0) {s+=clasa[i].nota[j]; k++;}
clasa[i].media=(float)s/k;}

G
for (i=0;i<n;i++)
{cout<<clasa[i].nume<<" "<<clasa[i].pren<<" ";

DA
cout<<clasa[i].media<<endl;} }
1. ntr-un vector cu nregistrri, se pstreaz atributele a n drept-
Tem unghiuri: lungimea, limea, aria i perimetrul. Numrul n i dimensi-
unile laturilor dreptunghiurilor se introduc de la tastatur. S se afie-

PE
ze dreptunghiul cu suprafaa cea mai mare i dreptunghiul cu perimetrul cel mai mic.
2. ntr-un vector cu nregistrri, se pstreaz atributele a n dreptunghiuri: lungimea,
limea i diagonala. Numrul n i dimensiunile laturilor dreptunghiurilor se introduc
de la tastatur. Se mai citete de la tastatur o valoare d. S se afieze dreptun-
ghiurile a cror diagonal are dimensiunea d.
I
3. ntr-un vector cu nregistrri se pstreaz atributele a n puncte. Atributele punctului
sunt coordonatele i cadranul n care se gsete. Numrul n i coordonatele
punctelor se introduc de la tastatur. S se afieze punctele grupate dup cadran.

IC

Rspundei:
1. Scriei cte o nregistrare pentru fiecare dintre urmtoarele obiecte specificate prin
CT

lista lor de atribute:


a) carte = (titlu, autor, an_aparitie, editura, nr_pagini, pret);
b) paralelipiped dreptunghic = (x1,y1,z1; x2,y2,z2; x3,y3,z3 coordonatele celor trei
coluri reprezentative);
DA

c) main = (marc, numr, culoare, serie, an fabricaie, pre);


d) calculator = (marc, memorie, procesor, imprimant, monitor);
e) elev = (numr_matricol, nume, prenume, anul_naterii, clasa);
f) material = (cod, denumire, unitate_msur, pre, cantitate_intrat,
DI

cantitate_ieit, stoc).
2. Se consider urmtoarele declaraii:
struct s1 {char a; int b;};
RA

struct s2 {long a; float b;};


struct s3 {s1 a; s2 b;};
s3 a,b;
Precizai tipul cmpurilor: a.a.a; a.a.b; a.b.a; a.b.b; b.b.b; b.b.a; b.a.a i
ITU

b.a.b.
3. Ce se va afia n urma execuiei urmtoarei secvene de program:
typedef int mat[4][4];
struct ex {char a[20]; int b; char c; mat d;};
ED

ex a[5][5]; int i,j,k,l;



Informatic 195
for(i=0;i<5;i++)

IC
for(j=0;j<5;j++)
for(k=0;k<4;k++)
for(l=0;l<4;l++)

OG
a[i][j].d[k][l]=i+j+k+l;
cout<<a[4][4].d[3][3]<<endl<<a[i-1][j-1].d[k-1][l-1];
4. Comparai urmtoarele programe. Ce realizeaz? Analizai modul n care subpro-
gramele transmit rezultatele ctre modulul apelant. Scriei a treia variant de program

G
folosind variabile globale.
struct polinom struct polinom

DA
{int n; {int n;
int c[20];}; int c[20];};
void citire(polinom &p) polinom citire()
{int i; {int i; polinom p;

PE
cout<<"gradul"; cin>>p.n; cout<<"gradul = "; cin>>p.n;
for (i=0; i<=p.n; i++) for (i=0; i<=p.n; i++)
{cout<<"coeficientul lui x^" {cout<<"coeficientul lui x^"
<<p.n-i<<" = "; <<p.n-i<<" = ";
cin>>p.c[i];} } cin>>p.c[i];}
I
int valoare (polinom p, int a) return p;}
{int x=0,i; int valoare (polinom p, int a)
for (i=0; i<=p.n ; i++) {int x=0,i;

x=x*a+p.c[i]; for (i=0;i<=p.n;i++) x=x*a+p.c[i];


return x;} return x;}
IC

void main() void main()


{polinom p; int a; {polinom p; int a;
citire(p); cout<<"a= "; cin>>a; p=citire(); cout<<"a= "; cin>>a;
CT

cout<<valoare(p,a);} cout<<valoare(p,a);}
Adevrat sau Fals:
1. Urmtoarea declaraie este corect:
DA

struct s1
{struct s2 {int a; float b;}; int a;};
2. Urmtoarele declaraii nu sunt corecte:
struct s2 {int a; float b;};
DI

struct s1 {s2 a; int b;};


3. Urmtoarele declaraii sunt corecte:
struct s1 {s2 a; int b;};
RA

struct s2 {int x; float y;};


Alegei:
1. Care dintre urmtoarele variante reprezint o declarare corect a unei variabile
structurate cu dou componente, una de tip ntreg i una de tip real?
ITU

a. int float x[2]; b. float x[2];


c. struct d. typedef struct
{float x; {long a;
int a;} x; float b;} inreg;
ED

inreg x;

196 Implementarea structurilor de date
2. Care dintre urmtoarele variante reprezint o declarare corect a dou variabile

IC
simple, una de tip ntreg i una de tip real?
a. int float x[2]; b. int x; float y;
c. float x; long y; d. struct

OG
{int a;float b;} x;
3. Pentru declaraiile urmtoare:
struct masina {char tip[20],culoare[10],nr[10];};
masina x,a[50];

G
care dintre instruciuni sunt corecte?
a. a[10]=x.tip; b. cin>>x.nr;
c. x=a[10]; d. a[10]=x;

DA
4. Pentru declaraiile urmtoare:
struct data {int zi,luna,an;};
struct persoana

PE
{char nume[15], pren[15];
data data n;};
data dn; persoana pers;
care dintre instruciunile de atribuire sunt corecte?
a. pers.data n=dn; b. pers.data n.zi=dn.zi;
I
c. dn.data n.zi=10; d. pers.data n.luna=5;
5. Variabilele p i q memoreaz n dou cmpuri x i y dou numere ntregi reprezen-
tnd coordonatele punctelor P i Q din plan. tiind c distana dintre P i Q se
calculeaz cu ajutorul formulei sqrt((xp-xq)2 + (yp-yq) 2) stabilii care dintre expresiile

urmtoare calculeaz distana dintre P i Q:


IC

a. sqrt((pow(p.x+q.x,2)-pow(p.y+q.y,2))
b. sqrt((pow(p.x-q.x,2)+pow(p.y-q.y,2))
c. sqrt((p.x-q.x)(p.x-q.x)+(p.y-q.y)(p.y-q.y))
CT

d. sqrt((pow(px-qx,2)+ pow(py-qy,2))
(Bacalaureat Simulare 2003)
6. Condiia ca dou puncte distincte A i B (de tip structur) s aparin aceleiai axe
de coordonate este:
DA

a. (A.x==0)&&(B.x==0)&&(A.y==0)&&(B.y==0)
b. ((A.x==0)||(B.x==0))&&((A.y==0)||(B.y==0))
c. A.x==0 && B.x==0 || A.y==0 && B.y==0)
d. ((A.x==0)&&(B.x==0))||((A.y==0)&&(B.y==0))
DI

(Bacalaureat Sesiunea special 2003)


Miniproiecte:
Pentru realizarea miniproiectelor se va lucra n echip. Fiecare miniproiect va conine:
RA

a. descompunerea problemei n subprobleme i rezolvarea fiecrei subproble-


me cu ajutorul unui subprogram;
b. obiectul care este prelucrat i atributele sale, preciznd care dintre aceste atribute
sunt date de intrare i care sunt date de ieire (exemplu: pentru problema 1, obiectul
ITU

este segmentul, atributele care sunt date de intrare sunt coordonatele punctelor de la
extremitile segmentului, iar atributul lungimea segmentului este dat de ieire);
c. diagrama structurii de date folosit i modul n care se aloc spaiul de memorie
unei nregistrri;
d. explicarea algoritmilor folosii pentru rezolvarea problemei;
ED

Informatic 197
e. citirea datelor dintr-un fiier text pe primul rnd al fiierului va fi scris numrul

IC
de obiecte care se prelucreaz (n) i apoi, pe urmtoarele n rnduri, separate
prin spaiu, pentru fiecare obiect, valorile atributelor care sunt date de intrare.

OG
1. ntr-un vector cu nregistrri se pstreaz atributele a n segmente din plan. Atributele
segmentului sunt punctele de la extremitile lui (precizate prin coordonatele lor) i
lungimea segmentului. S se afieze segmentul (prin coordonatele punctelor din
extremiti) care are lungimea cea mai mare i segmentul care are lungimea cea mai
mic. Dac exist mai multe segmente care ndeplinesc aceste proprieti, s se

G
afieze toate segmentele.
2. ntr-o clas sunt maxim 30 de elevi, fiecare elev fiind identificat prin nume i prenume.

DA
Elevul poate primi maxim 5 note la o disciplin, pe semestru, i o not la tez. Se citesc
de la tastatur: numrul de elevi din clas i, pentru fiecare elev, numele, prenumele i
notele. Dac are mai puin de 5 note, notelor lips li se va atribui valoarea 0. S se
calculeze i s se afieze mediile elevilor din clas la acea disiplin, n ordinea:

PE
a) descresctoare a mediilor; b) alfabetic a numelui i prenumelui.
3. n doi vectori cu nregistrri (clasa1 i clasa2) sunt pstrate informaii despre elevii din
dou clase: numele, prenumele i media general. Cei doi vectori sunt ordonai cresctor
dup medie. S se interclaseze cei doi vectori n vectorul clase, care trebuie s conin
I
suplimentar i informaia despre clasa elevului. S se afieze informaiile din acest
vector. S se afieze informaii despre elevul cu media cea mai mic i despre elevul
cu media cea mai mare. S se afieze media mediilor generale pe fiecare clas i pe
ambele clase mpreun. S se afieze ce clas are media pe clas mai mare.

4. ntr-un vector cu nregistrri se pstreaz atributele a n triunghiuri: laturile, aria,


perimetrul i tipul triunghiului (oarecare, isoscel etc.). S se afieze informaiile despre
IC

triunghiuri, grupate dup tip (grupa triunghiurilor isoscele, a triunghiurilor oarecare etc.).
5. ntr-un vector cu nregistrri, se pstreaz atributele a n numere: valoarea numrului i
CT

descompunerea lui n factori primi. Se introduc de la tastatur dou numere naturale p


i k. S se afieze numerele care conin n descompunerea lor factorul prim exprimat
prin p la puterea k. (Indicaie: atributul descompunerea numrului n factori primi va fi
implementat ca un vector de nregistrri care conine un cmp pentru divizorul prim i
DA

un cmp pentru puterea divizorului; la nregistrarea corespunztoare numrului va


trebui adugat cmpul numr de factori primi).
6. ntr-o fabric sunt m secii, iar n fiecare secie lucreaz n muncitori. Atributele fiec-
rui muncitor sunt: numele, prenumele, secia, salariul orar, timpul lucrat (exprimat n
DI

ore) i salariul. Pentru fiecare muncitor se va calcula salariul (care este egal cu
produsul dintre salariul orar i timpul lucrat). S se afieze totalul salariului pe fiecare
secie i pe ntreaga fabric.
7. O persoan este caracterizat de urmtoarele atribute: sex, vrst, nlime,
RA

greutate. Se analizeaz un grup de 100 de persoane. S se afieze:


a. procentul de femei i procentul de brbai;
b. vrsta medie a grupului, vrsta medie a femeilor i vrsta medie a brbailor.
c. procentul de femei i procentul de brbai peste vrsta medie a grupului;
ITU

8. Pentru grupul de 100 de persoane analizat la problema anterioar, s se afieze:


a. nlimea medie a grupului i nlimea medie a femeilor;
b. procentul de femei i procentul de brbai peste nlimea medie a grupului;
c. greutatea medie a grupului, a femeilor i a brbailor;
ED

d. procentul de femei i procentul de brbai peste greutatea medie a grupului.



198 Implementarea structurilor de date

IC
2.5. Lista
Pentru rezolvarea unei probleme, n multe cazuri se pot folosi mai muli algoritmi, din care

OG
trebuie ales cel mai eficient:
 la nivel conceptual, alegerea algoritmului se face n funcie de complexitatea algorit-
milor descoperii pentru rezolvarea problemei, fiind preferat algoritmul care are com-
plexitate mai mic algoritmul care consum cel mai puin resursele calculatorului;
 la nivel logic, alegerea se face n funcie de modul n care pot fi implementai algoritmii n

G
limbajul de programare ales, fiind preferat algoritmul care are o implementare mai uoa-
r algoritmul care consum cel mai puin resursele programatorului.

DA
Nu ntotdeauna cei doi algoritmi coincid, programatorul urmnd s decid criteriul folosit
pentru alegerea algoritmului. Un rol important n implementarea eficient a unui algoritm
l joac modul n care au fost organizate datele n colecia de date.

PE
Pe lng criteriile pentru clasificarea datelor studiate, mai exist i urmtoarele criterii:
Alocarea memoriei interne

Structuri statice Structuri dinamice


I
Dimensiunea zonei alocate este fix. Dimensiunea zonei alocate nu este fix.
Alocarea ei se face n timpul compilrii, n Alocarea sau eliberarea zonelor de memorie
funcie de modul n care a fost declarat folosite de structur se face n timpul
structura, iar n timpul execuiei programului execuiei programului, n funcie de numrul

nu mai poate fi modificat. de componente ale structurii.


IC

Implementarea n limbajul de programare


CT

Structuri implicite Structuri explicite


Structura creat la nivel conceptual este Structura creat la nivel conceptual nu este
implementat la nivelul limbajului de implementat la nivelul limbajului de
programare. Reprezentarea sa este programare. Reprezentarea sa se face folosind
DA

implicit i nu mai necesit informaii structurile implicite implementate, n limbaj, fiind


suplimentare pentru localizarea necesare informaii suplimentare pentru
componentelor. localizarea componentelor.

Dispunerea elementelor n memorie


DI

Structuri contigue Structuri dispersate


Elementele sunt dispuse n zone contigue Elementele sunt dispuse n zone dispersate de
RA

de memorie, care permit localizarea uneia memorie; pentru a putea localiza elementele, n
dintre ele folosind o adres de referin i structur, trebuie s se memoreze pentru fiecare
deplasarea fa de adresa de referin. element i adresa la care se gsete.
ITU

Structurile statice au un mare dezavantaj, deoarece alocarea zonei de memorie se face


la compilarea programului (n funcie de modul n care a fost declarat structura), iar n
timpul execuiei programului pot s apar urmtoarele cazuri:
 spaiul alocat structurii este insuficient;
 spaiul alocat structurii este mult mai mare dect este necesar.
ED

Informatic 199
Acest dezavantaj este eliminat prin folosirea structurilor dinamice, la care dimensiunea

IC
zonei de memorie alocate nu mai este fix, deoarece alocarea memoriei se face n timpul
execuiei programului, n funcie de numrul de componente ale structurii la acel moment.

OG
Scop: exemplificarea modului n care identificai problemele n care putei folosi structura
de date de tip list pentru a le rezolva.

G
Enunul problemelor pentru care trebuie aleas o structur de date i conceput
algoritmul pentru prelucrarea lor:

DA
1. ntr-o bibliotec, exist o colecie de cri organizate n ordinea alfabetic a autorilor. Un
cititor poate mprumuta o carte (se extrage o carte din colecie) sau poate napoia o carte
(se insereaz o carte n colecie). Toate aceste operaii trebuie executate astfel nct s se
pstreze organizarea n ordine alfabetic a autorilor.

PE
2. La o benzinrie s-a format o coad de ateptare. Mainile sunt servite n ordinea
venirii: prima main sosit este servit, iar ultima main venit se aaz la sfritul
cozii. Toate aceste operaii trebuie executate astfel nct s se pstreze ordinea n
care au sosit mainile i s-au aezat la coad.
I
3. ntr-o stiv de cri, volumele sunt aezate n ordinea alfabetic a titlurilor. Trebuie
extras o carte din stiv fr a deranja modul n care sunt ordonate crile n stiv.
La nivel conceptual, toate aceste colecii de date reprezint un ir de date de acelai tip,

care trebuie prelucrate prin inserarea i extragerea de elemente, pstrndu-se o


anumit ordine de aranjare a elementelor. Dac la nivel logic s-ar alege soluia de a
IC

grupa aceste elemente ntr-o structur de date de tip vector, algoritmii de prelucrare
care sunt algoritmi de actualizare a vectorilor vor necesita multe deplasri de elemente
care consum timp de prelucrare.
CT

Caracteristicile operaiilor de prelucrare a vectorilor sunt:


 Vectorul este o structur de date care are lungimea fizic fix, iar implementarea lui
la nivel fizic este un proces prin care se face conversia locaiei conceptuale a unui
element, n locaia real, din memoria intern.
DA

 Orice operaie de adugare sau extragere a unui element din colecie modific lungi-
mea logic a vectorului.
 Pentru a insera un element n colecie, trebuie deplasate toate elementele spre
dreapta, ncepnd cu poziia inserrii.
DI

 Pentru a extrage un element din colecie, trebuie deplasate toate elementele spre
stnga, de la sfrit, pn n poziia din care se extrage.
n cazul structurilor care trebuie s-i pstreze n timpul exploatrii ordonarea dup un
RA

anumit criteriu, mecanismul vectorilor este greoi. n aceste cazuri, se poate alege ca soluie
de implementare a structurii de date lista care nu este o structur fizic de organizare
a datelor, ci o structur logic, ce degreveaz programatorul de ordonarea dup
indice a structurii, impus de vectori. Listele sunt structuri de date care, spre
ITU

deosebire de vectori, au marele avantaj c permit i implementare prin alocarea


dinamic a memoriei.
ED

200 Implementarea structurilor de date

IC
Lista este o structur de date logic, liniar, cu date omogene, n care fiecare
element are un succesor i un predecesor, exceptnd primul element, care nu are
dect succesor, i ultimul element, care nu are dect predecesor.

OG
Aparent, vectorul i lista par s fie aceeai structur de date: sunt structuri omogene i
secveniale (liniare) n care fiecare element are un succesor i un predecesor, cu
excepia primului i a ultimului element, care au numai succesor, respectiv numai
predecesor. ntre cele dou structuri exist ns urmtoarele deosebiri:

G
Criteriul Tabloul de memorie Lista
Dispunerea Sunt structuri contigue. Pot fi structuri dispersate. Predecesorul,

DA
elementelor Predecesorul, elementul i elementul i succesorul nu sunt n locaii de
n memorie succesorul se gsesc n locaii memorie contigue. Programatorul trebuie s
contigue prin mecanismul de defineasc mecanismul prin care elementele
implementare a structurii de date la structurii vor fi legate unele de altele pentru

PE
nivel fizic. a putea fi regsite n memorie.
Implementarea Sunt structuri implicite. Fiind o Sunt structuri explicite. Fiind o structur
n limbaj structur fizic, este implementat n logic, trebuie aleas o metod de
limbajul de programare. Nu necesit implementare folosind structurile fizice
informaii suplimentare pentru loca- existente. Necesit informaii suplimentare
I
lizarea elementelor structurii n me- pentru localizarea elementelor structurii n
moria intern, deoarece mecanismul memoria intern, deoarece mecanismul
prin care este implementat fizic prin care este implementat fizic nu asigu-
asigur identificarea elementelor r identificarea elementelor.

Alocarea Sunt structuri statice. Sunt structuri statice sau dinamice, n


funcie de implementarea aleas.
IC

memoriei
Se definete lungimea listei (n) ca fiind numrul de elemente ale listei. Lista vid este lis-
ta care are lungimea 0 (nu are nici un element). Elementele listei se mai numesc i noduri.
CT

2.5.1. Implementarea listelor n limbajul C++


n funcie de modul n care se aloc memoria intern, se pot folosi metodele:
DA

Metode de implementare fizic a listelor

static dinamic
DI

folosind vectori folosind pointeri


RA

n funcie de modul n care sunt aranjate elementele n list, se pot folosi metodele:
Metode de implementare a listelor
ITU

secvenial nlnuit

numai static static dinamic


ED

Informatic 201
2.5.1.1. Implementarea prin alocare secvenial

IC
Nodurile listei sunt stocate ntr-un bloc contiguu de locaii de memorie cu adrese
consecutive. De exemplu, dac avem o list format din cuvinte de maximum 4

OG
caractere, acestea vor fi scrise ntr-un bloc contiguu de locaii de 5 octei.
bloc contiguu de locaii de memorare de 5 octei

'a 'l' 'f' 'a' '\0' 'b' 'e' 't 'a' '\0' ........... 'z' 'e' 't' 'a' '\0'

G
primul nod al listei al doilea nod al listei utimul nod al listei

DA
Aceast implementare este cea mai simpl i se face folosind un vector de iruri de
caractere:
typedef char nod[5];

PE
nod lista[100];
S-a declarat o list care poate avea maxim 100 de noduri. Informaia dintr-un nod este de
tip ir de caractere cu lungimea de 5 caractere. Acest tip de list se mai numete i list
contigu.
n implementarea prin alocare secvenial, algoritmii pentru operaiile de prelucrare a
I
listei sunt cei folosii pentru operaiile de prelucrare a vectorilor i necesit foarte multe
operaii de deplasare a elementelor n vector.

2.5.1.2. Implementarea prin alocare nlnuit


Nodurile listei nu mai sunt stocate succesiv n memorie.
IC

Exemplu O list este format din 5 cuvinte (noduri), fiecare cuvnt avnd maxim 4
caractere. Nodurile listei se exploateaz n ordine alfabetic:
CT

Lista = {"alfa", "beta", "gama", "teta", "zeta"}


Aceast implementare se poate face att static, ct i dinamic, ntre cele dou implemen-
tri existnd urmtoarele diferene:
 n implementarea static, nodurilor listei li se aloc un bloc contiguu de locaii de
DA

memorie (zona de memorie alocat vectorului);

Memoria intern
DI

bloc contiguu de locaii de memorare de 5 octei, identificate prin indici

1 2 3 4 5
RA

"gama" "zeta" "beta" "alfa" "teta"

nodul 3 nodul 5 nodul 2 nodul 1 nodul 4


(ultim) (prim)
ITU

Aranjarea nodurilor listei n implementarea static

 n implementarea dinamic, nodurile listei ocup locaii dispersate din memorie


(a cror adres poate fi pstrat cu ajutorul pointerilor).
ED

202 Implementarea structurilor de date

IC
Memoria intern
5 locaii de memorie dispersate

OG
identificate prin adresele adr1, adr2, adr3, adr4, adr5
"beta" "gama" "alfa"
nodul 2 nodul 3 nodul 1 (prim)
la adresa adr2 "zeta" la adresa adr3 "teta" la adresa adr1

G
nodul 5 (ultim) nodul 4
la adresa adr5 la adresa adr4

DA
Aranjarea nodurilor listei n implementarea dinamic

Deoarece n ambele cazuri de implementare nodurile nu sunt aranjate succesiv, ci aleato-

PE
riu, n memorie, trebuie implementat un mecanism prin care s se precizeze ordinea real a
acestor noduri (ordinea n care se nlnuiesc n list). Aceasta nseamn c:
 trebuie cunoscut locul din care ncepe lista (lanul de noduri), adic poziia primului
nod din list (nodul prim) n exemplu, nodul "alfa";
 trebuie cunoscut locul n care se termin lista, adic poziia ultimului nod din list
I
(nodul ultim) n exemplu, nodul "zeta";
 pentru fiecare nod din list, cu excepia ultimului nod, trebuie cunoscut nodul care
este succesorul lui de exemplu, pentru nodul "gama" trebuie cunoscut c

succesorul su este nodul "teta".


Metoda folosit pentru implementare este ca Informaia Informaia pentru
IC

un nod al listei s conin dou tipuri de infor- propriu-zis legtur


maii: informaia propriu-zis i informaia
de legtur (informaia prin care se identific nodul care urmeaz n structur, adic
CT

adresa acestui nod). Informaia pentru legtur va fi:


 n cazul implementrii statice indicele din vector al succesorului;
 n cazul implementrii dinamice adresa succesorului exprimat printr-un pointer.
DA

n ambele cazuri, informaia de legtur memorat n ultimul nod este constanta NULL
sau 0 (care semnific faptul c ultimul nod nu se leag de nimic).

Memoria intern
DI

indicii elementelor vectorului

1 2 3 4 5
RA

"gama" 5 "zeta" 0 "beta" 1 "alfa" 3 "teta" 2


ITU

nlnuirea nodurilor listei n implementarea static


ED

Informatic 203

IC
Memoria intern
adresele nodurilor adr1, adr2, adr3, adr4, adr5

OG
"beta" adr3 "gama" adr4 "alfa" adr2

adr2 adr3 adr1

G
"zeta" NULL "teta" adr5

DA
adr5 adr4

nlnuirea nodurilor listei n implementarea dinamic

PE
Implementarea static pentru alocarea nlnuit se face folosind un vector de
nregistrri:
typedef unsigned adresa;
struct nod
I
{char sir[5]; //informaia propriu-zis
adresa urm;}; //informaia pentru legtur
nod lista[100];

n variabila urm se va memora adresa succesorului (indicele din vector al succesorului).


n general, putem spune c, pentru implementarea static a listei i pentru prelucrarea cu
IC

algoritmii specifici unei liste, trebuie declarate urmtoarele tipuri de date i variabile:
const unsigned NMAX=100;
typedef unsigned adresa;
CT

struct nod
{<tip 1> <info 11>, <info 12>, ..., <info 1n>;
<tip 2> <info 21>, <info 22>, ..., <info 2n>;
.............................................
DA

<tip m> <info m1>, <info m2>, ..., <info mn>;


adresa urm;};
nod lista[NMAX+1];
DI

Cmpurile <info ij> sunt cmpurile cu informaii, iar cmpul urm este cmpul care conine
informaia de legtur (adresa succesorului). Se definete constanta NMAX pentru a putea
folosi n expresii lungimea fizic a vectorului. Deoarece indicele 0 se folosete pentru adresa
NULL, n vectorul care implementeaz lista, elementul cu indicele 0 nu se folosete.
RA

n liste, algoritmii de inserare i eliminare a unor noduri din structur se simplific foarte mult:
 Inserarea unui nod const n alocarea zonei de memorie n care se scrie nodul i
legarea lui la structur (stabilirea legturii cu predecesorul i cu succesorul lui).
 Eliminarea unui nod const n ruperea nodului din structur, prin legarea predece-
ITU

sorului su cu succesorul lui, i eliberarea zonei de memorie pe care a ocupat-o.


Implementarea structurilor de date cu ajutorul listelor are urmtoarele avantaje:
 alocarea dinamic a memoriei care o gestioneaz mult mai eficient;
 algoritmii de prelucrare care sunt mult mai eficieni (se execut mult mai puine
ED

operaii pentru inserarea i tergerea unui element).



204 Implementarea structurilor de date

IC
Metoda de Avantajul alocrii dinamice a Avantajul algoritmilor
implementare memoriei de prelucrare
static secvenial nu nu

OG
static nlnuit nu da
dinamic nlnuit da da
Se observ c implementarea static secvenial nu aduce niciunul dintre avantajele

G
listelor, fiind o implementare n care lista este de fapt un vector.
Algoritmii pentru prelucrarea unei liste nlnuite sunt aceiai, att n cazul im-

DA
plementrii statice, ct i n cazul implementrii dinamice. Deoarece informaiile pe care
le avei nu v permit nc abordarea alocrii dinamice a memoriei, pentru prezentarea
algoritmilor se va folosi implementarea static.
Aadar, lista este o structur logic de date, parcurs liniar, care are dou extremiti

PE
(nceput i sfrit), n care fiecrui element i se asociaz o informaie suplimentar
referitoare la locul elementului urmtor, din punct de vedere logic.

2.5.2. Clasificarea listelor


I
Liste liniare

Liste generale Liste restrictive


Nu exist restricii pentru operaiile de Exist restricii pentru operaiile de
IC

inserare i tergere a elementelor din list inserare i tergere a elementelor din list
(se pot face n orice poziie a listei). (se pot face numai la extremiti).
CT

Stiva Coada
Operaiile de introducere i extragere Operaia de introducere a elementelor se
DA

a elementelor se pot face numai face pe la o extremitate, iar extragerea


printr-una dintre extremiti. elementelor prin cealalt extremitate.
DI

Lista simplu nlnuit Lista dublu nlnuit Lista circular


Fiecare element pstreaz Fiecare element pstreaz Este o list nlnuit n
legtura cu un singur vecin legtura cu ambii vecini care elementul ultim se
(de obicei, succesorul). (succesorul i predecesorul). leag de elementul prim.
RA

Lista simplu nlnuit


ITU

prim ultim
info urm info urm info urm info NULL
ED

Informatic 205

IC
Lista circular simplu nlnuit
prim ultim

OG
info urm info urm info urm info urm

Lista dublu nlnuit

G
DA
prim NULL info urm pred info urm

PE
ultim pred info NULL pred info urm

Tem
I
Reprezentai grafic o list simplu nlnuit prin predecesori i o list
circular dublu nlnuit.

2.5.3. Algoritmi pentru prelucrarea listelor generale


Operaiile care se pot executa asupra listelor sunt:


IC

 iniializarea listei se creeaz lista vid;


 crearea listei se adaug repetat elemente la list, pornind de la lista vid;
 inserarea unui element n list la nceput, la sfrit, n interior;
CT

 eliminarea unui element din list la nceput, la sfrit, n interior;


 parcurgerea listei se viziteaz elementele listei pentru a obine informaii;
 cutarea n list a unui element care ndeplinete anumite condiii;
 concatenarea a dou liste;
DA

 divizarea n dou liste.


Pentru a simplifica algoritmii pentru prelucrarea listei, vom considera c un nod al listei
conine numai un cmp cu informaie i cmpul pentru realizarea legturii.
DI

const unsigned NMAX=100;


typedef unsigned adresa;
struct nod
{int info; adresa urm;};
RA

nod lista[NMAX+1];
adresa prim,ultim,p;
unsigned nr el,liber[NMAX];
int n;
ITU

Vei mai folosi urmtoarele date i structuri de date:


 Variabilele prim i ultim reprezint adresele (indicele poziiei din vector) n care sunt
memorate primul i respectiv ultimul nod; ele v ajut s identificai extremitile listei.
 Variabila p este adresa (indicele) unui nod curent din list (este folosit pentru parcur-
ED

gerea listei).

206 Implementarea structurilor de date
 Variabila n conine valoarea care se atribuie cmpului cu informaii.

IC
 Variabila nr_el este lungimea listei (numrul de noduri ale listei).
 Vectorul liber este o hart a nodurilor libere: liber[p] are valoarea 1 dac nodul

OG
cu adresa (indicele) p este liber i valoarea 0 dac nodul cu adresa p este ocupat. Prin
acest vector, se implementeaz mecanismul de alocare i de eliberare a zonei de
memorie necesare unui nod. Atunci cnd se insereaz un nod, mai nti trebuie s i se
aloce memorie intern. Cutnd n vectorul liber, se va putea identifica prima
locaie liber din vectorul lista. Atunci cnd se terge un element, se elibereaz

G
memoria alocat n vectorul lista, prin actualizarea informaiei din vectorul liber.
Exist urmtoarele cazuri speciale de liste:

DA
 Lista vid: att nodul prim ct i nodul ultim nu exist, i indicii folosii pentru
adresarea lor au valoarea NULL:
prim = ultim = NULL;
 Lista cu un singur nod: nodul prim este i nodul ultim i nu mai este legat de

PE
nici un alt element:
lista[prim].info = val;
lista[prim].urm = NULL;
ultim = prim; I
Exist urmtoarele stri ale listei, care trebuie cunoscute n algoritmii de prelucrare:
 Lista vid. Aceast stare trebuie cunoscut, atunci cnd se elimin noduri din list,
deoarece n lista vid nu exist noduri care s fie eliminate. Pentru testarea unei liste
dac este vid, se poate implementa funcia operand este vida(), care va furniza

valoarea 1 (adevrat), dac lista este vid, i valoarea 0 (fals) dac lista nu este vid.
int este vida(adresa prim)
IC

{return prim==NULL;}
 Lista plin. Aceast stare poate s apar din cauza implementrii statice a listei. Ea
trebuie cunoscut atunci cnd se adaug noduri la list, deoarece se poate depi
CT

lungimea fizic a vectorului. n lista plin nu mai exist locaii libere n vector, n care
s se adauge noduri. Pentru testarea unei liste dac este vid, se poate implementa
funcia operand este plina(), care va furniza valoarea 1 (adevrat), dac lista
este plin, i valoarea 0 (fals) dac lista nu este plin.
DA

int este plina()


{return nr el == NMAX;}

2.5.3.1. Iniializarea listei


DI

Prin acest algoritm se creeaz lista vid, n care att nodul prim ct i nodul ultim nu
exist, i vor avea valoarea NULL. n vectorul liber, toate elementele au valoarea 1
(toate elementele din vectorul listei sunt libere).
RA

Implementarea algoritmului. Se folosete funcia procedural init() ai crei parametri


prim i ultim de tip adresa se transmit prin referin, deoarece sunt parametri de ieire.
void init(adresa &prim, adresa &ultim)
{ultim=prim=NULL; nr el=0;
ITU

for (adresa p=1;p<=NMAX; p++) liber[p]=1;}

2.5.3.2. Alocarea memoriei


Pentru a putea aduga un nod la list trebuie mai nti s i se aloce o zon de
memorie. Prin acest algoritm se gsete prima poziie liber n vectorul lista.
ED

Informatic 207
Implementarea algoritmului. Se folosete funcia operand aloc mem() care furnizeaz

IC
adresa (indicele) primei poziii libere n vector variabila local p de tip adres.
adresa aloc mem()

OG
{adresa p;
for (adresa p=1; !liber[p]; p++);
liber[p]=0; nr el++;
return p;}

G
2.5.3.3. Crearea listei
Deoarece n algoritmii de prelucrare trebuie s se cunoasc adresa primului nod, este impor-

DA
tant adugarea primului nod la lista vid. Paii algoritmului de creare a unei liste sunt:
PAS1. Se adaug primul nod la list (nodul prim).
PAS2. Ct timp mai exist informaie execut: se adaug un nod la list.

2.5.3.4. Adugarea primului nod la list

PE
Prin acest algoritm se adaug primul nod n list. Spaiul alocat acestui nod este prima
poziie din vector (poziia cu indicele 0). n vectorul liber, poziia 0 se va nregistra ca
ocupat prin atribuirea valorii 0. Nodul prim i nodul ultim au valoarea 1. Nodul prim,
fiind unicul nod, nu mai este legat de alt nod.
I
prim = ultim = 1
lista val NULL ...............

liber 0 1 1 ...............
1 2 3
IC

n lista cu un singur nod, adresa de legtur a nodului prim are valoarea NULL i att
nodul prim ct i nodul ultim au aceeai adres. Paii executai n acest algoritm sunt:
CT

PAS1. Se cere alocarea de memorie pentru nodul prim.


PAS2. Se scrie informaia n nodul prim.
PAS3. Adresei de legtur a nodului prim i se atribuie valoarea NULL.
PAS4. Nodului ultim i se atribuie adresa nodului prim.
DA

Implementarea algoritmului. Se folosete funcia procedural adauga primul nod() ai c-


rei parametri se transmit astfel: prim i ultim de tip adresa prin referin, deoarece sunt
parametri de ieire, iar n, care conine informaia util, prin valoare, deoarece este parametru
de intrare.
DI

void adaug primul_nod(adresa &prim, adresa &ultim, int n)


{prim=aloc_mem(); lista[prim].info=n; lista[prim].urm=NULL; ultim=prim;}

2.5.3.5. Adugarea unui nod la list


RA

Pentru adugarea unui nod la list (prin scriere la adresa p care i s-a alocat), n funcie
de cerinele problemei, se poate folosi unul dintre algoritmii urmtori:
1. adugarea n faa primului nod;
ITU

2. adugarea dup ultimul nod;


3. adugarea ntr-o poziie n interiorul listei.
n toate cele trei variante adugarea se poate face numai dac lista nu este plin.
ED

208 Implementarea structurilor de date
Adugare n faa primului nod

IC
Paii executai n acest algoritm sunt:
PAS1. Se cere alocarea de memorie pentru nodul p.

OG
PAS2. Se scrie informaia n nodul p.
PAS3. Dac lista este vid, nodul p adugat va fi i nodul ultim.
PAS4. Nodul p se leag de nodul prim.
PAS5. Nodul p inserat devine nodul prim.

G
Adugare n faa primului nod
prim

DA
ultim
info urm info urm info urm info NULL

PE
p info urm p devine nodul prim

Implementarea algoritmului. Se folosete funcia procedural adauga inainte prim() ai


crei parametri se transmit astfel: prim i ultim de tip adresa prin referin, deoarece
I
sunt parametri de intrare-ieire i n care conine informaia util prin valoare,
deoarece este parametru de intrare.
void adaug inainte prim(adresa &prim, adresa &ultim, int n)

{adresa p; p=aloc mem();


lista[p].info=n; lista[p].urm=prim; //nodul p se leag de nodul prim
IC

if (este vid(prim)) ultim=p;


prim=p;} //nodul p devine nodul prim
Adugare dup ultimul nod
CT

Paii executai n acest algoritm sunt:


PAS1. Se cere alocarea de memorie pentru nodul p.
PAS2. Se scrie informaia n nodul p.
PAS3. Nodul p este nod terminal (nu se leag de nimic adresa de legtur este NULL).
DA

PAS4. Nodul ultim se leag de nodul p adugat.


PAS5. Dac lista este vid, nodul p inserat va fi