Documente Academic
Documente Profesional
Documente Cultură
DISCIPLINA: INFORMATICA
CONȚINUTURI
I. Tablouri bidimensionale
IV. Subprograme
V. Recursivitate
I.TABLOURI BIDIMENSIONALE
Tablourile bidimensionale funcţionează ca o matrice şi se pot declara astfel:
• La fel ca şi în cazul tablourilor unidimensionale, şi în cazul tablourilor bidimensionale, la
declarare, se trece dimensiunea maximă a liniilor (dim_linie) şi dimensiunea maximă a
coloanelor (dim_coloana).
Exemplu:
Prezentăm în continuare câteva declarări de tablouri bidimensionale:
int a[10][10]; // declararea unui tablou bidimensional cu maxim 100 de // elemente (10*10),
fiecare de tip întreg;
float x[5][5]; // declararea unui tablou bidimensional cu maxim 25 de // elemente(5*5),
fiecare de tip real simplă precizie;
char s[20][10]; // declararea unui tablou bidimensional cu maxim 200 de // elemente(20*10),
fiecare de tip caracter;
Compilatorul C++ alocă un spaţiu de memorie egal cu numărul de linii înmulţit cu numărul
de coloane ale tabloului, rezervând bineînţeles octeţi în funcţie de tipul de bază al fiecărui
tablou.
• Accesul la fiecare element al tabloului se face prin numele acestuia urmat între
paranteze, de indicele liniei şi indicele coloanei (adică poziţia pe care o ocupă în tablou).
Iniţializarea elementelor unui tablou se poate face total sau parţial la declararea lor:
int b[2][3]={ {1, 2, 3}, {4, 5, 6} };
• Astfel, elementul b[0][0] are valoarea 1, elementul b[0][1] are valoarea 2, elementul b[0][2]
are valoarea 3, elementul b[1][0] are valoarea 4, elementul b[1][1] are valoarea 5, elementul
b[1][2] are valoarea 6.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
O constantă de tip șir de caractere se declară între două caractere “. În memoria internă, o
constantă de acest tip este reținută sub forma unui vector de caractere. Fiecare componentă a șirului
(începând cu cea de indice 0) reține codul ASCII al caracterului pe care îl memorează. Convenția este ca
ultimul octet să rețină 0 (codul caracterului nul). Caracterul nul este memorat automat. Trebuie rezervate
lungimea_șirului+1 caractere char (+1 pentru caracterul nul).
Limbajul C/C++ permite inițializarea unui tablou de caractere printr-o constanta șir, care include automat
caracterul NULL.
Exemplu :
char vect[11]=”calculator”;
char vect[]=”calculator”; (compilatorul face calculul numărului de octeți necesari)
char vect[100]=”calculator”; (s-au rezervat mai mulți octeți decât era necesar)
Șirurile de caractere sunt de fapt tablouri de caractere, care au ca ultim element un terminator de șir, caracterul
NULL.
Exemplu:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’}; // tablou de caractere
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’}; // sir de caractere cu elementele abcd
Șirurile de caractere pot fi inițializate încă de la declarare sau citite pe parcursul programului.
a. Citirea unui șir de caractere se poate face ca citirea oricărui tablou, într-un for, caracter cu
caracter (deși nu este recomandată). În acest caz, terminatorul de șir nu este memorat automat, el
trebuie pus explicit după ultimul caracter din șir.
Exemplu:
char c[20];
for(int i=0;i<=5;i++)
cin>>c[i];
cout<<c<<endl; //se va afișa șirul format din cele 6 caractere, urmat de caractere
//„reziduale”, inițializate implicit la compilare, din cauza ca n-a fost pus
//terminatorul de șir
c[6]=0;
cout<<c<<endl; //a fost pus terminatorul de șir, deci șirul va fi afișat corect
b. Se poate face pur și simplu, folosind cin>>. Caracterul nul este adăugat automat.
Dezavantajul este că, în acest fel, nu se pot citi șiruri care conțin mai multe cuvinte
separate prin spații. Citirea șirului se sfârșește la întâlnirea primului caracter alb (de ex,
daca se citește “ora de informatica”, variabila c va reține numai “ora”).
Exemplu
char c[30];
cin>>c;
cout<<c;
c. Se poate folosi o funcție specială pentru citirea șirurilor de caractere, inclusă în biblioteca
string.h (varianta recomandată).
Exemplu
char a[30],x;int nr;
cin.get(a,nr,x);
Funcția cin.get citește un șir de caractere sau până când au fost citite nr-1 caractere, sau dacă
s-a întâlnit caracterul x. Al treilea parametru poate lipsi, caz în care el este implicit caracterul
’\n’ (new line). Sunt citite și caracterele albe, caracterul NULL este inserat automat, iar
caracterul transmis ca ultim parametru nu este inserat în șir.
Exemplu
char a[30];
cin.get(a,5,’s’); //daca se citește șirul “maimuta”, variabila a va reține “maim”
cin.get(a,15,’s’); //dacă se citește șirul “maimuta”, variabila a va reține “maimuta”
cin.get(a,15,’t’); //dacă se citește șirul“maimuta”, variabila a va reține “maimu”
cin.get(a,4,’t’); //dacă se citește șirul “maimuta”, variabila a va reține “mai”
cin.get(a,10); //daca se citește șirul “maimuta”, variabila a va reține “maimuta”
Funcția cin.get( ) fără parametri are rolul de a citi un caracter (alb sau nu).
Funcția cin.get(char c) are rolul de a citi un caracter (alb sau nu) pe care îl încarcă în variabila
c.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Exemplu
char a[30],b[30];
cin.get(a,15);
cin.get(b,10);
Dacă se încearcă citirea șirurilor „sarbatoare” și „vacanta”, se observă ca a=”sarbatoare”, b=””
(nici nu apucăm să citim șirul b). Varianta corectă este:
cin.get(a,15);
cin.get();
cin.get(b,10);
Funcția strlen
int strlen(nume_sir); – returnează lungimea efectivă a unui șir (fără a număra terminatorul de
șir).
Exemplu:
char a[50]=”ora de informatica”; strlen(a) = 18
Functia strcpy
strcpy(sir_destinatie,sir_sursa); – copiază șirul sir_sursa în sir_destinatie (se
simulează atribuirea a=b).
ATENTIE!! Nu este permisă atribuirea între două șiruri de caractere folosind operatorul =.
Atribuirea se face folosind funcția strcpy.
Exemplu:
char a[50]=”primul sir”,b[40]=”al doilea sir”;
a=b; //eroare
strcpy(a,b); a = ”al doilea sir”; b=”al doilea sir”;
Funcția strcat
strcat(dest,sursa); – adaugă șirului dest șirul sursa. Șirul sursa rămâne nemodificat.
Operația se numește concatenare și nu este comutativș.
Exemplu:
char *a=”vine ”,*b=”vacanta?”;
strcat(a,b); a = ”vine vacanta?”;
Funcția strncat
strncat(dest,sursa,nr); – adaugă dest primele nr caractere din șirul sursa. Șirul sursa
rămâne nemodificat.
Exemplu:
char *a=”vine ”,*b=”vacanta?”;
strncat(a,b,4); a = ”vine vaca”;
Funcția strchr
strchr(sir,c); – are rolul de a căuta caracterul c în șirul sir. Căutarea se face de la stânga la
dreapta, iar funcția întoarce adresa subșirului care începe cu prima apariție a caracterului c. Dacă
nu este găsit caracterul, funcția returnează 0. Diferența dintre adresa șirului inițial și cea a
subșirului returnat reprezintă chiar poziția caracterului căutat în șirul dat.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Exemplu:
char *a=”acesta este un sir”,b=’t’,c=’x’,d;
cout<<strchr(a,b); se tipareste ”ta este un sir”;
cout<<strchr(a,c); nu se tipareste nimic (se tipareste 0 daca se face o conversie la
int a lui strchr(a,c) ;
d= strchr(a,b);
cout<<”Caracterul apare prima data la pozitia ”<<d-a;
Funcția strrchr
strrchr(sir,c); – are același rol cu strchr, cu deosebirea că returnează adresa ultimei apariții
a caracterului (căutarea se face de la dreapta spre stânga; r = right)
Functia strcmp
int strcmp(sir1,sir2); – are rolul de a compara două șiruri de caractere. Valoarea returnată
este <0 (dacă sir1<sir2), =0 (dacă sir1=sir2) și >0 (dacă sir1>sir2). Funcția strcmp face
distincție între literele mari și cele mici ale alfabetului.
Obs: Funcția strcmp returnează diferența dintre codurile ASCII ale primelor caractere care nu
coincid.
Funcția stricmp
int stricmp(sir1,sir2); – are același rol cu strcmp, cu deosebirea cș nu face distincție între
literele mari și cele mici ale alfabetului (i = ignore).
Funcția strstr
strstr(sir1,sir2); – are rolul de a identifica dacă șirul sir2 este subșir al șirului sir1. Dacă
este, funcția returnează adresa de început a subșirului sir2 în șirul sir1, altfel returnează adresa
0. În cazul în care sir2 apare de mai multe ori în sir1, se returnează adresa de început a primei
apariții. Căutarea se face de la stânga la dreapta.
Funcția strtok
strtok(sir1,sir2); – are rolul de a separa șirul sir1 în mai multe șiruri (cuvinte) separate între
ele prin unul sau mai multe caractere cu rol de separator. Șirul sir2 este alcătuit din unul sau mai
multe caractere cu rol de separator.
Funcția strtok acționează în felul următor:
o Primul apel trebuie să fie de forma strtok(sir1,sir2); Funcția întoarce adresa primului caracter
al primei entități. După prima entitate, separatorul este înlocuit automat prin caracterul nul.
o Următoarele apeluri sunt de forma strtok(NULL,sir2); De fiecare dată, funcția întoarce adresa
de început a următoarei entități, adăugând automat după ea caracterul nul.
o Când șirul nu mai conține entități, funcția returnează adresa nulă.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Exemplu:
//Sa se separe cuvintele dintr-un text.
#include <iostream.h>
#include <conio.h>
#include <string.h>
void main()
{char text[100],cuv[10][10],*p,*r,separator[]=",. !?";int i=0,nr=0;
clrscr();
cout<<"Dati sirul:";cin.get(text,100);
strcpy(p,text);
p=strtok(p,separator);
while (p)
{strcpy(cuv[++nr],p);
p=strtok(NULL,separator);}
cout<<"Sunt "<<nr<<" cuvinte:"<<endl;
for (i=1;i<=nr;i++) cout<<cuv[i]<<endl;
getch();}
O structură este un ansamblu format din una sau mai multe variabile grupate
împreună sub un singur nume. Structurile se deosebesc de tablouri prin următoarele
aspecte:
o elementele unei structuri pot avea tipuri diferite,
o structurile pot fi atribuite,
o funcţiile pot returna structuri,
o elementele unui structuri nu sunt variabile anonime ci au câte un nume,
o referirea unui element al unei structuri se realizează cu operatorul de selecţie
( . ) şi nu cu operatorul de indexare ( [ ] ).
Dacă dorim să prelucrăm date referitoare la mai mulţi elevi, pentru fiecare elev trebuie
să cunoaştem:
Numele – char[20]
Prenumele – char[20]
Nota matematică - float
Nota informatică - float
Vârsta - int
În C++ există un tip de date, numit struct, care permite ca fiecărui elev să-i
corespundă o singură înregistrare.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Înregistrările imbricate
Putem avea un tip structurat ce conţine în interiorul său un alt tip structurat.
struct elev
{ char nume[20], prenume[20];
struct
{ int clasa;
float note[20];
} situatie;
int varsta;
};
Dacă inr este o variabilă de tipul elev. Atunci accesarea elementelor situate în
interiorul structurii se face astfel:
inr.situatie.clasa – se accesează câmpul clasa al substructurii
inr.situatie.note[0] – se accesează prima notă a vectorului inclus în substructură
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
IV. SUBPROGRAME
Definirea unei funcţii – este constituită dintr-un antet, care conţine numele funcţiei,
tipul rezultatului returnat de funcţie, lista parametrilor funcţiei şi un bloc de instrucţiuni,
care descrie prelucrările efectuate de funcţie.
Apelul funcţiilor
Apelul unei funcţii se poate realiza în două moduri – printr-o instrucţiune de apel
sau ca operand într-o expresie.
Instrucţiunea de apel a unei funcţii are următorul format general:
nume (lista_parametri_actuali);
unde nume reprezintă numele funcţiei, iar lista parametrilor actuali este formată dintr-o
succesiune de expresii separate prin virgulă.
Utilizăm instrucţiuni de apel atunci când funcţia apelată nu returnează nici o valoare
sau atunci când nu dorim să utilizăm valoarea returnată de funcţie, ci ne interesează doar
efectuarea prelucrărilor descrise de funcţie.
În cazul în care dorim să utilizăm valoarea returnată de funcţie, apelăm funcţia ca
operand într-o expresie.
La apelul unei funcţii, valorile parametrilor actuali sunt atribuite parametrilor
formali corespunzători. Parametri actuali trebuie să corespundă cu parametrii formali ca
număr, ordine şi tip.
Variabilele locale – sunt declarate în blocul unei funcţii, li se alocă memorie pe stivă,
memoria rămâne alocată până la sfârşitul execuţiei blocului în care este declarată variabila,
sunt vizibile numai în blocul în care sunt declarate.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Parametri transmişi prin valoare – au rolul de a transmite date din zona de program
în care s-a apelat funcţia înspre funcţie. Funcţia va memora aceste date pe segmentul de
stivă pus la dispoziţie. După terminarea execuţiei funcţiei, segmentul de stivă se eliberează
şi astfel programul nu mai are acces la variabilele memorate pe stivă. Din acest motiv
parametrii transmişi prin valoare nu pot transmite datele modificate în cadrul funcţiei
înspre zona de program de unde a fost apelată funcţia.
La apel, aceşti parametrii pot fi: valori, variabile, expresii şi chiar funcţii.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Liste liniare
O listă colecţie de elemente de acelaşi tip aflate într-o relaţie de ordine: x1, x2, … xn.
Caracteristica principală a listelor liniare în opoziţie cu tablourile unidimensionale, este aceea
că numărul de elemente nu este cunoscut de la început.
Deşi există posibilitatea implementării listelor cu ajutorul tablourilor unidimensionale, se
utilizează mai puţin acest mod de reprezentare. În practică, listele se implementează utilizând
alocarea dinamică a memoriei.
Operaţiile specifice prelucrării listelor:
- adăugarea unui element la sfârşitul listei
- inserarea unui element în listă
- accesul la un element al listei
- ştergerea unui element din listă
Pentru lista liniară vom reprezenta înlănţuirea elementelor listei memorate într-un tablou
unidimensional cu reutilizarea spaţiului eliberat în urma operaţiilor de ştergere. În cadrul fiecărui
element al listei vom memora două categorii de informaţii: informaţia utilă pe care o conţine
elementul listei şi indicele de tablou corespunzător elementului următor din listă. Un element al
listei astfel organizat se numeşte nod.
nod
În cadrul ultimului nod al listei, indicele care desemnează elementul următor are valoarea -1,
marcând astfel sfârşitul listei. Pentru gestionarea unei astfel de liste este necesar să memorăm
indicele primului nod din listă. Deoarece una dintre operaţiile posibile asupra unei liste liniare este
ştergerea unui nod, pot rămâne zone de memorie neutilizate ale tablourilor. Astfel se impune
gestionarea spaţiului liber al tabloului în scopul reutilizării lui. Pentru aceasta, vom folosi un
vector caracteristic s definit astfel:
1 dacă lista[i] - contine un nod al listei
s[i]
0 dacă lista[i] - nu contine un nod al listei
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
Stiva este o listă liniară care funcţionează după principiul ultimul intrat este primul ieşit
(LIFO).
Operaţiile ce se pot efectua asupra unei stive sunt:
- adăugarea unui element în vârful stivei
- extragerea unui element din stivă
Operaţiile ce se efectuează asupra unei stive se realizează numai la vârful stivei, prin urmare
este suficient să memorăm indicele nodului din vârful stivei într-o variabilă vf. Dacă vf este -1,
atunci vom spune că stiva este vidă.
Coada este o listă liniară ce funcţionează după principiul primul intrat este primul ieşit
(FIFO).
Operaţiile ce se pot efectua asupra unei cozi sunt:
- adăugarea unui element la sfârşitul cozii
- extragerea unui element din coadă
Pentru gestionarea unei liste liniare de tip coadă avem nevoie de două variabile: prim şi
ultim. Dacă prim > ultim atunci coada este vidă.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț
V. RECURSIVITATEA
Recursivitatea este una dintre noţiunile fundamentale ale informaticii. Utilizarea frecventă a
recursivităţii s-a făcut după anii '80. Multe dintre limbajele de programare evoluate şi mult utilizate
(Fortran, Cobol) nu permiteau scrierea programelor recursive.
Noţiunea de recursivitate din programare derivă în mod natural, din noţiunea matematică
cunoscută sub numele de recurenţă. O noţiune este definită recurent dacă în cadrul definiţiei apare
noţiunea care se defineşte.
În linii mari, recursivitatea este un mecanism general de elaborare a programelor. Ea a apărut din
necesităţi practice (transcrierea directă a formulelor matematice
recurente) şi reprezintă acel mecanism prin care un subprogram
(procedură, funcţie) se autoapelează.
Un algoritm recursiv are la bază un mecanism de gândire
diferit de cel cu care ne-am obişnuit deja. Atunci când scriem un
algoritm recursiv este suficient să gândim ce se întâmplă la un anumit
nivel, pentru că, la orice nivel, se întâmplă exact acelaşi lucru.
Un algoritm recursiv corect trebuie să se termine; contrar,
programul se va termina cu eroare şi nu vom primi rezultatul aşteptat.
Condiţia de terminare va fi pusă de programator.
Un rezultat matematic de excepţie afirmă că, pentru orice algoritm iterativ, există şi unul recursiv
echivalent şi invers. Pentru orice algoritm recursiv există şi unul iterativ echivalent.
Pentru a putea implementa recursivitatea, se foloseşte structura de date numită stivă.
Mecanismul unui astfel de program poate fi generalizat cu uşurinţă pentru obţinerea recursivităţii.
Atunci când un subprogram se autoapelează, se depun în stivă:
valorile parametrilor transmişi prin valoare;
adresele parametrilor transmişi prin referinţă;
valorile tuturor variabilelor locale (declarate la nivelul subprogramului).
Exemple:
2. Cea mai simplă şi mai familiară funcţie exprimată în termeni recursivi este factorialul:
n! = 1 dacă n=0 sau n! = n * (n - 1)! dacă n > 0.
unsigned long fact (int n)
{
if (n==0) return 1;
else return n * fact (n-1);
}
3. Şirul Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, ..., în care primii doi termeni sunt 0 si 1, iar, în rest,
fiecare termen se obţine însumând cei doi termeni care îl preced.
Prin urmare, o definiţie recursivă pentru şirul lui Fibonacci este:
fib: N -> N
fib(n) = n, dacă n<=1 şi fib(n) = fib(n-1) + fib(n-2), dacă n > 1.
Autoapelarea se poate realiza în două moduri: direct (în corpul funcţiei apare explicit un apel
recursiv) sau indirect (în corpul funcţiei apare apelul unei alte funcţii care, la rândul său, apelează direct
sau indirect funcţia respectivă).
Mecanismul care face posibilă recursivitatea derivă din modul de funcţionare a funcţiilor. Ca şi în
cazul oricărui apel de funcţie, şi în cazul funcţiilor recursive se alocă o zonă de memorie pe stivă pentru
valorile parametrilor, precum şi pentru valorile variabilelor locale. Această zonă de memorie rămâne
alocată pe tot parcursul execuţiei apelului funcţiei, fiind eliberată la momentul revenirii în funcţia
apelantă. Stiva nu este gestionată explicit de către programator, ci de către sistem.
Recursivitate
1. Se citeste un vector a cu n elemente numere naturale. Sa se calculeze elementul maxim
din vector. Se va folosi o functie recursiva pentru citire si una recursiva pentru determinarea
elementului maxim.
#include<iostream>
using namespace std;
int main()
{ int n,a[100];
cin>>n;
citire(a,n);
afis(a,n);
cout<<max(a,1,n);
system("pause");
return 0;
}
int max(int n)
{ if ( n <= 9 ) return n;
else
{
int m = max(n/10);
if ( m > n%10 )
return m;
else
return n%10; }}
int main(){
cout << max(23614);
system("pause");
return 0;}
int main(){
cout <<rast(23456,0);
system("pause");
return 0;
}
5. Sa se scrie o functie recursiva care calculeaza cate cifre are un numar natural.
#include<iostream>
using namespace std;
int main()
{ cout << NC(2405);
system("pause");
return 0;}
float suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + 1.0/n;}
int main(){
cout<<suma(5);
system("pause");;
return 0;
}
int suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + n*(n+1);}
int main(){
cout<<suma(3);
system("pause");;
return 0;}
int fib(int n)
{ if(n==1 || n==2) return 1;
else return fib(n-1)+fib(n-2);}
float suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + (float)fib(n)/n;}
int main(){
cout<<suma(5);
system("pause");;
return 0;}
int main(){
int n;
cin>>n;
cout<<suma(n);
system("pause");
return 0;}
int main(){
int n;
cin>>n;
cout<<putere(n);
system("pause");
return 0;
}
11.Sa se calculeze recursiv de cate ori apare o valoare intreaga x intr-un vector a cu n
elemente intregi.
#include<iostream>
using namespace std;
int a[100],n,x;
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>x;
cout<<nrap(n,x);
system("pause");
return 0;}
12. Sa se scrie o functie recursiva care numara cate vocale mici are un cuvant transmis ca
parametru.
#include<iostream>
float suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + (float)n/(n+1)+(float)(n+1)/n;}
int main(){
int a[100],n;
is>>n;
for(int i=0;i<n;i++)
is>>a[i];
bule_rec(a,n);
for(int i=0;i<n;i++)
os<<a[i]<<" ";
is.close();
os.close();
return 0;}
int main(){
int a[100],n;
is>>n;
for(int i=0;i<n;i++)
is>>a[i];
elev_rec(a,n,0,1);
for(int i=0;i<n;i++)
os<<a[i]<<" ";
is.close();
os.close();
return 0;}