Documente Academic
Documente Profesional
Documente Cultură
Definitie
Stiva este o structura de date, cu valori de acelasi tip, in care adaugarea (operatia PUSH) si extragerea de elemente (operatia POP) se realizeaza la varf.
Corelare
Cu termenul STIVA ne-am mai intalnit la expresia stiva de lemne, insa imaginea sugerata este una lipsita de ordine. Un cuvant care explica mai bine structura stivei, este cuvantul TEANC. Apare clar ideea ca elementele se suprapun unul altuia, in ordine. Un exemplu de folosire a ideii de stiva este construirea oglinditului unui numar natural. Fie n un numar natural. Sa se creeze numarul n2, numarul oglinda al lui n. (n=1972=> n2=2791). Ideea este de a lua cate o cifra de la sfarsitul lui n (POP) si a o adauga la sfarsitul lui n2 (PUSH). Observam ca atat n , cat si n2, se comporta ca si stive. n2=0; do {cif=n%10; //elementul din varful stivei N n2=n2*10+cif; // PUSH in N2 n=n/10; //POP din N } while (n!=0) //verific daca stiva N este vida cout<<n2;
Implementare
Din punct de vedere al implementarii, pentru reprezentarea in memorie a unei stive, putem folosi vectorul. Declararea unei stive vide: int stiva[100], ns=0; Operatia PUSH: cresc numarul de elemente; folosesc prima pozitie neocupata; ns++;cin>>stiva[ns]; Operatia POP: daca exista elemente in stiva, elimin elementul din varf (practic nu sterg elementul, ci doar il ignor) if (ns>0) ns;
311 impartit la 8 produce catul 38 si restul 7 38 impartit la 8 produce catul 4 si restul 6 4 impartit la 8 produce catul 0 si restul 4 Luam resturile in ordine inversa si obtinem NB=4672. Algoritmul de mai jos urmareste exact acest tip de calcul. Se observa ca pentru constructia lui NB trebuie sa lipim fiecare rest in fata numarului NB. citeste N10; NB=0; p10=1; cat timp(N10!=0) { NB=NB+P10*(N10%B); P10=P10*10; N=N/B; } scrie NB.
Practic trebuie sa calculam o suma de produse a cifrelor din NB cu puteri ale bazei. Vom folosi algoritmul de prelucrare a cifrelor unui numar (NB). citeste NB, B; N10=0; PB=1; executa{ N10=N10+(NB%10)*PB; PB=PB*B; NB=NB/10; }cat timp (NB!=0); scrie N10;
Pentru noi problema este de a determina al N-lea termen din sir. Daca N=1 sau N=2, raspunsul este simplu, 1. In restul cazurilor trebuie ca avand mereu ultimile valori A si B, sa calculam noua valoare C=A+B. citeste N; A=1;B=1; daca (N<=2) atunci scrie 1; altfel {pentru i=3,N executa {//calculam noua valoare C=A+B; //pregatim noua pereche A=B;B=C} scrie B;}
Varianta 1.
citeste A, B; cmmdc=0; pentru D=1 pana la A executa daca (A%D==0 si B%D==0 ) atunci cmmdc=D; scrie cmmdc; Practic, cmmdc-ul va fi cel mult unul dintre numere. As putea sa fiu prevazator si sa aleg ca limita superioara pe cel mai mic dintre A si B. Si conditia de numitor comun se poate rescrie A%D +B%D==0.
Varianta 2.
citeste A,B min=A; daca (min>B) atunci min=B; pentru D=1 pana la min executa daca (A%D +B%D==0) atunci cmmdc=D; scrie cmmdc;
Varianta 3.
Problema nu e noua, Euclid (cca 325 265 .Hr.!!!!!) s-a gandit si el la acelasi lucru si a gasit o solutie.
OBS. M-am gandit de multe ori cum sa explic elevilor ce anume l-a facut pe Euclid sa se gandeasca la problema cmmdc si mi-am imaginat urmatorul scenariu: Euclid avea o camera de latime A si lungime B pe care sotia lui vroia sa o acopere cu placi patrate de gresie. Pentru a-si impresiona prietenele, placile trebuiau sa acopere integral suprafata camerei si sa fi cat mai mari. Cum a rezolvat Euclid problema? Practic trebuie desenat un caroiaj cu patrate de latura CMMDC. Daca D este divizorul comun a lui A si B, atunci estista A2 si B2 asa incat: A=D*A2 B=D*B2 si deduce ca si diferenta acestor numere are acelasi divizor comun A-B=D*(A2-B2)
Practic, in lenea lui de a calcula cmmdc(A,B), Euclid propune mereu o pereche mai mica (A -B, B) daca A>B sau (A, B-A) daca B>A. Deci, cmmdc(A, B) este (A-B, B) daca A>B (A, B-A) daca B>A A daca A==B
Se observa ca in primele doua cazuri trebuie sa reluam algoritmul, ceea ce ne duce cu gandul la urmatoarea secventa: citeste A,B cat timp (A!=B) executa daca (A>B) atunci A=A-B; altfel B=B-A; scrie A;
Varianta 4.
Deci varianta 3 e de acum 2000 de ani! Intre timp, s-a mai facut o varianta. Daca A=23456 si B=89 ar trebui sa se efectueze o multime de scaderi a lui B din A. Scaderi repetate, pana nu se mai poate scadea pe B din A! Asta este o impartire si ce ramane in A este restul. In consecinta, pe cel mai mare il vom transforma in restul impartirii. Cand ne oprim? Ne vom opri cand A sau B vor fi nule, ceea ce inseamna ca cealalta valoare, nenula, va fi CMMDC.
citeste A,B; cat timp (A*B!=0) executa //daca nici unul nu e nul. daca (A>B) atunci A=A%B; altfel B=B%A; scrie A+B; //afisez valoarea nenula Varianta 5. Desi varianta 4 e o solutie respectabila, inca nu e de ajuns. Practic, la fiecare iteratie se executa 2 teste cel din CAT TIMP si cel din DACA. Varianta urmatoare foloseste aceeasi idee de mai sus dar elimina unul din teste. citeste A,B; cat timp (B!=0) executa {R=A%B; A=B; B=R;} //se iese cand B este nul=> scrie A; Analiza variantelor Evident, ultima varianta este cea mai buna. Am explicat deja ratiunile prin care s-a trecut de la o varianta la alta. In vederea examenului de bacalaureat va trebuie toate variantele, indeosebi ultima pentru momentul cand va trebui sa programati.
Calculul CMMMC
Pentru calculul matematic a cmmdc pentru doua numere A si B, se realizeaza descompunerea in factori primi si apoi se considera termenii comuni, la puterea cea mai mica. Pentru calculul matematic a cmmmc pentru doua numere A si B, se realizeaza descompunerea in factori primi si apoi se considera termenii comuni si necomuni, la puterea cea mai mare. Practic daca as scrie produsul A*B ca inmultire intre descompunerile lor, as observa ca toti termenii existenti sunt fie parte a CMMDC, fie parte a CMMMC. De aici apare si relatia A*B=CMMDC(A,B)*CMMMC(A,B). Practic ne vom folosi de CMMMC(A,B)=A*B/CMMDC(A,B). citeste A,B A2=A; B2=B; //salvez separat datele initiale //calculez CMMDC cat timp (B!=0) {R=A%B; A=B; B=R;} //afisez CMMMC scrie CMMMC este , A2*B2/A.
Simularea instructiunii CAT TIMP EXECUTA cu EXECUTA CAT TIMP. Instructiunea CAT TIMP EXECUTA intai testeaza si apoi executa; daca comparam secventele de executie observam ca la CAT TIMP EXECUTA intai apare un test/conditie. si apoi este identica cu EXECUTA CAT TIMP; nu ramane decat sa folosim o instructiune de test pentru aceasta conditie;
Observati ca pentru transformarea unei instructiuni cat timp in una executa cat timp, nu trebuie dacat sa identificati conditia si secventa care se repeta; apoi copiati corespunzator in sablon. Simularea instructiunii EXECUTA CAT TIMP cu CAT TIMP EXECUTA .
citeste N; pentru D=1, N executa daca (N%D==0) atunci { scrie D; NR=NR+1} scrie NR;
Cu numarul de divizori putem stabili daca numarul N este prim.
In aceasta varianta se executa, in cel mai rau caz, N/2 operatii. Super! Am redus munca la jumatate! Se poate mai bine? Varianta 3. Sa cercetam, in continuare, perechile de potential divizori: 2 cu N/2, 3 cu N/3, 4 cu N/4, . Observ ca pe masura ce primul termen creste, al doilea scade. Deduc ca, la un moment dat cei doi termeni pot fi egali. Adica ar putea fi un element X astfel incat N==X*X sa fie adevarat! In consecinta X=radical(N) . Deci ultima pereche care ar trebui studiata este cea cu radical (N). D=2; cat timp (D<=radical(N) si N%D!=0) executa D=D+1; daca (N%D==0) atunci scrie divizibil altfel scrie prim Este cert ca radical(N)<N/2. Iata ca am obtinut un numar mai mic de operatii. Sa cercetam cat de eficienti sunt algoritmii nostri. Numarul N=611953 este prim, spun unii. varianta 1 va executa maxim 611951 pasi varianta 2 va executa maxim 305 976 pasi
E ceva, nu?
Varianta 4. Si inca mai merge daca (N==2) atunci scrie prim altfel daca (nN%2==0 ) atunci scrie divizibil altfel { o D=3; o cat timp (D<=radical(N) si N%D!=0) executa D=D+2; o daca (N%D==0) atunci scrie divizibil o altfel scrie prim } Algoritmul de mai sus verifica daca N este 2 si elimina din discutie numerele pare. Pentru ca majoritatea numerelor prime sunt impare, parcurg numai valorile impare si le intreb daca nu cumva sunt divizori pentru N. Varianta 4 va efectua maxim 390 pasi pentru N=611953.
citeste X; //prelucrez X
........ }
citeste x; cat timp (x!=0) { //prelucrez valorea X ......... //trec la valoarea urmatoare citeste X }
Probleme
1. 2. 3. 4. 5. Sa se calculeze suma/produsul valorilor din sir Sa se determine valoarea minima/maxima dintre valorile citite. O valoare data Y se gaseste in sir? De cate ori apare o valoare data Y? Presupunand ca sirul reprezinta coeficientii uni polinom ( dati incepand cu gradul cel mai mic), calculati valoarea polinomului intr-un punct Y.
In prelucrarea cifrelor numarului, cel mai usor ajungem la ultima cifra (N%10) . Dupa prelucrarea ei, ultima cifra va trebui inlaturata (N=N/10). Si totul trebuie repetat cat timp N mai are cifre (N!=0). De vreme ca nu stim cate cifre are N, nu putem folosi intructiunea FOR/PENTRU. Raman instructiunile repetitive cu un numar necunoscut de pasi : CAT TIMP EXECUTA/WHILE si EXECUTA CAT TIMP/ DO WHILE. Pentru CAT TIMP EXECUTA/WHILE am un contraargmuent. Algoritmul ar trebui sa fie
cat timp (N!=0) executa { //prel ultima cifra a lui N .......N%10; //stergem ultima cifra N=N/10; }
Daca utilizatorul doreste sa aplice algoritmul pentru valoarea zero, nu se va efectua nimic si secventa noastra nu se va executa.Evident, situatia se poate evita prin plasarea unui test inainte de CAT TIMP , care sa verifice daca N este nul. Nu ramane decat varianta cu EXECUTA CAT TIMP/DO WHILE.
executa{ //prel ultima cifra a lui N .......N%10; //stergem ultima cifra N=N/10; } cat timp (N!=0);
Cateva probleme clasice pentru acest algoritm: 1. 2. 3. 4. 5. 6. 7. 8. Sa se numere cate cifre are numarul N Sa se stabileasca cate cifre pare/impare are numarul N. Sa se stabileasca daca N contine o cifra data, CIF. Sa se numere de cate ori apare cifra CIF in numarul N. Sa se determine cifra maxima/minima din numarul N Sa se construiasca oglinditul numarului N. Pentru N=3648 se va afisa 8463. Sa se stabilesca daca N este palindrom (egal cu oglinditul sau). Pentru un numar N dat, sa se construiasca cel mai mare numar natural care se poate forma cu cifrele lui N.
cat timp (N!=0) executa { //prel ultima cifra a lui N .......N%10; //stergem ultima cifra
N=N/10; }
Sintaxa: PENTRU contor<-exp_init,exp_fin EXECUTA instructiune Efect: pentru fiecare valoare a contorului intre expresia initiala si expresia finala se executa instructiunea;
Exemplu: pentru i <- 1,10 executa scrie Nu ma prinzi!; pentru fiecare valoarea a variabile i, de la 1 la 10, se afiseaza Nu ma prinzi! de 10 ori se afiseaza Nu ma prinzi! daca secventa ce trebuie repetata contine mai multe instructiuni, acestea se vor grupa cu acolade Observatii: practic, pentru fiecare valoare a lui i, intai se testeaza daca nu s-a depasit valoarea finala 10 si apoi se executa instructiunea; algoritmic, propozitia de mai sus este : o i<-1; cat timp (i<=10) {scrie Nu ma prinzi!; i<-i+1; }; practic , secventa de mai sus me explica faptul ca instructiunea pentru este o clona a instructiunii cat timp. instructiunea este ceruta daca descrierea algorimului spune de la valoarea X la valoarea Y, pentru primele X valori, de X ori,
Exemplul 1. Sa se afiseze numerele pare pana la o valaore N, naturala. intreg n,i; citeste n; pentru i<- 0,n executa daca (i%2==0) atunci scrie i. Observatii: algoritmul ia fiecare valoare intre 0 si n si o testeaza daca este para (restul impartirii lui i la 2 sa fie nul : i%2==0) se efectueaza n pasi din care jumatate sunt gresiti; trebuie o varianta mai buna
Exemplul 2. Aceeasi problema dar incercam sa mergem din doi in doi intreg n,i; citeste n; pentru i<-0,n,2 executa scrie i. intreg n,i; citeste n; pentru i<-0,n/2 executa scrie i*2.
o o
Observatie: in primul caz, 2-ul de dupa n (i<-0,n,2 ) stabileste cresterea lui i cu 2 si nu cu 1 asa cum este implicit in al doilea caz, ne folosim de faltul ca valorile cautate sunt pare, divizibile cu 2;
Exemplul 3 Sa se calculeze suma primelor N numere naturale. o evident, stim formula n*(n+1)/2 dar sa incercam un algoritm; o va trebui sa adunam, la o suma , toate valoarile de la 1 la n intreg n,i,suma; citeste n; suma<-0; pentru i<- 0 ,n executa suma<- suma +i; scrie suma. Exemplul 3. Se citeste un sir de N valori intregi. Sa se determine cea mai mare valoare citita (valoarea maxima dintr-un sir). intreg n,i,max,val; citeste n;
citeste max; pentru i<-2,n executa {citeste val; daca val>max atunci max<-val;}; scrie val.
INSTRUCTIUNEA FOR
Exista trei instructiuni (structuri) repetitive folosite in toate limbajele: instructiunea repetitiva cu test initial CAT TIMP (WHILE) (se foloseste cand numarul de repetitii este nedefinit) instructiunea repetitiva cu test final REPETA-PANA CAND (DO WHILE sau REPEAT) (se foloseste cand numarul de repetitii este nedefinit) instructiunea repetitiva cu un numar cunoscut de pasi PENTRU (FOR) (se foloseste cand numarul de repetitii este cunoscut - un numar fix de ori.)
Sintaxa: FOR(initializare; test final; pasul urmator) instructiune; for (i=A; i<=B; i++) {secventa de repetat} for (i=1; i<=n; i++) {secventa de repetat} Efect: pentru fiecare valoare a contorului i intre expresia initiala si expresia finala se executa instructiunea; Exemplu: for (i=1; i<=n; i++) cout<< Nu ma prinzi!; pentru fiecare valoarea a variabilei i, de la 1 la N, se afiseaza Nu ma prinzi!; de N ori daca secventa ce trebuie repetata contine mai multe instructiuni, acestea se vor grupa cu acolade Observatii: instructiunea este ceruta daca descrierea algorimului spune de la valoarea X la valoarea Y, pentru primele X valori, de X ori,