Calculatorul, considerat de mulți cea mai mare invenție a secolului al XX-lea, influențează într-un mod sau altul viețile noastre. Este folosit… [308711]
[anonimizat] a [anonimizat], [anonimizat]. [anonimizat], [anonimizat].
Evoluția calculatoarelor a făcut posibilă creșterea capacității de memorare și prelucrarea mai eficientă și mai rapidă a informațiilor. [anonimizat], [anonimizat] ’95, [anonimizat] a acestora. [anonimizat]-[anonimizat], aplicații grafice dinamice și comerț pe Internet. [anonimizat] a [anonimizat] o mulțime de probleme. [anonimizat] a fost integrat și a devenit un instrument indispensabil în multe instituții și întreprinderi.
[anonimizat], dezvoltă gândirea și contribuie la formarea caracterului și a personalității. [anonimizat], dezvoltă și provoacă o analiză progresivă a detaliilor, o rezolvare în context general a problemelor particulare. [anonimizat], diferită de gândirea teoretică și abstractă. [anonimizat] a unui mod de lucru ordonat are consecințe deosebite în evoluția viitoare a elevului.
Se dorește formarea la elevi a [anonimizat]. [anonimizat], [anonimizat].
Scopul acestei lucrări este de a propune o metodă de predare a recursivității în liceu bazată pe folosirea unei platforme de e-Learning. Designul platformei este original. Deși în prezenta lucrare m-[anonimizat], platforma poate fi folosită pentru orice alt conținut.
[anonimizat] o parte, [anonimizat]-a lungul celor 15 ani de predare a [anonimizat]. [anonimizat], prin prezentarea cărora se poate mări motivația elevilor pentru studiul acestei teme și a informaticii în ansamblu.
La liceu studiul algoritmilor și programării se începe cu structurile iterative. Iterația este execuția repetată a [anonimizat] o condiție. [anonimizat].
Deși rezolvarea problemelor în liceu se face la început în mod iterativ, o teoremă de bază a programării stucturate afirmă că pentru orice algoritm iterativ care rezolvă o problemă, există un algoritm recursiv echivalent cu el care rezolvă aceeași problemă. [22] În cazul recursivității rezolvarea problemei se face prin autoapelarea algoritmului (funcției) până la satisfacerea unei condiții de oprire.
Recursivitatea are multe aplicații practice, care pot să capteze atenția elevilor și să crească motivația, dar are și o parte științifică consistentă și interesantă atât din punctul de vedere al profesorului, cât și al elevului. Pe de altă parte, având aplicații practice interesante se pretează a fi studiate și la clase cu alt profil nu doar la cele de profil informatică și poate chiar să constituie un opțional la decizia școlii și la clase de profil științe ale naturii și chiar și la clase de filologie.
Recursivitatea oferă un plus de claritate problemelor, iar programele au dimensiuni reduse. Datorită faptului că la fiecare autoapel se ocupă o zonă de memorie, recursivitatea este eficientă numai dacă numărul de autoapelari nu este prea mare pentru a nu se ajunge la umplerea zonei de memorie alocată, caz în care programul se va termina cu eroare. Recursivitatea presupune mai multă memorie în comparație cu iterativitatea, dar ținând cont că apelurile se fac într-o zonă rezervată de memorie, problema memoriei necesare pentru autoapelare nu constituie un dezavantaj major al programelor recursive față de cele iterative.
Să ne imaginăm un copac. Fiecare ramură a copacului este formată din alte ramuri, la rândul lor formate din ramuri din ce în ce mai mici până când ajungem la cele mai mici ramuri. Acestea sunt formate dintr-o tulpină și mai multe frunze. Am descris ramura unui copac folosind-ne de aceeași noțiune, ramura, până când am ajuns la cele mai mici elemente care o descriu, tulpina și frunzele.
Ca exemplu de recursivitate să considerăm structura de arbore. Un arbore binar este format dintr-o mulțime de noduri care are proprietatea că un nod este rădăcina arborelui, iar celelalte se împart în două submulțimi care la rândul lor sunt arbori. Arborele se definește prin intermediul lui însuși.
Arborele genealogic îl putem folosi pentru a defini conceptul de strămoș al unei persoane:
Un părinte este strămoșul copilului. (”Baza”)
Părinții unui strămoș sunt și ei strămoși (”Pasul de recursie”).
Dacă Y este copilul lui X, iar Y are ca fiu pe Z, pentru a verifica dacă Z este descendent al lui X va trebui să verificăm dacă Z este descendent al lui Y. Apelăm, deci, din nou la definiție, însă pentru o altă persoană, mai apropiată de X, și anume copilul și nu nepotul. [43]
În aplicațiile pe calculator una din cele mai cunoscute utilizări ale structurii de arbore este la organizarea sistemului de fișiere: fișierele sunt păstrate în directoare (numite uneori și foldere) care sunt definite recursiv ca secvențe de directoare și fișiere. Această definiție recursivă reflectă o descompunere natural recursivă și este identică cu definiția unui anumit tip de arbore.
Aplicații ale recursivității se găsesc și în fizică. De exemplu mișcarea oscilatorie amortizată sau graficul efectului Doppler. Efectul Doppler apare atunci când un obiect în mișcare trece pe lângă urechea umană. La apropierea de ureche, intensitatea sunetului scade, acest lucru semănând cu autoapelurile efectuate în recursivitate până la atingerea condiției de adâncime. Odată trecut de urechea umană sunetul crește în intensitate. În informatică acest lucru seamănă cu revenirea repetată în subprogramul inițial. [44]
În politică și sociologie, este o combinație de tactici (politice, militare sau economice – dezbină și stăpânește) de câștigare și menținere a puterii prin divizarea unei populații în entități mai mici care luate separat au putere mai mică decât cel care își impune voința. Este deseori întâlnită ca o strategie în care grupuri de putere mică sunt împiedicate să se unească și să devină mai puternice. Folosită efectiv, această strategie permite celor cu putere reală puțină să-și impună voința asupra celor care colectiv au putere mare (sau ar avea dacă ar reuși să se unească). Expresia este atribuită lui Filip al II-lea, rege al Macedoniei (382-336 Î. C), descriind politica sa împotriva orașelor state grecești. Această strategie necesită multă îndemânare și finețe politică. [31]
Fenomenul recursiv apare și în muzică, în toate creațiile muzicale prin repetarea elementelor componente ale acestora. Se reliefează mai mult sau mai puțin în funcție de genul lor. De exemplu pseudofabula ”Într-o nu știu care seară” cântată de formația Rosu și Negru. În melodii precum binecunoscutul cântec folcloric Ciuleandra, interpretat de Maria Tănase, recursivitate se evidențiază prin ritmul schimbat al acestuia, ritm ce pornește încet și se accentuează pe parcurs.
În literatura română, recurența are sensul de revenire. Prin povestirile în ramă, înțelegem una sau mai multe suite de narațiuni independente, înrudite tematic și depănate în temeiul unei învoieli sau al unei convenții dintre niște emițători și receptori mai mult sau mai puțini numeroși. O poveste într-o poveste, este o tehnică literară. În acest caz, povestea din interior are adesea o semnificație simbolică și psihologică pentru personajele poveștii din exterior. Există adesea o paralelă între cele două povești și ficțiunea din povestea interioară este folosită pentru a dezvălui adevărul în povestea exterioară. [44]
Un alt exemplu elocvent pentru recursivitate este reprezentat de fractali. Aceste obiecte afișează o structură auto-similară la o scară mare, dar finită. Fractalii prezintă anumite avantaje datorită cărora sunt folosiți în economie în simularea tendinței prețurilor bunurilor de consum, dar și în astronomie și metrologie, chimie și fizică.
În religie fractalul este socotit una din cheile de acces la „codul sursă” al creației lui Dumnezeu. Fractali aproximativi sunt ușor de observat în natură. Exemplele includ norii, fulgii de zăpadă, cristalele, lanțurile montane, fulgerele, rețelele de râuri, conopida sau brocoli.
Un alt exemplu celebru cu multe aplicații practice îl reprezintă șirul lui Fibonacci, definit recursiv prin relația Xn+1=Xn+Xn-1 cu X0=X1=1. Aranjamentul frunzelor unor plante este dispus într-o secvență Fibonacii în jurul tulpinii. Arborii, ferigile și alte plante sunt fractali și pot fi modelați pe calculator folosind un algoritm recursiv. „Natura recursivă este evidentă în aceste exemple – o ramură a unui arbore sau o frunză a unei ferigi este o copie în miniatură a întregului: nu identice, dar similare: structura cepei, dacă învelișul exterior este îndepărtat, sub acesta vom găsi o ceapă similară, petalele margaretelor, semințele florii soarelui. Pornind de la așezarea semințelor florii soarelui, Cristobal Vila arată cum există o multitudine de cercuri care se interesectează. În aceste cercuri se înscriu triunghiuri echilaterale care au vârfurile pe cerc. Șase triunghiuri laterale alăturate formează un hexagon. Apoi trasează o perpendiculară pe latura comună a triunghiurilor. Punctele în care se intersectează acest șase perpendiculare formează un nou hexagon. Acest hexagon alăturat altuia de lângă el, format prin aceeași metodă, și apoi alăturat celui de-al treilea, apoi celui de-al patrulea, și tot așa, formează structura aripilor unui fluture. Conexiunile geometrice ar putea continua la nesfârșit trecânt prin toată creația, de la cele mai mici detalii până la cele mai mari. Toată natura respectă regula de creștere a șirului lui Fibonacci.”[45]
Spirala cochiliei unui melc urmărește dimensiunile date de secvența lui Fibonacci.
Corpul uman respectă, de asemenea, șirul lui Fibonacci. Sistemul de vase sanguine și vase pulmonare, structura plămânilor prezintă un model recursiv, mâna umană are 5 degete, fiecare deget având 3 falange separate prin 2 încheieturi. În medie, dimensiunile falangelor sunt 2, 3 și 5 cm, în continuarea lor este un os al palmei care are în medie 8 cm. [45]
Păpușa Matrioșka este o jucărie din lemn, o păpușă viu colorată, goală pe interior, în care sunt introduse alte păpuși, mai mici, identice. Sunt, de asemenea, folosite metaforic, ca și model de design, cunoscute drept „principiul matrioșcei” sau „principiul păpușii cuibărite”. Acestea sunt un exemplu de obiect într-un alt obiect similar, care apare în design-ul multor obiecte naturale sau create de om, de designeri, spre exemplu în stratificarea hainelor sau design-ul unor mese, unde o masă mai mică este așezată pe alta mai mare ș.a.m.d.
Matematicienii folosesc termenul de recursivitate în sintagma ”formulă de recurență”, care are sensul de formulă care exprimă un termen dintr-un șir, în funcție de valorile altor termeni anteriori.
Am încercat să combin teoria și algoritmii, într-o platformă e-Learning pentru instruire și formare. Aceasta permite predarea, învățarea, evaluarea elevilor, precum și accesarea teoriei, a exercițiilor rezolvate, a problemelor, a fișelor de lucru și a testelor.
Învățarea prin e-Learning se bazează pe o predare modernă, într-o altă modalitate decât cea clasică, mult mai atractivă și specifică atât nevoilor profesorilor, cât mai ales a elevilor și în care un rol important îl au fixarea cunoștințelor și evaluarea acestora.
O platformă de e-Learning este un soft complex care permite administrarea unui domeniu (subdomeniu), gestionarea utilizatorilor pe domeniul respectiv, crearea și un management accesibil al cursurilor împreună cu activitățile și resursele asociate acestora, evaluarea online/offline sau autoevaluarea, comunicarea sincronă sau asincronă și multe altele. Aceasta presupune o învățare prin colaborare, bazată pe proiecte și sarcini individuale și de grup. Astfel, învățarea devine eficientă când profesorul construiește un material de învățare, pentru ca elevii săi să interacționeze cu acest material de învățare și să experimenteze, pentru a înțelege. În acest context, elevul este parte a unei comunități de învățare, în care este pus în situația de a înțelege ce are de făcut, de a explica celorlalți și de face împreună. [29]
E-Learning-ul implică interacțiunea unui complex de factori: mediul educațional, metode de învățare, tehnici IT având ca scop creșterea performanțelor celor care folosesc platforma de e-Learning în procesul de învățare.
Lucrarea prezintă și propune un site ușor de vizualizat făcut pentru înțelegerea mai bună a recursivității, prin metode interactive de învățare și aplicare a noțiunilor teoretice, prin rezolvare de exerciții. Pe de altă parte, această aplicație este și un ajutor pentru profesor, ușurând munca de predare și evaluare a elevilor.
De asemenea, ținând cont de faptul că elevii petrec tot mai mult timp în fața calculatorului și mulți dintre ei sunt pasionați de construirea de pagini Web, este importantă motivarea elevilor să combine utilul cu plăcutul și să se familiarizeze cu tehnologiile, metodele și instrumentele cu ajutorul cărora pot construi site-uri de Internet cât mai atractive și mai dinamice.
Am încercat să aplic cât mai multe metode pentru dinamizarea paginilor Web, pentru a face și legătura între programarea în C++, care se învață la ora actuală în cadrul orelor de curs din liceu și programarea necesară în JavaScript, pentru a face comparații între ele, asemănări și deosebiri, pentru provocarea elevului de a învăța și partea de algoritmică.
CAPITOLUL 1. PARTEA ȘTIINȚIFICĂ
Scopul acestui capitol este de a face o sinteză a principalelor caracteristici ale recursivității și programelor recursive, precum și de a prezenta exemple de utilizare a recursivității în diversele tehnici de programare și în probleme care folosesc arbori și grafuri. Fractalii sunt un exemplu care ilustrează folosirea recursivității și acestea sunt de asemenea prezentate succint în acest capitol.
Pentru elaborarea acestei părți am făcut o sinteză din lucrările [03, 10, 11, 13, 14, 15, 22, 24, 27].
Menționez că toate aceste noțiuni prezentate se regăsesc în platforma despre recursivitate pe care am proiectat-o și care reprezintă partea originală a acestei lucrări.
1. 1. Principiul recursivității
În informatică și matematică, recursivitatea este un concept fundamental.
Recursivitatea, folosită cu multă eficiență în matematică, s-a impus în programare, odată cu apariția unor limbaje de nivel înalt, ce permit scrierea de module ce se autoapelează (PASCAL, LISP, ADA, ALGOL, C sunt limbaje recursive, spre deosebire de FORTRAN, BASIC, COBOL, nerecursive).
Dacă iterația e execuția repetată a unei porțiuni de program, până la îndeplinirea unei condiții (while, repeat, for), recursivitatea presupune execuția repetată a unui modul, însă în cursul execuției lui (și nu la sfârșit, ca în cazul iterației), se verifică o condiție a cărei nesatisfacere, implică autoapelarea modulului de la începutul său.
În programare, recursivitatea este exprimată cu ajutorul funcțiilor, deoarece ele se identifică printr-un nume care este specificat apoi în apeluri.
O funcție este recursivă dacă apelul său apare când funcția este activă (lansată în execuție). Funcția rămâne activă până la încheierea execuției sale, chiar dacă între timp se mai activează și alte funcții.
Idea de recursivitate a unei funcții se bazează pe posibilitatea de a întrerupe execuția funcției pentru un anumit set de parametri pentru a începe o nouă execuție cu un alt set de parametri. Acest sistem de întrerupere se desfășoară în lanț până în momentul în care setul de parametri are o anume configurație particulară. Atunci se încheie execuția funcției pentru ultimul apel și apoi se revine în ordine inversă pentru a continua execuția funcțiilor întrerupte.
Recursivitatea constă în execuția repetată a unei secvențe de program, dar verificarea condiției de terminare se face în timpul execuției și nu la sfârșitul secvenței, iar în cazul în care condiția de terminare nu se verifică, porțiunea de program se apelează din nou ca o funcție, în particular ca o procedură a blocului care încă nu și-a terminat execuția când condiția de terminare este verificată se reia execuția din locul în care procedura s-a autoapelat. O funcție se poate autoapela recursiv, în cazul în care se autoapelează trebuie să existe o condiție de terminare, în caz contrar se intră în ciclul infinit. În general, la apelul unei funcții se creează un set de elemente locale acesteia, elemente ce sunt recunoscute doar în interiorul funcției. În cazul în care o astfel de funcție se autoapelează se creează un nou set de variabile locale diferite de cele corespunzătoare apelului anterior. La fiecare apel de funcție trebuie alocată o zonă de memorie pentru variabilele locale ale acesteia și trebuie reținută și adresa sau instrucțiunea din cadrul funcției de la care se va relua execuția în cazul terminării recursivității.
O soluție recursivă este eficientă numai dacă numărul de autoapeluri nu este mare. Structurile de program necesare și suficiente în exprimarea recursivității sunt procedurile și subrutinele ce pot fi apelate prin nume.
Dacă apelul apare în instrucțiunea compusă a funcției, deci conține o referință la el însuși, recursivitatea se numește directă. Dacă apelul apare în instrucțiunea compusă a altei funcții care se apelează din prima funcție, recursivitatea se numește indirectă.
Recursivitate directă Recursivitate indirectă
Ex: int A(…) void B(…); void A(…)
{ …… void A(…); { …… B(…)……..}
A(…)…..} void main() void B(…)
{….} {……. A(….)……}
Exemplul 1: Exemplu de recursivitate directă: Să se calculeze suma primelor n numere naturale. S=1+2+3+…+n, definită prin relațiile: S0=0; Sn= Sn-1 + n, pentru n>=1.
Suma numerelor naturale (inițial suma este zero, apoi suma(n) este suma primelor n-1 adunate cu n):
ITERATIV RECURSIV
int suma(int n) int suma(int n)
{ {
int s=0; if(n= =0)
for(int i=1; i<=n;i++) return 0;
s = s + i; else
return s; } return suma(n-1)+n; }
Se observă că recurența este realizată prin autoapelul funcției suma. Pentru aceasta sunt necesare 2 elemente: formula de recurență Sn= Sn-1+n care este cazul general al soluției: return suma(n-1)+n; și o valoare inițială cunoscută (condiția de terminare = inițializarea) S0 = 0, cazul de bază al soluției: return 0. Este obligatoriu să existe o condiție de oprire a repetiției. Cele două cazuri se combină folosind o structură alternativă if…else. Condiția de oprire a recurenței este exprimată printr-o expresie logică ce trebuie să depindă de parametri funcției sau de variabilele locale (ex: n=0), se trece de la cazul general la cazul de bază, deci trebuie să se asigure condiția de ieșire din recurență: condiția de consistență (suma(n-1)).
Exemplul 2: Exemplu de recursivitate indirectă: Să se calculeze termenii șirurilor (a) și (b) definite prin: a0=a, b0=b, (a,b>0),
float a(int);
float b(int);
int n, a0, b0;
int main()
{ cout<<”a=”; cin>>a0;
cout<<”b=”; cin>>b0;
cout<<”n=”; cin>>n;
cout<<”b(”<<n<<”)=”<<b(n)<<endl;
cout<<”a(”<<n<<”)=”<<a(n)<<endl; }
float b(int n)
{ if(n==0)
return b0;
else
return sqrt(a(n-1)*b(n-1)); }
float a(int n)
{ if(n==0)
return a0;
else
return (a(n-1)+b(n-1))/2.0; }
Pentru a calcula termenul de rang n din șirul a sunt necesari termenul de rang n-1 din șirul a, dar și termenul de rang n-1 din șirul b. Deci funcția care calculează termenii șirului a, folosește recursivitate directă, iar pentru calcularea termenilor șirului b, se folosește recursivitate indirectă.
Apelul recursiv al unei funcții face ca pentru toți parametri-valoare să se creeze copii locale apelului curent (în stivă), acestea fiind referite și asupra lor făcându-se modificările în timpul execuției curente a funcției. Când execuția funcției se termină, copiile sunt extrase din stivă, astfel încât modificările operate asupra parametrilor-valoare nu afectează parametri efectivi de apel, corespunzători.
De asemenea pentru toate variabilele locale se rezervă spațiu la fiecare apel recursiv. În cazul parametrilor-variabilă, nu se crează copii locale, ci operarea se face direct asupra spațiului de memorie afectat parametrilor efectivi, de apel.
Pentru fiecare apel recursiv al unei funcții se crează copii locale ale parametrilor valoare și variabilelor locale, ceea ce poate duce la risipa de memorie; iar orice parametru-variabilă poate fi suprimat prin referirea directă în funcție a variabilei ce figura ca parametru de apel.
Principiul recursivității afirmă că orice program recursiv poate fi transformat în unul iterativ, dar algoritmul său poate deveni mai complicat și mai greu de înțeles. De multe ori, soluția unei probleme poate fi elaborată mult mai ușor, mai clar și mai simplu de verificat, printr-un algoritm recursiv. Varianta recursivă poate duce la o viteză de execuție și spațiu de memorie prea mari, iar transformarea în una nerecursivă, elimină aceste dezavantaje.
Recursivitatea în cascadă este un tip de recursivitate care trebuie evitat, fiind de dorit o implementare iterativă în acest caz. Un exemplu tipic este șirul lui Fibonacci:
Xn-1 = Xn + Xn-1, X0 = X1 = 1. De exemplu, pentru calculul lui X10, se observă că se repetă calculul termenilor de rang mai mic decât 10 de mai multe ori, ducând la un timp de execuție exponențial.
Implementarea recursivă pentru calculul termenului n a șirului lui Fibonacci este dată în exemplul următor :
Exemplul 3: Șirul lui Fibonacci. a) Aflarea termenului n. b) Aflarea primilor n termeni ai șirului lui Fibonacci.
int fibo(int n)
{ if(n<=1)
return n;
else
return fibo(n-1)+fibo(n-2); }
int main ()
{ int n;
cin>>n;
cout<<fibo(n); //termenul n
for(i=0;i<n;i++) //primii n termeni
cout<<fibo(i)<<" "; }
Figura . Apelurile pentru calcularea termenului 10 al șirului lui Fibonacci
Recursivitatea implică folosirea a cel puțin unei stive. La fiecare apel recursiv sunt depuse în stivă niște date, care sunt extrase la revenirea din acel apel.
Stiva este o succesiune ordonată de elemente, delimitată prin două capete, în care adăugarea și eliminarea elementelor se poate face la un singur capăt, numit vârful stivei. În orice moment putem scoate din stivă doar elementul care a fost introdus ultimul, deci lucrează după principiul LIFO (“Last In First Out”, în traducere “ Ultimul intrat primul ieșit”). Altfel spus, extragerea valorilor din stiva se face în ordine inversă introducerii lor.
O funcție recursivă trebuie să respecte următoarele reguli: funcția trebuie să poată fi executată, cel puțin într-o situație, fără a se autoapela; funcția recursivă se va autoapela într-un mod în care se tinde spre ajungerea în situația de execție fără autoapel.
Pentru a permite apelarea recursivă a funcțiilor limbajele de programare dispun de mecanisme speciale: de suspendare a execuției programului apelant, de salvare a informațiilor necesare și de reactivare a programului suspendat.
Limbajul C++ dispune de propria sa stivă, numită stivă internă, gestionată de către compilator, care ocupă o parte din memoria internă rezervată programului. Orice funcție folosește această stivă atunci când se execută. În momentul în care o funcție K apelează o funcție S, se salvează automat pe stiva internă adresa de revenire și contextul modulului apelant K (care cuprinde totalitatea variabilelor locale și a parametrilor transmiși prin valoare). Odată cu închiderea execuției modulului apelat S, se revine în K, restaurându-se valorile salvate pe stiva internă. În cazul unei funcții recursive (care este atât modulul apelant cât și modulul apelat), acest mecanism al stivei este de foarte mare importanță: atunci când se execută un lanț de auto-apeluri recursive, la fiecare auto-apel variabilele locale și parametri funcției recursive se salvează pe stivă, iar la revenirea în ordine inversă din lanț aceste valori se restaurează de pe stivă. [13]
La fiecare apel al funcției se efectuează următoarele:
1. Se salvează adresa următoarei instrucțiuni de după apelul funcției.
2. Controlul programului este transferat primei instrucțiuni din cadrul funcției apelate.
3. Pe segmentul de stivă al funcției se crează un nou nivel.
4. Se memorează pe acest nivel de stivă, parametri formali ai funcției: valorile parametrilor de tip valoare și adresele parametrilor de tip referință (în cazul în care există), valorile variabilelor locale și adresa de revenire, adresa intrucțiunii cu care va continua programul întrerupt la reluarea execuției sale. Deși variabilele locale ale funcției apelate au aceiași identificatori cu cei ai funcției apelante, orice referire la acești identificatori se asociază ultimului set de variabile alocate în stivă. Zona de stivă rămâne alocată pe tot parcursul execuției funcției apelate și se dealocă în momentul revenirii în programul apelant. Stiva nu este gestionată explicit de programator, ci de către limbaj. La terminarea execuției funcției apelate recursiv se reface contextul programului din care s-a făcut apelul.
5. Instrucțiunile funcției se execută în secvență.
6. Funcția conține un test, pe una dintre ramurile testului se reapelează funcția și se reia procedeul de la punctul 1.
7. Pe cealaltă ramură a testului se vor executa instrucțiunile de după reapelarea funcției pentru fiecare nivel al stivei, cu valorile parametrilor și ale variabilelor de pe acel nivel de stivă. Acest lucru se întâmplă deoarece la fiecare reapel s-a salvat adresa de revenire din funcția apelantă. La atingerea unuia dintre cazurile de bază (condiția de oprire), urmează să se revină din autoapelări.
8. Se termină execuția funcției și se eliberează segmentul de stivă alocat.
Deci pentru n=3, pentru apelul funcției suma(3), au fost salvate pe stivă valorile 3, 2, 1, în această ordine. În lanțul revenirii, se restaurează și se adaugă la sumă valorile respective în ordinea inversă salvării, respectiv 1, 2, 3.
Pe caz general, programul calculează suma primelor n numere naturale 1, 2, 3, …, n în această ordine.
Figura . Mecanismul de funcționare al stivei
În cazul unui număr mare de autoapelări, există posibilitatea ca segmentul de stivă să se ocupe total, caz în care programul se va termina cu eroarea Stack Overflow. Aceasta se întâmplă mai ales atunci când condiția de terminare este pusă greșit și functția se apelează la nesfârșit.
Datorită faptului că la fiecare autoapel se ocupă o zonă de memorie, recursivitatea este eficientă numai dacă numărul de autoapelări nu este prea mare pentru a nu se ajunge la umplerea zonei de memorie alocată.
O gândire recursivă exprimă concentrat o anumită stare, care se repetă la infinit. Această gândire se aplică în elaborarea algoritmilor recursivi cu o modificare esențială: adăugarea condiției de terminare. În absența acestei condiții nu se poate vorbi despre un algoritm deoarece aceștia sunt finiți. Atunci când gândim un algoritm recursiv, privim problema la un anumit nivel. Ce se întâmplă la acel nivel se va întâmpla la toate celelalte.
În continuare se prezintă formularea recursivă a calculului factorialului. Fie Fn=n! Știm că 0!=1, deci f(0)=1, iar n!=n*(n-1)!, deci f(n)=n*f(n-1).
Exemplul 4: Pentru un n dat, citit de la tastatură, să se calculeze n!
ITERATIV RECURSIV
int factorial(int n) int factorial(int n)
{ int f=1; { if(n==0)
for(i=1;i<=n;i++) return 1;
f = f*i; else
return f; } return factorial(n-1)*n ; }
Modul de alocare al memoriei este prezentat în figura următoare:
Figura . Mecanismul de funcționare al stivei pentru calcularea lui n!
”În Matematică există o infinitate de șiruri de numere, care au la bază o formulă, pe baza căreia se generează elementele șirului. De exemplu șirul de numere prime: „2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,… 97, 101, 103,…2n+1,…2n+1” este format din numere care se împart exact doar la 1 și la ele însele. Sau șirul de numere pare naturale: „2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22…n” a cărui elemente se împart exact la doi ( n=2p). Sau șirul de numere formate din puteri ale lui 3: „3, 9, 27, 81, 243, 729, 2187…” care mai poate fi scris și „31, 32, 33, 34, 35, 36, 37, 38, 39,…”.
Printre infinitatea de șiruri existente în lumea matematicii, italianul Leonardo of Pisa, cunoscut și sub numele de Fibonacci, a descoperit un șir de numere extraordinar de interesant: „0, 1,1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597…”. Formula pe baza căruia se obține acest șir este una foarte simplă:
Primele două elemente ale șirului sunt 0 și 1, iar al treilea element se obține aduându-le pe primele două: 0+1 = 1. Al patrulea se obține aduându-le pe al treilea cu al doilea (2+1=3). Al cincilea se obține aduându-le pe al patrulea cu al treilea (3+2=5), și tot așa, până la infinit.
Șirul lui Fibonacci poate fi reprezentat și geometric într-o multitudine de feluri. Mai jos puteți vedea o reprezentare geometrică simplă, ușor de înțeles chiar și pentru cei mai puțin familiari cu legile matematicii.
Figura . Aplicație geometrică a șirului lui Fibonacci [45]
Am desenat un dreptunghi cu lungimea de 55 cm și lăținea de 34 cm. În interiorul acestuia desenăm un pătrat care să aibe latura exact cât lățimea (de 34 de cm). În acest moment s-au format două figuri mai mici: un pătrat cu latura de 34 de cm și un dreptunghi cu lungimea de 34 de cm și lățimea de 21 cm (55-34). Repetăm procedeul și desenăm iarăși un pătrat în dreptunghiul mic abia format. De data această pătratul va avea ca latură 21 cm. În acest moment pe lângă acest nou pătrat a apărut și un alt dreptunghi și mai mic cu lungimea de 21 cm și lățimea de 13 cm (34-21). Repetăm procedeul și vom obține alt pătrat cu latura de 13 cm și un dreptunghi și mai mic cu lungimea de 13 cm și lățimea de 8 cm. Și tot așa până când ajungem să desenăm ultimul pătrat care va avea latura exact de 1 cm și care va forma în celaltă parte tot un pătrat de 1 cm. Dimensiunile geometrice ale acestui dreptunghi sunt exact elementele Șirului lui Fibonacci. Dacă am desena un arc de cerc din pătratul cel mai mic și l-am continua prin celălalt mai mare, și apoi prin următorul și tot așa, am obține o spirală. Dacă am încadra acest dreptunghi cu latura de 55 cm într-unul și mai mare cu latura de 89 cm, iar pe acesta de 89 cm într-unul de 144 cm, și tot așa, atunci spirala obținută ar fi din ce în ce mai mare, dar ar urmări exact aceeași formulă.” [45]
1. 2. Algoritmi elementari descriși în mod recursiv
Scopul acestui subcapitol este de a prezenta modul recursiv de implementare în limbajul C++ a unor probleme elementare cum ar fi sume, produse, probleme cu cifre, cu divizori, vectori și matrici.
Exemplul 5: Să se calculeze suma numerelor impare mai mici sau egale cu n, folosind un subprogram recursiv. Dacă n=10, se va afișa 25 = 1+3+5+7+9.
int suma(int n)
{ if(n==0) return 0;
else
if(n%2!=0)
return n+suma(n-1);
else
return suma(n-1); }
int main ()
{ int n;
cin>>n;
cout<<suma(n); }
Exemplul 6: Să se calculeze produsul K=1*4*7*10*…*3n-2, folosind un subprogram recursiv. Dacă n=4 se va afișa 280 = 1*4*7*10.
int produs(int n)
{ if(n==0)
return 1;
else
return produs(n-1)*(3*n-2); }
int main ()
{ int n;
cin>>n;
cout<<produs(n); }
Exemplul 7: Dându-se două variabile n și k scrieți programul care calculează recursiv combinări de n luate câte k. Dacă n=4 și k=2 se va afișa 6, iar dacă n=7 și k=2 rezultatul este 21.
int combinari(int n,int k)
{ if(k==0 || k==n)
return 1;
else
if(k==1)
return n;
else
return combinari(n-1,k)+combinari(n-1,k-1); }
int main ()
{ int n,k;
cin>>n>>k;
cout<< combinari(n,k); }
Exemplul 8: Funcția lui Ackermann este o funcție cu două argumente, definită prin următoarele 3 ecuații:
Dacă m=1 și n=2 atunci A(1,2) = 4, pentru m=1 și n=3 A(1,3) = 5, iar pentru m=2 și n=4 A(2,4) = 11.
int ack(int m,int n)
{ if(m==0)
return n+1;
else
if(n==0)
return ack(m-1,1);
else
return ack(m-1,ack(m,n-1)); }
int main ()
{ int n,m;
cin>>m>>n;
cout<<ack(m,n); }
Exemplul 9: Pentru un număr dat x să se calculeze recursiv suma divizorilor lui. Pentru n=10 se va afișa 18 = 1+2+5+10
int suma_div(int x,int d)
{ if(d>x) return 0;
else
if(x%d==0)
return suma_div(x,d+1)+d;
else
return suma_div(x,d+1); }
int main ()
{ int n;
cin>>n;
cout<<”suma divizorilor=”,suma_div(x,1); }
Exemplul 10: Pentru un număr dat x să se afișeze recursiv divizorii proprii. Pentru n=20 se va afișa 2 4 5 10.
void divizori(int x,int d)
{ if(d<=x/2)
{ if(x%d==0)
cout<<d<<" ";
divizori(x,d+1); } }
int main ()
{ int n;
cin>>n;
cout<<”suma divizorilor=”, divizori(x,2); }
Exemplul 11: Folosind o funcție recursivă să se verifice dacă un număr este prim. De exemplu pentru n 13 sau 23 se va afișa ”e prim”, iar dacă pentru n se citește valoarea 20 sau 135 se va afișa ”nu e prim”.
int prim(int n,int d)
{ if(d==1) return 1;
else
if(n%d==0)
return 0;
else
return prim(n,d-1); }
int main ()
{ int n;
cin>>n;
if(prim(n,sqrt(n)))
cout<<"e prim";
else
cout<<"nu e prim"; }
SAU
int prim(int n,int d)
{ if(d>sqrt(n)) return 1;
else
if(n%d==0)
return 0;
else
return prim(n,d+1); }
int main ()
{ int n;
cin>>n;
if(prim(n,2))
cout<<"e prim";
else
cout<<"nu e prim"; }
Exemplul 12: Să se creeze un număr cu cifre date de la tastatură.
int numar(int n)
{ int cif;
cin>>cif;
if(cif<0 || cif>9)
return n;
else
return numar(n*10+cif); }
int main()
{ cout<<numar(0); }
Exemplul 13: Să se afle inversul unui număr dat. Dacă se citește pentru n valoarea 1234 se va afișa valoarea 4321.
int invers(int n,int nr)
{ if(n<10)
return nr+n;
else
return invers(n/10,10*(nr+n%10)); }
int main ()
{ int n;
cin>>n;
cout<<invers(n,0); }
Exemplul 14: Pentru un număr x citit de la tastaură, să se afle suma cifrelor lui. Dacă pentru x se citește valoarea 345 se va afișa 12.
int suma_cif(int x)
{ if(x==0)
return 0;
else
return x%10+suma_cif(x/10); }
int main ()
{ int x;
cin>>x;
cout<< suma_cif(x); }
Exemplul 15: Se citește o valoare n și apoi n elemente. Se cere să se afișeze aceste valori. Citirea și afișarea vectorului se vor face folosind funcții recursive. Dacă se citește un număr X, să se calculeze numărul de apariții ale lui X în vector.
void citire(int v[],int n)
{ if(n>0)
{ citire(v,n-1);
cin>>v[n]; } }
void afisare(int v[],int n)
{ if(n>0)
{ afisare(v,n-1);
cout<<v[n]<<” ”; } }
int numarare(int x,int n, int v[])
{ if(n==0)
return 0;
else
if(v[n]==x)
return 1+numarare(x,n-1,v);
else
return numarare(x,n-1,v); }
int main ()
{ int n, v[100], x;
cin>>n;
citire(v,n);
afisare(v,n);
cout<<numarare(x,n,v); }
Exemplul 16: Se citesc două numere n și m, apoi n*m elemente. Se cere să se afișeze aceste valori sub formă de matrice, câte m elemente pe n linii. Citirea și afișarea matricii se vor face folosind funcții recursive. Să se calculeze apoi suma elementelor din matrice.
void citire(int a[][30],int n,int m, int i,int j)
{
if(i<=n)
if(j<=m)
{ cin>>a[i][j];
citire (a,n,m,i,j+1); }
else
citire(a,n,m,i+1,1); }
void afisare(int a[][30],int n,int m, int i,int j)
{
if(i<=n)
if(j<=m)
{ out<<setw(3)<<a[i][j]<<" ";
afisare(a,n,m,i,j+1); }
else
{ out<<endl;
afisare(a,n,m,i+1,1); } }
int suma(int a[][30],int n,int m, int i,int j)
{
if(i<=n)
if(j<=m)
return a[i][j]+suma(a,n,m, i,j+1);
else
return suma(a,n,m, i+1,1);
else
return 0; }
int main ()
{
int n,m,i,j,a[10][10];
cin>>n>>x;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
cin>>a[i][j];
citire(a,n,m,1,1);
afisare(a,n,m,1,1);
cout<<suma(a,n,m,1,1);
}
Mai multe exemple pot fi găsite în Anexa 7.
1. 3. Tehnici de programare care utilizează recursivitatea
1. 3. 1. Divide et impera
Metoda Divide et Impera (Împarte și Stăpânește) este o metodă de programare care se aplică problemelor care pot fi descompuse în subprobleme independente, similare problemei inițiale (se rezolvă prin aceeași metodă), de dimensiuni mai mici și care pot fi rezolvate foarte ușor. Procesul se reia până când, în urma descompunerilor repetate, se ajunge la probleme care admit rezolvare imediată (caz de bază).
De obicei împărțirea se realizează până când șirul obținut este de lungime 1 sau o lungime impusă, caz în care rezolvarea directă a subproblemei este foarte ușoară.
După cum sugerează și numele "etapele rezolvării unei probleme" (numită problema inițială) în DIVIDE ET IMPERA sunt:
descompunerea problemei inițiale în subprobleme independente, de dimensiuni mai mici, similare problemei de bază, până se ajunge la probleme de o dimensiune impusă;
rezolvarea directă a problemei obținute;
combinarea soluțiilor găsite;
În anumite cazuri descompunerea poate conduce direct la soluția problemei fără a fi nevoie de recombinare. Dacă descompunerea se face până la dimensiunea 1, nu mai este nevoie de rezolvare directă a subproblemelor.
Divide et impera este o tehnică folosită pentru a realiza soluții eficiente pentru o anumită clasă de probleme: acestea conțin subprobleme disjuncte și cu structură similară. În cadrul acestei tehnici se disting trei etape: divide, stăpânește și combină.
Mulțimea datelor de intrare poate fi divizată în 2 submulțimi disjuncte sau mai multe, prin divizarea indicilor, pentru cazul a două submulțimi: indicii din stânga: st și indicii din dreapta: dr. Intervalul care se divizează este [st, dr] și anume: [st, mij] și [mij+1,dr] unde mij=(st+dr)/2.
Pentru a se înțelege mai bine se va explica grafic în aplicația următoare.
Exemplul 17: Să se determine suma elementelor unui vector de întregi utilizând metoda Divide et Impera.
Figura . Mecanismul de funcționare a metodei Divide et Impera
Programul pentru rezolvarea problemei din exemplul de mai sus, împreună cu explicații, este descris în cele ce urmează.
int v[20],n,rez;
void combina(int x, int y, int &rez) // se combină soluțiile obținute însumând cele 2 valori
{ rez=x+y; }
void dei(int st, int dr, int &rez)
{ int rez1,rez2;
if(st==dr) // dacă este caz de bază (atunci cand mulțimea conține un singur element –
//adică cele 2 capete ale intervalului sunt identice)
rez=v[st]; // se obține soluția corespunzatoare problemei
else // altfel se trece la divizarea intervalului
{ int mij=(st+dr)/2; // mulțimea datelor de intrare este divizată în 2 submulțimi disjuncte prin divizarea
// multimii indicilor în două submulțimi disjuncte de indici mij este /mijlocul intervalului [st,dr]
dei(st,mij,rez1); // se apelează functieul dei() pentru primul interval
dei(mij+1,dr,rez2); // se apelează functieul dei() pentru al doilea interval
combina(rez1,rez2,rez); // se combină sol obținute până se obține sol pb inițiale
} }
int main()
{ cout<<"n=";cin>>n; //se citește numărul de elemente ale vectorului
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; //se citesc cele n elemente ale vectorului
cin>>v[i]; }
dei(1,n,rez); //se apelează funcția ce folosește metoda divide et impera
cout<<"suma celor "<<n<<" elemente ale vectorului "<<rez; }
Exemplul 18: Să se calculeze simultan suma și produs elementelor dintr-un vector
void dei(int st, int dr, int &rez1, int &rez2)
{ int x1,x2,y1,y2;
if(st==dr)
rez1=rez2=v[st];
else
{ int mij=(st+dr)/2;
dei(st,mij,x1,x2);
dei(mij+1,dr,y1,y2);
rez1=x1+y1;
rez2=x2*y2; } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]=";
cin>>v[i]; }
dei(1,n,rez1,rez2);
cout<<"suma celor "<<n<<" elemente ale vectorului este "<<rez1<<endl;
cout<<"prod celor "<<n<<" elemente ale vectorului este "<<rez2<<endl; }
Un alt exemplu tipic pentru folosirea recursivității și a tehnicii Divide et Impera este căutarea binară.
Exemplul 19: Să se caute, într-un șir de numere ordonate strict crescător poziția în care se găsește o valoare dată x. Dacă valoarea nu se găsește să se afișeze un mesaj.
Pașii algoritmului sunt:
P1. Se divizează vectorul în doi subvectori
P2. Dacă elementul situat pe poziția din mijloc: v[mij]=x, atunci se afisează m și “gata”,
dacă v[m]<x atunci căutarea se face în prima jumătate (in intervalul [st, mij]),
altfel căutarea se va face în a doua jumătate (în intervalul [mij+1,dr]). Acest pas se execută până se găsește elementul sau până când vectorul nu mai poate fi împărțit.
int v[20],n,rez,x;
void cauta(int st, int dr, int &rez)
{ if(dr>=st)
{ int mij=(st+dr)/2;
if(v[mij]==x)
rez=mij;
else
if(x<v[mij])
cauta(st,mij,rez);
else
cauta(mij+1,dr,rez); } }
void main()
{ rez=0;
cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]=";
cin>>v[i]; }
cout<<"x=";cin>>x;
cauta(1,n,rez);
if(rez==0)
cout<<"nu exista";
else
cout<<"pe poz "<<rez; }
Algoritmul următor este cel de interclasare ce se execută pe doi vectori, ordonați după același criteriu, pentru a obține un al treilea vector, care să conțină elementele primilor doi vectori, ordonate după același criteriu. Algoritmul de sortare prin interclasare se bazează pe observația că orice vector care conține un singur element este un vector sortat, deci după ce s-a ajuns la subvectori cu un singur element se combină soluțiile prin interclasarea celor doi vectori sortați, obținându-se un vector sortat.
Exemplul 20: Sortarea prin interclasare (MergeSort)
void interclaseaza(int st, int dr, int mij)
{ int i=st,j=mij+1,k=0,x[20];
while (i<=mij && j<=dr)
if(v[i]<v[j])
x[++k]=v[i++];
else
x[++k]=v[j++];
while (i<=mij)
x[++k]=v[i++];
while (j<=dr)
x[++k]=v[j++];
for(k=1,i=st;i<=dr;k++,i++)
v[i]=x[k]; }
void mergesort(int st, int dr)
{ int mij;
if(st<dr)
{ mij=(st+dr)/2;
mergesort(st,mij);
mergesort(mij+1,dr);
interclaseaza(st,dr,mij); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]=";
cin>>v[i]; }
mergesort(1,n);
for(int i=1;i<=n;i++)
cout<<v[i]<<" "; }
Un alt algoritm de ordonare care folosește tehnica Divide et Impera este algoritmul de sortare rapidă – QuickSort. Rezolvând, se execută următoarele operații:
Primul element din vector, numit pivot, este mutat pe poziția pe care va trebui să se găsească în vectorul sortat apoi se descompune vectorul în doi subvectori:
-vectorul din stânga pivotului: elementele mai mici decât el vor fi mutate în vector în fața sa
-vectorul din dreapta pivotului: elementele mai mari vor fi mutate în vector după el
Se repetă procesul de descompunere în subvectori până când se obțin vectori cu un singur element.
Se folosesc variabilele logice pi, pentru parcurgerea cu indicele i (se folosește pentru parcurgerea vectorului de la început către poziția pivotului – se incrementează), pj pentru parcurgerea cu indicele j (se folosește pentru parcurgerea vectorului de la sfârșitul lui către poziția pivotului – se va decrementa). Ele au valoarea 1 dacă se parcurge cu acel indice și 0 dacă nu se parcurge cu acel indice.
Exemplu:
Cei doi indici i și j sunt initializați cu extremitățile vectorului (i=1; j=5) și parcurgerea începe cu indicele j (pi=0; pj=1).
Se compară pivotul (3) cu ultimul element (2). Deoarece pivotul este mai mic, cele două valori se interschimbă, și se schimbă și modul de parcurgere (pi=1; pj=0 => avansează indicele i).
Se compară elementul din pozitia i (4) cu elementul din pozitia j (3). Deoarece 4>3, cele două valori se interschimbă, ș se schimbă și modul de parcurgere (pi=0; pj=1 – avansează indicele j)
Se compară elementul din pozitia i (3) cu elementul din pozitia j (5). Deoarece 3<5, cele două valori nu se interschimbă, și se păstrează modul de parcurgere (pi=0; pj=1 – avansează indicele j)
Se compară elementul din poziția i (3) cu elementul din pozitia j (1). Deoarece 3>1, cele două valori se interschimbă, și se schimbă și modul de parcurgere (avansează indicele i). Cei doi indici fiind egali, algoritmul se termină.
Pivotul=3 este pus pe poziția unde va fi în vectorul sortat, iar în fața lui se găsesc numai elementele mai mici decât el, iar după el cele mai mari.
Apoi “o ia de la capăt” cu fiecare din cele două “jumătăți”.
Exemplul 21: Sortarea rapida (QuickSort)
void schimb(int &a, int &b)
{ int aux=a;
a=b;
b=aux; }
void QuickSort(int st, int dr)
{ int mij;
if(st<dr)
{ int i=st,j=dr,pi=0,pj=1; //pivotul fiind pe pozitia st, parcurgerea incepe cu indicele j
while (i<j)
{ if(v[i]>v[j])
{ schimb(v[i],v[j]);
schimb(pi,pj); }
i=i+pi;
j=j-pj; }
mij=i;
QuickSort(st,mij-1);
QuickSort(mij+1,dr); } }
int main()
{ rez=0;
cout<<"n="; cin>>n;
for(i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
QuickSort(1,n);
for(i=1;i<=n;i++)
cout<<v[i]<<" ";
}
O problemă foarte cunoscută este cea a turnurilor din Hanoi. Se dau trei tije (stânga, mijloc, dreapta) și n discuri de diferite dimensiuni, stivuite pe tija stângă în ordine descrescatoare a dimensiunilor lor, formând un “turn” ca în figura următoare.
Figura . Problema turnurilor din Hanoi
Să se scrie programul care mută cele n discuri de pe tija STÂNGA pe tija DREAPTA, astfel încât ele sa fie ordonate ca la început. Mutările se fac cu următoarele restricții:
la fiecare mișcare se mută doar un disc;
un disc nu poate fi plasat peste unul mai mic;
tija MIJLOC poate fi utilizată ca poziție intermediară.
Se observă că pentru n=1, turnul se mută printr-o singură mutare, deci U1=1, pentru n=2, turnul se poate muta prin 3 mutări, deci U2=3, iar pentru n=3, turnul se poate muta prin 7 mutări, deci U3=7.
Pentru 3 discuri, mutările sunt:
se mută discul 1 din pozitia STÂNGA în poziția DREAPTA
se mută discul 2 din pozitia STÂNGA în poziția MIJLOC
se mută discul 1 din pozitia DREAPTA în poziția MIJLOC
se mută discul 3 din pozitia STÂNGA în poziția DREAPTA
se mută discul 1 din pozitia MIJLOC în poziția STÂNGA
se mută discul 2 din pozitia MIJLOC în poziția DREAPTA
se mută discul 1 din pozitia STÂNGA în poziția DREAPTA.
Pentru 4 discuri, mutările sunt ilustrate în figura următoare.
Figura . Transferul pentru 4 discuri [41]
În cazul unui turn format din n discuri, problema mutării celor n discuri poate fi redusă la problema mutării a n-1 discuri, astfel:
se mută primele n-1 discuri în poziția MIJLOC, folosind tija DREAPTA;
se muta discul rămas în poziția DREAPTA;
se muta cele n-1 discuri din pozitia MIJLOC în pozitia DREAPTA, folosind tija STANGA drept poziție intermediară.
Deci s-a format un turn cu n-1 discuri. Dacă presupunem că s-au făcut un număr minim de mutări, înseamnă că s-au făcut Un-1 mutări. În continuare, mutăm discul cel mai mare de pe tija STÂNGA pe tija DREAPTA, folosind o singură mișcare. Apoi se mută turnul cu n-1 discuri de pe tija din MIJLOC pe tija DREAPTA, peste discul cel mai mare. Acest lucru poate fi făcut prin minim Un-1 mutări. În total s-au făcut:
Un = Un-1 +1 + Un-1 = 2 Un-1 + 1 mutări.
Astfel s-a obținut o relație de recurență între numărul minim de mutări pentru un turn cu n discuri și unul format din n-1 discuri, motiv pentru care acest joc este foarte des folosit ca exemplu pentru tehnici de programare care folosesc recurența. Folosind procedeul numit inducție matematică, se poate demonstra ușor că numărul minim de mutări în cazul turnului cu n discuri este: Un = 2n – 1.
Este chiar și un joc inventat de matematicianul francez Edouard Lucas și a fost comercializat ca jucărie pentru toate vârstele încă din anul 1883. La început era confecționat din lemn și consta în câteva discuri de mărimi diferite și 3 bețișoare. Provocarea este de a muta turnul format din discuri de pe un bețișor pe alt bețișor liber, urmând două reguli simple: la fiecare mutare se mută un singur disc și niciodată nu se așază un disc mai mare peste un disc mai mic. Bineînțeles, scopul este acela de a realiza mutarea turnului folosind cât mai puține mutări.
Se spune că acest joc este inspirat de legenda Turnului lui Brahma, aflat într-un templu al orașului indian Benares. Acest turn este format din 64 de discuri de aur, pe care preoții templului trebuie să le mute, respectând regulile de mai sus. Legenda spune că atunci când turnul discurilor de aur va fi complet transferat pe o altă tijă, templul se va prăbuși iar lumea va lua sfârșit. Dacă preotii ar lucra zi și noapte, făcând câte o mutare în fiecare secundă, conform regulilor specificate în legendă numărul minim de mișcări este de 264-1 = 18.446.744.073.709.551.615 (se citește 18 trilioane 446 biliarde 744 bilioane 73 miliarde 709 milioane 551 mii 615). Dacă numărul acesta reprezintă secunde, asta ar însemna circa 584 942 417 355 de ani. Deci putem sta liniștiți, sfârșitul lumii e departe: chiar dacă preoții ar munci fără încetare și ar face o mutare pe secundă, tot le-ar trebui multe mii de milioane de ani pentru a-și termina treaba.
După ce matematicienii au epuizat de întors pe toate fețele acest joc, ei au descoperit și alte variante, mult mai provocatoare din punct de vedere matematic. De exemplu, care ar fi numărul maxim de mutări prin care se poate transfera turnul de pe un bețișor pe altul, fără a reveni la o configurație anterioară? Dar dacă jocul ar avea 4 sau mai multe bețișoare în loc de 3? Acestea sunt doar câteva exemple care ne arată cum se poate transforma o problemă relativ simplă într-una de o mare complexitate matematică, prin modificarea minimă a unei singure variabile din enunțul problemei…”, dar cu ajutorul informaticii acestea se pot rezolva destul de ușor! [42]
Exemplul 22: Problema turnurilor din Hanoi: se mută n discuri de pe tija a pe tija b folosind tija c ca și tijă intermediară.
void hanoi(char a, char b, char c, int n)
{
if (n==1)
cout<<”Mutarea: ”<<a<<”–><<b<<endl;
else
{ hanoi(a, c, b, n-1);
cout<<”mutarea: ”<<a<<””<<b<<endl;
hanoi(c, b, a, n-1); } }
void main()
{ int n;
char a=’A’,b=’B’,c=’C’;
cout<<”n=”; cin>>n;
hanoi(a,b,c,n); }
O categorie specială, interesantă și frumoasă, cu o definiție recursivă este cea a fractalilor. ”Fractalii sunt forme și modele extraordinare create cu ajutorul ecuațiilor matematice. O definiție intuitivă a fractalului este aceasta: Un fractal este o figură geometrică fragmentată sau frântă, care poate fi divizată în părți, astfel încât fiecare dintre acestea să fie (cel putin aproximativ) o copie miniaturală a întregului. Cuvântul ’fractal’ a fost introdus de matematicianul Benoit Mandelbrot în 1975 și provine din latinescul ’fractus’, care înseamnă spart sau fracturat. Fractalul, ca obiect geometric, are în general următoarele caracteristici:
este auto-similar (macar aproximativ sau stochastic): dacă se mărește orice porțiune dintr-un fractal, se vor obține (cel puțin aproximativ) aceleași detalii cu cele ale fractalului întreg.
are o definiție simplă și recursivă – pentru a vă imagina fractalul corespunzator unei funcții f(x), considerați elementele x, f(x), f(f(x)), f(f(f(x))), etc.
are detaliere și complexitate infinită: orice nivel de magnificare pare identic și are o structură fină la scări infinit de mici.” [35]
Exemple celebre de fractali sunt triunghiul lui Sierpinski care se obține pornind de la un triunghi și decupând recursiv triunghiul (central) format de mijloacele fiecărei laturi sau fulgul de zăpadă al lui Koch, curba lui Koch care se obține pornind de la un triunghi echilateral și se înlocuiește treimea din mijloc de pe fiecare latură cu două segmente astfel încât să se formeze un nou triunghi echilateral exterior. Apoi se execută aceiași pași pe fiecare segment de linie a formei rezultate.
Figura . Triunghiul lui Sierpinski [30] și curba lui Koch [47]
Exemplul 23: Modele fractale, curba lui Koch
int x,y;float alfa;
void stanga(float unghi)
{ alfa+=unghi*M_PI/180.; }
void dreapta(float unghi)
{ alfa-=unghi*M_PI/180.; }
void deseneaza(float L)
{ int x1=x; int y1=y;
x+=(int)(L*cos(alfa));
y+=(int)(L*sin(alfa));
line(x,y,x1,y1); }
void koch(int n, float L)
{ if(n==0)
deseneaza(L);
else
{ koch(n-1,L/3); stanga(60);
koch(n-1,L/3); dreapta(120);
koch(n-1,L/3); stanga(60);
koch(n-1,L/3); } }
void nucleu_koch(int n, float L)
{ koch(n,L); dreapta(120);
koch(n,L); dreapta(120);
koch(n,L); dreapta(120); }
int main()
{ int n,L;
cout<<"n=";cin>>n;
cout<<"L="; cin>>L;
nucleu_koch(n,L); }
Mai multe exemple pot fi găsite în Anexa 8.
1. 3. 2. Backtracking
Metoda Backtracking este o tehnică algoritmică de găsire a soluțiilor unei probleme care verifică anumite condiții date. Există probleme în care utilizarea metodei backtracking este indispensabilă, nefiind cunoscute alte metode pentru rezolvarea lor.
Metoda backtracking se aplică problemelor în care soluția se poate reprezenta sub forma unei stive, implementată ca un vector ca și cum elementele sale ar fi așezate "pe verticală", unul peste altul. Dacă la un moment dat stiva st conține elementele st[l], st[2], …, st[k], atunci pozitia k a elementului cel mai de sus, se numește vârful stivei. În general, pozitia unui element în vectorul stivă este numită nivel al stivei. Adăugarea și extragerea de elemente în/din stivă, se poate face numai pe la capătul de sus al acesteia.
Exemplul 24: Să se genereze permutările de n elemente.
Permutările de n elemente sunt mulțimile ordonate ce conțin elementele mulțimii {1, 2, …, n} în care fiecare element apare o singură dată. Cum construim aceste permutări? Exemplific pentru cazul n=3, permutările pe mulțimea {1, 2, 3}.
cu elementul 1 pe prima pozitie, putem alcătui permutările (1, 2, 3) și (1, 3, 2), așezând elementele 2 și 3 pe a doua și a treia poziție în cele două cazuri valide;
cu elementul 2 pe prima poziție generăm analog permutările (2, 1, 3) și (2, 3, 1);
cu elementul 3 pe prima poziție obținem (3, 1, 2) și (3, 2, 1).
Prin urmare, permutările căutate sunt (1,2,3),(1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).
Cum putem genera efectiv aceste permutări? Formăm mulțimea tuturor numerelor de trei cifre alcătuite numai din cifrele 1, 2 și 3 în care fiecare cifră apare o singură dată. Aceste numere sunt 123, 132, 213, 231, 312, 321. Ele generează tocmai permutările căutate, putem proceda astfel:
generăm toate soluțiile valide adică toate numerele de trei cifre care se pot forma cu cifrele 1, 2 și 3. Parcurgând mulțimea {1,2,3} prin enumerare în ordine crescătoare vom obține pe rând numerele: 111, 112, 113, 121, 122, 123, 131,132, 133, 211, 212, 213, 221, 222, 223, 231, 232, etc.
dintre aceste numere le alegem doar pe acelea care îndeplinesc condițiile problemei. În cazul nostru avem o singură condiție, aceea ca cifrele numărului să fie distincte. Astfel, vor fi considerate soluții doar numerele 123, 132, 213, 231, 312 și 321.
Aplicarea acestui algoritm generează 27 de numere (adică 33) dintre care doar 6 (adică 3!) ne conduc la permutările căutate. Pe caz general, pentru a obține permutările de n elemente suntem nevoiți să "vizităm" nn numere. Mai mult pentru n=5 se generează 3125 de numere din care doar 120 sunt soluții! Iar pentru valori mari ale lui n, problema este practic imposibil de rezolvat. S-a calculat că pentru a rezolva problema în cazul n=100 calculatorul are nevoie de 4*1013 ani!
Folosind metoda backtracking nu se generează toate soluțiile valide, ci numai acelea care îndeplinesc anumite condiții specifice problemei numite condiții de validare.
În general numărul de elemente care intră în componența soluțiilor poate să difere de la o soluție la alta. Să considerăm cazul în care toate soluțiile au același număr de elemente, întrucât acesta se întâlnește cel mai frecvent. Vom nota cu n numărul de elemente ale soluțiilor reprezentate pe stiva st. Astfel, o configurație a vectorului-stivă st formată din elementele (st[l], st[2],…, st[n]), se va numi soluție finală. Tot pe caz general, fiecare componentă st[i] poate lua valori într-o anumită mulțime Si, cu i=1, 2, …, n. Ansamblul mulțimilor Si adică produsul cartezian S1xS2x…xSn, se numește spațiul soluțiilor valide. Din nou vom face o particularizare, considerând pentru început că toate componentele st[i] (i=1 ,2, …,n) iau valori în aceeași mulțime S.
Ca să evităm generarea tuturor soluțiilor valide și să le obținem numai pe acelea care îndeplinesc soluțiile de validare, fiecare soluție va fi construită în stivă st pas cu pas, completând stiva nivel cu nivel. Astfel, pentru a obține o soluție finală cu n nivele, de forma st=(st[l], st[2], …,st[n]), vom "trece" prin niște configurații intermediare ale stivei numite soluții parțiale. Cu alte cuvinte, o soluție parțială este o configurație a stivei de forma (st[l], st[2],…, st[k]), unde k va lua succesiv toate valorile de la 1 la n. La rândul său, fiecare soluție partială (st[l], st[2],…,st[k]) se obține prin completarea cu încă un nivel a soluției parțiale anterioare (st[1], st[2],…,st[k-1]).
Principiul de funcționare și caracteristicile metodei Backtracking pentru generarea permutărilor de n elemente, pentru n=3 se pot alcătui cu elementele mulțimii {1,2,3} dispuse în diverse ordini, adică (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).
Reprezentarea în stivă a celor șase soluții enumerate mai sus arată astfel:
Figura . Reprezentarea pe stivă a celor șase soluții
În continuare urmărim, pas cu pas, evoluția stivei și modul de obținere a soluțiilor finale:
soluțile finale (st[l], st[2], …, st[n]) vor fi configurații ale stivei de forma st=(st[1], st[2], st[3]), cu n=3 nivele.
notând cu k vârful stivei, soluțiile parțiale (st[l], st[2],…,st[k]) sunt configurații de forma (st[l]) (stiva cu un nivel, pentru k=1, și (st [1], st[2] ) (cu două nivele, pentru k=2).
spațiul soluțiilor valide este mulțimea {1, 2, 3}; cu alte cuvinte fiecare componentă st[i] (i=1, 2, 3) poate lua valori doar din rândul elementelor aceleiași mulțimi s={1, 2, 3} .
Generarea soluțiilor începe de la primul nivel.
Pe fiecare nivel k, "încercăm" să punem pe rând, în ordine, valorile din spațiul soluțiilor, până când găsim una care generează o soluție validă. Altfel spus, vrem să dăm o valoare elementului st[k] astfel încât să obținem o soluție parțială (st[1], st[2],…, st[k]) care îndeplinește condițiile de validare. Dacă găsim o asfel de valoare, atunci ”urcăm” în stivă la nivelul următor, prin incrementarea lui k, în scopul de a completa soluția cu un nivel. Pe acest nivel următor reluăm procedeul descris.
Problema permutărilor se caracterizează printr-o singură condiție de validare: valorile memorate pe stivă trebuie să fie distincte. Permutările, adică soluțiile finale pe care dorim să le aflăm, sunt alcătuite numai din valori distincte, iar în momentul în care pe stivă se repetă o anumită valoare, configurația obținută nu mai are cum să ne conducă spre o permutare! Concret această condiție de validare este aceasta: în momentul în care vrem să punem o valoare pe nivelul k al stivei, respectiva valoare st[k] nu trebuie să se mai găsească pe nici unul dintre nivelele anterioare. Componenta st[k] trebuie să fie diferită de toate componentele anterioare st[1], st[2], …, st[k-1].
În exemplul dat, chiar prima valoare din spațiul soluțiilor {1,2,3}, adică valoarea 1, este validă. Așadar, “urcăm" la nivelul următor k=2, în scopul completării soluției.
Și pe nivelul k=2 încercăm valori din mulțimea {1,2,3}, până la găsirea uneia valide. Prima valoare care poate fi încercată pe nivelul k=2 este 1, dar aceasta nu generează o soluție validă, deoarece aceeași valoare 1 există și pe nivelul anterior (o permutare este alcătuită din elementele mulțimii {1,2,3}, într-o anumită ordine, fiecare element luat o singură dată, deci cu configurația [1,1] pe primele două nivele, nu putem ajunge la o permutare). A doua valoare care poate fi încercată pe nivelul k=2 este 2, care a generat soluția parțială validă [1,2], deci trecem la nivelul următor pentru a o completa.
Cu configurația [1,2] pe primele două nivele, pe nivelul k=3 o luăm de la capăt cu încercarea valorilor din mulțimea {1,2,3}. Primele două valori încercate pe nivelul k=3, în speță 1 și 2, generează configurațiile [1,2,1] și [1,2,2]. Aceste soluții nu sunt valide, din cauza apariției pe nivelul 3 a unui element care a mai fost pe un nivel anterior.
Ultima valoare care poate fi încercată pe nivelul k=3 este 3, obținându-se soluția [1,2,3]; aceasta este validă, dar și finală, adică o permutare, deoarece conține toate elementele mulțimii {1,2,3}, fiecare element luat o singură dată.
Se constată că pe nivelul al treilea nu mai putem încerca nici o valoare, deoarece au fost “vizitate" toate elementele din spațiul soluțiilor valide {1,2,3}.
Dacă la un moment dat, pe un anumit nivel, nu mai există nici o valoare neîncercată din spațiul soluțiilor, vom face un pas înapoi, la nivelul anterior, și reluăm căutarea cu valorile rămase neîncercate pe acest nivel anterior. Respectivul nivel a mai fost vizitat, dar l-am abandonat după ce am pus o valoare care a generat o soluție validă, deci se poate să fi rămas aici valori neîncercate. "Coborârea" la nivelul anterior se face prin decrementarea vârfului k al stivei. Dacă nici pe acest nivel nu mai avem valori neîncercate, mai facem un pas înapoi ș.a.m.d. Această micșorare a lui k stă la originea numelui metodei, "backtracking" însemnând tocmai “pas înapoi".
Așadar ne întoarcem la nivelul k=2 unde am mai fost, dar pe care l-am abandonat imediat după ce am găsit soluție parțială validă [1,2].
Pe nivelul k=2 am încercat numai valorile 1 și 2, rămânând valoarea 3 pe care o încercăm acum. Ea generează soluția partială [1,3], care la rândul ei este validă. La fel cum am procedat de fiecare dată când am obținut o soluție parțială validă, vom urca din nou la nivelul următor k=3, pentru a completa și această soluție.
Cu configurația [1,3] pe primele două nivele, o luăm de la capăt cu valorile ce pot fi încercate pe nivelul al treilea. Prima astfel de valoare 1 generează o soluție care nu este validă, și anume [1,3,1], a doua valoare 2 generează solutia [1,3,2], care este validă, dar și finală.
După obținerea unei soluții finale, dacă pe ultimul nivel au mai ramas valori neîncercate, vor fi "vizitate" și acestea, întrucât mai poț apărea astfel și alte soluții finale.
Pe nivelul k=3, mai trebuie încercată valoarea 3; aceasta conduce la soluția [1,3,3], care nu este validă. În acest moment, pe nivelul al treilea am epuizat toate valorile din spațiul soluțiilor valide.
Acum suntem nevoiți să facem un pas înapoi, la nivelul k=2. Așadar s-a "consumat" un alt "moment de backtracking". Dar cu valorea 1 pe primul nivel, și pe nivelul al doilea au fost încercate toate valorile 1,2 ,3, deci trebuie să mai facem încă un pas înapoi, "coborând" pană la nivelul k=l.
Pe nivelul k=l, am încercat până acum numai valoarea 1, așa că trecem la următoarea valoare 2, obținând o soluție validă cu un nivel. Trecem la nivelul următor k=2, pentru a completa soluția anterioară luând din nou la rând valorile din mulțimea 1, 2, 3, ș.a.m.d.
În continuare sunt reprezentate toate configurațiile prin care trece stiva, inclusiv cele explicate până acum.
Figura . Reprezentarea configurațiilor stivei
Algoritmul se încheie în momentul în care, în urma unor pași înapoi, am,ajuns din nou la nivelul 1 și nu mai există nici o valoare neverificată pe acest nivel (practic facem încă un pas înapoi ajungând la nivelul k=0, adică stiva vidă).
int st[10];
int n,k,ev,as;
void init() //se initializeaza elem din varful stivei. In acest moment se va inregistra // urmatorul element al solutiei
{ st[k]=0; }
int succesor() // verifica daca mai exista un element pentru nivelul k al
{ if(st[k]<n) // solutiei (un succesor). Daca mai exista se trece la
{ st[k]=st[k]+1; // urm elem, iar functia returneaza valoarea 1, altfel 0.
return 1; }
else return 0; }
int valid() // verifica daca valoarea atribuita elementului xk al solutiei indeplineste conditia de continuare,
//adica poate fi considerata ca face parte din solutia problemei
for(int i=1; i<k;i++)
if(st[k]==st[i]) return 0;
return 1; }
int solutie() //verificadaca s-au obtinut toate elementele solutiei
{ return k==n; }
void tipar() //afiseaza elementele solutiei
{ for(int i=1;i<=n;i++)
cout<<st[i]<<" ";
cout<<endl; }
void bt(int k) //partea fixa
{ init(k); // se initializeaza stiva pentru elem k al solutiei
while(succesor(k)) // cat timp se gaseste succesor pentru elem k al solutiei
if(valid(k)) // daca succesorul este element al solutiei
if(solutie(k)) //daca s-au obtinut toate elementele solutiei
tipar(k); // atunci se afiseaza
else
bt(k+1); } //altfel se apeleaza functieul pentru a gasi elem k+1 al solutiei
void main()
{ cout<<"n=";cin>>n;
bt(1); }
Mai multe exemple pot fi găsite în Anexa 9.
1. 4. Grafuri
Pentru a înțelege utilitatea grafurilor, să ne imaginăm cum arată un oraș. El poate fi privit ca un ansamblu de străzi care se intersectează între ele. Pentru a ajunge dintr-un loc în altul trebuie parcurse niște străzi și trecute niște intersecții. Dar ce facem în momentul în care, de exemplu, un turist străin de oraș, întreabă cum poate să ajungă din punctul X în punctul Y? Dacă traseul pe care trebuie să-l parcurgă turistul este mai complicat, nu va fi suficientă o explicație în cuvinte. Dacă mai întâi se reprezintă intersecțiile prin puncte, apoi străzile care "leagă" aceste intersecții vor fi reprezentate prin linii drepte sau curbe, care în desen vor uni punctele deja fixate atunci s-a construit astfel un graf. Dacă turistul dorește să ajungă din locul X în locul Y mergând pe jos, cu desenul în față, el își va putea stabili singur traseul pe care trebuie să-l parcurgă. Dar dacă dorește să meargă cu autoturismul, apare o problemă: în oraș există cu siguranță străzi cu sens unic. Dând străzilor o anumită orientare, cu ajutorul unor săgeți "pictate" pe liniile sau curbele care reprezintă străzile în desen. O stradă pe care se poate circula cu mașina în ambele sensuri va fi marcată prin săgeți în ambele sensuri, sau chiar prin două linii(curbe), câte una pentru fiecare sens.
În primul caz s-a construit un graf neorientat, iar în al doilea caz un graf orientat.
Dar deplasarea turistului implică niște costuri. De exemplu, în cazul în care el va merge cu autoturismul, aceste costuri se regăsesc în cantitatea de benzina consumată care depinde de numărul de kilometri parcurși. Dacă pe desen va fi scrisă în dreptul fiecărei linii(curbe) și lungimea străzii aferente, atunci turistul va putea găsi drumul cel mai scurt pe care trebuie să-l parcurgă. Astfel turistul va rezolva una dintre cele mai importante aplicații ale grafurilor, și anume: Problema drumului optim, sau problema drumului de cost minim.
Un GRAF este o pereche ordonată de mulțimi (X,U) unde X este o mulțime finită și nevidă, iar U o mulțime de perechi formate cu elemente distincte din X. Elementele mulțimii X se numesc vârfuri sau noduri, iar elementele mulțimii U se numesc muchii sau arce. Ordinul grafului este dat de numărul de noduri. Un drum (muchie) Uk = [xi, xj] este elementul care leagă 2 noduri. Criteriul de clasificare folosit este proprietatea de simetrie a mulțimii U și anume pentru orice pereche de noduri (xi,xj) dacă {xi,xj}U, atunci și{xj,xi}U.
1. 4. 1. Grafuri neorientate
Un exemplu foarte simplu de graf este rețeaua de străzi a unui oraș. Străzile sunt muchii în graf, iar intersecțiile reprezintă vârfurile grafului. Întrucât mergând pe jos ne putem deplasa pe orice stradă în ambele sensuri, vom spune ca din punctul de vedere al pietonilor, "graful" unui oraș este neorientat.
Un graf neorientat este graful care are proprietatea de simetrie. Mulțimea U este formată din perechi neordonate [xi,xj]. Orice pereche de noduri care formeaza o muchie [xi,xj] se numesc noduri adiacente. Un nod este incident cu muchia care îl formează. Nodurile vecine unui nod xi sunt toate nodurile xj care sunt adiacente cu el. Oricare dintre cele două noduri care se gasesc la capatul unei muchii se numesc noduri extreme. Nodurile xi si xj se numesc extremitățile muchiei [xi,xj]. Două muchii ui și uj care au o extremitate comună, nodul xk se numesc muchii incidente.
Teorema 1: [14] Dacă G, graf neorientat are n noduri, atunci numărul total de grafuri neorientate care se pot forma cu aceste noduri este .
Gradul unui nod este dat de numărul muchiilor incidente cu nodul și se notează cu d(xk). Un nod terminal este un nod care are gradul egal cu 1, iar un nod izolat este nodul care are gardul egal cu 0.
Teorema 2: [14] Dacă G are m muchii și n noduri atunci între gradul nodurilor și numărul muchiilor există următoarea relație: suma gradelor tuturor nodurilor grafului este egală cu dublul numărului de muchii: d(xi)=2m.
Proprietatea 1: Numărul nodurilor de grad impar este par.
Proprietatea 2: Numărul minim de muchii, pe care trebuie să le aibă un graf neorientat, cu n noduri, ca să nu existe noduri izolate, este (n+1)/2.
Teorema 3: [14] Dacă graful G are n noduri(n>=2), atunci cel puțin două noduri au același grad.
Ṣir grafic este un șir de n numere întregi pozitive (d1,d2,….,dn) care pot reprezenta gradele unui graf neorient, cu n noduri.
Proprietatea 3: Condițile necesare ca un șir de n numere întregi pozitive (d1,d2,….,dn) să fie un șir grafic sunt:
a. di<=n-1, pentru orice i=1,n
b. suma d1+d2+…+dn trebuie să fie un număr par.
Reprezentarea și implementarea grafurilor neorientate
Matricea de adiacență [14] este o matrice binară de tip n x n, ale cărei elemente sunt definite astfel : a[i][j]=
Proprietate: Elementele de pe diagonala principală au valoarea 0 și este simetrică față de diagonala principală, deoarece, dacă există muchia [i,j] atunci există și muchia [j,i].
Poprietatea de simetrie: [xi, xj] aparține lui U => [xi, xj] aparține lui U.
Suma elementelor matricei de adicență este egală cu 2*m. Gradul unui nod i este egal cu suma elementelor de pe linia i sau coloana i. Nodurile adiacente nodului i sunt nodurile j (j=1,n) pentru care elementele din linia i sunt egale cu 1. (a[i][j]=1). Numărul de vecini ai nodului i este egal cu gradul nodului. Muchia [i,j] a grafului reprezintă un element de adiacență care îndeplinește condiția: a[i][j]=a[j][i]=1.
Matricea de incidență [14] este o matrice binară cu n linii și m coloane (An,m), ale cărei elemente ai,j sunt definite astfel: a[i][j]=
Proprietate: Pentru fiecare coloană există două elemente cu valoarea 1, iar restul elementelor au valoarea 0. Matricea de incidență are 2*m elemente egale cu 1.
Din matricea de incidență se pot obține următoarele informații: gradul unui nod, nodurile adiacente unui nod, numărul de vecini ai nodului, muchiile.
Lista muchiilor [14] este formată din m elemente care conțin fiecare câte o pereche de noduri (xi,xj) care formează o muchie.
Din lista muchiilor putem obține următoarele informații: gradul unui nod, nodurile adiacente ale unui nod, numărul de vecini ai unui nod.
Lista de adiacență [14] este formată din listele Li (1<=i<=n) care conțin toți vecinii unui nod Xi la care se poate ajunge direct din nodul Xi adică toate nodurile Xj pentru care [Xi, Xj] aparține lui U. Lista Li a vecinilor unui nod i al grafului este formată din nodurile j adiacente nodului i.
1. 4. 2. Grafuri orientate
Numim graf orientat (DIGRAF), o pereche ordonată de mulțimi G= (X, U), unde X este o mulțime finită și nevidă numită mulțimea nodurilor (vârfurilor), U este o mulțime formată din perechi ordonate de elemente ale lui X numită mulțimea arcelor.
Un graf care nu are proprietatea de simetrie. Mulțimea U este formată din perechi ordonate [xi, xj]. Nodul xi se numește extremitate inițială, iar nodul xj se numește extremitate finală. Succesor este orice nod la care ajunge un arc, care iese din nodul xi, iar predecesor este orice nod de la care intră un arc. Nod sursă este nodul care are mulțimea succesorilor formată din toate celelalte noduri, iar mulțimea predecesorilor este vidă. Nod destinație este nodul care are mulțimea predecesorilor formată din toate celelalte noduri, iar mulțimea succesorilor este multimea vidă.
Teorema 4: [14] Dacă graful orientat G are n noduri atunci numărul total de grafuri orientate care se pot forma cu aceste noduri este g=
Gradul intern a lui xi este numărul nodurilor care intră în xi: d+(x). Gradul extern a lui xi este numărul nodurilor care iasă din xi: d-(x). Nod terminal este un nod care are suma gradelor egală cu 1, iar nod izolat este nodul care are suma gradelor egala cu 0.
Teorema 5: [14] Suma gradelor interne ale tuturor nodurilor este egală cu suma gradelor externe ale tuturor nodurilor și cu numărul de arce.
Reprezentarea și implementarea grafurilor orientate
Matricea de adiacență [14] este o matrice binară de tip n x n, ale cărei elemente sunt definite astfel : a[i][j]=
Matricea de adiacență a unui graf orientat nu este simetrică față de diagonala principală.
Proprietate: Elementele de pe diagonala principală au valoarea 0. Suma elementelor matricei de adiacență este egală cu m (numărul de arce). Gradul extern al nodului este egal cu suma elementelor de pe linia i, iar gradul intern al nodului este egal cu suma elementelor din coloana i. Succesorii nodului i sunt nodurile j=1,n pentru care elementele din linia i sunt egale cu 1. Nodurile adiacente nodului i sunt nodurile (j=1,n ) pentru care elementele din linia i sau din colona i sunt egale cu 1 (a[i][j]=1 sau a[j][i]=1) sau este egală cu reuniunea dintre mulțimea succesorilor și mulțimea predecesorilor nodului. Numărul de vecini ai nodului i este dat de cardinalul mulțimii de noduri adicente nodului i. Arcul [i,j] al grafului reprezintă un element al matricei de adicență care îndeplinește condiția: a[i][j]=1.
Matricea de incidență a unui graf orientat [14] este o matrice cu n linii și m coloane, ale cărei elemente sunt definite astfel:
Proprietate: Pe fiecare coloană există un element cu valoarea 1 și un element cu valoarea -1, iar restul elementelor au valoarea 0. Matricea de incidență are m elemente egale cu 1 și m elemente egale cu -1. Suma elementelor matriciei este 0.
Din matricea de incidență se pot obține următoarele informații: gradul intern/extern al unui nod, succesorii/predecesorii nodului, nodurile adiacente nodului, numărul de vecini ai nodului, arcele care intră sau ies dintr-un nod.
Lista muchiilor [14] este formată din m elemente care conțin fiecare câte o pereche de noduri (xi,xj) care formează un arc.
Din lista muchiilor putem obține următoarele informații: gradul extern/intern al nodului, succesorii și predecesorii, nodurile adiacente, numărul de vecini.
Lista de adiacență [14] este formată din listele Li (1<=i<=n) care conțin toți vecinii unui nod Xi la care se poate ajunge direct din nodul Xi adică toate nodurile Xj pentru care [Xi, Xj] aparține lui U. Lista Li ai vecinilor unui nod i al grafului este formată din nodurile j care sunt succesorii nodului i.
Graful nul are mulțimea U vidă (nu are muchii, are numai noduri izolate). Matricea de adiacență a unui graf nul este matricea 0.
Graful complet este graful în care oricare ar fi două noduri ale grafului, ele sunt adiacente. Fiecare nod are gradul egal cu n-1.
Teorem 6: [14] Numărul m de muchii ale unui graf complet (neorientat) este m=n*(n-1)/2
Teorem 7: [14] Numărul de grafuri orientate complete care se pot construi cu n noduri este
Matricea de adiacență a unui graf neorientat complet are toate elementele egale cu 1 în afară de diagonala principală. Pentru un graf orientat complet avem a[i][j]=1 sau a[j][i]=1
Numărul minim de arce într-un graf orientat complet este egal cu numărul de muchii ale unui graf neorientat complet. Numărul maxim de arce într-un graf orientat complet este egal cu dublul muchiilor într-un graf neorientat complet.
1. 4. 3. Grafuri derivate dintr-un graf
Graful parțial [14] este graful Gp=(x,v) unde v<=U se obține prin eliminarea unor muchii. (rămân toate nodurile, se șterg muchii).
Teorema 8: [14] Numărul de grafuri parțiale ale unui graf cu m muchii este egal cu 2m
Subgraful [14] este graful Gs=(y,v) unde y<=x, v<=U se obține prin suprimarea din graful G a unor noduri și a tuturor muchiilor (arcelor) incidente cu aceste noduri.
Teorema 8: [14] Numărul de subgrafuri ale unui graf cu n noduri este 2n -1
Graful complementar [14] are proprietatea că două noduri sunt adiacente în graful Gc dacă ele nu sunt adiacente în graful G. Graful Gc nu conține nici o muchie din graful G. La graful orientat, dacă avem arcul [xi,xj] atunci în graful complementar putem avea arcul [xi,xj].
Conexitatea grafurilor
Lanțul este o succesiune de noduri care are proprietatea că, oricare ar fii 2 noduri succesive ele sunt adiacente.
Fiecare pereche de noduri succesive din lanț reprezintă parcurgerea unei muchii. La definirea unui lanț nu se ține cont de orientarea arcelor.
Lungimea unui lanț reprezintă numărul de muchii, respectiv arce care sunt în lanț.
Extremitățile unui lanț sunt formate din nodul cu care începe și se termină lanțul, iar sublanțul este un șir continuu de noduri din lanțul inițial.
Dacă am clasifica lanțurile în funcție de noduri atunci avem lanțuri elementare și neelementare, iar în funcție de muchii sunt lanțuri simple și compuse
Teorema 10: [14] Dacă un graf conține un lanț între două noduri x și y, atunci conține un lanț elementar între nodurile x și y.
Teorema 11: [14] Dacă un lanț este elementar, atunci este și lanț simplu.
Un lanț care are toate muchiile distincte două câte două și extremitățile coincid se numește ciclu. Dacă toate nodurile unui ciclu sunt distincte cu excepția extremităților, ciclul se numește ciclu elementar. Un graf fără cicluri se numește graf aciclic.
Teorema 12: [14] Dacă un graf conține un ciclu, atunci conține și un ciclu elementar.
Într-un graf orientat se definește un drum ca fiind o succesiune de noduri care au proprietatea că oricare 2 noduri successive sunt legate printr-un arc. Lungimea unui drum este dată de numărul de arce care îl compun. Drumul de lung minimă este drumul cu număr minim de arce. Subdrumul este format dintr-un subșir al drumului. Drumul elementar este drumul în care nodurile sunt distincte două câte două, iar drumul simplu este drumul în care arcele sunt distincte.
Teorema 13: [14] Dacă un graf neorienatat conține un drum între 2 noduri x și y atunci conține și un drum elementar între x și y.
Matricea drumurilor este o matrice pătrată binară de dimensiune n, reprezentând ordinul grafului, definită astfel :
Informațiile din matricea drumurilor se pot folosi pentru a verifica dacă există drum între două noduri ale grafului. Matricea drumurilor se obține din maticea de adiacență prin transformări succesive astfel: se generează toate nodurile k, iar pentru fiecare nod k se generează toate perechiile de noduri i și j (i și j !=k) și se verifică dacă a[i][k] și a[k][j]=1. În caz afirmativ, în matricea de adiacență se atribuie valoarea 1 elementului a[i][j].
Într-un graf orientat un drum care are toate arcele distincte și extremitățile coincid se numeste circuit. Circuit elementar este circuitul în care toate nodurile sunt distincte două câte două în afară de primul și ultimul.
Teorema 14: [14] Dacă un graf conține un circuit atunci conține și un circuit elementar.
Un graf care are proprietatea că pentru orice pereche de noduri diferite există un lanț care să le lege, se numește graf conex, iar un subgraf conex esteo ‘parte’ conexă dintr-un graf care nu este conex. Componentă conexă a unui graf este un subgraf conex care conține numărul maxim de noduri din G, care au proprietatea că sunt legate printr-un lanț. Un graf neconex este format din mai multe componente conexe. Graful conex este format dintr-o singură componentă conexă.
Teorema 15: [14] Numărul minim de muchii necesare pentru ca un graf neorientat cu n noduri să fie conex este n-1.
Dacă un graf cu n noduri are k componente conexe atunci numărul minim de muchii care trebuie adăugate ca să devină conex este k-1. Dacă un graf conex cu n noduri are n-1 muchii atunci orice pereche d noduri este legată printr-un lant și numai unu. Dacă un graf neorientat cu n noduri și m muchii este conex, numărul maxim de muchii care se pot elimina pentru a obține un graf parțial conex este m-n+1. Dacă un graf are n noduri, m muchii și k componente conexe, numărul de muchii care trebuie eliminate, pentru a obține un graf parțial aciclic este m-n+k.
Teorema 16: [14] Un graf neorientat conex cu n noduri și n-1 muchii este aciclic și maximal cu aceasta proprietate.
Pentru a obține, dintr-un graf neorientat conex, două componente conexe, numărul minim de muchii care trebuie înlăturate este gradul minim din graf.
Teorema 17: [14] Numărul maxim de muchii dintr-un graf neorientat cu n noduri și k componente conexe este (n-k)*(n-k+1)/2.
Un graf orientat care are proprietatea că, pentru orice pereche de noduri, există un drum care să le lege se numește graf tare conex. Un subgraf tare conex al grafului G este un subgraf, care are proprietatea ca este tare conex. Dacă un graf nu este conex, se numește componentă tare conexă a grafului, un subgraf conex maximal cu această proprietate (conține numărul maxim de noduri G, cu proprietatea că sunt legate printr-un drum). Un graf tare conex, are o singură componentă tare conexă. Subgraful predecesorilor unui nod este acel nod și mulțimea nodurilor din care este accesibil nodul. Subgraful succesorilor unui nod este acel nod și mulțimea nodurilor, care sunt accesibile din el. Componenta tare conexă, din care face parte un nod, este dată de intersecția dintre subgraful predecesorilor și succesorilor acelui nod. Pentru a verifica dacă un graf este conex, se verifică dacă între nodul 1 și fiecare dintre celelalte noduri există un lanț elementar. Pentru a verifica dacă există un drum între două noduri, se folosește matricea drumurilor.
Un graf G=(X,U) pentru care s-a definit o funcție cost f:U->R+ care asociază fiecărei muchii U un nr real pozitiv, numit costul muchiei, se n umește graf ponderat. Costul unui drum este suma costurilor muchiilor care formează acel drum.
Matricea costurilor unui graf este o matrice patratică ale cărei elemente a[i][j] sunt definite astfel: a.matricea costurilor minime:
b.matricea costurilor maxime:
Pentru determinarea drumului cu costul minim sau maxim între două noduri ale unui graf se poate folosi algoritmul Roy-Floyd și algoritmul Dijkstra. Algoritmul Roy-Floyd presupune găsirea drumului optim între două noduri oarecare i și j prin descoperirea drumurilor optime care îl compun. Matricea trece prin n transformări, în urma cărora fiecare element a[i][j] va memora costul minim dintre nodurile i și j.
-se foloseste pentru a gasi drumul optim intre doua noduri oricare i si j
-matricea trece prin k transformari (k de la 1 la n)
-pentru fiecare pereche de noduri i si j, daca a[i][k]+a[k][j]<a[i][j], atunci a[i][j]=a[i][k]+a[k][j]
Exemplul 25: Implementarea algoritmului Roy-Floyd
#include<fstream>
int a[100][100],n;
int const MAX=5000;
ifstream f(“cost.txt”);
void init()
{ f>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) a[i][j]=0;
else a[i][j]=MAX; }
void citire()
{ int i,j,c;
while(f>>i>>j>>c)
a[i][j]=c;
f.close(); }
void transformare()
{ for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][k]+a[k][j]<a[i][j])
a[i][j]=a[i][k]+a[k][j]; }
void afisare()
{ cout<<”costul drumurilor minime intre nodurile:”<<endl;
for(int i=-1 ;i<=n ;i++)
for(int j=1;j<=n;j++)
if(a[i][j]<MAX && i!=j)
cout<<”(“<<i<<”,”<<j<<”)-“<<a[i][j]<<endl; }
int main()
{ init(); citire();
transformare();
afisare(); }
Algoritmul Dijkstra construiește drumurile cu cost minim care pornesc de la un nod oarecare x – nodul sursă – până la fiecare nod din graful G – nodul destinație.
Exemplul 26: Implementarea algoritmului Dijkstra
#include<fstream.h>
int a[100][100],d[100],s[100],p[100],n;
int const MAX=5000;
ifstream f("cost.txt");
void init()
{ f>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) a[i][j]=0;
else a[i][j]=MAX; }
void citire()
{ int i,j,c;
while(f>>i>>j>>c)
a[i][j]=c; }
void generare_drum(int x)
{
int i,j,min,y;
s[x]=1;
for(i=1;i<=n;i++)
{ d[i]=a[x][i];
if(i!=x && d[i]<MAX)
p[i]=x; }
for(i=1;i<=n-1;i++)
{ for(j=1,min=MAX;j<=n;j++)
if(s[j]==0 && d[j]<min)
{ min=d[j];
y=j; }
s[y]=1;
for(j=1;j<=n;j++)
if(s[j]==0&&d[j]>d[y]+a[y][j])
{ d[j]=d[y]+a[y][j];
p[j]=y; } } }
void drum (int i)
{ if(p[i]!=0)
drum(p[i]);
cout<<i<<" "; }
void afisare(int x)
{ for(int i=1;i<=n;i++)
if(i!=x)
if(p[i]!=0)
{ cout<<"drumul cu costul de la nodul:"<<x;
cout<<"la nodul "<<i<<" are costul "<<d[i]<<endl;
drum(i);
cout<<endl; }
else
cout<<"Nu exista drum de la:"<<x<<" la “<<i<<endl;}
int main()
{ int x;
cout<<"x=";cin>>x;
init(); citire();
generare_drum();
afisare(x); }
Graful bipartit [14] este graful G=(X,U), dacă există mulțimea A și B, cu proprietatea că AUB=X și AB= și orice muchie din mulțimea U are o extremitate în A și cealaltă extremitate în B. Un graf bipartit G, este graf bipartit complet, dacă pentru orice nod xi din A (xi lui A) și xj din B (xj B) există o muchie care le leagă.
Se numește lanț hamiltonian, lanțul elementar, care conține toate nodurile grafului. Lanțul hamiltonian în care nodul inițial coincide cu nodul final se numește ciclu hamiltonian. Un graf care conține un ciclu hamiltonian se numește graf hamiltonian. Un graf hamiltonian nu poate conține noduri izolate.
Teorema 18: [14] Dacă fiecare nod al unui graf are gradul mai mare sau egal cu n/2, atunci graful este hamiltonian.
Se numește lanț eulerian, lanțul care conține toate muchiile grafului o singură dată. Dacă nodul inițial coincide cu nodul final, se numește ciclu eulerian. Un graf, care conține un ciclu eulerian, se numește graf eulerian. Un graf eulerian poate conține noduri izolate. Pentru ca un graf sa poate fi transformat în graf eulerian, trebuie să îndeplinească următoarele condiții: dacă numărul de noduri este par, să nu existe noduri cu gradul maxim și numărul de noduri cu gradul impar, să fie par. Deci numărul minim de muchii care trebuie adăugate este egal cu jumătate din numărul de noduri cu grad impar.
Teorema 19: [14] Un graf care nu conține noduri izolate este eulerian dacă și numai dacă este conex și gradele tuturor nodurilor sunt pare.
Graf turneu [14] este un graf orientat în care între oricare două noduri există un singur arc. Graful turneu este un graf complet.
Teorema 20: [14] Orice graf turneu conține un drum elementar, care trece prin toate nodurile grafului.
Parcurgerea grafului reprezintă operația prin care sunt examinate nodurile unui garf pornind de la nodul i, astfel încât fiecare nod accesibil din nodul i pe muchiile adiacente să fie atins o singură dată. Vecinii unui nod sunt reprezentați de toate nodurile accesibile din el și adiacente lui.
Vizitarea sau traversarea unui graf este operația prin care se parcurge graful trecându-se de la un nod i la nodurile vecine lui într-o anumită ordine. Există două metode pentru parcurgerea grafurilor:
Exemplul 27: Parcurgerea în lățime (BF – Breadth First): se vizitează mai întâi un nod inițial, apoi vecinii acestuia, apoi vecinii nevizitați ai acestora etc.
int n,a[10][10],vizitat[20],c[20],prim,ultim,k;
void citeste()
{ cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j]; }
void init(int k)
{ prim=ultim=1;
c[ultim]=k;
vizitat[k]=1; }
int este_vida()
{ return ultimo==prim; }
void adauga(int i)
{ ultim++;
c[ultim]=i;
vizitat[i]=1; }
void elimina()
{ prim++; }
void prelucrare()
{ k=c[prim];
for(int i=1;i<=n;i++)
if(a[k][i]==1 && vizitat[i]==0)
adauga(i);
elimina(); }
void afisare()
{ for(int i=1;i<=n;i++)
cout<<c[i]<<” “; }
void main()
{ citeste();
cout<<”nod de pornire”;cin>>k;
init(k);
while(!este_vida())
prelucrare();
cout<<”nodurile vizitate prin metoda BF sunt:”<<endl;
afisare(); }
Exemplul 28: Parcurgerea în adâncime (DF – Depth First): se vizitează mai întâi un nod i după care se trece la primul vecin nevizitat j al lui i, apoi se trece la primul vecin nevizitat al lui j etc până când se parcurge în adâncime ramura apoi se revine la nodul de la care s-a plecat ultima dată și se trece la următorul vecin.
Int n, a[10][10],vizitat[20],st[20],vf,k;
void citeste()
{//se citeste matricea de adiacenta
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j]; }
void init(int k)
{ vf=1; st[vf]=k;
vizitat[k]=1; }
int este_vida()
{ return vf==0; }
void adauga(int i)
{ vf++; st[vf]=I; vizitat[i]=1; }
void elimina()
{ vf–; }
void prelucrare()
{ int i=1;
k=st[vf];
while(i<=n && (a[k][i]==0 || a[k][i]==1 && vizitat[i]==1)))
i++;
if(i==n+1) elimina();
else { cout<<i<<” “; adauga(i); } }
int main()
{ citeste();
cout<<”nodul de pornire:”;cin>>k;
cout<<”nodurile vizitate prin metoda DF sunt:”<<endl;
cout<<k<<” “;Init(k);
while(!este_vida())
prelucrare(); }
Mai multe exemple pot fi găsite în Anexa 10.
1. 4. 4. Arbori
O categorie importantă de grafuri sunt acelea în care muchiile sunt niște legături de tip “părinte-fiu”. Un astfel de graf se numește arbore. Se presupune că fiecare nod posedă niște legături spre alte noduri numite fii. Nodul în cauză se mai numește și nod “tată” sau “părinte”. Oricare dintre noduri poate avea niște legături nule. Acele noduri care au numai legături nule se numesc și noduri terminale sau frunze. Unul dintre noduri are o poziție privilegiată, în sensul că el nu este fiul nimănui. Acesta se numește nodul rădăcină, sau simplu, rădăcina arborelui. Deci un graf neorientat conex și fără cicluri se numește arbore (liber).
Teorema 21: [14] Fie un graf G=(x,u). Următoarele afirmații sunt echivalente:
1. G este arbore.
2. G este un graf conex, minimal în raport cu aceasta proprietate (eliminând o muchie oarecare, se obține un graf ne-conex).
3. G este un graf fără cicluri, maximal în raport cu această propietate (adăugând o muchie oarecare, se obține un graf care are cel puțin un ciclu).
4. Graf aciclic cu n-1 muchii.
5. Garf conex cu n-1 muchii.
6. Orice pereche de noduri e legată printr-un singur lanț.
Teorema 22: [14] Un arbore cu n varfuri are n-1 muchii.
Orice arbore cu n>=2 conține cel puțin 2 noduri terminale (rădăcina și o frunză). Există un nod în care nu intră nici un arc, numit rădăcina arborelui. Cu excepția rădăcinii, fiecare nod are proprietatea că în el intră un singur arc. Acesta, leagă nodul respectiv de un alt nod numit predecesor sau părinte. Dintr-un nod pot ieși unul sau mai multe arce. Fiecare astfel de arc, leagă nodul respectiv de un alt nod numit succesor sau fiu al nodului.
Nodurile sunt organizate pe nivele, primul nivel fiind ocupat de nodul-rădăcină. Nodurile de pe ultimul nivel se caracterizează prin faptul că din ele nu mai iasă nici un arc și se numesc noduri terminale sau frunze.
Figura . Exemplu de arbore
În arborele din figura de mai sus, avem:
– Nodul 1 este rădăcina arborelui (de pe nivelul 0);
– Frunzele arborelui sunt nodurile: 3 (aflat pe nivelul 1); 5, 7(aflate pe nivelul 2) și 8, 9 (de pe nivelul 3);
– Succesorii (descendent, urmaș) nodului 2 sunt nodurile 5 și 6; la rândul său, nodul are ca predecesor (ascendent, strămoș) nodul 1.
Nodurile pot conține o așa numită informație utilă, care poate fi de orice tip. De obicei aceste informații se mai numesc și chei ale arborelui. Ordinul unui nod este dat de numărul de descendenți direcți. Orice nod al arborelui poate fi considerat rădăcină. Dacă un graf parțial al unui graf G este arbore parțial el se numește arbore parțial al grafului G.
Teorema 23: [14] Un graf G conține un arbore parțial dacă și numai dacă este un graf conex.
Arborele cu rădăcină se poate implementa prin:
1. Referințe descendente: vectorul de tați: 0 1 1 1 2 2 4 6 6
indici: 1 2 3 4 5 6 7 8 9
Exemplul 29: Se citește un număr natural n. Construiți un arbore cu proprietatea că fiecare nod are numărul de descendenți direcți cu 1 mai mare decât nivelul pe care se află. Excepție fac frunzele și nodul pentru care se termină cele n noduri. Afișați vectorul de tați.
Rădăcina (aflată pe nivelul 0) are un singur descendent direct, nodul de pe nivelul 1 are două, cele de pe nivelul 2 au câte trei, etc. De exemplu pentru n=15, vectorul de tați este: 0 1 2 2 3 3 3 4 4 4 5 5 5 5 6
int main()
{ int v=1,k=2,niv=1,p=1,i, tata[100],n;
cout<<"n=";cin>>n;
tata[1]=0; //primul nod este radacina deci pe pozitia 1 vectorul tata are valoarea 1
while(k<=n)
{ p=p*niv; //numărul maxim de noduri de pe fiecare nivel
for(i=1;i<=p && k<=n;i++)
{ tata[k++]=v; //valoarea pusa in vectorul de tati – nodul tata
if(i%niv==0) // dupa ce se completeaza numarul de fii ai unui nod, se trece la
v++; } //urmatorul nod de pe acelasi nivel
niv++; } //se trece la urmatorul nivel
for(i=1;i<=n;i++)
cout<<tata[i]<<" "; }
2. Referințe ascendente: vectorul de noduri terminale.
Nod terminal: 3 5 7 4 1 2 6 6
Părinte nod terminal: 1 2 4 1 2 6 6 9
indici: 1 2 3 4 5 6 7 8
Teorema 24: [14] Numărul total de arbori liberi ce se pot forma cu n noduri este nn-1.
Un arbore care are propietatea că fiecare nod, cu excepția frunzelor are cel mult doi descendenți (succesori) se numește arbore binar. Într-un arbore binar, cei doi succesori ai unui nod (dacă există) se numesc succesor stâng respectiv succesor drept. Un arbore cu propietatea că fiecare nod, cu excepția frunzelor are exact doi descendenți (succesori) se numește arbore binar strict. Ordinul unui nod al arborelui poate fi doar 0,1 sau 2. Un arbore binar strict cu n noduri terminale are în total 2*n-1 noduri și număr impar de noduri. Numărul de frunze este egal cu numărul de noduri neterminale+1.
Un arbore binar se numește echilibrat dacă diferența dintre înălțimile celor 2 subarbori ai oricărui nod e cel mult 1, iar arbore binar perfect echilibrat este cel care are proprietatea că diferența dintre numărul nodurilor celor 2 subarbori ai oricărui nod e cel mult 1.
Arbore binar complet este arborele binar care are toate nodurile terminale pe același nivel.
Figura . Exemplu de arbore binar
Arborii binari se pot implementa:
A. STATIC:
1. Folosind doi vectori ce memorează cei doi succesori ai unui nod:
nod 1 2 3 4 5 6 7 8 9 10
st 2 4 0 7 6 0 0 9 0 0
dr 3 5 8 0 0 0 0 10 0 0
Exemplul 30: Se dă un arbore binar cu n noduri prin vectorii de descendenți st și dr. Afișați frunzele arborelui, nodurile cu un singur descendent direct, nodurile cu doi descendenți direcți.
Pentru arborele și vectorii de mai sus se afișează:
Frunzele: 6, 7, 9, 10
Nodurile cu un singur descendent direct: 3, 4, 6
Nodurile cu doi descendenți direcți: 1, 2, 8
#include<iostream>
int i,n,st[100],dr100];
int main()
{ cout<<"n="; cin>>n;
cout<<"succesorii din stanga: ";
for(i=1;i<=n;i++)
cin>>st[i];
cout<<"succesorii din dreapta: ";
for(i=1;i<=n;i++)
cin>>dr[i];
cout<<"frunzele: ";
for(i=1;i<=n;i++)
if(st[i]==0 && dr[i]==0)
cout<<i<<" ";
cout<<endl<<"nodurile cu un singur descendent: ";
for(i=1;i<=n;i++)
if(st[i]*dr[i]==0 && st[i]+dr[i]!=0)
cout<<i<<" ";
cout<< endl<<"nodurile cu doi descendenti: ";
for(i=1;i<=n;i++)
if(st[i]!=0 && dr[i]!=0)
cout<<i<<" "; }
2. Folosind doi vectori în care se memorează filiația nodurilor:
nod 1 2 3 4 5 6 7 8 9 10
tata 0 1 1 2 2 5 4 3 8 8
fii 0 -1 1 -1 1 -1 -1 1 -1 1
fii[i]=-1 => i este succesor stâng
1 => i este succesor drept
0 => i este rădăcină
Exemplul 31: Se dă un arbore binar cu n noduri prin vectorii tata și fii (reprezentarea cu legături ascendente de tip tată și respectiv poziția fiilor: -1 pentru stânga, 1 pentru dreapta).
Afișați vectorii de descendenți st și dr.
Pentru arborele și vectorii de mai sus se afișează:
st: 2, 4, 0, 7, 6, 0, 0, 9, 0, 0 dr: 3, 5, 8, 0, 0, 0, 0, 10,0, 0
int i,n,st[100],dr[100],tata[100],fii[100];
int main()
{ cin>>n;
for(i=1;i<=n;i++)
cin>>tata[i];
for(i=1;i<=n;i++)
cin>>fii[i];
for(i=1;i<=n;i++)
{ if(tata[i]!=0)
{ if(fii[i]==-1) st[tata[i]]=i;
if(fii[i]==1) dr[tata[i]]=i; } }
for(i=1;i<=n;i++)
cout<<st[i]<<" ";
cout<<endl;
for(i=1;i<=n;i++)
cout<<dr[i]<<" "; }
B. Dinamic folosind pointeri. Se face prin definirea unui tip de dată pentru un nod din arbore și adresa unui nod. Tipul de dată este definit ca o înregistrare care conține trei categorii de câmpuri: informația utilă, adresa subarborelui stâng și adresa subarborelui drept.
struct nod{
int info;
nod *st,*dr; }*r;
Exemplul 32. Implementarea dinamică a arborilor și parcurgerea lor în inordine, preordine și postordine
Vom considera că fiecare nod al arborelui subordonează un subarbore binar stâng și un subarbore binar drept. Se definesc subprograme recursive care utilizează tehnica Divide et Impera.
Principalele modalități de parcurgere ale unui arbore binar sunt:
A) Prin metode specifice grafurilor: în adâncime și lățime.
B) Prin metode specifice arborilor binari :
Parcurgerea în inordine (stânga–rădăcină–dreapta SRD) – se parcurge mai întâi subarborele stâng, apoi rădăcina, apoi subarborele drept.
Parcurgerea în preordine (rădăcină–stânga–dreapta RSD) – se parcurge mai întâi rădăcina, apoi subarborele stâng, apoi subarborele drept.
Parcurgerea în postordine (stânga–dreapta–rădăcină SDR) – se parcurge mai întâi subarborele stâng, apoi subarborele drept și la sfârșit rădăcina.
#include<iostream>
#include<conio>
struct nod{ int info;
nod*st,*dr; }*r;
void srd(nod *c)
{ if(c)
{ srd(c->st);
cout<<c->info<<" ";
srd(c->dr); } }
void rsd(nod *c)
{ if(c)
{ cout<<c->info<<" ";
rsd(c->st);
rsd(c->dr); } }
void sdr(nod *c)
{ if(c)
{ sdr(c->st);
sdr(c->dr);
cout<<c->info<<" "; } }
nod* citire()
{ int nr;
nod*c;
cout<<"nr de ordine "; cin>>nr;
if(nr)
{ c=new nod;
c->info=nr;
c->st=citire();
c->dr=citire();
return c; }
else return 0; }
int main()
{ clrscr();
r=citire();
cout<<endl<<"parcurgere srd – in inordine "<<endl;
srd(r);
cout<<endl<<"parcurgere rsd – in preordine "<<endl;
rsd(r);
cout<<endl<<"parcurgere sdr – in postordine "<<endl;
sdr(r); }
Arborele binar de căutare [14] este un arbore binar cu proprietatea că pentru fiecare nod cheia din succesorul stâng este mai mică decât cheia din nod, iar cheia din succesorul drept este mai mare decât cheia din nod (nu există mai multe chei cu aceeași valoare).
struct nod {
int info;
nod*st,*dr; }*q;
int n,x;
void inserare(nod *&r,int x)
{ if(r)
if(r->info==x) cout<<"nr deja inserat "<<endl;
else if(r->info<x) inserare(r->dr,x);
else inserare(r->st,x);
else { r=new nod; r->info=x; r->st=c->dr=0; } }
void sterge(nod *r, nod *q)
{//se cauta in subarborele drept al nodului curent r primul nod care nu are succesor drept q
if(q->dr) sterge(r,q->dr);
else { nod *p; r->info=q->info; p=q->st; delete q; q=p; } }
void stergere (nod *&r, int x)
{ nod *q;
if(r)
if(r->info==x) //daca s-a gasit nodul
if(r->st==NULL && r->dr==NULL)
{ delete r; r=NULL; } //daca este nod terminal
else
if(r->st==NULL)
{ q=r->dr; delete r; r=q; } //daca are numai succesor drept
else
if(r->dr==NULL)
{ q=r->st; delete r; r=q; } //daca are numai succesor stang
else sterge(r,r->s); //daca are si succesor stang si succesor drept
else //daca nu s-a gasit
if(r->info<x)
stergere(r->dr,x); //cauta in succesorul drept
else
stergere(r->st,x); //cauta in succesorul stang
else
cout<<”Cheia nu exista”; }
void svd(nod *r) //parcurgere in inordine
{ if(r)
{ svd(r->st); cout<<r->info<<" "; svd(r->dr); } }
int cautare(nod *r,int x)
{ if(r)
if(r->info==x) return 1;
else
if(r->inf<x) cautare(r->dr,x);
else cautare(r->st,x);
else return 0; }
int minim(nod *r)
{ if(r->st)
return minim(r->st)
else return r->info; }
int maxim(nod *r)
{ if(r->dr) return maxim(r->dr)
else return r->info; }
int main()
{ cout<<"nr de noduri "; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"valoarea de inserat "; cin>>x;
inserare(q,x); }
cout<<endl<<"arborele are urmatoarele noduri "<<endl;
svd(q);
cout<<endl<<"valoarea de cautat "; cin>>x;
if(cautare(q,x))
cout<<"s-a gasit!";
else
cout<<"nu s-a gasit!";
cout<<endl<<”Minimul este “<<minim(r);
cout<<endl<<”Maximul este “<<maxim(r);
cout<<”Cheia care se sterge:”; cin>>x; stergere(r,x); }
Mai multe exemple pot fi găsite în Anexa 11.
CAPITOLUL 2. PARTEA DIDACTICĂ.
METODE ACTIV-PARTICIPATIVE DE PREDARE ȘI EVALUARE A RECURSIVITĂȚII ÎN LICEU
2. 1. Introducere
Scopul acestui capitol este să prezinte mai multe metode tradiționale care pot fi folosite în predarea recursivității cât și metode activ-participative pentru predarea recursivității în liceu. Am prezentat metodele tradiționale împreună cu avantajele și dezavantajele lor și am evidențiat rolul metodelor activ-participative în motivarea elevilor pentru studiul recursivității. De asemenea ele au un rol important în crearea de deprinderi și abilități utile elevilor.
Se vorbește tot mai mult despre activități, care trebuie să fie centrate pe elev, pe interesele, nevoile și idealurile lui. De aceea, pe lângă metodele și tehnicile tradiționale profesorul ar trebui să includă și metode moderne, interactive, astfel încât procesul de predare-învățare să fie unul eficient. Profesorul trebuie să fie un bun organizator, care să-și încurajeze și să-și stimuleze elevii să participe cu interes la ore, să coopereze, să analizeze ceea ce aud, să își exprime părerile, să ajungă la identificarea răspunsurilor corecte, din care apoi să descopere cunoștințe noi.
Metodele și tehnicile interactive încurajează munca în echipă și implică o învățare activă. Elevii participă la propria lor formare și se consultă cu colegii și profesorul, făcând schimb de cunoștințe pentru a progresa.
Procesul de învățare condus de către profesor trebuie să aibă în vedere o multitudine de finalități:
crearea unei baze cu noțiuni teoretice
dezvoltarea abilităților de a îmbina noțiunile teoretice cu problemele practice
realizarea procesului de înțelegere de către elevi a materialului predat
motivarea elevilor în studiul temei respective
crearea unei atitudini pozitive față de studiu în general,
responsabilizarea studiului individual,
crearea de aptitudini de lucru în echipă
Etimologic, termenul metodă provine din grecescul „methodos”, care înseamnă „drum spre”. Metodele de învățământ pot fi definite ca „modalități de acțiune cu ajutorul cărora, elevii, în mod independent sau sub îndrumarea profesorului, își însușesc cunoștințe, își formează priceperi și deprinderi, aptitudini, atitudini, concepția despre lume și viață”. [09]
Există mai mulți factori subiectivi care influențează procesul de învățare:
mediul social în care elevii își desfășoară activitatea
structura psihică a elevilor, particularitățile de vârstă și cele individuale ale elevilor
natura mijloacelor de învățământ
modul în care e receptat feedbackul.
Una din îndatoririle societății contemporane este regândirea instituției școlare, precum și a educației în toate cele trei aspecte ale ei: formală, informală și nonformală. Sistemul școlar, prin oferta sa educativă, contribuie la dezvoltarea, formarea și evoluția personalității copilului.
Deși, teoretic vorbind, există un oarecare acord asupra punctelor de vedere privind rolul evaluării și al metodelor de evaluare, la nivel practic este percepută și practicată diferit de la o școală la alta, de la un profesor la altul. Evaluarea este practicată în toate acțiunile umane. La nivel educațional însă ea nu mai este un act final al învățării, ci se integrează în procesul de învățare.
Evaluarea are ca scop cunoașterea efectelor activității desfășurate, în vederea optimizării ei, prin colectarea, organizarea și interpretarea rezultatelor obținute prin instrumentele de evaluare.
De-a lungul anilor gradul de obiectivitate și de acuratețe al metodelor de evaluare a fost obiectul multor polemici. Practic, cea mai bună soluție o constituie îmbinarea lor. Strategiile moderne de evaluare urmăresc să ofere elevilor suficiente și variate posibilități de a demonstra ceea ce știu, dar mai ales, ceea ce pot să facă (priceperi, deprinderi, abilități, competențe). Acestea sunt: proiectul; portofoliul; fișa pentru activitatea personală a elevului; hărțile conceptuale; tehnica 3-2-1; metoda R.A.I.; studiul de caz; observarea sistematică a activității și a comportamentului elevului; jurnalul reflexiv; investigația; interviul; înregistrări audio și/sau video.
2. 2. Metode tradiționale
Deoarece elevii sunt diferiți este necesară folosirea cât mai multor metode de predare care să le valorifice potențialul.
Din punct de vedere cronologic, metodele educaționalese impart in: metode tradiționale și metode moderne.
În învățământul tradițional, principalele metode sunt cele orale:
Expunerea didactică – este o metodă ce a fost folosită timp îndelungat și constă în prezentarea verbală, sub forma unui monolog, a unui volum de informație, de către profesor către elevi. Importanța utilizării metodei expunerii în general reiese din faptul că, pe de o parte, scurtează timpul însușirii de către elevi a ceea ce vrea profesorul să transmită, ceea ce, prin metode bazate pe descoperire, ar fi mult mai dificil. Pe de altă parte, ea constituie o ocazie permanentă pentru profesor de a oferi elevului un model (sau o sugestie de model) de ordonare și sistematizare a informației din diverse domenii. În cazul recursivității se folosește atât la prezentarea noțiunilor teoretice, cât și la structurarea lor.
În funcție de vârsta elevilor și de experiența lor, expunerea didactică poate îmbrăca mai multe variante: povestirea, explicația, prelegerea școlară.
Povestirea este folosită atunci când se dorește prezentarea informației sub formă descriptivă sau narativă cu respectarea ordinii în timp sau spațiu a obiectelor, fenomenelor și evenimentelor. Explicațiile nu lipsesc cu desăvârșire, dar ele ocupă un loc secundar în raport cu prezentarea faptelor. De exemplu pentru motivare se poate povesti elevilor despre fractali, despre legenda turnurilor din Hanoi sau despre tacticile militare de tip divide et impera folosite de-a lungul timpului de marile puteri.
Explicația este o metodă de comunicare orală în care predomină argumentarea rațională. Este o formă de expunere a unui subiect, a problemelor de lămurit (mai detaliat, în cazul în care elevul are întrebări), a regulilor și a teoremelor, prin care se prezintă în mod logic cauze, motive, relații, funcții, sensuri. Este frecvent însoțită de demonstrații. Se pornește de la teorie la practică, de la abstract la concret. În acest caz se clarifică diferite noțiuni și metode și dacă este cazul și teoreme și formule prezentate elevilor.
Prelegerea școlară reprezintă forma de expunere prin care informația este prezentată ca o succesiune de idei sau interpretări de fapte separate într-un tot unitar. Prezentarea noțiunilor recursive și aplicarea metodei recursivității în diferite tehnici de programare pot constitui subiectul unei prelegeri.
Observarea poate fi independentă sau dirijată parțial de profesor, desfășurându-se după un plan prestabilit. Ea precizează obiectivele observării, notarea datelor esențiale și prelucrarea lor. Pe cât posibil elevii vor lucra independent, sugerându-li-se doar direcțile principale, lucru necesar pentru a-i pregăti în vederea cercetării. Prin observare elevul urmărește sistematic materialul predat în vederea identificării unor caracteristici semnificative. Se aplică mai ales la activități cu caracter practic, însoțind explicația, și antrenând spiritul de observație și curiozitatea. Observarea reprezintă una dintre metodele de învățare prin cercetare și descoperire. Spre exemplu, elevii pot fi provocați să observe cum se aplică recursivitatea la celelalte tehnici de programare și chiar și în alte domenii de activitate.
Conversația didactică este o metodă de comunicare orală care are ca obiectiv formularea de întrebări și răspunsuri în vederea stimulării și dirijării activitatii de învățare propriu-zise. Se folosește în scopul însușirii de către elevi a unor noi cunoștințe. Trebuie să predomine întrebările: Cum? De ce? Ce însemnătate are? și nu: Cine? Unde? Ce este? Să fie formulate clar, simplu, corect și să solicite răspunsuri corecte, precise, să îl determine pe elev să se folosească de informațiile de care dispune, să facă o serie de asociații care să-l conducă la descoperirea unor noi aspecte ale noțiunilor învățate. De exemplu elevilor li se pot pune astfel de întrebări: De ce se folosește recursivitatea? De ce este mai practică folosirea recursivității în anumite probleme și nu funcțiile iterative? Cum poate fi folosită în problemele date spre rezolvare? etc.
Descrierea este o metodă de comunicare oral-expozitivă. A descrie înseamnă a înșirui însușirile pe care le are un obiect, un fenomen etc. Oferă posibilitatea de a dezvolta spiritul de observație al elevilor. În cadrul descrierii, se poate utiliza cu succes comparația, pentru a scoate în evidență asemănările și deosebirile legate de anumite noțiuni. În cazul recursivității se pot evidenția, spre exemplu, asemănările și deosebirile dintre funcțiile iterative și cele recursive.
Demonstrația are tot un caracter practic, dar trebuie însoțită de explicație verbală, pe secvențe. Elevii sunt atenționați să observe ceea ce demonstrează profesorul. Diferitele formule ce apar în prezentarea noțiunilor teoretice pot fi demonstrate pentru a justifica elevilor veridicitatea lor. De exemplu, faptul că numărul de muchii dintr-un graf este egal cu jumătate din numărul elementelor egale cu 1 din matricea de adiacență a unui graf neorientat poate fi demonstrat prin aceea că matricea de adiacență, fiind simetrică față de diagonala principală, elementele a[1][2]=a[2][1]=1 reprezintă aceeași muchie.
Lucrul cu manualul reprezintă metoda didactica în cadrul căreia învățarea are ca sursă de informare a elevului manualul sau alte surse asemănătoare punându-se astfel bazele autoinstruirii și educației permanente. Folosirea manualului în învățare are ca punct de plecare lectura individuală a materialului specificat de către profesor. Lucrul cu manualul înlocuiește momentele de expunere a profesorului, poate fi folosit pentru a urmări exemplele prezentate, pentru a discuta noțiunile teoretice și formulele prezentate. Sau, în cazul manualelor alternative, să lectureze optional noțiunile prezentate și într-o altă formă.
Exercițiul presupune repetarea conștientă a unei activități având ca scop formarea de deprinderi, consolidarea cunoștințelor și dezvoltarea capacităților intelectuale. Consolidarea cunoștințelor reprezintă aspectul teoretic al acțiunilor implicate în exercițiu. Se pot folosi exerciții în care se dă algoritmul și datele inițiale, iar elevul trebuie să precizeze anumite date de ieșire, dar și exerciții prin care să rezolve diferiți algoritmi recursivi.
În mod tradițional, toate acestea sunt metode centrate pe profesor, acesta având rolul major și activ în cadrul procesului didactic, transmițând cunoștințe și impunând punctul de vedere, rolul elevilor reducându-se la urmărirea expunerilor și explicațiilor profesorului. Elevii acceptă pasiv ideile transmise și încearcă să rețină și să reproducă ideile auzite lucrând izolat.
2. 3. Metode activ participative folosite în predarea recursivității
Metodologia didactică actuală presupune în plus implicarea activă și conștientă a elevilor în procesul propriei formări, dar și în stimularea creativității acestora. Elevii nu sunt priviți doar ca receptori de informații, ci și ca participanți activi la actul educativ. În procesul instructiv-educativ, încurajarea comportamentului participativ înseamnă pasul de la „a învăța” la a „învăța să fii și să devii”. Principalul avantaj al metodelor activ-participative îl reprezintă implicarea elevilor în actul didactic, pregătirea acestora pentru a face față situațiilor, dobândind dorința de angajare și acțiune și formarea capacității acestora de a emite opinii și aprecieri asupra subiectelor studiate.
Metodele activ-participative, în antiteză cu metodele tradiționale de învățare, pun accent pe învățarea prin cooperare, stimulând motivația și ajutând elevii să-și exprime opțiunile în domeniul educației, culturii, a folosirii timpului liber, putând deveni coparticipanți la propria formare. Elevii participă activ la educație nu doar recepționează informații.
Noul model de învățare este un model activ ce presupune implicarea directă a elevului în procesul de dezvoltare a capacităților de învățare, în asimilarea cunoștințelor și dobândirea gândirii critice. Activitatea la clasă presupune un nou tip de relaționare pe mai multe direcții: profesor – elev, elev – elev, elev – profesor, diametral opuse față de tipul unidirecțional profesor – elev al modelului clasic.
Gândirea critică înseamnă a deține cunoștințe utile, a avea convingeri raționale, a propune opinii personale, a accepta că ideile proprii pot fi discutate și evaluate, a construi argumente suficiente propriilor opinii, a participa activ și a colabora la găsirea soluțiilor.
Principalele metode de dezvoltare a gândirii critice sunt: metoda Ciorchinelui; metoda Mozaic; metoda Cubul; metoda Turul Galeriei; metoda 6/3/5; metoda Lotus; metoda Palariile ganditoare; metoda Frisco; metoda Schimba perechea; metoda Explozia stelara; diagrama Venn; metoda Cauza-efect.
Pentru ca învățarea prin cooperare să se bucure de un real succes, se impune respectarea unor reguli. Elevii trebuie să fie dispuși să lucreze în echipă. Se impune respectarea a două condiții: asigurarea unui climat pozitiv în clasă și formularea unor explicații complete și corecte asupra sarcinii de lucru, astfel încât aceasta să fie înțeleasă de toată lumea.
În vederea asigurării unui climat pozitiv în sala de clasă este necesar ca elevii să aibă impresia că au succes în ceea ce fac. Pentru a avea succes într-o clasă e necesar să ai, ca profesor, așteptări rezonabile de la elevi, să utilizezi în mod eficient strategii de management educațional, să stabilești obiective clare pe care să le comunici elevilor, să valorifici la maxim timpul destinat predării și să practici o evaluare obiectivă.
Profesorii trebuie să ofere explicații cât mai clare și să se asigure că ele au fost corect înțelese de către elevi, de aceasta depinzând eficența muncii în grup. Prin metodele moderne se încurajează initiațiva, creativitatea și participarea activă a elevilor.
2. 3. 1. Metoda ciorchinelui
Metoda chiorchinelui este o metodă de învățare activă, o metodă grafică, o metodă brainstorming nelineară care stimulează găsirea conexiunilor dintre ideile despre subiect, reprezintă o modalitate de a construi sau realiza asociații de idei sau de a releva noi sensuri ale ideilor însușite anterior, care încurajează elevii să gândească liber și deschis, de a se implica activ în procesul de gândire. (Brainstorming-ul reprezintă formularea a cât mai multor idei, oricât de fanteziste ar putea părea acestea, ca răspuns la o situație enunțată, după principiul cantitatea generează calitatea.)
Poate fi nedirijat, când elevii noteză toate ideile posibile într-o rețea a ciorchinelui realizată de ei și semidirijat, când profesorul stabilește niște criterii pe baza cărora elevii vor completa ciorchinele.
Metoda chiorchinelui dezvoltă la elevi:
capacitățile cognitive (identificare, definire, interpretare, clasificare, formulare);
abilități de de muncă în echipă;
atitudini.
“Ciorchinele” este o tehnică flexibilă care poate fi utilizată atât individual, cât și ca activitate de grup. Este o „strategie de găsire a căii de acces la propriile cunoștințe, înțelegeri sau convingeri legate de o anumită temă” [25].
Când se aplică individual, tema pusă în discuție trebuie să fie familiară elevilor, întrucât ei nu mai pot culege informații și afla idei de la colegi. În acest caz, utilizarea „ciorchinelui” poate reprezenta o pauză în brainstorming-ul de grup, dând posibilitatea elevilor să gândească în mod independent.
Folosită în grup, tehnica „ciorchinelui” dă posibilitatea elevilor să ia cunostință de ideile altora, de legăturile si asociațiile dintre acestea. [17]
Această metodă poate fi folosită în activitățile de învățare, activitățile de fixare a cunoștințelor, evaluarea sumativă a unei unități de învățare.
Metoda pornește de la prezentarea și scrierea cuvăntului/cuvintelor-cheie în mijlocul tablei, apoi elevii sunt învurajați să scrie cuvinte sau sintagme în legătură cu tema pusă în discuție. Urmează apoi realizarea propriu-zisă a ciorchinelui în care profesorul le cere elevilor să lege cuvintele sau ideile propuse prin linii care evidențiază conexiunile între idei, realizând astfel o structura în formă de ciorchine, ca, în final să aibă loc reflecția asupra idelor emise și conexiunilor realizate.
Reguli pentru utilizarea acestei tehnici: notarea tuturor ideilor legate de tema respectivă; lipsa judecății ideilor expuse; dintr-o idee dată pot apărea alte idei, astfel se pot construi „sateliți” ai ideii respective; apariția legăturilor numeroase și variate între idei.
Avantajele tehnicii: fixarea ideilor și structurarea informațiilor; înțelegerea ideilor; poate fi aplicată atât individual, cât și la nivelul întregii clase pentru sistematizarea și consolidarea cunoștințelor; în etapa de reflecție, elevii pot fi ghidați prin intermediul unor întrebări, în ceea ce privește gruparea informațiilor în funcție de anumite criterii.
Limite: enunțarea unor idei și urmarea unor piste nerelevante pentru tema pusă în discuție; timpul îndelungat necesar pentru aplicare; posibila implicare inegală a elevilor în activitate; lipsa exercițiului poate conduce la ineficiența tehnicii, la primele aplicări; cadrul didactic trebuie să aleagă cu grijă termenii cheie, pentru că pot apărea dificultăți în a stabili relații între aceștia.
De exemplu am scris în mijlocul tablei, iar elevii în mijlocul foii de hârtie cuvântul RECURSIVITATE. Elevii au scris în jurul lui diferite alte cuvinte: ALGORITMI RECURSIVI, DIVIDE ET IMPERA, BACKTRACKING, GRAFURI, care au legătură cu recursivitatea, apoi s-au trasat linii care evidențiază relațiile dintre ele. S-au notat toate ideile, sintagmele sau cunoștințele sugerate de elevi cu privire la tema respectivă, în jurul cuvintelor deja scrise, trăgându-se linii (pe măsură ce s-au scris cuvinte și idei noi) între toate ideile care par a fi conectate. Activitatea s-a oprit când s-au epuizat toate ideile sau până la expirarea timpului destinat acestei activități.
Etapele pot fi precedate de brainstorming în grupuri mici sau în perechi, ceea ce favorizează îmbogățirea și sintetizarea cunoștințelor, profesorul scriind pe tablă, fără a comenta sau judeca, rezultatele grupurilor. În ultima etapa a lecției, ciorchinele a fost reorganizat utilizându-se unele din conceptele găsite de elevi sau de profesor.
Rezultatele individuale, realizate pe foi, s-au adăugat de către fiecare elev în propriul portofoliu. Notarea s-a făcut după criterii dinainte stabilite și cunoscute de către elevi. Evaluarea presupune analiza, corectarea, critica, lauda, ierarhizarea și luarea deciziei, notarea atât a ”procesului” cât și a ”produsului”.
Figura . Medota ciorchinelui pentru reprezentarea noțiunilor privitoare la recursivitate
2. 3. 2. Proiectul
.
Proiectul este o metodă interactivă de predare – învățare, o investigație sistematică a unui subiect, care presupune implicarea activă a elevilor pe tot parcursul activităților desfășurate. Se desfășoară pe o perioadă de timp de câteva zile sau câteva săptămâni. De obicei cuprinde o parte teoretică și una practică, experimentală. Un proiect înseamnă mai mult decât un exercițiu, este ceva mai complex, trebuie să judece, să studieze. Începe în clasă prin definirea clară și alegerea temei, a sarcinilor de lucru, prin stabilirea obiectivelor, a cerințelor, (ce se dorește să se obțină în final) și a etapelor intermediare. Se specifică regulile impuse (cum se repartizează munca în grup), etica realizării proiectului (ce se întâmplă dacă un elev copiază de la altul și cum trebuie tratate aceste situații). De asemenea trebuie precizat modul de evaluare – se vizualizează rezultatele printr-un program, se execută algoritmii pentru diferite date de intrare, se verifică modul de realizare a algoritmilor astfel încât să se ajungă la soluționarea problemelor. Termenul de predare și criteriile după care va fi evaluat proiectul trebuie stabilite astfel încât elevul să-și poată organiza în timp munca. Munca se continuă acasă și în sala de clasă pe parcursul unui interval de timp stabilit în funcție de tema proiectului. Proiectul este o activitate personalizată care presupune colectarea datelor si realizarea produsului. Elevii pot decide nu numai asupra conținutului acestuia, dar și asupra formei lui de prezentare. În tot acest timp elevul are permanente consultări cu profesorul. De regulă, aceste activități se finalizează tot în clasă, prin prezentarea în fața colegilor a produsului realizat și dacă este cazul, a aplicației realizate.
Poate fi realizat individual sau în grup. Principalele avantaje ale folosirii proiectului este faptul că facilitează învățarea prin cooperare dacă se lucrează pe grupe și dezvoltă capacitățile de investigare și sistematizare a informațiilor, stimulează autonomia elevilor și creativitatea acestora.
Evaluarea proiectului presupune din partea profesorului multă atenție. Profesorul poate să alcătuiască fișe de evaluare în care să consemneze în mod regulat observații și aprecieri asupra activității fiecărui elev/grup de lucru, poate efectua evaluări parțiale.
Este indicat ca profesorul să le recomande elevilor ca în realizarea proiectului să respecte următoarea structură: [26]
a. Pagina de titlu (include tema proiectului, numele autorului/autorilor, școala, clasa, perioada de realizare);
b. Cuprinsul (se precizează titlurile capitolelor și subcapitolelor);
c. Introducerea (se fac referiri la importanța temei, cadrul conceptual și metodologic);
d. Dezvoltarea elementelor de conținut prezentate în cuprins;
e. Concluzii;
f. Bibliografie;
g. Anexe.
În cadrul acestei cercetări, am împărțit clasa în grupe de câte trei-patru elevi și am enunțat temele pentru proiecte – titluri cuprinse în metoda ciorchinelui aplicată cu o oră înainte:
1. Algoritmi elementari recursivi
2. Metoda Divide et Impera: turnurile din Hanoi și metode de sortare care folosesc această metodă
3. Fractalii – fascinantele obiecte geometrice, desenare și generare
4. Backtracking: comparare între problemele implementate iterativ și cele implementate recursiv
5. Grafuri neorientate: aplicarea lor în probleme din viața practică – realizarea unei hărți cu orașele județului și a distanțelor dintre ele și găsirea celui mai scurt drum dintre două localități specificate
6. Grafuri orientate: aplicarea lor în probleme din viața de zi cu zi – realizarea unei hărți a orașului cu specificarea străzilor cu sens unic și găsirea drumului între diferite clădiri istorice specificate
7. Arbori parțiali de cost minim: algoritmul lui Kruskal și algoritmul lui Prim
Proiectul s-a desfășurat pe durata a 4 săptămâni. Voi detalia primul proiect dintre cele propuse. Elevii au căutat materiale pentru documentație (inclusiv fișele de lucru), apoi au trecut la cea de-a două etapă: realizarea propriu-zisă a proiectului. Am stabilit împreună cu grupa structura proiectului, detaliile fiecărei secțiuni, cerințele și termenele, elevii putându-și organiza munca și știind după ce criterii vor fi evaluați. Apoi și-au împărțit sarcinile, astfel încât fiecare elev a cercetat diferite aspecte: unul prezentarea metodei, iar ceilați algoritmii elementari recursivi: sume, produse, funcții speciale, algoritmii recursivi referitori la divizorii și cifrele unui număr și algoritmii recursivi pentru vectori și matrici. Problemele au fost rezolvate în limbajul C++, folosind CodeBlocks. Am observat, notat și îndrumat continuu elevii pentru aplicațiile realizate în laborator. Examinările orale le-am folosit în mod continuu pe parcursul orelor în care elevii au lucrat la proiect, ceea ce mi-a oferit informații relevante referitoare la nivelul de pregătire al elevilor, am putut surprinde calitatea și cantitatea de cunoștiințe asimilate de elevi și implicit am depistat unele lacune, pe care le-am completat prin activități de recuperare orientate pe elev. Spre final au combinat toate cele patru părți, constituind un tot unitar, apoi au prezentat forma finală a proiectului folosind Microsoft PowerPoint și planșe.
În figura 14 sunt prezentate primele pagini ale documentației proiectului realizat de elevi.
Figura . Documentație proiect recursivitate (Anexa 12)
Prin proiectul final am evaluat următoarele deprinderi și capacitățile ale elevilor:
adecvarea metodelor de lucru și a instrumentelor alese la obiectivele propuse în proiect
folosirea corespunzătoare a materialelor bibliografice, modul de prelucrare și valorificare a informației obținute din diferitele surse bibliografice
oferirea unor soluții corecte, prin rezolvarea de probleme
relevanța proiectului (utilitate, conexiuni intra și interdisciplinare)
modul de prezentare al proiectului (claritate, coerență, capacitate de sinteză) și capacitatea de a lucra în echipă.
În tabelul de mai jos am prezentat criteriile după care au fost evaluați elevii în cadrul proiectului.
Tabelul . Criterii de evaluare proiect [23]
2. 3. 3. Portofoliul
Este „o metodă de evaluare complexă, longitudinală, proiectată într-o secvență mai lungă de timp, care oferă posibilitatea de a se emite o judecată de valoare, bazată pe un ansamblu de rezultate.” [07]
„Raportul de evaluare” (portofoliul), apreciază prof. I. T. Radu, „constituie nu atât o metodă distinctă de evaluare, cât un mijloc de valorizare a datelor obținute prin evaluări realizate.” [19]
Portofoliul este ușor adaptabil la orice disciplină și se folosește în cadrul evaluării sumative, care permite urmărirea progresului în învățare al elevului prin completarea acestuia în perioade de timp mai mari (semestru, an școlar sau chiar ciclu de învățământ).
Structura unui portofoliu, consideră A. Stoica: „poate fi exclusiv o sarcină a profesorului, în sensul că el este cel care stabilește scopul, contextul, realizează proiectarea lui, formulează cerințele standard și selectează produsele reprezentative ale activității elevilor sau poate implica și contribuția elevilor în modul în care acesta se construiește: elevii pot alege anumite instrumente de evaluare sau eșantioane din propria activitate, considerate semnificative din punct de vedere al calității lor.”[26]
Pentru a facilita munca de elaborare a portofoliului, profesorul va comunica elevilor intenția de a realiza un portofoliu și poate prezenta elevilor un model de portofoliu apoi va preciza componența și criteriile în funcție de care va realiza evaluarea acestuia.
Portofoliul elevilor poate fi evaluat și pe parcursul întocmirii lui, chiar și prin puncaj pentru respectarea termenelor de realizare a diferitor elemente din portofoliu, lucrând fiecare în ritm propriu, pentru a responsabiliza elevii și a se deprinde de a realiza la timp sarcinile primite. Se pot utiliza metode obișnuite de evaluare pentru fiecare element în parte. Se analizează nivelul de competență a elevului și progresul realizat de elev pe parcursul întocmirii portofoliului, fiind o perioadă mai lungă de timp. Alt avantaj al utilizării portofoliului este și acela că implică efectiv elevii în demersul evaluativ; cultivă responsabilitatea elevilor pentru propria învățare și pentru rezultatele obținute; nu induc stări emoționale negative, evaluarea având ca scop îmbunătățirea activității elevilor.
Portofoliul include lucrările pe care le face elevul individual sau în grup, rezumate, fișe individuale de lucru, probleme rezolvate – temă sau probleme suplimentare, schițe, proiecte, teme, teste și lucrări semestriale, chestionare, fotografii sau filmulețe care să demonstreze activitatea desfășurată de elev individual sau împreună cu colegii săi, autoevaluări scrise de elev, rezultatele obținute prin celelalte metode și tehnici de evaluare (probe orale, scrise, practice, observarea sistematică a comportamentului elevului, proiectul, autoevaluarea), precum și sarcini specifice fiecărui capitol. Elevul poate alege și alte materiale și diferite realizări de ale sale să includă în portofoliu.
Dezavantajul este însă că forma de prezentare poate crea o impresie mai bună decât conținutul portofoliului, a calităților lui. Nu toți elevii pot fi responsabilizați în realizarea portofoliului, necesită timp mare de realizare și de evaluare, dar și dificultatea în identificarea originii probelor (dacă este o realizare proprie sau a unui frate mai mare, părinte).
Portofoliul poate fi arătat și părinților sau unui profesor de la facultate, cum a fost cazul unei eleve de ale mele care a studiat în Germania și a prezentat portofoliul întocmit la liceu, profesorului de informatică de la facultatea unde a studiat. Portofoliul conținea lecțiile studiate în liceu, împărțite pe capitole, algoritmi elementari, fișe de lucru, teme, teme suplimentare, proiecte realizate de-a lungul liceului, poze ale planșelor și prezentări Power Point, teste și evoluția notelor în timp.
În continuare este prezentat un exemplu de portofoliu prin care au fost evaluați individual elevii.
Tematica: Recursivitatea
Perioada de completare a portofoliului: un semestru
Competențe care se urmăresc:
-înțelegerea modului de funcționare a stivei
-descrierea în limbaj natural a algoritmilor recursivi
-descrierea celor două tipuri de recursivitate, exemplificare și rezolvare de probleme
-aplicarea unor metode de verificare pentru algoritmii recursivi
-descrierea medotei folosite
-utilizarea corectă a termenilor specifici
Conținutul portofoliului:
-fișe de lucru rezolvate independent
-programe implementate independent
-teste scrise
-referat prezentat
-fișe de evaluare ale elevului
-fișa de observație a profesorului privind implicarea în activități și discuții
-studiu de caz (aplicații propuse)
-fișa de autoevaluare a elevului
Nota finală a elevului, dată de portofoliu, la sfărșitul semestrului este formată din media tuturor notelor testelor, evaluărilor, proiectului și autoevaluării, criteriile de evaluare fiind prezentate în cele ce urmează.
Criterii de evaluare:
Aspectul general: (20p)
-prezentarea portofoliului sub formă de mapă/dosar
-foaia de început completă
-aspectul estetic (aspectul exterior, structurarea și aranjarea materialului), respectarea regulilor, a normelor gramaticale, ortografice și de punctuație
-conținutul fiecărui material este semnificativ pentru subiectul tratat, capacitatea de a redacta texte coerente, adecvate cerințelor
-termenii de specialitate sunt folosiți adecvat, claritatea și precizis
-toate materialele au fost întocmite la timp, punctualitate, abilități de organizare și disciplinare
-materialele sunt aranjate în ordine cronologică
Conținut: (70p)
-portofoliul este complet (numeric) – 5p
-realizarea unui referat de prezentare a metodei (abilități de comunicare scrisă) – 5p
-realizarea de reprezentări ale stivei aplicate unor funcții (imagini, scheme, tabele etc, însoțite de explicații) – 5p
-realizarea de funcții pentru cele două tipuri de recursivitate – 5p
-proiectarea algoritmilor fundamentali – 10p
-rezolvarea fișelor de lucru și a temelor – 10p
-rezolvarea temelor suplimentare – 10p
-adăugarea de materiale proprii, diferite realizări, filmulețe – 5p
-observarea unui progres sau atingerea standului maxim de competență (prin probe orale, teste, lucrări semestriale, chestionare) – 5p
-manifestarea unei atitudini constructive în activitatea de grup – 5p
-capacitatea de autoevaluare – 5p
Oficiu -10p
Din experiența mea profesională portofoliul este o metodă alternativă de evaluare, agreată de elevi, deoarece lucrează și acasă în liniște fără a fi stresați, știind că pot întreba unde au nelămuriri, fără a fi depunctați cum este cazul unei evaluări și chiar posibilitatea de a lua o notă mai mare. Elevul se familiarizează astfel cu lucrul individual, cu lucrul în echipă, cu observația, cercetarea și sistematizarea materialelor pentru diferite proiecte sau activiți cotidiene.
În continuare sunt prezentate câteva fișe de lucru, teme suplimentare, teste, o fișă de analiză a procesului de învățare și o fișă de autoevaluare a portofoliului.
Fișă de lucru 1
1. Pentru definiția de mai jos a funcției f, ce se afișează ca urmare a apelului f(121,1)?
void f(long n, int i)
{ if(n!=0)
if(n%3>0)
{ cout<<i;
f(n/3,i+1); }}
2. Pentru definiția de mai jos a funcției f, ce se afișează ca urmare a apelului f(12345)?
void f(long n)
{ cout<<n%10;
if(n!=0)
{ f(n/100);
cout<<n%10;}}
3. Pentru definiția alăturată a funcției f, ce se afișează ca urmare a apelului f(26)?
void f (int x)
{ if(x>0)
if(x%4==0)
{ cout<<’x’;
f(x-1); }
else
{ f(x/3);
cout<<’y’; }}
4. Pentru definiția alăturată a funcției f, ce se afișează ca urmare a apelului f(15,2)?
void f (int n, int x)
{ if(x>n) cout<<0;
else
if(x%4<=1) f(n,x+1);
else
{ f(n,x+3);
cout<<1; }}
5. Pentru funcției f definită mai jos, ce se afișează ca urmare a apelului f(3,17)?
void f ( int a, int b)
{ if(a<=b)
{ f(a+1,b-2);
cout<<’*’;}
else cout<<b;}
6.Se consideră funcția alăturată. Ce valoare are f(15,2)? Dar f(128,2)?
int f(int a, int b)
{ if (b<1) return -1;
else
if (a%b==0) return 1+f(a/b,b);
else return 0; }
7. Se consideră funcția f definită alăturat. Ce se va afișa în urma apelului f(12345)?
void f(long int n)
{ if (n!=0)
{ if (n%2 == 0)
cout<<n%10;
f(n/10);}}
a. 513 b. 24 c. 42 d. 315
8.Se consideră funcția f, descrisă alăturat. Ce se va afișa în urma apelului f(3)?
void f(int n)
{ if (n!=0)
{ if (n%2==0)
cout<<n<<’ ’;
f(n-1);
cout<<n<<’ ’; }
else cout<<endl; }
9. Se consideră funcția f cu definiția alăturată. Ce valoare are f(1213111,1)?
int f (long n, int k)
{ if (n!=0)
if(n%10==k)
return 1+f(n/10,k);
else return 0;
else return 0;}
a. 5 b. 3 c. 2 d. 1
10. Se consideră funcția cu definiția alăturată. Ce valoare are f(3,1)?
int f(int n,int y)
{ if(n!=0)
{ y=y+1;
return y+f(n-1,y);}
else return 0;}
a. 9 b.6 c. 7 d.8
Fișă de lucru 2
1. Pentru funcția f definită alăturat, stabiliți care este valoarea f(5). Dar f(23159)?
int f(int n)
{int c;
if (n==0)
return 9;
else
{ c=f(n/10);
if (n%10<c)
return n%10;
else return c;}}
2. Se consideră funcția, f, definită alăturat. Ce valoare are f(100)? Scrieți o valoare pentru x astfel încât f(x)=1.
int f(int n)
{ if(n==0)
return 0;
else
return n%2+f(n/2);}
3. Considerăm funcția recursivă definită alăturat. Ce se va afișa în urma apelului f(’C’)?
void f(char c)
{ if (c>’A’)
f(c-1);
cout<<c;
if (c>’A’)
f(c-1); }
4. Pentru funcțiile f1 și f2 definite alăturat, stabiliți care este valoarea lui f1(3). Dar f2(41382)?
long f1(int c)
{ if (c%2==1)
return 1;
else
return 2; }
long f2(long n)
{ if (n==0)
return 0;
else
return f1(n%10)+f2(n/10); }
5. Pentru funcțiile f și g definite mai jos, scrieți care este rezultatul returnat la apelul g(11). Dar rezultatul returnat la apelul f(6)?
long g(long x)
{ if (x>9)
return (x/10 + x%10);
else
return x;}
long f(int c)
{ if (c<1)
return 1;
else
return g(c+f(c-1)); }
6. Funcția F are definiția alăturată. Ce valoare are F(3)?
int F(int n)
{ if(n==0 || n==1)
return 1;
else
return 2*F(n-1)+2*F(n-2);}
1 b. 12 c. 6 d. 10
7. Funcția f are definiția alăturată. Ce se va afișa în urma apelului f(12345)?
void f(long n)
{ if (n>9)
{ cout<<n/100;
f(n/10);}}
a.1231210 b.123121 c.1234123121 d.123
8. Funcția f are definiția alăturată. Ce se va afișa în urma apelului f(12345,0)?
void f(long n, int i)
{if (i<n%10)
{ cout<<n%10;
f(n/10,i+1);}}
a. 54321 b. 543 c. 54 d. 5432
9. Funcția F are definiția alăturată. Ce valoare are F(18)?
int F(int x)
{ if (x<=1)
return x;
else
return x+F(x-2);}
a. 90 b. 171 c. 91 d. 18
10. Funcția F are definiția alăturată. Ce valoare are F(5)?
int F(int x)
{ if(x!=0)
return x+F(x-1);
else
return x;}
a. 5 b. 10 c. 15 d. 6
Fișa de lucru 3 – se rezolvă pe parcursul mai multor ore și ca temă de casă
1. Să se calculeze valorile funcției Manna Pnuell definită astfel:
F(x)= x-1, dacă x>=12
F(F(x+2)), dacă x<12 Să se calculeze pas cu pas pentru F(8) și F(20).
2. Scrieți programul care calculează valoarea polinomului lui Cebîsev definit recursiv astfel:
T0(x)=1 T1(x)=2x
Tn(x)=2xTn-1(x)-Tn-2(x), pt n>=2 Calculați pas cu pas T5(2).
3. Scrieți programul care calculează valoarea polinomului lui Laquerre, definit recursiv în felul următor:
L0(x)=1 L1(x)=2-x
Ln(x)=(2n-x)Ln-1(x)-nLn-2(x), pt n>1
4. Să se determine și să se afișeze numărul întregilor n, 1<=n<=2002, pt care F(n)=n, unde F este definită astfel:
F(1)=1 F(3)=3
F(2k)=F(k)
F(4k+1)=2F(2k+1)-F(k)
F(4k+3)=3F(2k+1)-2F(k)
5. Scrieți un program care afișează pe ecran valoarea K(b,n,t) unde k se definește astfel:
K(b,1,t)=bt K(b,n,1)=b
K(b,n+1,t+1)=k(b,n,K(b,n+1,t)), iar b,n,t se vor citi de la tastatură. Calculați pas cu pas K(4,2,2).
6. Scrieți algoritmul care verifică dacă un număr este prim.
7. Scrieți algoritmul care verifică dacă un număr are toate cifrele egale cu k.
8. Scrieți algoritmul care (subprogramul recursiv + apelul) care verifica daca un numar este perfect.
9. Scrieți algoritmul care verifică dacă un număr are cel puțin o cifră divizibilă cu q.
10. Se citesc n elemente într-un vector. Să se afișeze media aritmetică a elementelor care au numai cifre divizibile cu 3 și exact k divizori.
11. Se citesc n*n elemente într-o matrice. Să se afișeze în ordine crescătoare elementele care au toate cifrele egale.
12. Se citesc n elemente într-un vector. Câte dintre elementele pare au suma divizorilor număr impar?
13. Se citesc elemente într-o matrice. Să se afișeze elementele de deasupra diagonalei principale care au suma cifrelor divizibile cu 3 un număr mai mare decât 10.
14. Se citesc elemente într-o matrice. Să se afișeze elementele de sub diagonala secundară care au toate cifrele egale cu 3.
15. Se citesc n elemente într-un vector. Să se calculeze produsul elementelor care au număr par de divizori.
16. Se citesc n elemente într-un vector. Să se calculeze suma elementelor prime și apoi să se afișeze elementele care sunt formate numai din cifre pare.
17. Se citesc n*n elemente într-o matrice. Să se afișeze ordonate crescător elementele palindroame care se afla deasupra diagonalei principale.
18. Se citesc elemente într-o matrice. Să se verifice dacă toate elementele de sub diagonala secundară au suma cifrelor mai mare decat 10.
Temă suplimentară 1
Realizarea de algoritmi recursivi pentru citirea, afișarea și parcurgerea recursivă a vectorilor și diferite prelucrări asupra elementelor lor.
Temă suplimentară 2
Realizarea de algoritmi recursivi pentru citirea, afișarea și parcurgerea recursivă a matriciilor și diferite prelucrări asupra elementelor lor.
Temă suplimentară 3
Pentru matricile pătratice: parcurgerea recursivă a diagonalelor, a zonelor de sub diagonale și deasupra și a zonelor de nord, sud, est, vest.
Test 1 – BILETUL NR.1
1.(1p) Se consideră următoarea funcție:
int f(int x);
{ if (x==0) return 0;
else return (f(x-1)+2*x-1);}
Pentru ce valoare a parametrului x funcția f va întoarce valoarea 25?
a) 10 b) 3 c) 15 d) 5
2.(1.50p) Care din următoarele declarații de funcții sunt corecte? În cazul celor care sunt corecte ce se afisează pentru i=5?
a) void unu(int i)
{ cout<<i<<” “; unu(i+1);}
b) int doi(int i)
{ if(i<=10) { cout<<i<<” ”; return doi(i+1); }
else return 0; }
c)int trei (int i)
{ if(i<=10)
{ trei(i+1);
cout<<i<<” “;}}
d) void patru(int i)
{ cout<<i<<” “;
if(i>=0) patru(i-1); }
3.(1p) Se consideră programul următor:
int x,y;
int f(int a, int b)
{ if (a!=b) if (a>b) return f(a-b,b);
else return f(a,b-a);
else return x*y / a;}
int main()
{cin>>x>>y; cout<<f(x,y);}
Ce valoare va fi afișată pentru setul de date de intrare x=32, y=14 ?
a)2 b) 256 c)200 d)224 e)14
4.(1p)Ce afișează programul de mai jos?
int v[50],i ;
int m(int a, int b)
{ if(a>b) return 0;
else if(a= =b) return v[a];
else return (m(a,(a+b)/2)+m((a+b)/2+1,b);}
int main()
{ for(i=1;i<11;i++) v[i]=i;
cout<<m(3,8);}
5.(1p) Ce valoare va returna funcția f pentru un set de date de intrare format din elementele vectorului v={4, 0, -1, 2, 8, -7, 5, -3,3,-6} la apelul f(v,8)?
int f(int v[], int n)
{ if (n==-1) return 0;
else if (v[n]<0) return f(v,n-1);
else return v[n] + f(v,n-1); }
a) 9 b) 22 c) 19 d) 5
6.(1.50p) Care va fi valoarea returnată de funcția următoare în urma apelului f(0,5)?
int f(int n, int m)
{ if (n==m) return n;
else return 2*f(n,(n+m)/2)+f((n+m)/2+1,m);}
a) 15 b) 5 c) 29 d) 33
7. (1p) Presupunem că în cadrul unui program există 4 proceduri (A,B,C,D) și că există următoarele apeluri:
procedura C apeleaza procedura A
procedura B apeleaza procedura C
procedura D se autoapeleaza
procedura A apeleaza procedura D
Care este ordinea corectă la declararea procedurilor?
Oficiu: 2p
Test 2
1. (1p) Scrieți un program care folosește o funcție recursivă pentru calculul sumei:
S=1*3-2*5+3*7-4*9+…+n*(2n+1)
2. (4p) Se citesc n elemente într-un vector. Se cere să se afle dacă în vector există cel puțin un număr prim. (subprogram recursiv pentru citirea și afișarea elementelor vectorului, număr prim, parcurgerea vectorului pentru verificare)
3.(4p) Se citesc n*n elemente într-o matrice. Să se calculeze media aritmetica a elementelor de sub diagonala principală care au suma cifrelor număr divizibil cu k. (subprogram recursiv pentru citirea și afișarea elementelor matricii, suma cifrelor unui număr, parcurgerea sub diagolala principală)
Oficiu: 1p
Fișa de analiză a procesului de învățare
Am înțeles cu ușurință………………………………………………………………………………………………
A fost dificil să ……………………………………………………………………………………………………….
Cea mai ușoară temă a fost ………………………………… pentru că ……………………………………..
Învăț mai ușor când ………………………………………………………………………………………………….
Învăț cu dificultate când ……………………………………………………………………………………………
Îmi propun să ………………………………………………………………………………………………………….
Fișa de autoevaluare a portofoliului
1. Ai efectuat integral și la timp temele? da / nu
2. Ți-ai corectat greșelile? Ți-ai refăcut temele greșite? da / nu
3. Respectă portofoliul tău structura corespunzătoare? da / nu
4. Urmărind calificativele și notele obținute la lucrări și teme constați că: ai progresat / ai regresat / ești constant?
5. Numește cea mai reușită temă și subiectele la care ai luat cele mai bune note
…………………………………………………………………………………………………………………………………
6. Numește două elemente originale din portofoliul tău
…………………………………………………………………………………………………………………………………
7. Ce reușești să faci mai bine acum față de începutul anului sau al semestrului?
…………………………………………………………………………………………………………………………………
8. Consideri că ai dovedit originalitate, imaginație în organizarea portofoliului? da / nu
9. Ți-a plăcut să lucrez la redactarea lui? da / nu
10. Consideri că portofoliul tău merită calificativul / nota …..
pentru că: …………………………………………………………………………………………………………………
Pentru elaborarea acestei părți am consultat lucrările [04, 05, 06, 12, 20].
2. 4. Folosirea resurselor electronice și a platformelor de e-Learning
Astăzi activitățile ne sunt dominate de noile tehnologii. Aproape că nu ne mai putem desfășura activitatea profesională fără ajutorul calculatorului. Aceasta a dus la nevoia de a regândi mijloacele educației, astfel încât să conducă la o mai mare eficiență a învățării școlare și la plasarea elevului în centrul actului educațional. Unul din obiectivele principale ale învățământului modern este continua îmbunătățire a proceselor de predare-învățare și aceasta prin utilizarea noilor tehnologii multimedia.
Calculatorul nu va înlocui niciodată total acțiunea profesorului, dar posibilitățile de informare, prelucrare și stocare pe care le oferă calculatorul, constituie oportunități de accesare a surselor de informații, ne dă un plus de cunoaștere în termeni cantitativi, dar și în termeni calitativi. Se oferă accesul comod și eficient la informațiile și cunoștințele cele mai noi, metode noi și eficiente de predare, învățare și evaluare a cunoștințelor, instruire și formare permanentă. Aplicarea tehnologiei informației și a comunicațiilor în domeniul educației a condus la crearea a ceea ce se numește e-Learning.
Particularitățile specifice tehnologiilor de e-Learning aduc noi dimensiuni în educație și care pot fi complementare sau alternative față de metodele tradiționale din domeniul educației. Aceste particularități oferă posibilitatea organizării învățământului online pe subiecte sau teme, în timp ce învățământul tradițional este organizat pe grupe/clase de vârstă.
Învățarea clasică este în prezent complementată de folosirea platformelor e-Learning, fiind un soft complex care permite administrarea unui domeniu, deoarece permit utilizarea mai eficientă a resurselor materiale, prezentare mai rapidă și interactivă, îmbunătățesc calitativ conținutul învățământului, sprijină procesul de învățare individuală și permit utilizatorilor să acceseze o serie de surse de informare. Nu înlocuiește sistemele educaționale tradiționale, nu înlocuiește dialogului direct dintre profesor și elevi, ci ajută procesul de învățare, completează activitatea didactică din școală prin posibilitatea de creare a unor resurse pentru e-learning particularizate pe anumite teme. Folosirea acestor platforme poate conduce creșterea motivației elevilor prin atracția pe care aceștia o au față de activitățile asistate de calculator și fiind obișnuiți cu lucrul pe calculator încă de mici, venind în întâmpinarea dorințelor și a nevoilor de instruire ale elevilor. Elevii pot fi îndrumați să utilizeze aceaste abilități pentru a folosi constructiv timpul liber.
Lecția online acoperă același conținut și pune aceleași probleme ca și o lecție care se desfășoară în sala de clasă tradițională. Avantajul evident este că o astfel de lecție poate fi accesată oricând și de oriunde. Cursurile suport sunt stocate pe hardul unui computer într-o formă specifică și pot fi accesate printr-un navigator de Internet. Elevului îi este permis să acceseze informațiile într-un ritm mai alert sau mai încetinit după cum îi este necesar.
Materialele de învățare sunt prezentate într-o formă multimedia (prin îmbinare de text, sunet, imagine și chiar filme) sau în modul hyperlink (în care accesul la informații se realizează prin legături multiple de la o singură pagină).
Tehnologiile multimedia permit o strânsă legătură între efectele audiovizuale în vederea realizării de lecții, cursuri, prezentări complexe care să fie ușor de urmărit, sa fie sugestive, și mai ales să contribuie la asimilarea de noi cunoștințe.
Astfel, învățarea devine eficientă când profesorul construiește un material de învățare, pentru ca elevii săi să interacționeze cu acest material de învățare și să experimenteze, pentru a înțelege. În acest context, elevul este parte a unei comunități de învățare, în care este pus în situația de a înțelege ce are de făcut, de a explica celorlalți și de face împreună. Profesorii au acces la aceleași materiale ca și studenții, dar dispun de drepturi suplimentare pentru a crea sau a modifica conținuturi de învățare pentru curs și de a urmări progresul și rezultatele elevilor.
Utilizarea tehnologiilor hipermedia este o caracteristică pregnantă a tuturor sistemelor de e-learning. În sens larg, prin e-learning se înțelege totalitatea situațiilor educaționale în care se utilizează semnificativ mijloacele Tehnologiei Informației și Comunicațiilor (TIC). În accepțiunea modernă, procesul de învățământ bazat pe resurse utilizează atât modele clasice cu suporturile cunoscute (modele fizice), cât și modele virtuale aparținând tehnologiei multimedia.
Un astfel de model virtual îl reprezintă E-Learning-ul. Pentru utilizarea este necesară o bună corelare a aspectelor tehnice cu cele pedagogice. Integrarea metodelor de e-Learning nu este automată, ci este un proces complex, care implică nu doar tehnologii, dar și aspecte curriculare și pedagogice, de organizare instituțională, competențe ale cadrelor didactice, finanțe etc.
Avantaje ale e-Learning-ului:
-folosirea mai eficientă a timpului
-accesibilitate, diverse metode pedagogice
-posibilitatea de a reveni ușor la anumite informații
-eficientizarea reținerii prin folosirea memoriei vizuale
-creșterea atractivității lecției
-feedback oferit de programele de evaluare
-posibilitatea de a reface anumite teste
-dezvoltă aptitudini de studiu individual
-creșterea motivației elevilor pentru că văd ceva concret
-activitățile sunt mai diverse.
Printre dezavantaje putem enumera următoarele:
-necesită experiență în domeniul utilizării calculatoarelor
-costuri mari pentru proiectare și întreținere, producerea materialelor necesare
-elevii trebuie să fie extrem de motivați pentru participare
-împiedică socializarea elevului, integrarea în colectivitate, crearea de legături interumane, afective.
Pentru a realiza o comparație între cele două moduri de lucru, am conceput lecții și plane de lecții pentru predarea aceluiași conținut în sistem clasic și folosind platforma de e-Learning proiectată de mine și, de asemenea, exerciții și test online. Acestea se găsesc în anexe. Pentru elaborarea acestui subcapitol am consultat și adaptat resursele [21, 33, 39].
2. 5. Comparație între metodele tradiționale și cele moderne
În tabelele de mai jos am prezentat aspecte ale metodelor tradiționale în contrast cu metodele moderne și o paralelă cu avantaje și dezavantaje:
1. Generalități ale metodelor tradiționale în paralel cu a celor moderne, avantaje și dezavantaje:
Tabelul . Generalități ale metodelor tradiționale și a celor moderne
2. Învățarea, prezentată din prisma celor două tipuri de metode, avantaje și dezavantaje:
Tabelul . Învățarea, prezentată din prisma celor două tipuri de metode
3. Elevul, rolul și responsabilitățile lui:
Tabelul . Rolul și responsabilitățile elevilor
4. Profesorul, rolul și responsabilitățile lui:
Tabelul . Rolul și responsabilitățile profesorului
5. Evaluarea elevilor, între tradițional și modern, avantaje și dezavantaje:
Tabelul . Evaluarea elevilor, între tradițional și modern
Din toate cele menționate rezultă faptul că profesorul trebuie să-și schimbe concepția și metodologia instruirii și educării, să coopereze cu elevii, să devină un model real de educație permanentă, să se implice în deciziile educaționale, să asigure un învățământ de calitate. Pregătirea managerială a profesorului, însușirea culturii manageriale, nu numai cea tradițională psihopedagogică și metodică, pot asigura înțelegerea și aplicarea relației autoritate-libertate, ca nou sens al educației, prin predare-învățare și rezolvarea altor situații din procesul educațional școlar. [46]
2. 6. Evaluarea satisfacției elevilor
Pentru evaluarea satisfacției elevilor am conceput un chestionar. Scopul acestui chestionar este de a evalua ideile și sentimentele elevilor față de experiența de învățare din timpul lecțiilor. Unele lecții folosind metode tradiționale, iar altele folosind platforma de e-Learning concepută personal.
Faceți aprecieri răspunzând cu DA sau NU pentru următoarele întrebări:
Acordați puncte pe o scară de la 1 la 5.
Cât timp ați studiat folosind platforma pentru recursivitate?
Ce ți-a plăcut cel mai mult la această platformă?
Ce ți-a plăcut cel mai puțin la această platformă?
Care au fost cele mai ușoare activități pentru tine?
Care au fost cele mai dificile activități pentru tine?
Ce tip de lecție ți-a plăcut mai mult (tradițional sau folosind platforma). De ce?
Un element important atât pentru elevi cât și pentru profesori este feed-back-ul. Elevii primesc acest feed-back prin explicațiile profesorilor la greșelile pe care le fac sau prin răspunsurile date de sistemele de e-learning la testele on-line. Profesorii pot primi un feed-back relativ la eficiența metodelor de învățare folosite dând elevilor să completeze teste de evaluare a satisfacției față de anumită activitate de învățare.
Capitolul 3. Aplicație practică:
Platforma e-learning pentru recursivitate
Scopul acestui capitol este de a prezenta parea aplicativă, originală a acestei lucrări care constă în proiectarea unei pagini WEB care să fie folosită pentru predarea recursivității de către profesor și să fie folosită de elevi în procesul de acumulare de noi cunoștințe, fixare de cunoștințe și evaluare. Pentru mai multe detalii tehnice referitoare la acest capitol pot fi consultate resursele [01, 02, 08, 16, 18, 36, 38, 48].
3. 1. Tehnologii folosite și detalii de implementare
O parte integrantă, poate cea mai importantă, a Internetului este reprezentată de World Wide Web (WWW). World Wide Web reprezintă un grup de calculatoare și servicii Internet care permit accesarea facilă și, totodată, rapidă a informațiilor, cât și deplasarea printre resursele existente pr plan mondial. Aceste servicii WWW includ medii de tip hipertext, cât și informații multimedia. Internetul este reprezentat, de asemenea, de oamenii care răspund pentru realizarea tehnică a accesului la servicii, care colaborează împreună în crearea unor servicii informative interesante; oamenii care, conectându-se la rețea, folosesc totalitatea informațiilor acumulate de la crearea rețelei Internet.
Principalele tehnologii folosite în realizarea site-ului sunt HTML și JavaScript. Acestea sunt prezentate în cele ce urmează.
3. 1. 1. Limbajul HTML și JavaScript
Limbajul HTML (Hypetext Markup Language) este un mod de înregistrare a documentelor de tip hypertext sub formă de fișiere de tip text. HTML prezintă sintaxa documentului și definește complexul așa-ziselor elemente de marcare, care nu sunt prezentate pe monitorul utilizatorului, dar definesc modul de prezentare a informațiilor.
Paginile actuale de Web care sunt accesibile în rețeaua Internet sunt scrise în limbajul HTML. Se remarcă însă faptul că limbajul acesta este permanent dezvoltat și lărgit cu definiții ale noilor elemente de marcare, care permit introducerea în documentele de tip hipertext a unor noi forme de transmitere a mesajelor, dezvoltând astfel alte modalități de formatare a documentului. Formatarea actuală a textului prin manipularea caracterelor și a culorilor, foloșirea tabelelor, a formularelor, precum și a graficii, animației și a sunetului conduc la faptul că documentele HTML vizualizate cu ajutorul browserelor grafice pe Internet sunt atractive din punct de vedere vizual, iar navigarea prin intermediul hiperlinkurilor este destul de simplă. O trăsătură importantă a documentelor de tip hipertext moderne este posibilitatea introducerii în ele a elementelor de interacțiune cu utilizatorul, de exemplu formulare sau applet-uri scrise în limbajul Java, deci programe realizate în fereastra browserului.
Inițial internetul a constat din pagini statice, care erau actualizate doar ocazional de către deținătorii lor. Ulterior au fost realizate și sisteme de gestiunea automată a informațiilor dintr-un site Web, numite Content Management Systems. Acestea puteau construi pe loc – în mod dinamic, la cerere – versiunea cea mai nouă posibil a paginii web, și anume prin consultarea unei bănci de date (sigur că și aceasta trebuia actualizată permanent, dar asta se facea pe căi tradiționale, nelegate direct de WWW). Dar și această tehnică împarte oamenii în “creatori” de pagini Web și “consumatori” mai mult sau mai puțin pasivi ai acestor pagini/informații/documente.
Un site web static este un site web format dintr-o colecție de fișiere al căror conținut trebuie modificat fizic pentru a reda un conținut diferit de cel inițial. Asta înseamnă că dacă un client are un site web static și la un moment dat își schimbă un număr de telefon și vrea să-l afișeze în site pe cel nou va trebui să apeleze la cei care i-au realizat site-ul să facă modificarea cu pricina și să încarce apoi pagina modificată înapoi pe server în locul celei vechi. La fel ar trebui să procedeze și în cazul în care ar avea de adăugat texte noi sau pagini noi.
Spre deosebire de această metodă, site-urile dinamice au posibilitatea de a rezolva toate aceste lucruri într-un mod mai rapid și mai elegant. De obicei dispun de o interfață de administrare a site-ului unde clientul poate să facă aceste modificări chiar online iar paginile modificate să fie afișate imediat în site-ul său.
Un site web dinamic este un site care se mișcă foarte repede. Acest lucru se datorează faptului că modificările din continutul său se fac mult mai rapid decât în cazul unui site web static. Practic în aceasta constă dinamismul unui site web: în capacitatea acestuia de a prezenta vizitatorilor săi un conținut variat fără a fi nevoie de intervenția permanentă a designer-ului sau al webmaster-ului.
Limbajul de programare Java, elaborat de firma Sun Microsystems, a reprezentat o adevărată revoluție în programarea pentru Internet. Java este un limbaj de programare complex, orientat pe obiecte și bazat pe puternicul limbaj C++. Cea mai importantă caracteristică a aplicațiilor Java este portabilitatea de a rula, teoretic, pe orice platformă pentru care a fost scris un interpretor pentru mașina virtuală Java.
Limbajul JavaScript este un limbaj mult mai simplu care permite definirea comportamentului unor elemente dintr-o pagină Web și dinamizarea acestora. Este un limbaj obiectual și multi-platformă, ceea ce înseamnă că același cod este interpretat la fel, indiferent de platforma pe care rulează browserul.
Limbajul JavaScript permite și specificarea unor răspunsuri la diferite acțiuni, cum ar fi deschiderea unei pagini, deplasarea mouse-ului într-o anumită zonă a ecranului, afișarea unui mesaj după ce se dă click pe un buton, etc.
Există o multitudine de tehnologii de programare pentru a realiza un site dinamic și deși sunt diferite ca implementare, în final rezultatele sunt aceleași pentru vizitatorii săi. Îmbogățirea paginii cu elemente dinamice necesită din partea webmasterului anumite competențe în domeniul programării. Limbajul JavaScript permite, cu un efort minim, transformarea unei pagini Web neatractive și statice într-una dinamică, colorată care atrage atenția asupra profesionalismului autorului.
Un program JavaScript este scris între tag-urile <SCRIPT> </SCRIPT> ale unei pagini WEB. După prima vedere se pare că JavaScript nu diferă de HTML, dar în timp ce HTML defineste structuri, layout-uri și legături între documente, JavaScript adaugă logică și facilități de programare.
De exemplu pentru afișarea zilei, datei, orei și a formulei de salut corespunzătoare, pe ecran am folosit următorul cod în Java Script:
<SCRIPT language="JavaScript" type="text/javascript">
var month = new Array();
month[0]="Ianuarie";
month[1]="Februarie";
month[2]="Martie";
month[3]="April";
month[4]="Mai";
month[5]="Iunie";
month[6]="Iulie";
month[7]="August";
month[8]="Septembrie";
month[9]="Octobrie";
month[10]="Noiembrie";
month[11]="Decembrie";
var
day = new Array();
day[1]="Luni";
day[2]="Marti";
day[3]="Miercuri";
day[4]="Joi";
day[5]="Vineri";
day[6]="Sambata";
day[0]="Duminica";
today = new Date();
date = today.getDate();
day = (day[today.getDay()]);
month = (month[today.getMonth()]);
year = (today.getFullYear());
suffix = (date==1 || date==21 || date==31) ? "" : "" &&
(date==2 || date==22) ? "nd" : "" && (date==3 || date==23) ? "" : ""
function print_date()
{ document.write(day + "," + "<br>" + date + "<sup>" + "</sup>" + ", " +
month + "<br>" + year); }
</SCRIPT>
<SCRIPT>print_date();</SCRIPT>
Blocul SCRIPT poate fi plasat în blocul de antet HEAD sau în blocul de corp BODY al unei pagini de WEB. În funcție de locul de plasare a scriptului avem scripturi de antet sau scripturi de conținut.
Dacă un script este introdus în secțiunea ”head”, atunci el va fi executat doar atunci când va fi apelat (ca urmare a unei acțiuni a utilizatorului: click pe un buton,…).
Dacă un script este introdus în secțiunea ”body”, atunci el va fi executat atunci când va fi încărcată (afișată) secțiunea ”body” (conținutul paginii Web). Altfel spus acest script generează conținutul paginii HTML.
JavaScript, ca majoritatea limbajelor de programare, este scris în format text și organizat în declarații, blocuri formatate din seturi de declarații și din comentarii.
O declarație este o propoziție formată din unul sau mai multe elemente, cuprinse într-o linie, de exemplu alert (“hello”). Un bloc este format dintr-un set de declarații cuprinse între acolade ({}). Un bloc de declarații este folosit, de exemplu, în funcții sau în instrucțiuni condiționale. Într-o declarație se pot folosi variabile, date ca șiruri și numere, operatori și expresii. O declarație comunică browser-ului să întreprindă o acțiune. Acesta, după execuția ei, preia altă declarație, o interpretează s.a.m.d.
Sintaxa limbajului JavaScript este familiar persoanelor care au folosit limbaje ca C. Aspectul cel mai delicat reprezintă faptul că multitudinea de obiecte dintr-un browser (ferestre, frame-uri, formulare etc) pot fi controlate din JavaScript prin simpla referință la obiect. Obiectele au proprietăți încorporate, numite atribute, iar programele orientate-obiect pot foarte ușor să le modifice pe acestea. Aplicând conceptul de orientat-obiect pentru lumea browserelor, putem modela browserul ca o colecție de obiecte, cuprinzând ferestre, farme-uri, formulare etc.
Tag-ul SCRIPT conține două atribute cu valori obligatorii:
language =”JavaScript” comunică browser-ului că limbajul de script este JavaScript
type=”text/JavaScript”, atribut care comunică browser-ului că scriptul este scris în format text, care este organizat în format JavaScript
Una din componentele de bază ale limbajului de programare sunt tipurile de date accesibile în timpul aplicației. Fără ele, construirea programelor nu ar fi posibilă. În limbajul JavaScript există șase tipuri de date: numerice, șiruri, boolean, obiecte, null, undefined (nedefinit).
În majoritatea limbajelor de programare, structurile de bază sunt tablourile, adică mulțimi de date ordonate. JavaScript se diferențiază prin faptul că tablourile din acest limbaj pot conține orice tip de date, printre care și alte tablouri și/sau obiecte.
Variabilele sunt folosite în JavaScript pentru a stoca valori în scripturile noastre. Variabilele sunt simboluri care înlocuiesc datele ce se pot modifica în timpul execuției. Deși nu este impusă, este considerată o bună practică să se declare variabilele înainte de a fi folosite. Pentru a comunica browser-ului că dorim să creăm o variabilă, se folosește declarația în două părți: cuvântul cheie var și numele variabilei – care este format dintr-un set de caractere alfanumerice, dar primul caracter trebuie să fie o literă.
Nu se declară, în mod obligatoriu, tipul unei variabile, este suficient să indicăm numele ei. Tipul poate fi dat în urma unei atribuiri.
Cu ajutorul constantelor și variabilelor putem să construim expresii. Pentru a efectua aceste operațiuni este necesar să folosim operatori. În programele JavaScript se pot folosi operatori aritmetici, operatori de atribuire, operatori relaționali, operatori logici, operatorul de concatenare și operatori speciali (operatorul condițional, eliminarea unui obiect sau element din tablou, crearea unei instanțe a unui obiect).
Expresiile construite cu ajutorul operatorilor constituie un fel de “fraze” în limbaj de programare. Totuși, în afară de faptul că ele calculează anumite valori, nu sunt elemente active ale limbajului care să influențeze efectiv acțiunile programului în limbajul JavaScript În acest scop, trebuie folosite instrucțiuni. Fiecare program conține instrucțiuni, de obicei despărțite între ele de semnul punct și virgulă. Există trei mari categorii de instrucțiuni: de atribuire, de decizie și repetitive.
O instrucțiune condițională JavaScript este asemănătoare cu instrucțiunea condițională din limbajele de programare complexe. Există trei instrucțiuni condiționale: if, if….else și switch…case.
De exemplu, pentru folosirea formulei de salut corespunzătoare am folosit următorul cod JavaScript:
if (time < 10)
{ document.write("<center><b><h4>Bună dimineata!</h4></b></center>"); }
else
if (time<20)
{ document.write("<center><b><h4>Bună ziua! </h4></b></center>"); }
else
{ document.write("<center><b><h4>Bună seara! </h4></b></center>"); }
Atunci când dorim să executăm un grup de instrucțiuni în mod repetat, se folosesc instrucțiunile de ciclare. Și JavaScript acceptă următoarele instrucțiuni de ciclare: for și for în, while, do…while.
Pe lângă instrucțiunile "for" și "while" avem și alte instructiuni 'complementare' care pot fi executate împreună cu acestea.
var
day = new Array();
day[1]="Luni";
day[2]="Marti";
day[3]="Miercuri";
day[4]="Joi";
day[5]="Vineri";
day[6]="Sambata";
day[0]="Duminica";
document.write("Afiseaza numele fiecarei zile: <br />");
for (i=0; i<7; i++)
{ document.write(day[i] + "<br />"); }
break – întrerupe definitiv executia unui ciclu.
continue – sare peste instructiunile care au mai ramas din ciclul respectiv.
label (eticheta) – permite ieșirea dintr-un ciclu cu instructiuni ciclice imbricate, la o locatie specificata a scriptului.
with – se foloseste pentru a fi evitata specificarea repetata la referirea unui obiect, când ii accesam metodele sau proprietățile.
Funcțiile ajută la divizarea mai multor sarcini pe care trebuie să le facă un program.
O funcție poate conține mai multe instrucțiuni și comenzi care ulterior pot fi utilizate ușor și de mai multe ori prin apelarea functiei care le conține.
Dacă un program necesită multe linii de cod, folosind funcțiile putem împărți codul în părți mai mici pe care le putem utiliza separat acolo unde este nevoie.
Pot fi două feluri de funcții:
Predefinite – cum sunt de exemplu: "parseInt(string)", "parseFloat(string)", …
Create de programator:
– care returnează o valoare, folosește pentru aceasta instrucțiunea return
– care nu returnează o valoare
Definirea unei funcții este bine să se facă în partea de antet (<HEAD>) a unui program html. Scripturile se scriu în blocul <SCRIPT language="JavaScript">…</SCRIPT>. Blocul <SCRIPT> poate fi plasat în blocul de antet al paginii, <HEAD>, sau în blocul de conținut al paginii <BODY>. Apelul funcției poate fi introdus într-un script din corpul paginii.
Exemplu de funcție ce realizează cronometrarea răspunsului elevilor:
function doTimer()
{ if (!timer_is_on)
{ timer_is_on=1;
timedCount(); } }
function stopCount()
{ clearTimeout(t);
timer_is_on=0; }
Apelul funcțiilor de mai sus în corpul paginii WEB:
<form>
<input type="button" value="Start!" onClick="doTimer()" />
<input type="text" id="txt1" />
<input type="button" value="Stop!" onClick="stopCount()" />(Hai să vedem în cât timp raspunzi!!!)
</form>
3. 1. 2. Metode pentru realizarea dinamizării paginilor Web cu JavaScript
JavaScript nu este un program orientat pe obiecte (OOP), cum sunt C++ sau Java, dar este bazat pe obiecte.
În lumea din jurul nostru obiectele sunt de exemplu: o carte, o mașină, un televizor; în JavaScript obiectele sunt de exemplu: un formular, o fereastră, butoane, imagini …
Toate elementele dintr-o pagină sunt văzute de JavaScript ca fiind obiecte. Javascript funcționează pe principiile programării orientate obiect, în care fiecare element – tabel, fereastră, imagine, buton, legătură reprezintă un obiect și are propriul set de proprietăți.
În limbajele de programare orientate pe obiect, deci și în JavaScript, elementele de bază sunt obiectele. Un obiect este un lucru din lumea înconjurătoare. Toate elementele dintr-o pagina sunt văzute de JavaScript ca fiind obiecte. Obiectele au anumite proprietăți, de exemplu în lumea reală televizoarele au butoane, mașinile au roti; așa și în JavaScript obiectele au proprietăți: formularele au buton, ferestrele au titluri.
Un obiect este o reprezentare a unei entități din lumea reală sau conceptuală. Tot ce putem vedea, atinge, clasifica reprezintă obiecte ale lumii reale și tot ce putem gândi reprezintă obiecte ale lumii imaginare. Un obiect are 3 caracteristice: stare, comportament și identitate.
Starea unui obiect reprezintă totalitatea datelor care conțin informații referitoare la acesta, una din condițiile posibile în care poate exista un obiect. Fiecare obiect are un număr de proprietăți, numite și atribute, care au o valoare. Valorile unei proprietăți (atribut) pot face parte dintr-un tip de bază (întreg, real etc.) sau pot fi alte obiecte. Cu alte cuvinte, starea unui obiect conține structura esențială a obiectului: atributele și valorile sale. Obiectele nu sunt izolate, ele comunică între ele, trimit mesaje.
Comportamentul unui obiect se referă la modul în care un obiect reacționează (schimbă starea) la mesajele primite, precum și la modul cum acționează (trimite mesaje altor obiecte).
Identitatea unui obiect este proprietatea prin care obiectul se distinge de oricare alt obiect din sistem. Schimbarea stării unui obiect nu influențează identitatea sa. Identitatea face un obiect să fie unic.
O pagină WEB poate conține mai multe obiecte, de exemplu pot exista 2 formulare, form1 și form2, care aparțin clasei FORMULARE. Ele diferă prin câmpurile lor. JavaScript le poate identifica astfel pe fiecare.
Pe lângă obiecte și proprietăți, în JavaScript avem și termenul "metode".
Metodele reprezintă funcțiile pe care un obiect poate să le facă. Ferestrele se deschid cu metoda "open()", butoanele au metoda "click()". Parantezele rotunde "()" arată că se face referire la o metodă, nu la o proprietate. Astfel, putem rezuma că un obiect este o colecție de proprietăți și funcții (metode).
Exemplu de fereastră folosită în pagina WEB creată:
function Deschide_fereastra()
{ iwin=window.open("pb/pb1.cpp", "IWIN", "status=no, toolbar=no, scrollbars=yes, menubar=no, location=no, menu=no, width=450, height=1000 top=0 left=600" ); }
Figura . Exemplu de fereastră WEB
Deci o metodă reprezintă implementarea unei operații. Așadar, o metodă este o unitate de cod scris într-un limbaj orientat pe obiect. La o metodă ne putem gândi ca la un verb, pentru că are la bază o acțiune, o operație. Dacă într-un limbaj orientat pe obiect se definește o funcție și se scrie codul care determină ce trebuie să execute funcția, atunci declarația funcției este o operație, iar corpul funcției este o metodă.
Dacă considerăm obiectul Submit al unui formular, atributurile nume și dimensiune sunt proprietăți (atribute ale obiectului). Dacă se execută clic pe buton, formularul este trimis către server, deci se execută o operație a cărei implementare se numește metodă.
Proprietățile și legăturile alcătuiesc caracteristicile structurale, deoarece ele indică structura obiectelor, iar operațiile și metodele sunt caracteristici dinamice, deoarece ele comunică comportamentul obiectelor. Sintaxa pentru foloșirea obiectelor este:
obiect.proprietate
obiect.metoda()
Punctul (.) se foloseste pentru a specifică detinatorul metodei sau proprietății.
Obiectele pot avea instanțe, atunci când proprietățile lor au valori. De exemplu, obiectul număr complex poate avea instanță un număr complex particular. În JavaScript există obiecte create de utilizator, obiecte intrinseci și obiecte ale browser-ului. Obiectele browser-ului sunt obiecte care implică intervenția browser-ului.
JavaScript organizează toate elementele unei pagini web într-o ierarhie. Toate elementele sunt văzute ca obiecte și fiecare obiect are anumite proprietăți și metode sau alte obiecte.
Cu JavaScript putem manipula ușor obiectele. JavaScript înțelege fereastra browser-ului ca pe un obiect window, acesta conține anumite elemente, cum ar fi de exemplu bara de stare (status bar).
În fereastra browser-ului putem încărca (afișa) un document. Aceasta pagină din interiorul navigatorului este un obiect document.
Obiectul document
Acesta este unul din obiectele cele mai importante în JavaScript, este folosit foarte des.
Obiectul Window lasă conținutul unui document web în grija obiectului Document, acesta este responsabil de conținutul afișat pe o pagină și se poate lucra cu el pentru afișarea de paginii HTML dinamice.
Obiectul document conține mai multe proprietăți, cum ar fi culoarea de fundal a paginii (bgcolor) sau alte obiecte, cum sunt tag-urile HTML. Toate elementele HTML sunt proprietăți ale obiectului document, și la rândul lor acestea sunt obiecte. Un obiect HTML este de exemplu un formular, o etichetă DIV sau un link.
Exemplu:
<div class="rbcWidgetArea widgetYouTube" style="text-align: center;">
<iframe src="https://www.youtube.com/embed/lXyCRP871VI?rel=0&wmode=transparent" width="150" height="95" wmode="Opaque" frameborder="0" allowfullscreen>
</iframe>
</div>
Figura . Adăugare link film youtube
Proprietatea all este cea mai importantă proprietate a obiectului document. Este o proprietate de tip obiect, care are, la rândul ei, alte proprietăți și metode. Este un obiect vector ale tuturor elementelor care se găsesc într-o pagină, așa cum forms, images sunt obiecte vector al tuturor formularelor, respectiv ale tuturor imaginilor dintr-o pagină.
Fiecare element al vectorului all este tot un obiect. De exemplu, elemente (obiecte) ale vectorului all sunt: HTML, HEAD, BODY, câte un element pentru fiecare imagine (IMG), paragraf (K) etc.
Modelul Obiectului Document (DOM) este un standard stabilit de Consorțiul Web și definește o structură logică și standardizată a documentelor, o ordine prin care putem parcurge și edita elemente și conținut din documente HTML sau XML, independentă de platformă și de limbaj, definind structura logică a documentelor și modalitățile de accesare și de modificare a lor.
Această structură logică este una arborescentă, orientată-obiect: documentele sunt modelate utilizând obiecte, iar modelul nu oferă doar o vizualizare structurată a documentului, ci și o manieră de specificare a comportamentului lui și a obiectelor componente. Fiecare element al unui document poate fi privit, deci, ca un obiect, fiecare obiect având identitate și propriile sale funcții.
Exact ca și în modelul obiect din cadrul metodologiei orientate-obiect, DOM identifică: interfețele și obiectele utilizate să reprezinte și să manipuleze un document; semantica acestor interfețe și obiecte (inclusiv comportamentul și atributele lor); relațiile și dependențele între aceste interfețe și obiecte.
Aceste interfețe sunt abstractizări, similare claselor abstracte de baza din C++, oferind o modalitate de accesare și de modificare a reprezentării interne a unui document în cadrul unei aplicații. Interfețele nu implică o implementare concretă, particulară, a funcțiilor pe care le definesc, fiecare aplicație DOM putând stoca documentele în oricare reprezentare internă convenabilă, atâta timp cât interfețele DOM sunt suportate. DOM este conceput să evite dependența de implementare.
Elementele principale legate de lucrul pe partea de client din JavaScript se axează pe ceea ce putem face cu paginile HTML, mai exact – ceea ce poate face vizitatorul cu scriptul Javascript încărcat în pagina HTML.
Primul set de obiecte are o legatură cu navigatorul și cu etichetele HTML din acesta. Se poate accesa sau transfera conținutul unei etichete HTML (de exemplu dintr-un <div> … </div>) utilizând id-ul acesteia.
Evenimente
Evenimentele sunt elemente foarte importante în programarea JavaScript. Acestea sunt acțiuni provocate de cele mai multe ori de vizitatorul paginii.
Dacă vizitatorul apasă un buton din pagină se provoacă evenimentul "Click". Dacă mouse-ul este deasupra unui link, se declanșează un eveniment "MouseOver".
JavaScript poate reacționa la unele evenimente. Aceasta se poate realiza cu ajutorul "event-handlers" (manageri de evenimente sau gestionar de evenimente).
Handlerele de evenimente se adaugă ca atribute ale etichetelor HTML.
De exemplu, dacă dorim să apelăm o funcție "nume_functie()" de fiecare dată când s-a modificat un anumit obiect Text, procedăm astfel: atribuim funcția "nume_functie()" handlerului de eveniment "onChange" al obiectului Text respectiv, ca în exemplul de mai jos:
<input type="text" size="25" name="nume" onChange="nume_functie(this)">
– "onChange" este atribut al etichetei <input>, a carui valoare, între ghilimele, este functia "nume_functie()". În locul functiei dintre ghilimele putem să scriem direct tot codul din funcție, separând prin caracterul ; comenzile JavaScript (acest lucru este nerecomandat în cazul unui cod mare).
Mecanismul care permite ca funcțiile să fie apelate din codul HTML al paginii este acela de tratare a evenimentelor. De exemplu, evenimente pot fi: încărcarea și descărcarea unei pagini web de către browser, evenimente numite onload, respectiv onunload sau la executarea unui clic pe un buton are loc evenimentul onclick.
Conceptul de tratare a evenimentelor constă tocmai în crearea de funcții care să reacționeze la evenimentele importante.
În JavaScript există 18 evenimente. Un obiect recepționează anumite evenimente, exemplu: elementul HTML <BUTTON atribute>, în JavaScript e considerat obiectul BUTTON. El poate recepționa evenimentul onclick (clic cu mouse-ul pe suprafața lui). În urma acestui eveniment se poate lansa o funcție.
Exemplul 1:
<input type="button" value="Numărul de noduri" onClick="alert('Graful are 8 noduri')">
Figura . Exemplu de obiect BUTTON
Exemplu 2:
<input type="button" class="button" value="Fişă teorie" onClick="Deschide_fereastra44()">
Se modifică dimensiunea și culoarea butoanelor.
<style>
.button {
background-color: red;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer; }
.button2 {background-color: blue;}
</style> [38]
Tot ce se poate vedea pe un site web sunt obiecte. Primul obiect este fereastra, care în JavaScript este obiectul window, care are ca metode: alert, prompt, confirm etc. O fereastră conține un obiect document care are printre metode write etc. Un document poate avea unul sau mai multe formulare și un formular poate avea unul sau mai multe elemente.
Obiectele formular sunt stocate într-un tablou, numit forms, unde ordinea în tabel este ordinea în care apar formularele în script. În tabel, numărarea componentelor începe cu 0.
O altă metodă de a anima o pagină sau un formular constă în completarea automată a unor căsuțe cu informații în funcție de informațiile din alte elemente, deja introduse. Această metodă poate fi realizată cu evenimentul onchange, care este executat când un element pierde focus-ul (iese din atenție) și valoarea elementului s-a modificat de la intrarea în atenție (primește focus).
De exemplu:
Numărul de noduri: <INPUT type="text" name="univ" value=" " onchange = "formatare(this)">
Mulţimea nodurilor: <INPUT type="text" name="tel" value=" " onChange="formatare(this)">
Numărul de muchii: <INPUT type="text" name="univ" value=" " onchange = "formatare(this)">
Mulţimea muchiilor: <TEXTAREA rows=2 cols=30 wrap="off" onchange ="formatare(this)"> </TEXTAREA>
Figura . Căsuțe de informații
Căsuțele de validare sunt utilizate pentru a selecta unul sau mai multe articole set de articole. Casuțele de validare multiplă sunt de tipul checkbox în htm Valoarea checkbox a atributului type a tag-ului INPUT se poate asocia și cu atributele name, value și checked.
Exemplu de folosire a căsuțelor de validare:
<font color=red size=6>4. La fiecare apel recursiv al unui subprogram, ce sunt memorate în segmentul de stivă? </font>
<h3><input type="checkbox" name="exb1" value="1" onclick = "caseta(1)"> Adresa de revenire
<input type="checkbox" name="exb1" value="1" onchange = "caseta(1)"> valorile variabilelor locale
<input type="checkbox" name="exb1" value="1" onchange = "caseta(1)"> valorile parametrilor transmişi prin valoare
<input type="checkbox" name="exb1" value="1" onchange = "caseta(1)"> adresele parametrilor transmişi prin referinţă
Figura . Evidențierea selecției căsuțelor de validare, utilizând JavaScript
Atributul checked, care în JavaScript este proprietatea checked, are o valoare booleană: true dacă proprietatea există și false în caz contrar.
Exemplu de folosire a căsuțelor de validare care folosesc atributul checked:
<legend align="left"> Adevărat sau fals</legend>
1. Nodul x este incident cu nodul y dacă formează o muchie.
<input type="radio" name="ex1" value="Adevarat"onchange = "formatare(this)">Adevărat
<input type="radio" name="ex1" value="Fals"onchange = "formatare(this)">Fals
<br>
Figura . Căsuțe de validare care folosesc atributul checked
În HTML, mai există și listele de opțiuni care se introduc cu tag-urile <SELECT>…</SELECT> și <OPTION>…</OPTION>.
Cum atributele unui tag HTML devin proprietățile obiectului în JavaScript, putem spune că obiectul SELECT are proprietățile: name, multiple (în cazul în care sunt selectate mai multe elemente din listă), size (în cazul afișării mai multor elemente din listă), options (vector de obiecte OPTION), selectedIndex (reține indexul opțiunii selectate).
Obiectul OPTION are proprietățile: value și selected (care ia valoarea true dacă opțiunea este selectată).
Butoanele Radio se folosesc pentru a selecta o opțiune din mai multe. Dacă mai multe butoane au același nume, ele aparțin aceleiași selecții și se exclud unul pe celălalt.
Mai jos este un exemplu de folosire a butoanelor radio:
<font color=red size=6>8. Care este condiţia de oprire? </font>
<h3><input type="radio" name="exb5" value="0" onclick="radio(0);"> factorial(n-1)*n;
<input type="radio" name="exb5" value="1" onclick="radio(1);"> n==0
<input type="radio" name="exb5" value="0" onclick="radio(0);"> p=1
<input type="radio" name="exb5" value="0" onclick="radio(0);"> return 1;
</h3>
Figura . Butoane radio
Pentru a modifica unele elemente dintr-un formular, după ce acesta a fost trimis programului de scriptare CGI în vederea prelucrării, se poate folosi evenimentul onsubmit, ca atribut al elementului SUBMIT.
Dacă dorim, de exemplu, să validăm datele dintr-un formular sau să corectăm unele informații introduse, se poate asocia o funcție în JavaScript evenimentului onsubmit.
În exemplul următor, considerăm o funcție creeaza_parola(), care creează un element de tip ascuns (tipul hidden), numit parolă, din: prima literă a numelui și a prenumelui și din lungimea numelui. Numele acestui element și valoarea creată vor fi trimise spre prelucrare programului CGI.
Când se execută clic pe butonul SUBMIT, acesta recepționează evenimentul onsubmit care apelează funcția creeaza_parola(), care se execută și apoi formularul este trimis programului CGI.
3. 1. 3. Imagini în JavaScript
Atributele elementului IMG sunt: src, alt, id, width, height, border, hspace, vspace.
În JavaScript elementul html IMG devine obiectul IMG, care are, ca proprietăți atributele elementului IMG enumerate mai sus cu excepția atributului ID.
Evenimentele recepționate de elemental IMG sunt:
-Onclick – evenimentul se produce când se execută un clic pe un obiect aflat pe pagină
-Ondblclick – evenimentul se produce când se execută dublu clic pe un obiect
-Onmousemove – evenimentul se produce în mod continuu, când cursorul mouse-ului se mișcă pe un obiect
-Onmouseover – evenimentul se produce, o singură dată, când se trece cu mouse-ul se mișcă peste un obiect
-Onmouseout – evenimentul se produce când mouse-ul părăsește suprafața unui obiect
Din modul de definire se observă că aceste evenimente pot fi recepționate și de alte obiecte, nu doar de obiectul IMG.
Pentru a schimba aspectul unei pagini, pe măsură ce vizitatorul parcurge o pagină, cu ajutorul mouse-ului se folosesc elementele care recepționează evenimentele de mai sus, cunoscute și sub numele de elemenete rollover.
Un element rollover este produs de unul dintre evenimentele definite mai sus și are loc când un vizitator al unei pagini trece cu mouse-ul peste un obiect imagine, text, element al unui formular.
Pentru a folosi elemente rollover putem utiliza două metode:
metoda directă – prin asocierea unei acțiuni atributului onmouseover (de exemplu) al unui tag HTML, caz în care nu se folosește JavaScript
metoda indirectă – prin crearea unei funcții JavaScript apelată de atributul onmouseover (de exemplu) la declanșarea unui eveniment (onmouseover). Se folosește, mai ales, dacă se dorește să aibă loc mai multe acțiuni ca răspuns la un eveniment.
<IMG ID="divide" src="img/1divide.png" height="175" width="260"
onmousemove="divide.height+=2, divide.width+=2">
Figura . Mărire imagine când se trece cu mouse-ul pe deasupra ei
Se pot realiza și animații încărcând imaginile în variabile. Funcția animație() va afișa la o secundă sau la un alt interval de timp dorit o imagine. În felul acesta se va crea impresia derulării unui film.
Se știe că orice obiect are metodele constructor și destructor, înseamnă că obiectele image vor avea constructorul new Image(), care va crea o imagine în memorie. Imaginile fiind în memorie, în cazul în care dorim să realizăm o animație nu se mai pierde timp cu încărcarea lor ca în cazul unui fișier avi de animație.
Exemplu de realizarea a unei animații:
<head>
<script type="text/javascript">
<!–>
var image1=new Image()
image1.src="img/melc_rec.png"
var image2=new Image()
image2.src="img/conbrad1.png"
var image3=new Image()
image3.src="img/aloe1.jpg"
//–>
</script></head><body>
<img src="img/melc_rec.png" name="slide" width="130" height="170">
<script type="text/javascript">
<!–
var step=1
function animatie(){
document.images.slide.src=eval("image"+step+".src")
if(step<3) step++
else step=1
setTimeout("animatie()",2000)}
animatie()
//–></script></body>
CAPITOLUL 4. PREZENTAREA APLICAȚIEI. DESIGNUL ȘI FUNCȚIONALITATEA APLICAȚIEI
Pentru crearea aplicației am folosit limbajul HTML. La realizarea acestui site am avut în vedere ca acesta să exprime cât mai clar și mai simplu partea teoretică a lecției și să conțină aplicații concrete – exerciții și probleme – pentru înțelegerea noțiunilor prezentate, corelând teoria și practica. De asemenea, am utilizat metodele și tehnicile de optimizare a paginilor Web prezentate în lucrare folosind JavaScript.
Site-ul este structurat în mai multe pagini HTML, fiecare pagină având legătura cu pagina principală, după cum se poate observa din diagramă.
Figura . Organigrama site-ului
Pagina principală, de pornire, a site-ului “1rec-cadre-ca un tabel.html” conține doar tag-ul <FRAMESET> însoțit de atributul <ROWS> prin care am definit exact împărțirea paginii în trei zone. Am folosit procente pentru a defini mărimea rândurilor și coloanelor care au format cele trei cadre și am stabit ce pagină va fi afișată în fiecare dintre ele folosind tag-ul <FRAME> cu atributul SRC cu ajutorul căruia am indicat sursa cadrului.
<html> <head></head>
<frameset rows="14%,*" border=0>
<frame src="1rec-sus.html">
<frameset cols="11%,*" border=0>
<frame src="1rec-stanga.html">
<frame name="dreapta" src=1rec-dreapta.html scrolling=yes>
</frameset> </frameset> </html>
Figura 30. Pagina principală
Primul cadru este conceput ca un antet al site-ului, antet care nu se va modifica pe parcursul navigării în site și conține titlul cu animația realizată folosind marquee. Conține și patru opțiuni de meniu: Acasă – se revine la pagina de start, Anunțuri – cu diferite anunțuri și link-uri, Forum și Logare.
<html><head><title>Gradul I</title>
<style type="text/css">
ul { list-style-type:none;
margin:0; padding:0;
padding-top:6px; padding-bottom:6px;}
li { display:inline;}
a:link,a:visited {
font-weight:bold; font-size:17px;
color:#FFFFFF; background-color:red;
text-align:center; padding:6px;
text-decoration:none;}
a:hover,a:active { background-color:#daa520;}
</style></head>
<body background="img/fractali-s.jpg" width="80" align="center">
<table border="0">
<td><pre> </pre> </td><td width="75"><img src="img/rec1.jpg" width="75" height="75"> </td>
<td><ul> <li><a href="1rec-cadre-ca un tabel.html" target="_parent">   Acasa    </a></li><br><br>
<li><a href="1rec-cadre-ca un tabel-anunturi.html" target="_parent">Anunturi</a>
</ul></td><td width="1250">
<marquee width="1250" height="80" direction="right" behavior="alternate" scrolldelay="90">
<img src="img/titlu_rec.jpg" alt="sigla" width="300" height="80"></marquee> </td><td><ul>
<li><a href="1rec-cadre-ca un tabel-forum.html" target="_parent"> Forum </a></li><br><br>
<li><a href="1rec-cadre-ca un tabel-logare.html" target="_parent"> Logare </a></li>
</ul></td><td width="75"><img src="img/rec.jpg" width="75" height="75"></td>
</table> </body> </html>
Figura . ”Antetul” site-ului
În coloana din stanga care, de asemenea, rămâne nemodificată pe parcursul vizitării site-ului, se afișează, folosind un script, o formulă de salut, în funcție de ora la care este accesat site-ul, folosind instrucțiunea if și aplicând obiectul document cu metoda de scriere write; apoi se folosește obiectul Array (tablou unidimensional) și Date împreună cu metodele necesare (getDate, getMonth, getFullYear) pentru aflarea orei (care se modifică asemenea unui ceas electronic), datei și zilei săptămânii, apoi cu ajutorul funcției print_date și obiectul document, cu metoda write se afișează aceste informații. Am folosit și o funcție pentru animație care folosește trei imagini creând impresia derulării unui film și un link către melodia formației Rosu și Negru – Pseudofabula.
<html> <head> <title>Gradul I</title>
<script type="text/javascript"> <!–>
var image1=new Image()
image1.src="img/MELC_REC.png"
var image2=new Image()
image2.src="img/conbrad1.png"
var image3=new Image()
image3.src="img/aloe1.jpg"
//–>
</script> <script type="text/javascript">
function startTime()
{ var today=new Date();
var h=today.getHours();
var m=today.getMinutes();
var s=today.getSeconds();
// add a zero în front of numbers<10
m=checkTime(m);
s=checkTime(s);
document.getElementById('txt').innerHTML=h+":"+m+":"+s;
t=setTimeout('startTime()',500); }
function checkTime(i)
{ if (i<10) { i="0" + i; }
return i; }
function apel()
{ alert("Apasa aici pentru a trece mai departe!"); }</script>
<SCRIPT language = "JavaScript">
function Afiseaza() { alert("Butonul initial apasat") }
function schimba()
{ if (but.value == "mesaj_1") but.value = "mesaj_2"
else but.value="mesaj_1"
setTimeout("schimba()",2000) } </SCRIPT>
<SCRIPT language = "JavaScript">
function calcul_valoare()
{ if (punctaj.nr.value.length > 0 && punctaj.punc.value.length > 0)
{ punctaj.val.value = punctaj.nr.value * punctaj.punc.value } } </SCRIPT>
<SCRIPT language="JavaScript">
function formatare(obiect)
{ obiect.style.color = "green"
obiect.style.background = "cyan"
obiect.style.fontStyle = "italic"
obiect.style.fontWeight = "bold" } </SCRIPT>
<STYLE> #par { color:#FFFFFF; font-size:20; font-style:italic;} </STYLE>
<SCRIPT language="JavaScript">
i=255, rel=0
function aparitie() { i–
par.style.color=255*256*256+256*i+i
rel=setTimeout ("aparitie()" , 15)
if(i==0) clearTimeout(rel)
p1.style.color="blue" } </SCRIPT>
</head>
<body bgcolor="#33CCFF" onResize="22" onLoad="startTime(),aparitie()"
LINK="#00FF33" vlink="red" ALINK="#0000CC">
<FONT color="#FF0000" SIZE="5"> <center><h3> <div id="txt"></div></h3>
<script type="text/javascript">
var d = new Date();
var time = d.getHours();
if (time < 10) { document.write("<center><b><h4>Bună dimineata!</h4></b></center>");}
else if (time<20) { document.write("<center><b><h4>Bună ziua! </h4></b></center>"); }
else { document.write("<center><b><h4>Bună seara! </h4></b></center>"); }
</script><script language="JavaScript" type="text/javascript">
var month = new Array();
month[0]="Ianuarie";month[1]="Februarie";month[2]="Martie";
month[3]="April";month[4]="Mai";month[5]="Iunie";
month[6]="Iulie";month[7]="August";month[8]="Septembrie";
month[9]="Octobrie";month[10]="Noiembrie";month[11]="Decembrie";
var day = new Array();
day[1]="Luni";day[2]="Marti";day[3]="Miercuri";day[4]="Joi";
day[5]="Vineri";day[6]="Sambata";day[0]="Duminica";
today = new Date();date = today.getDate();day = (day[today.getDay()]);
month = (month[today.getMonth()]);
year = (today.getFullYear());
suffix = (date==1 || date==21 || date==31) ? "" : "" &&
(date==2 || date==22) ? "nd" : "" && (date==3 || date==23) ? "" : ""
function print_date()
{ document.write(day + "," + "<br>" + date + "<sup>" + "</sup>" + ", " +month + "<br>" + year);}</script>
<script>print_date();</script></div></font> <br><br>
<img src="img/melc_rec.png" name="slide" width="130" height="170">
<script type="text/javascript"><!–
var step=1
function animatie(){document.images.slide.src=eval("image"+step+".src")
if(step<3)step++
else step=1
setTimeout("animatie()",2000) }
animatie()//–>
</script> <form>
<input type="button" value="schimbă în galben" name="button1" onClick="document.bgColor='#FFFF99'">
<input type="button" value="schimbă în verde " name="button2" onClick="document.bgColor='#99FF99'">
</form></pre>
<iframe width="150" height="95" src="https://www.youtube.com/embed/ezSD8F5zQqk" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe></center>
</body></html>
În dreapta este un meniu (format, de fapt, din imagini) cu legături la celelalte pagini ale site-ului. Imaginile se pot mări pentru o mai bună vizibilitate folosind evenimentul onMouseMove, modificând dimensiunile și pe lățime și pe lungime, ca de exemplu:
<IMG ID="prezentare" src="img/1general.png" height="175" width="260" onmousemove="prezentare.height+=2, prezentare.width+=2>
Figura . Cadrul din dreapta
Pagina 1recursivitatea-inceputul.html este pagina care va fi afișată la accesarea legăturii de la Prezentare generală a recursivității. Ca urmare, în momentul accesării acestui link se deschide o nouă pagină ce conține lecția și exerciții pentru recursivitate, dar și legături către acestea și către alte două pagini, una ce conține întrebări recapitulative, iar cealaltă un test sumativ. Aceste opțiuni apar doar în această pagină a site-ului.
<a href="1recapitulare_functii.html" target="dreapta">Recapitulare funcţii</a>
<A href="#lectia">Lecţia</A>
<A href="#exercitii">Exerciţii</A>
<a href="1parola.html" target="dreapta">Evaluare finală</a>
Figura . Prezentare generală – pagina despre recursivitate
În marginea din stânga paginii se găsește un meniu ascuns care conține o legătură la pagina principală și o legătură către începutul paginii curente, folosind următorul cod în secțiunea <head>:
<style>
#mySidenav a {
position: fixed;
left: -80px;
transition: 0.2s;
padding: 15px;
width: 100px;
text-decoration: none;
font-size: 20px;
color: white;
border-radius: 0 5px 5px 0;
display: block;}
#mySidenav a:focus
{ left: 0; display: block;}
#mySidenav a:hover
{ left: 0; display: block;}
#acasa { top: 20px;
background-color: #f44336;
border-bottom: 3px solid transparent;
display: block;}
#susus { top: 80px;
background-color: #2196F3;
display: block;}
</style>
Iar în secțiunea <body> avem următorul cod:
<div id="mySidenav" class="sidenav">
<a href="1rec-dreapta.html" id="acasa">Acasă</a>
<a href="#sus" id="susus">Sus</a></div>
Dacă se accesează link-ul de mai jos, se deschide pagina care conține întrebările recapitulative și meniul ascuns către pagina principală, către începutul paginii curente și către pagina cu lecția despre recursivitate.
Figura . Link pentru recapitularea noțiunilor despre funcții
Prima dată elevul dă răspuns în ferestrele indicate, apoi poate vizualiza răspunsul corect apăsând declanșatorul și se deschide o fereastră ce conține răspunsul corect, dar care se derulează pas cu pas unde este cazul, pentru a se putea discuta.
Figura . Pagina pentru recapitulare
În pagina principală se prezintă exemple concrete, din viața de zi cu zi, iar lecția se poate urmări accesând butonul “Fișă teorie” care deschide într-o fereastră un document pdf cu partea introductivă și cea teoretică.
Figura . Declanșatorul și fereastra cu fișa noțiuni teoretice
Sunt apoi prezentate exemple și întrebări. Întrebările au variante de răspuns realizate cu butoane radio sau casete de text și, în funcție de răspunsul dat, se afișează un mesaj vizual, afirmativ sau nu.
<font color=red>2. O funcţie recursivă se poate implementa şi nerecursiv? </font>
<input type="radio" name="ex1" value="Adevarat" value="1" onclick="radio(1);">DA
<input type="radio" name="ex1" value="Fals" value="0" onclick="radio(0);">NU
<font color=red>4. La fiecare apel recursiv al unui subprogram, ce sunt memorate în segmentul de stivă? </font>
<input type="checkbox" name="exb1" value="1" onclick = "caseta(1)"> Adresa de revenire
<input type="checkbox" name="exb1" value="1" onchange = "caseta(1)"> valorile variabilelor locale
<input type="checkbox" name="exb1" value="1" onchange = "caseta(1)"> valorile parametrilor transmişi prin valoare
<input type="checkbox" name="exb1" value="1" onchange = "caseta(1)"> adresele parametrilor transmişi prin referinţă
Pentru aceasta s-au folosit funcțiile radio() și caseta() declarate în partea de antet astfel:
function radio( value )
{ if( value == 0 )
window.open("img/of.jpg", "IWIN", "status=no, toolbar=no, menubar=no, location=no, menu=no, scrollbars=yes, width=200, height=200 top=300 left=800");
else window.open("img/ok.png", "IWIN", "status=no, toolbar=no, menubar=no, location=no, menu=no, scrollbars=yes, width=200, height=200 top=300 left=800"); }
function caseta( value )
{ if( value == 0 )
window.open("img/of.jpg", "IWIN", "status=no, toolbar=no, menubar=no, location=no, menu=no, scrollbars=yes, width=200, height=200 top=300 left=800");
else window.open("img/ok.png", "IWIN", "status=no, toolbar=no, menubar=no, location=no, menu=no, scrollbars=yes, width=200, height=200 top=300 left=800");}
Figura . Intrebări cu variante de răspuns – răspuns corect
Figura . Intrebări cu variante de răspuns – răspuns greșit
La finalul grupului de întrebări se găsește un buton care deschide într-o fereastră un documentul care conține rezolvările exercițiilor.
Figura . Fișa cu rezolvări ale problemelor
Sunt exemple a căror rezolvare se poate vizualiza într-o fereastră separată, care se deschide într-o poziție specificată pe ecran, doar la apăsarea unui declanșator, pentru ca inițial elevul să încerce să rezolve acest exercițiu pe baza definițiilor și proprietăților din lecția învățată. La fiecare exercițiu propus se poate alege fereastra care conține rezolvarea problemei sau cea care conține un exemplu concret, împreună cu rezultatul obținut. Codul prin care se realizează aceasta este dat mai jos:
<SCRIPT language="JavaScript">
function Deschide_fereastra1()
{iwin=window.open("pb/rec1.txt", "IWIN", "status=no, toolbar=no, menubar=no, location=no, scrollbars=yes,menu=no, width=450, height=250 top=150 left=800" );}
function Deschide_fereastra2()
{iwin=window.open("pb/daterec1.txt", "IWIN", "status=no, toolbar=no, menubar=no, location=no, menu=no, scrollbars=yes, width=450, height=250 top=150 left=800");}
Figura . Fereste independente
Am realizat animații și folosind site-ul Ezgif.com – Animated gifs made easy. Imaginile se deschid într-o altă fereastră, când se apasă un declanșator, și se derulează dând impresia unui document PowerPoint.
<INPUT type="button" class="button2" value=" Algoritm ITERATIV " onClick= "Deschide_fereastra20()">
<INPUT type="button" class="button" value=" Algoritm RECURSIV " onClick= "Deschide_fereastra21()">
Figura . Exemplu: parcurgerea pas cu pas pentru apelul suma(5).
Codul JavaScript pentru activarea ferestrei cu imagini este:
function Deschide_fereastra20()
{iwin=window.open("point/iterativ.gif", "IWIN", "status=no, toolbar=no, menubar=no, location=no, scrollbars=yes,menu=no, width=650, height=550 top=10 left=680" );}
De asemenea, am mai folosit și animații care rulează doar când mouse-ul se află deasupra acestora:
<img src="point/poze/cit-afis-vect/slide1.jpg" onMouseOver="MouseRollover(this)" onMouseOut="MouseOut(this)" width=550, height=450>
Am folosit două funcții JavaScript, una pentru a începe derularea și cea de a două pentru a specifica imaginea ce rămâne când nu ne mai aflăm cu mouse-ul deasupra ei.
<script language="javascript">
function MouseRollover(MyImage) { MyImage.src = "point/citire-vect.gif"; }
function MouseOut(MyImage) { MyImage.src = "point/poze/cit-afis-vect/slide4.jpg"; }
Figura . Imagini care se derulează când mouse-ul este deaspura lor
Tot de pe această pagină se poate accesa testul sumativ, de la legătura Evaluare_finală, dar aceasta se poate realiza doar după ce se introduce parola, pentru ca elevii să nu poată vedea întrebările testului decât în ziua planificată.
Figura . Legătura spre pagina de test
Am folosit pentru aceasta legătură codul:
<a href="1parola.html" target="dreapta">Evaluare finală</a>
Documentul 1parola.html conține codul:
<html>
<head>
<title>Tutorial</title>
<script language="JavaScript">
var parola;
var cuvant="testdata";
parola=prompt('Introduceti parola pentru a vizualiza continutul documentului!','');
if (parola==cuvant)
window.location="1evaluare.html";
else{ alert('Parola GRESITA!!!');
window.location="1recursivitatea-inceputul.html";}
</script>
</head>
<body></body>
</html>
Dacă parola este greșită se afișează un mesaj de eroare apoi se reîntoarce la pagina despre recursivitate.
Figura . Mesaj pentru introducere parolă greșită
Dacă parola este introdusă corect se deschide pagina care conține întrebările testului ale cărui răspunsuri se trimit pe e-mail. De asemenea conține cele trei legături de întoarcere la pagina principală, la începutul paginii curente și la pagina cu lecția despre recursivitate.
Figura . Pagina de test
A doua pagină, cea în care se prezintă metoda Divide et Impera, împreună cu exerciții specifice, se poate accesa prin legătura din pagina principală a platformei.
Figura . Prezentare generală – Divide et Impera
În pagina principală se mai găsește un buton pentru fișa de teorie. Sunt și exerciții rezolvate, dar, ca și la lecția anterioară, rezolvarea nu se dă direct, ci se poate afla prin apăsarea butonului care deschide fereastra cu codul programului.
Figura . Parte a paginii cu exerciții
În marginea din stânga paginii se găsește meniul ascuns cu legătura la pagina principală și la începutul paginii curente, meniu care se găsește pe fiecare pagină a site-ului.
Figura . Meniu lateral și link pentru ”poveste”
Dacă se accesează link-ul de mai sus, se deschide pagina care conține legenda Turnurilor din Hanoi și a jocului inspirat din această legendă, o scurtă descriere a strategiilor militare folosite de diferiți conducători și meniul ascuns care conține în plus și o legatură către pagina cu lecția Divide et Impera.
Figura . Pagina cu ”povestea”
Figura . Continuarea paginii de lectură
Tot din pagina lecției, de la legătura Test, se poate accesa, doar după introducerea parolei, testul care conține întrebări specifice.
Figura . Legătura spre pagina de test
Figura . Pagina de test de la metoda Divide et Impera
Urmează pagina 1back.html ce conține partea teoretică și exerciții pentru metoda backtracking și, de asemenea, legătura către un test care poate fi vizualizat tot după ce se introduce o parolă.
Figura . Prezentare generală – Metoda Backtracking
Ca și în celelalte pagini prezentate până acum, sunt și exerciții rezolvate, dar, la fel, rezolvarea nu se dă direct, ci se poate afla prin apăsarea butonului care deschide fereastra cu codul programului.
Figura . Partea de exerciții a paginii
Figura . Pagina cu testul pentru metoda backtracking
Site-ul mai conține pagina 1fractali.html cu noțiuni generale despre fractali, exemple de fractali celebri și probleme de generare a fractalilor.
Figura . Prezentarea paginii – Fractali
Urmează pagina 1diz-incerc.html ce conține teoria pentru grafuri orientate, neorientate, exerciții și un test recapitulativ.
Figura 59. Prezentare generală – Grafuri
Lecțiile conțin noțiunile teoretice, exemple și exerciții.
Figura 60. Noțiuni teoretice
La exerciții se dau enunțuri și indicații unde este cazul, dar și rezolvări, totuși nu direct, ci rezolvările sunt vizibile doar atunci când se apasă un buton care deschide fereastra cu rezolvarea problemei.
Exerciţiul 1:</FONT>
Pe primul rând al fişierului "graf.txt" se găseşte un număr natural nenul n.
Pe următorul rând se găsesc n*n elemente. Să se verifice dacă matricea ce se poate forma cu cele n*n elemente reprezintă matricea de adiacenţă a unui
graf neorientat <h3> <FONT COLOR="red">Indicaţii</FONT></h3>
– diagonala principală conţine numai 0
– elementele din matrice sunt doar 0 sau 1
– matricea este simetrică faţă de diagonala principală
</pre>
<INPUT type="button" name="Deschide" value="Rezolvare problemă " onClick="Deschide_fereastra()">
<INPUT type="button" name="Deschide1" value="Exemplu" onClick="Deschide_fereastra1()">
<pre><FONT COLOR="red" SIZE="5">
Figura . Exerciții
Înainte de a se apuca de lucru, elevul are posibilitatea de a porni un cronometru pentru a măsura timpul necesar pentru rezolvarea exercițiului și de asemenea pentru a opri în momentul în care termină. Pentru aceasta se foloseste evenimentul onClick care apelează funcția scrisă în antet doTimer() pentru a porni cronometrarea când se apasă butonul de pornire, și tot evenimentul onClick, dar care apelează funcția stopCount() pentru oprirea cronometrării.
<script type="text/javascript">
var c=0;var t;
var timer_is_on=0;
function timedCount()
{document.getElementById('txt1').value=c;
c=c+1;
t=setTimeout("timedCount()",1000);}
function doTimer()
{if (!timer_is_on)
{ timer_is_on=1;
timedCount(); }}
function stopCount()
{clearTimeout(t);
timer_is_on=0;}
var c1=0;
var t1;
var timer_is_on1=0;
function startTime()
{var today=new Date();
var h=today.getHours();
var m=today.getMinutes();
var s=today.getSeconds();
// add a zero în front of numbers<10
m=checkTime(m);
s=checkTime(s);
document.getElementById('txt').innerHTML=h+":"+m+":"+s;
t=setTimeout('startTime()',500);}
function checkTime(i)
{if (i<10)
{ i="0" + i; }
return i;}
function apel(){alert("Apasa aici pentru a trece mai departe!");}</script>
<SCRIPT language="JavaScript">
function Mareste(){ graf.width+=10 graf.height+=5} </script>
Am folosit formulare cu butoane care conțin întrebări al căror răspuns apare într-o casetă în partea de sus a ecranului:
<form> <input type="button" value="Numărul de noduri" onClick="alert('Graful are 8 noduri')">
<input type="button" value="Mulţimea nodurilor" onClick="alert('X={1,2,3,4,5,6,7,8}')">
<input type="button" value="Numarul de muchii" onClick="alert('Graful are 11 muchii')">
<input type="button" value="Mulţimea muchiilor" onClick="alert('{[1,2]; [1,3]; [1,4]; [2,3]; [2,5]; [2,6]; [3,6]; [4,7]; [4,8]; [5,6]; [7,8]}')">
<input type="button" value="Nodurile adiacente nodului 2" onClick="alert('1,3,5,i6 sunt noduri adiacente cu nodul 2')">
<input type="button"value="Muchiile incidente cu nod 4" onClick="alert('[1,4];[4,7];[4,8]')">
<input type="button" value="Nodurile vecine cu nodul 4" onClick="alert('1, 7 şi 8 sunt noduri vecine cu nodul 4')">
<input type="button" value="Muchiile pentru care este extrem nodul 3" onClick="alert('[1,3]; [2,3]; [3,6]')">
<input type="button" value="Muchiile [1,3] şi [3,2] sunt" onClick="alert('muchii incidente')">
</form>
Figura . Butoane cu întrebări
În ultima parte – Exerciții, sunt enunțuri de probleme pentru fiecare din cele două subcapitole ale lecției de grafuri: grafuri neorientate și grafuri orientate, iar la final un test recapitulativ.
Fiecare exercițiu are enunț, indicații, rezolvare și exemplu. Dar rezolvarea nu se pune la dispoziție direct, în scopul de a provoca elevul să gândească singur și abia apoi să se verifice folosind rezolvarea pusă la dispoziție. Pentru aceasta se folosesc două butoane, care deschid două ferestre, una ce conține rezolvarea problemei și încă una ce conține un exemplu și cu răspunsul ce ar trebui să apară dacă problema este rezolvată corect.
Pentru aceasta se folosește evenimentul onclick care apelează funcția Deschide_fereastra care utilizează obiectul window cu metoda open de deschidere a unei noi ferestre, cu parametrii status, toolbar, menubar, location, menu dezactivați, parametrul scrollbars activ și dimensiunile ferestrei ce dorim să se deschidă și, de asemenea poziția pe ecran unde să apară.
Pentru exercițiile pe care elevul trebuie să le rezolve singur, se dă enunțul problemei, unde este cazul și indicații, iar pentru rezolvare se folosesc două câmpuri de tip textarea, cu paramerii care modifică fundalul, culoarea și stilul de scriere dacă se modifică aceste câmpuri, rezolvând problemele.
<FONT COLOR="red">Rezolvare</FONT>
<form><input type="button" value="Start!" onClick="doTimer()" />
<input type="text" id="txt1" />
<input type="button" value="Stop!" onClick="stopCount()" /><FONT COLOR="black" SIZE="4">(Hai să vedem în cât timp răspunzi!!!)
</font></form> <pre>
<form enctype="text/plain" action="mailto:raduade@yahoo.com?subiect=Grafuri neorientate pb 1" method="post">
<TEXTAREA COLS="50" ROWS ="10" NAME="exemplu1" onchange ="formatare(this)"> Scrieţi CODUL sursă
</TEXTAREA>
<TEXTAREA COLS="50" ROWS ="10" NAME="exemplu1" onchange ="formatare(this)"> Dacă fişierul date.txt conţine:
5
0 1 1 1 0
1 0 1 0 1
1 1 0 1 1 => Ce se afişează?
1 0 1 0 0
0 1 1 0 0
</TEXTAREA>
<input type="submit" value="Trimite răspunsurile"><input type="reset" value="Şterge tot"></form>
Figura . Exerciții
Testul recapitulativ folosește un formular care conține butoane radio, casete de validare, câmpuri text și de tip listă de opțiuni, iar la final câmpuri pentru identificare, un câmp a cărui valoare nu se poate modifica și nelipsitele butoane de reset și de trimitere a răspunsurilor prin e-mail. Fiecare tip de butoane sunt grupate în secțiuni separate.
<input type="button" value="Start!" onClick="doTimer111()" />
<input type="text" id="txt111" />
<input type="button" value="Stop!" onClick="stopCount111()" /><FONT COLOR="black" size="3">(Hai să vedem în cât timp răspunzi!!!)</font>
</form> <pre><h3><form enctype="text/plain" action="mailto:raduade@yahoo.com?subiect=Grafuri – probleme grila" method="post"><fieldset>
<legend align="left"> Adevărat sau fals</legend>
1. Nodul x este incident cu nodul y dacă formează o muchie.
<input type="radio" name="ex1" value="Adevarat"onchange = "formatare(this)">Adevărat
<input type="radio" name="ex1" value="Fals"onchange = "formatare(this)">Fals
<br>
<fieldset>
<legend align="left"> Alegeţi </legend><br>
1. Ce informaţii se pot obţine din matricea de adiacenţă a unui graf neorientat?
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Numărul de muchii
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Gradul unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Gradul intern al unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Gradul extern al unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Nodurile adiacente unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Succesorii unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Predecesorii unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Numărul de vecini ai unui nod
<input type="checkbox" name="exb1" value="Adevarat" onchange = "formatare(this)"> Muchiile <br>
2…</fieldset>
<fieldset>
<legend align="left"> Completaţi </legend><br>
1. Matricea de adiacenţă a unui graf neorientat este <input type="text" name="exc1" value="" size="50" onchange = "formatare(this)">
<br>
2….</fieldset>
<fieldset>
<legend align="left"> Alegeţi </legend><br>
1. Se consideră un graf orientat tare conex. Stabiliţi numărul circuitelor care conţin toate nodurile grafului:
<select name="exd1" onchange = "formatare(this)">
<option> Exact unul</option>
<option> Cel mult unul</option>
<option> Nici unul</option>
<option> Cel puţin unul</option>
</select>
<br>
</fieldset>
<fieldset>
<legend align="left"> Date </legend>
<br><font="red">
Nume test: <input type="text" name="Lectie" value="Test recapitulativ" readonly>
<br>
Nume: <input type="text" name="Nume" value=""onchange = "formatare(this)"> Clasă: <input type="text" name="Clasa" value=""onchange = "formatare(this)">
<br></font>
</fieldset><br><br>
<input type="submit" value="Trimite răspunsurile"><input type="reset" value="Şterge tot">
</form>
</pre>
<FONT COLOR="red" SIZE="3" FONT="Comic Sans MS" >
<A href="#sus">SUS</A>
</FONT>
</center>
Cadrul de sus mai conține o legătură către o pagină cu toate documentele cu partea teoretică, fișe cu enunțuri de probleme cu rezolvări și fișe de lucru.
Figura . Pagina de lucru
Pagina anunțuri are legătura în partea de sus a site-ului. Profesorul îți anunță cu ajutorul acestei pagini elevii despre activitățile la clasă.
Figura . Pagina anunțuri
Pagina Logare, va fi completată ulterior. Meniul lateral ascuns are în plus față de celelalte pagini și o opțiune pentru o pagină ce conține diferite link-uri pe care să le acceseze elevii.
Figura . Pagina Logare
Figura . Pagina cu link-uri
Ultima pagină este pagina de forum pe care o voi finaliza ulterior.
CAPITOLUL 5. CONCLUZII ȘI DEZVOLTĂRI VIITOARE
Lucrarea conține o aplicație originală care constă într-o platformă de e-Learning folosită momentan pentru predarea și evaluarea temei de recursivitate, dar poate fi folosită și pentru predarea și evaluarea altor capitole din cadrul informaticii, dar și din cadrul altor discipline de studiu.
Alegerea temei – Recursivitate – a fost făcută datorită faptului că, pe de o parte este un subiect dificil de înțeles pentru elevi și, pe de altă parte, are numeroase aplicații.
În interiorul lucrării este o prezentare detaliată a tehnologiilor folosite în proiectarea platformei de e-Learning împreună cu exemple detaliate de cod pentru rezolvarea diferitelor sarcini de către platformă. Astfel lucrarea poate fi folosită și ca un tutorial pentru proiectarea unor platforme similare sau se pot face modificări în cadrul platformei.
Ca dezvoltări viitoare îmi propun să realizez o cercetare metodico-științifică asupra efectului folosirii platformei de e-Learning realizând o evaluare a eficienței metodei prin statistici descriptive și prin formularea și validarea unor ipoteze statistice conform metotdologiei prezentate în [23].
Elementul cel mai dificil în realizarea acestei cercetări îl constituie obținerea datelor care presupun a avea o clasă care să poată fi împărțită în două grupe sau a avea două clase pe care să se facă studiul.
Oricum această cercetare este în afara scopului propus al prezentei lucrări, dar constituie un element prin care lucrarea poate fi fructificată în continuare.
În continuare doresc să mai completez acest site și cu alte teste de tip grilă, cu o parte de elemente de HTML și cu cât mai multe lecții și probleme. Dar nu numai despre recursivitate, ci să extind această platformă cu o parte care să poată fi folosită și de elevii claselor de gimnaziu. Și, de asemenea, să finalizez pagina de forum.
ANEXE
Anexa 1. Plan de lecție: Insușire de noi cunoștințe -Tradițional
Unitatea de învățământ: Liceul Teoretic „St. L. Roth” Mediaș
Disciplina: Informatică
Clasa: a XI-a Matematică-Informatică
Data:
Profesor: ADELA BĂRBAT
Unitatea de învățare: Recursivitate
Tema lecției: Recursivitatea directă
Tipul lecției: Insușire de noi cunoștințe
Locul de desfășurare: Laboratorul de informatică
Durata lecției: 50 min.
Scopul lecției:
– asimilare de noi cunostințe și formarea de priceperi și deprinderi în lucrul cu algoritmi recursivi
– extinderea metodelor de elaborare a algoritmilor pentru funcții
– formarea deprinderilor de a transpune în mod recursiv o problemă dată
– formarea abilităților de programare în limbajul C++
Metoda: predării, conversaṭiei euristice, explicația, algoritmizarea, problematizarea
Obiective operaționale :
– să definească și să clasifice recursivitatea
– să definească funcțiile recursive
– să descrie structura funcțiilor recursive
– pe baza explicațiilor date de profesor, elevul să conceapă un algoritm recursiv
– să identifice avantajele și dezavantajele utilizării acestor algoritmi recursivi în comparație cu cei iterativi.
– să scrie funcții C++ pentru recursivitate directă.
– să parcurgă un algoritm recursiv pas cu pas
– să realizeze importanța rezolvării problemelor folosind funcții recursive
Competențe specifice:
– să cunoască și să înțeleagă mecanismul recursivității
– să definească corect funcțiile recursive
– să transpună o problemă în termeni recursivi;
– să compare varianta iterativă cu cea recursivă pentru aceeași problemă;
– să analizeze modul diferit de funcționare a celor două implementări;
– să aplice mecanismul recursivității prin crearea unor funcții de recursivitate directă
Nivelul inițial al clasei:
Elevii și-au însușit toate noțiunile teoretice legate de tipurile de utilizare a funcțiilor;
Elevii utilizează și operează corect cu funcțiile nerecursive;
Material didactic: manualul, fișa de lucru, calculatorul
Desfășurarea lecției:
Moment organizatoric: (2 min)
Notarea absenților
Pornirea calculatoarelor
Recapitularea noțiunilor anterioare: (8 min) – conversația
Ce este o funcție?
O funcție reprezintă un grup de instrucțiuni (de declarare, executabile) scrise în vederea executării unei anumite prelucrări, identificat printr-un nume și implementat separat (în exteriorul oricărei alte funcții).
De ce se folosesc funcțiile?
Funcțiile permit împărțirea programelor care cresc în complexitate și dimensiune, în fragmente mai mici și mai ușor de gestionat sau atunci când se observă că o anumită secvență de instrucțiuni se repetă de mai multe ori în cadrul unui program, apelându-se în cadrul programului principal ori de câte ori va fi nevoie.
Cum pot fi folosite funcțiile în cadrul unui program?
Pentru a putea fi folosite în cadrul unui program, este nevoie ca funcția să fie declarată. Prin declararea unei funcții se specifică: tipul funcției, numele funcției, lista de parametri formali. La apelul unei funcții, valorile parametrilor efectivi se atribuie parametrilor formali corespunzători. În momentul în care se întâlnește un apel de funcție, controlul execuției programul este transferat primei instrucțiuni din funcție, apoi se execută secvențial instrucțiunile funcției.
Care este ordinea în care parametrii transmiși sunt memorați?
Memorarea parametrilor transmiși se face în ordinea în care aceștia figurează în antet: de la stânga la dreapta.
Ce conține stiva când parametrii sunt transmiși prin valoare? Dar prin referință?
Când parametrii sunt transmiși prin valoare stiva conține valorile transmise, iar în cazul celor transmiși prin referință stiva conține adresele variabilelor.
Numele parametrilor formali trebuie să fie același cu cel al parametrilor efectivi?
Nu
Captarea atenției și enunțarea obiectivelor: (5 min) – expunerea
anunțarea subiectului pentru tema respectivă
anunțarea obiectivelor urmărite;
anunțarea modului de desfășurare a activității;
Exemplu ilustrativ: Suntem pe o stradă, într-un oraș străin și căutăm o adresă. Vom întreba persoanele întâlnite pe drum și, presupunând că acestea știu să ne răspundă, apar situațiile:
-drumul este simplu și urmând indicațiile, putem ajunge direct
-drumul este complicat, parcurgem o porțiune din el, conform explicațiilor primite, apoi întrebăm din nou. Ne confruntăm cu o nouă versiune a problemei inițiale, dar, de data aceasta, dintr-un loc mai apropiat de destinația noastră.
Istorioara de mai sus rezumă esența repetiției unui anumit proces, punând în evidență și pericolul ciclării acesteia (ciclare=repetiție infinită).
Alt exemplu de raționament recursiv:
O cameră de luat vederi are în obiectiv un televizor care transmite imaginile primite de la cameră. În televizor se vede un televizor în care se vede un televizor…
Dirijarea învățării (Predarea lecției noi): (25 min) – expunerea, conversaṭia, exemplul (Elevii primesc o fișă cu noțiunile teoretice și se discută folosind această fișă)
Funcțiile care au fost folosite în rezolvarea problemelor de până acum, erau funcții ce se apelau din afara acestora, fiind numite funcții iterative. O să învățăm azi un nou tip de funcții, care se apelează din corpul lor.
O funcție care conține în corpul ei apeluri la ea însăși, adică se autoapelează, se numește funcție recursivă.
Totuși, o funcție recursivă, se apelează prima dată din afara ei, după care se autoapelează de un anumit număr de ori. La fiecare autoapelare a funcției se execută din nou secvența de instrucțiuni din corpul funcției, eventual cu alte date, creându-se un lanț de autoapeluri.
Structura unei funcții recursive arată astfel:
tip nume(parametri)
{
secvența_de_instr;
nume(parametri);
secventa_de_instr;
}
Putem spune că un algoritm recursiv are același efect cu cel al unei structuri repetitive. Astfel că, este necesar ca repetarea să nu aibă loc la infinit. Pentru a nu se executa funcția la infinit trebuie să existe cel puțin o condiție de oprire.
Varianta de rezolvare cu ajutorul funcțiilor recursive este recomandată pentru problemele definite prin relații de recurență, deoarece permit o formulare mai clară și mai concisă.
ȘIR = un șir a1,a2,…,an,… = o succesiune de valori numite elementele șirului aranjate într-o ordine bine definită
Fiecare element ocupă, în cadrul șirului, o poziție fixată = rangul elementului
Ex 1: 1,2,3,…,100,… șirul numerelor naturale nenule
Definirea unui șir
a) descriptiv – prin enumerarea sau descrierea elemntelor sale
Ex 1: 1,2,2,3,3,3,4,4,4,4,…. – în șir apar pe rând toate numerele naturale, fiecare astfel de număr repetându-se de atatea ori cât este valoarea sa
Ex 2: 1,1,1,1,… – șirul conține pe toate pozițiile valoarea 1
b) printr-o formulă – care exprimă forma generală a termenilor
Ex 1: 1,3,5,7,…..,2n-1,…… ak=2*k-1, k=1,∞
c) recursiv – cu ajutorul formulelor de recurență
Ṣiruri recurente. Relații de recurență
Unele șiruri pot fi definite cu ajutorul unor formule care exprimă orice termen al șirului, începând cu un anumit rang, în funcție de termenul (termenii) precedent = relație de recurență
Pentru a definii relația de recurență trebuie indicat primul (primii) termen.
Ex: șirul lui Fibonacci: F1 = 1
F2 = 1
F3 = F2 + F1 = 1 + 1 = 2
F4 = F3 + F2 = 2 + 1 = 3
F5 = F4 + F3 = 3 + 2 = 5
F6 = F5 + F4 = 5 + 3 = 8 …
Relația de recurență: Fk= 1, k=1,2
Fk = Fk-1+Fk-2, k>=3
OBS: Noțiunea de recursivitate din programare este derivată în mod natural din noțiunea de matematică. În matematică noțiunea este definită recursiv dacă în cadrul definiției apare însăși noțiunea care se definește.
Ex 1: n!=1*2*3*…*n relația de recurență k!= 1 , dacă k=0 k*(k-1)! ,dacă k>0
Ex 2: Sn=2+4+6+…+2n relația de recurență Sn= 0, dacă n=0
2*n + Sn-1, dacă n>0
În programare, recursivitatea este exprimată cu ajutorul funcțiilor, deoarece ele se identifică printr-un nume care este specificat apoi în apeluri.
O funcție este recursivă dacă apelul său apare când funcția este activă (lansată în execuție); funcția rămâne activă până la încheierea execuției sale, chiar dacă între timp se mai activează și alte funcții.
Idea de recursivitate a unei funcții se bazează pe posibilitatea de a întrerupe execuția subprogramului pentru un anumit set de parametrii pentru a începe o nouă execuție cu un alt set de parametrii. Acest sistem de întrerupere se desfășoară în lanț până în momentul în care setul de parametrii are o anume configurație particulară. Atunci se încheie execuția funcției pentru ultimul apel și apoi se revine în ordine inversă pentru a continua execuția funcțiilor întrerupte.
Recursivitatea constă în execuția repetată a unei secvențe de program, dar verificarea condiției de terminare se face în timpul execuției și nu la sfârșitul secvenței, iar în cazul în care condiția de terminare nu se verifică, porțiunea de program se apelează din nou ca o funcție, în particular ca o procedură a blocului care încă nu și-a terminat execuția când condiția de terminare este verificată se reia execuția din locul în care procedura s-a autoapelat. O funcție se poate autoapela recursiv, în cazul în care se autoapelează trebuie să existe o condiție de terminare, în caz contrar se intră în ciclul infinit. În general, la apelul unei funcții se creează un set de elemente locale acesteia, element ce sunt recunoscute doar în interiorul funcției. În cazul în care o astfel de funcție se autoapelează se creează un nou set de variabile locale diferite de cele corespunzătoare apelului anterior. La fiecare apel de funcție trebuie alocată o zonă de memorie pentru variabilele locale ale acestuia și trebuie reținută și adresa sau instrucțiunea din cadrul funcției de la care se va relua execuția în cazul terminării recursivității.
OBS: O soluție recursivă este eficientă numai dacă numărul de autoapeluri nu este mare.
Dacă apelul apare în instrucțiunea compusă a funcțieii, recursivitatea se numește directă. Dacă apelul apare în instrucțiunea compusă a unei alte funcții care se apelează din prima funcție, recursivitatea se numește indirectă.
Rec. Directa Rec. Indirecta
Ex: int A(…) void B(…); void A(…)
{ …… void A(…); { …… B(…)……..}
A(…)…..} void main() void B(…)
{….} {……. A(….)……}
Exemplu de recursivitate directă: Să se calculeze suma primelor n numere naturale. S=1+2+3+…+n, definită prin relațiile: S0=0; Sn= Sn-1 + n, pentru n>=1.
Suma numerelor naturale (inițial suma este zero, apoi suma(n) este suma primelor n-1 adunate cu n):
ITERATIV RECURSIV
int suma(int n) int suma(int n)
{ {
int s=0; if(n= =0)
for(int i=1; i<=n;i++) return 0;
s = s + i; else
return s; return suma(n-1)+n;
} }
Exemplu: parcurgerea pas cu pas pentru apelul suma(5).
s=0
i=1 s = 0+1=1 suma(5) = suma(4) + 5 = 10 + 5 = 15
i=2 s = 1+2=3 suma(4) = suma(3) + 4 = 6 + 4 = 10
i=3 s = 3+3=6 suma(3) = suma(2) + 3 = 3 + 3 = 6
i=4 s = 6+4=10 suma(2) = suma(1) + 2 = 1 + 2 = 3
i=5 s = 10+5=15 suma(1) = suma(0) + 1 = 0 + 1 = 1
suma(0) = 0
OBS: recurența este realizată prin autoapelul funcției suma.
sunt necesare 2 elemente:
formula de recurență:
Sn= Sn-1+n = cazul general al soluției: return suma(n-1)+n;
o valoare inițială cunoscută (condiția de terminare = inițializarea)
S0 = 0 = cazul de bază al soluției: return 0.
este obligatoriu să existe o condiție de oprire a repetiției. Cele două cazuri se combină folosind o structură alternativă if…else. Condiția de oprire a recurenței este exprimată printr-o expresie logică ce trebuie să depindă de parametrii functiei sau de variabilele locale (ex: n=0) => se trece de la cazul general la cazul de bază
trebuie să se asigure condiția de ieșire din recurență: condiția de consistență (suma(n-1)).
OBS:
Orice funcție recursivă trebuie să îndeplinească 2 cerințe:
să se poată executa cel puțin o dată fără a se autoapela
toate autoapelurile să se execute astfel încât să se tindă spre îndeplinirea condiției de execuție fără autoapelare.
Pentru orice algoritm recursiv există unul iterativ care rezolvă aceeași problemă.
Nu întotdeauna alegerea unui algoritm recursiv reprezintă un avantaj.
Recursivitatea presupune mai multă memorie în comparație cu iterativitatea.
Asigurarea feedbackului (fixarea cunoștințelor): (9 min)
exercițiul, conversaṭia;
se semnalează și se corectează eventualele erori apărute;
Se va discuta cu clasa lecția predată cerând elevilor să răspundă unor întrebări legate de funcții recursive.
Cum gândim un algoritm recursiv?
Ce se întâmplă la un nivel se întâmplă la orice nivel.
Subprogramul care se autoapelează trebuie să conțină instrucțiunile corespunzătoare unui nivel.
Starea tratată de subprogram se găsește pe un anumit nivel al stivei.
Orice subprogram recursiv se poate implementa și nerecursiv? Da
Funcția main () poate conține autoape? Nu
La fiecare apel recursiv al unui subprogram, ce sunt memorate în segmentul de stivă?
Adresa de revenire, valorile variabilelor locale și a parametrilor transmiși prin valoare și adresele parametrilor transmiși prin referința
Exercițiu: Scrieți o funcție recursivă pentru calculul lui n!=1*2*3…*n.
Care este condiția de oprire? if(n==0)
Cum definim n!?
ITERATIV RECURSIV
int factorial(int n) int factorial(int n)
{ {
int p=1; if(n= =0)
for(int i=1; i<=n;i++) return 1;
p = p * i; else
return p; return factorial(n-1)*n;
} }
Care sunt parametrii destinați calculului n!? Parametrul n
De câte ori se apelează funcția ce calculează n! pentru n=3? De 4 ori
Profesorul explică modalitatea de rezolvare a problemelor, cerând elevilor să rezolve problemele după modelul realizat ca exemplu.
Exercițiu: Să se scrie o funcție recursivă pentru a calcula al n-lea termen din șirul lui Fibonacci. Șirul lui Fibonacci fiind definit prin relația de recurență:
int fibo(int k)
{ if (k= =0 || k= = 1) return 1;
else return fibo(k-1) + fibo(k-2);}
Exemplu: parcurgerea pas cu pas pentru apelul fibo(5).
fibo(5) = fibo(4) + fibo(3) = 5 + 3 = 8
fibo(4) = fibo(3) + fibo(2) = 3 + 2 = 5
fibo(3) = fibo(2) + fibo(1) = 2 + 1 = 3
fibo(2) = fibo(1) + fibo(0) = 1 + 1 = 2
Se vor analiza împreună cu elevii avantajele și dezavantajele utilizării metodei recursive în raport cu cea iterativă.
Tema (1 min): -expunerea
Temă: Să se scrie o funcție recursivă care returnează valoarea funcției lui Ackerman ack(m,n). Funcția este definită:
Anexa 2. Plan de lecție: Insușire de noi cunoștințe – E-Learning
Unitatea de învățământ: Liceul Teoretic „St. L. Roth” Mediaș
Disciplina: Informatică
Clasa: a XI-a Matematică-Informatică
Data:
Profesor: ADELA BĂRBAT
Unitatea de învățare: Recursivitate
Tema lecției: Recursivitatea directă
Tipul lecției: Insușire de noi cunoștințe
Locul de desfășurare: Laboratorul de informatică
Durata lecției: 50 min.
Scopul lecției:
– asimilare de noi cunostințe și formarea de priceperi și deprinderi în lucrul cu algoritmi recursivi
– extinderea metodelor de elaborare a algoritmilor pentru funcții
– formarea deprinderilor de a transpune în mod recursiv o problemă dată
– formarea abilităților de programare în limbajul C++
Metoda: predării, conversaṭiei euristice, explicația, algoritmizarea, problematizarea
Obiective operaționale :
– să definească și să clasifice recursivitatea
– să definească funcțiile recursive
– să descrie structura funcțiilor recursive
– pe baza explicațiilor date de profesor, elevul să conceapă un algoritm recursiv
– să identifice avantajele și dezavantajele utilizării acestor algoritmi recursivi în comparație cu cei iterativi.
– să scrie funcții C++ pentru recursivitate directă.
– să parcurgă un algoritm recursiv pas cu pas
– să realizeze importanța rezolvării problemelor folosind funcții recursive
Competențe specifice:
– să cunoască și să înțeleagă mecanismul recursivității
– să definească corect funcțiile recursive
– să transpună o problemă în termeni recursivi;
– să compare varianta iterativă cu cea recursivă pentru aceeași problemă;
– să analizeze modul diferit de funcționare a celor două implementări;
– să aplice mecanismul recursivității prin crearea unor funcții de recursivitate directă
Nivelul inițial al clasei:
Elevii și-au însușit toate noțiunile teoretice legate de tipurile de utilizare a funcțiilor;
Elevii utilizează și operează corect cu funcțiile nerecursive;
Material didactic: manualul, fișa de lucru, calculatorul
Desfășurarea lecției:
1. Moment organizatoric: (2 min)
Notarea absenților
Pornirea calculatoarelor
2. Recapitularea noțiunilor anterioare: (8 min) – conversația
Se deschide pagina care conține întrebările recapitulative. Prima dată elevul dă răspuns în ferestrele indicate, apoi poate vizualiza răspunsul corect apăsând declanșatorul. Se deschide o fereastră ce conține răspunsul corect. Profesorul discută cu elevii întrebările.
î3. Captarea atenției și enunțarea obiectivelor: (5 min) – expunerea
anunțarea subiectului pentru tema respectivă
anunțarea obiectivelor urmărite;
anunțarea modului de desfășurare a activității;
Exemplu ilustrativ:
Suntem pe o stradă, într-un oraș străin și căutăm o adresă. Vom întreba persoanele întâlnite pe drum și, presupunând că acestea știu să ne răspundă, apar situațiile:
-drumul este simplu și urmând indicațiile, putem ajunge direct
-drumul este complicat, parcurgem o porțiune din el, conform explicațiilor primite, apoi întrebăm din nou. Ne confruntăm cu o nouă versiune a problemei inițiale, dar, de data aceasta, dintr-un loc mai apropiat de destinația noastră.
Istorioara de mai sus rezumă esența repetiției unui anumit proces, punând în evidență și pericolul ciclării acesteia (ciclare=repetiție infinită).
4. Dirijarea învățării (Predarea lecției noi): (25 min) – expunerea, conversaṭia, exemplul
Elevii urmăresc, în timp ce profesorul explică, noțiunile prezentate pe site. Li se specifică faptul că au posibilitatea să descarce pentru a imprima fișa care conține noțiunile teoretice discutate.
Se apasă declanșatoarele dorite pentru a vizualiza modul de parcurgere în cele două cazuri.
Se discută în continuare lecția:
5. Asigurarea feedbackului (fixarea cunoștințelor): (9 min)
exercițiul, conversaṭia;
se semnalează și se corectează eventualele erori apărute;
Se va discuta cu clasa lecția predată cerând elevilor să răspundă unor întrebări legate de funcții recursive.
Profesorul explică modalitatea de rezolvare a problemelor, cerând elevilor să rezolve problemele după modelul realizat ca exemplu.
6. Tema (1 min): -expunerea
Temă: Să se scrie o funcție recursivă care returnează valoarea funcției lui Ackerman ack(m,n). Funcția este definită:
Anexa 3. Plan de lecție: Formare de priceperi și deprinderi – Tradițional
Unitatea de învățământ: Liceul Teoretic „St. L. Roth” Mediaș
Disciplina: Informatică
Clasa: a XI-a Matematică-Informatică
Data:
Profesor: ADELA BĂRBAT
Unitatea de învățare: Recursivitate
Tema lecției: Parcurgerea recursivă a vectorilor
Tipul lecției: Formare de priceperi și deprinderi
Locul de desfășurare: Laboratorul de informatică
Durata lecției: 50 min.
Scopul lecției:
– formarea de priceperi și deprinderi în lucrul cu algoritmi recursivi
– formarea deprinderilor de a transpune în mod recursiv o problemă dată
– formarea abilităților de programare în limbajul C++
Metoda: conversaṭiei euristice, explicația, algoritmizarea, problematizarea
Obiective operaționale :
– să definească funcțiile recursive
– să descrie structura funcțiilor recursive
– să scrie funcții C++ pentru recursivitate directă.
– să parcurgă un algoritm recursiv pas cu pas
– să realizeze importanța rezolvării problemelor folosind funcții recursive
Competențe specifice:
– să realizeze aplicații utilizând algoritmi recursivi;
– să cunoască și să înțeleagă mecanismul recursivității
– să transpună o problemă în termeni recursivi;
– să compare varianta iterativă cu cea recursivă pentru aceeași problemă;
– să-și însușească mecanismul recursivității și să identifice condiția de ieșire din autoapeluri și cea de continuare
Nivelul inițial al clasei:
Elevii și-au însușit toate noțiunile teoretice legate de tipurile de utilizarea funcțiilor recursive
Elevii utilizează și operează corect cu funcțiile recursive, scriu programele sursă, le rulează și le depanează
Material didactic: fișa de lucru, calculatorul
Desfășurarea lecției:
Moment organizatoric: (2 min)
Notarea absenților
Pornirea calculatoarelor
Captarea atenției și enunțarea obiectivelor: (3 min) – expunerea
anunțarea subiectului pentru tema respectivă
anunțarea obiectivelor urmărite;
anunțarea modului de desfășurare a activității;
Reactualizarea noțiunilor anterioare: (10 min) – conversația
Ce este o funcție? De ce se folosesc funcțiile?
O funcție reprezintă un grup de instrucțiuni (de declarare, executabile) scrise în vederea executării unei anumite prelucrări, identificat printr-un nume și implementat separat (în exteriorul oricărei alte funcții). Funcțiile permit împărțirea programelor care cresc în complexitate și dimensiune, în fragmente mai mici și mai ușor de gestionat sau atunci când se observă că o anumită secvență de instrucțiuni se repetă de mai multe ori în cadrul unui program, apelându-se în cadrul programului principal ori de câte ori va fi nevoie.
Exerciții:
1. Se consideră funcția f de mai jos. Ce se va afișa în urma apelului f(12345)? R: 42
void f(long int n)
{ if (n!=0)
{ if (n%2 == 0) cout<<n%10;
f(n/10);}}
2. Se consideră funcția f cu definiția mai jos. Ce valoare are f(1213111,1)? R: 3
int f (long n, int k)
{ if (n!=0)
if(n%10==k) return 1+f(n/10,k);
else return 0;
else return 0;}
3. Se consideră funcția f definită mai jos. Ce valoare are f(12,2)? R: 4
int num_div(int x,int d)
{ if(d>x/2) return 0;
else if(x%d==0) return 1+num_div(x,d+1);
else return num_div(x,d+1); }
4. Se consideră programul de mai jos. Ce se va afișa după executarea lui? R: 33
int v[20]={1,2,3,4,5,6,7,8,9,10}
int f(int i, int j)
{ if(i>j) return 0;
else
if(i==j) return v[i];
else return f(i, (i+j)/2)+f((i+j)/2+1,j);}
int main()
{cout<<f(2,7);}
Intensificarea reținerii și asigurării transferului de informații: (10 min) – expunerea, conversaṭia, exemplul
Scrieți programul pentru citirea și afișarea elementelor unui vector în varianta recursivă.
void citire(int v[],int n) void afisare(int v[],int n)
{ if(n>0) { if(n>0)
{ citire(v,n-1); { afisare(v,n-1);
in>>v[n]; } } out<<v[n]<<" "; } }
int main()
{ int i,n,v[20];
cin>>n;
citire(v,n);
afisare(v,n); }
Să se verifice dacă într'un vector există cel puțin un element egal cu x.
int gasit(int x,int n)
{ if(n<0) return 0;
else if(a[n]==x) return 1;
else return gasit(x,n-1);}
int main()
{ int i,n,v[20],x;
cin>>n>>x;
citire(v,n); afisare(v,n);
if(gasit(x,n-1)) cout<<"s-a gasit";
else cout<<"nu s-a gasit";}
Asigurarea feedbackului și evaluarea performanței: (20 min)
exercițiul, conversaṭia;
se semnalează și se corectează eventualele erori apărute;
1. Se citesc n elemente într-un vector. Să se afișeze elementele care au cel putin k cifre.
#include<iostream.h>
#include<fstream.h>
ifstream in ("date.in");
void citire(int v[],int n)
{ if(n>0)
{ citire(v,n-1);
in>>v[n]; } }
void afisare(int v[],int n)
{ if(n>0)
{ afisare(v,n-1);
out<<v[n]<<" "; } }
int cifre(int x)
{ if(x==0) return 0;
else return 1+cifre(x/10); }
void afis_1(int v[],int n,int k)
{ if(n>0)
{ afis_1(v,n-1,k);
if(cifre(v[n])>=k) cout<<v[n]<<" "; } }
void main()
{ int n,v[10],k;
in>>n>>k;
citire(v,n); afisare(v,n); out<<endl;
afis_1(v,n,k); }
2. Se citesc n elemente într-un vector. Să se calculeze suma elementelor care au suma divizorilor număr par.
#include<iostream.h>
#include<fstream.h>
ifstream in("date.in");
void citire(int v[],int n){…}
void afisare(int v[],int n){…}
int suma_div(int x,int d)
{ if(d>x) return 0;
else
if(x%d==0) return d+suma_div(x,d+1);
else return suma_div(x,d+1); }
int suma(int v[],int n)
{ if(n==0) return 0;
else
if(suma_div(v[n],1)%2==0) return v[n]+suma(v,n-1);
else return suma(v,n-1); }
void main()
{ int v[10],n;
in>>n;
citire(v,n); afisare(v,n); out<<endl<<"s="<<suma(v,n); }
Tema (5 min): -expunerea, explicația
Se citesc n elemente într-un vector. Se cere:
1. Să se calculeze produsul elementelor perfecte.
2. Pentru fiecare număr prim să se afișeze cifrele lui.
3. Să se verifice dacă există cel puțin un număr care are suma cifrelor pare mai mică decât k.
Anexa 4. Plan de lecție: Formare de priceperi și deprinderi –Modern
Unitatea de învățământ: Liceul Teoretic „St. L. Roth” Mediaș
Disciplina: Informatică
Clasa: a XI-a Matematică-Informatică
Data:
Profesor: ADELA BĂRBAT
Unitatea de învățare: Recursivitate
Tema lecției: Parcurgerea recursivă a vectorilor
Tipul lecției: Formare de priceperi și deprinderi
Locul de desfășurare: Laboratorul de informatică
Durata lecției: 50 min.
Scopul lecției:
– formarea de priceperi și deprinderi în lucrul cu algoritmi recursivi
– formarea deprinderilor de a transpune în mod recursiv o problemă dată
– formarea abilităților de programare în limbajul C++
Metoda: conversaṭiei euristice, explicația, algoritmizarea, problematizarea
Obiective operaționale :
– să definească funcțiile recursive
– să descrie structura funcțiilor recursive
– să scrie funcții C++ pentru recursivitate directă.
– să parcurgă un algoritm recursiv pas cu pas
– să realizeze importanța rezolvării problemelor folosind funcții recursive
Competențe specifice:
– să realizeze aplicații utilizând algoritmi recursivi;
– să cunoască și să înțeleagă mecanismul recursivității
– să transpună o problemă în termeni recursivi;
– să compare varianta iterativă cu cea recursivă pentru aceeași problemă;
– să-și însușească mecanismul recursivității și să identifice condiția de ieșire din autoapeluri și cea de continuare
Nivelul inițial al clasei:
Elevii și-au însușit toate noțiunile teoretice legate de tipurile de utilizarea funcțiilor recursive
Elevii utilizează și operează corect cu funcțiile recursive, scriu programele sursă, le rulează și le depanează
Material didactic: fișa de lucru on-line, calculatorul
Desfășurarea lecției:
1. Moment organizatoric: (2 min)
Notarea absenților
Pornirea calculatoarelor
2. Captarea atenției și enunțarea obiectivelor: (3 min) – expunerea
anunțarea subiectului pentru tema respectivă
anunțarea obiectivelor urmărite;
anunțarea modului de desfășurare a activității;
3. Reactualizarea noțiunilor anterioare: (10 min) – conversația
Elevii care doresc, au în continuare pe site, probleme pe care le pot rezolva și verifica.
4. Intensificarea reținerii și asigurării transferului de informații: (10 min) – expunerea, conversaṭia, exemplul
Scrieți programul pentru citirea și afișarea elementelor unui vector în varianta recursivă.
Se trece cu mouse-ul pe deasupra imaginii și ea va începe să se deruleze pentru ca elevii să se poată și gândi cum trebuie rezolvat.
Să se verifice dacă într'un vector există cel puțin un element egal cu x.
Se discută cu elevii și rezolvă în CodeBlocks pentru a rula și verifica programul.
Elevii mai pot rezolva și alte probleme și apoi pot verifica dacă au rezolvat corect.
5. Asigurarea feedbackului și evaluarea performanței: (20 min)
exercițiul, conversaṭia;
se semnalează și se corectează eventualele erori apărute;
Se rezolvă în CodeBlocks.
Ex29. Se citesc n elemente într-un vector. Să se afișeze elementele care au cel putin k cifre.
#include<iostream.h>
#include<fstream.h>
ifstream in ("date.in");
void citire(int v[],int n)
{ if(n>0) { citire(v,n-1);
in>>v[n]; } }
void afisare(int v[],int n)
{ if(n>0) { afisare(v,n-1);
out<<v[n]<<" "; } }
int cifre(int x)
{ if(x==0) return 0;
else return 1+cifre(x/10); }
void afis_1(int v[],int n,int k)
{ if(n>0) { afis_1(v,n-1,k);
if(cifre(v[n])>=k) cout<<v[n]<<" "; } }
void main()
{ int n,v[10],k;
in>>n>>k;
citire(v,n); afisare(v,n); out<<endl; afis_1(v,n,k); }
30. Se citesc n elemente într-un vector. Să se calculeze suma elementelor care au suma divizorilor număr par.
#include<iostream.h>
#include<fstream.h>
ifstream in("date.in");
void citire(int v[],int n){…}
void afisare(int v[],int n){…}
int suma_div(int x,int d)
{ if(d>x) return 0;
else
if(x%d==0) return d+suma_div(x,d+1);
else return suma_div(x,d+1); }
int suma(int v[],int n)
{ if(n==0) return 0;
else
if(suma_div(v[n],1)%2==0) return v[n]+suma(v,n-1);
else return suma(v,n-1); }
void main()
{ int v[10],n;
in>>n;
citire(v,n); afisare(v,n);
out<<endl<<"s="<<suma(v,n); }
6. Tema (5 min): -expunerea, explicația
Se citesc n elemente într-un vector. Se cere:
1. Să se calculeze produsul elementelor perfecte.
2. Pentru fiecare număr prim să se afișeze cifrele lui.
3. Să se verifice dacă există cel puțin un număr care are suma cifrelor pare mai mică decât k.
Anexa 5: Plan de lecție: Evaluare sumativă– Tradițional
Unitatea de învățământ: LICEUL TEORETIC „ST. L. ROTH” MEDIAȘ
Disciplina: Informatică
Clasa: a XI-a Matematică-Informatică
Data:
Profesor: ADELA BĂRBAT
Unitatea de învățare: Recursivitate
Tema lecției: Test Recursivitate
Tipul lecției: Evaluare sumativă
Locul de desfășurare: Sala de clasă
Durata lecției: 50 min.
Material didactic: fișa de lucru
Desfășurarea lecției:
Moment organizatoric: (1 min)
Notarea absenților.
Pregătirea foilor și creioanelor pentru test.
Captarea atenției și enunțarea obiectivelor: (1 min)
Prezentarea conținutului ce urmează a fi verificat și forma de evaluare
Distribuirea testelor cu enunțurile problemelor
Desfășurarea testului: (45 min)
Elevii rezolvă testul de evaluare
Predarea testului: (1 min)
Elevii sunt rugați să predea lucrările profesorului
Discutarea rezolvărilor: (2 min)
Dacă timpul permite, profesorul discută împreună cu elevii răspunsurile corecte
TEST recursivitate
1.(1p) Se consideră următoarea funcție:
int f(int x);
{ if (x==0) return 0;
else return (f(x-1)+2*x-1); }
Pentru ce valoare a parametrului x funcția f va întoarce valoarea 25?
a) 10 b) 3 c) 15 d) 5
2.(1p) Se consideră programul următor:
int x,y;
int f(int a, int b)
{ if (a!=b)
if (a>b) return f(a-b,b);
else return f(a,b-a);
else return x*y / a;}
int main()
{cin>>x>>y; cout<<f(x,y);}
Ce valoare va fi afișată pentru setul de date de intrare x=32, y=14 ?
a)2 b) 256 c)200 d)224 e)14
3.(1p) Ce valoare va returna funcția f pentru un set de date de intrare format din elementele vectorului v={4, 0, -1, 2, 8, -7, 5, -3,3,-6} la apelul f(v,8)?
int f(int v[], int n)
{ if (n==-1) return 0;
else
if (v[n]<0) return f(v,n-1);
else return v[n] + f(v,n-1);}
a) 9 b) 22 c) 19 d) 5
4. (1p) Presupunem că în cadrul unui program există 4 proceduri (A,B,C,D) și că există următoarele apeluri:
procedura C apeleaza procedura A
procedura B apeleaza procedura C
procedura D se autoapeleaza
procedura A apeleaza procedura D
Care este ordinea corecta la declararea procedurilor?
5. (1p) Scrieți un program care folosește o funcție recursivă pentru calculul sumei: S=1*3-2*5+3*7-4*9+…+n*(2n+1)
6. (2p) Se citesc n elemente într-un vector. Se cere să se afle dacă în vector există cel puțin un număr prim. (subprogram recursiv pentru citirea și afișarea elementelor vectorului, număr prim, parcurgerea vectorului pentru verificare)
7. (2p) Se citesc n*n elemente într-o matrice. Să se calculeze media aritmetica a elementelor de sub diagonala principală care au suma cifrelor număr divizibil cu k. (subprogram recursiv pentru citirea și afișarea elementelor matricii, suma cifrelor unui număr, parcurgerea sub diagolala principală)
Oficiu: 1p
Matricea de specificații:
Barem de notare:
Barem de corectare:
Anexa 6: Plan de lecție: Evaluare sumativă – Modern
Unitatea de învățământ: LICEUL TEORETIC „ST. L. ROTH” MEDIAȘ
Disciplina: Informatică
Clasa: a XI-a Matematică-Informatică
Data:
Profesor: ADELA BĂRBAT
Unitatea de învățare: Recursivitate
Tema lecției: Test Recursivitate
Tipul lecției: Evaluare sumativă
Locul de desfășurare: Laboratorul de informatică
Durata lecției: 50 min.
Material didactic: calculatorul, test online
Desfășurarea lecției:
1. Moment organizatoric: (1 min)
Notarea absenților.
Pornirea calculatoarelor și accesarea site-ului.
2. Captarea atenției și enunțarea obiectivelor: (1 min)
Prezentarea conținutului ce urmează a fi verificat și forma de evaluare
Specificarea parolei pentru accesarea paginei de test: testdata
3. Desfășurarea testului: (45 min)
Elevii rezolvă testul de evaluare
4. Predarea testului: (1 min)
Elevii sunt rugați să trimită profesorului răspunsurile folosind declanșatorul .
5. Discutarea rezolvărilor: (2 min)
Dacă timpul permite, profesorul discută împreună cu elevii răspunsurile corecte
TEST recursivitate
Matricea de specificații:
Barem de notare:
Barem de corectare:
Anexa 7. Recursivitatea în algoritmică
Ex.1: S=1*2-2*4+3*6-4*8+…-n*(2n).
int suma(int n)
{ if(n==0) return 0;
else
if(n%2==0)
return suma(n-1)-n*2*n;
else
return suma(n-1)+n*2*n; }
int main ()
{ int n; cin>>n;
cout<<suma(n); }
Ex. 2: S=12-22+32-42+…-n2.
int suma(int n)
{ if(n==0) return 0;
else
if(n%2!=0)
return suma(n-1)+n*n;
else
return suma(n-1)-n*n; }
int main ()
{ int n; cin>>n;
cout<<suma(n); }
Ex. 3: Șirul lui Manna Pnuell
int manna(int n)
{ if(n>=12) return n-1;
else
return manna(manna(n+2)); }
int main ()
{ int n; cin>>n;
cout<<manna(n); }
Ex. 4: A la puterea n
int putere(int a,int n)
{if(n==0) return 1;
else
return a*putere(a,n-1); }
int main ()
{ int n,a; cin>>a>>n;
cout<<putere(a,n); }
Ex. 5: Să se verifice dacă un nr este perfect
int suma_div(int n,int d)
{ if(d>n/2) return 0;
else
if(n%d==0)
return suma_div(n,d+1)+d;
else
return suma_div(n,d+1); }
int main ()
{ int n; cin>>n;
if(suma_div(n,1)==n)
cout<<"este perfect";
else
cout<<"nu este perfect"; }
Ex. 6: Cel mai mare divizori a două numere
int cmmdc(int a,int b)
{ if(a==0) return b;
else
if(b==0) return a;
else
return cmmdc(b,a%b); }
// prin scaderi repetate
int cmmdc(int a,int b)
{ if(b==0 || a==b) return a;
else
if(a==0) return b;
else
if(a>b)
return cmmdc(a-b,b);
else
return cmmdc(a,b-a); }
int main ()
{ int v[50],i,n,cdc;
cin>>n;
for(i=1;i<=n;i++)
cin>>v[i];
cdc=v[1];
for(i=2;i<=n;i++)
cdc=cmmdc(cdc,v[i]);
cout<<cdc; }
Ex. 7: Să se afișeze cifrele unui număr
int cif(int x)
{ if(x!=0)
{ cout<<x%10<<” “;
cif(x/10); } }
int main ()
{ int x; cin>>x; cif(x); }
Ex. 8: Să se afișeze prima cifră a unui număr
int cifra(int n)
{ if(n>9)
return cifra(n/10);
else
return n; }
int main()
{ int x;
cin>>x;
cout<<cifra(x); }
Ex. 9: Să se verifice dacă într-un vector există cel puțin un element egal cu X
int a[100];
int gasit(int x, int n)
{ if(n<0) return 0;
else
if(a[n]==x) return 1;
else
return gasit(x,n-1); }
int main ()
{ int n,i,x; cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
cin>>x;
if(gasit(x,n-1))
cout<<"s-a gasit";
else
cout<<"nu s-a gasit"; }
Ex. 10: Să se verifice dacă există cel puțin un element pozitiv într-un vector
int a[100];
int verificare(int n)
{ if(n<0) return 0;
else
if(a[n]>0) return 1;
else return verificare(n-1); }
int main ()
{ int n,i; cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
if(verificare(n-1))
cout<<"s'a gasit";
else
cout<<"nu s'a gasit "; }
Ex. 11: Interclasarea a doi vectori folosind și algoritmul iterativ, dar și un algoritm recursiv. Să se afișeze elementele necomune divizibile cu 5.
#include <iostream>
using namespace std;
void citire(int v[100], int n)
{ if(n!=0)
{ citire1(v,n-1);
cin>>v[n]; } }
void afisare(int v[100], int n)
{ if(n!=0)
{ afisare(v,n-1);
cout<<v[n]<<" "; } }
void interclasic (int s[100], int v[100], int w[100], int &a, int n, int m)
{ int i=j=1; a=0;
while(i<=n && j<=m)
{ if(v[i]<w[j])
s[++a]=v[i++];
else
s[++a]=w[j++]; }
while(i<=n)
s[++a]=v[i++];
while(j<=m)
s[++a]=w[j++]; }
void interrec(int v[100], int s[100], int w[100], int &a, int m, int n,int i, int j)
{ if(i<=n && j<=m)
{ if(v[i]<w[j])
{ s[++a]=v[i];
interrec(v,s,w,a,m,n,i+1,j); }
else
{ s[++a]=w[j];
interrec(v,s,w,a,m,n,i,j+1); } }
else
{ if(i<=n)
{ s[++a]=v[i];
interrec(v,s,w,a,m,n,i+1,j); }
else
if(j<=m)
{ s[++a]=w[j];
interrec(v,s,w,a,m,n,i,j+1); } }
}
void necom(int v [100], int m, int n, int w[100], int i, int j )
{ if(i<=n && j<=m)
if(v[i]<w[j])
{ if(v[i]%5==0)
cout<<v[i]<<" ";
necom(v,m,n,w,i+1,j); }
else
{ if(w[j]<v[i])
{ if(w[j]%5==0)
cout<<w[j]<<" ";
necom(v,m,n,w,i,j+1); }
else
necom(v,m,n,w,i+1,j+1); }
else
{ if(i<=n)
{ if(v[i]%5==0)
cout<<v[i]<<" ";
necom(v,m,n,w,i+1,j); }
if(j<=m)
{ if(w[j]%5==0)
cout<<w[j]<<" ";
necom(v,m,n,w,i,j+1); } } }
int main()
{ int m, n,w[100],v[100],s[100],a=0;
cin>>n>>m;
citire(v,n); citire(w,m);
interclasic(s,v,w,a,n,m);
afisare(s,a); cout<<endl<<endl; a=0;
interrec(v,s,w,a,m,n,1,1);
afisare(s,a); cout<<endl<<endl;
necom(v,m,n,w,1,1);
return 0; }
Ex. 12: Lucru cu matrici pătratice și diagonale
void citire(int a[][10],int n, int i, int j)
{ if(i<=n)
if (j<=n)
{ cin>>a[i][j];
citire(a,n,i,j+1); }
else
citire(a,n,i+1,1); }
void afisare(int a[][10],int n, int i, int j)
{ if(i<=n)
if (j<=n)
{ cout<<a[i][j]<<" ";
afisare(a,n,i,j+1); }
else
{ cout<<endl;
afisare(a,n,i+1,1); } }
void subdp(int a[][10],int n, int i, int j)
{ if(i<=n)
if (j<i)
{ cout<<a[i][j]<<" ";
subdp(a,n,i,j+1); }
else
subdp(a,n,i+1,1) }
void deasupradp(int a[][10],int n, int i, int j)
{ if(i<=n)
if (j<=n)
{ cout<<a[i][j]<<" ";
deasupradp(a,n,i,j+1); }
else
deasupradp(a,n,i+1,i+2); }
void deasupradsec(int a[][10],int n, int i, int j)
{ if(i<n)
if (j<n-i+1)
{ cout<<a[i][j]<<" ";
deasupradsec(a,n,i,j+1); }
else
deasupradsec(a,n,i+1,1); }
void subdsec(int a[][10],int n, int i, int j)
{ if(i<=n)
if (j<=n)
{ cout<<a[i][j]<<" ";
subdsec(a,n,i,j+1); }
else
subdsec(a,n,i+1,n-i+1); }
int sumacol(int a[100][100], int n, int k, int i)
{ if(i<=n)
{ if(a[i][k]%3==1)
return sumacol(a,n,k,i+1)+a[i][k];
else
return sumacol(a,n,k,i+1); }
else
return 0; }
int cmmdc(int a, int b)
{ if(a%b==0)
return b;
else
return cmmdc(a,a%b); }
void CDp(int v[100], int a[100][100], int i, int j, int n,int &ct)
{ if(i<n)
{ if(j<n)
{ v[++ct]=a[i][j];
CDp(v,a,i,j+1,n,ct); }
else
CDp(v,a,i+1,i+2,n,ct); } }
int suma(int a[100][100], int i, int n)
{ if(i<=n)
return a[i][i]+suma(a,i+1,n);
else
return 0; }
int main()
{ int a[10][10],n,k;
cin>>n;
citire(a,n,1,1);
afisare(a,n,1,1);
cout<<endl;
subdp(a,n,2,1); cout<<endl;
deasupradp(a,n,1,2); cout<<endl;
deasupradsec(a,n,1,1); cout<<endl;
subdsec(a,n,2,n);
cout<<endl<<"Dati coloana "; cin>>k;
if(sumacol(a,n,k,1)==0)
cout<<"Nu sunt nr diviz cu 3 ";
else
cout<<"Suma este "<<sumacol(a,n,k,1);
CDp(v,a,1,2,n,ct);
cout<<suma(a,1,n)/n;}
Ex. 13: Lucru cu șiruri
//Se citeste un sir caracter cu caracter pana se citeste.
void siruri()
{ char s;
cin>>s;
if(s!='.')
{ siruri();
cout<<s; } }
//Sa se stearga vocalele dintr-un sir
void stergere(char s[100],int n)
{ if(n!=-1)
{ if(strchr("aeiouAeiou",s[n]))
strcpy(s+n,s+n+1);
stergere(s,n-1); } }
//Sa se afiseze cuvintele palindroame care incep cu o vocala
void vec(char s[100], char a[100][100], int &ct, int n)
{ char *p;
p=strtok(s," ");
while(p)
{ ++ct;
strcpy(a[ct],p);
p=strtok(NULL," "); } }
void paliv (char a[100][100],int ct)
{ char s[100];
if(ct!=0)
{ strcpy(s,a[ct]);
strrev(s);
if(strcmp(s,a[ct])==0)
if(strchr("AEIOUaeiou",a[ct][0]))
cout<<s<<" ";
paliv(a,ct-1); } }
int main()
{ int v[100],n,ct=0; char s[100],a[100][100];
siruri();
fin.getline(s,100);
cout<<s<<endl;
n=strlen(s)-1;
stergere(s,n);
vec(s,a,ct,n);
paliv(a,ct);
return 0; }
Ex. 14: Fractali – covorul lui Sierpinski
#include<conio.h>
#include<stdio.h>
#include<math.h>
#include<graphics.h>
#include<dos.h>
#include<stdlib.h>
using namespace std;
void fractal(int x,int y,int k)
{ rectangle(x-k/2,y-k/2,x+k/2,y+k/2);
line(x-k/2,y-k/6,x+k/2,y-k/6);
line(x-k/2,y+k/6,x+k/2,y+k/6);
line(x-k/6,y-k/2,x-k/6,y+k/2);
line(x+k/6,y-k/2,x+k/6,y+k/2);
delay(10);
floodfill(x,y,WHITE);
if (k>5)
{ fractal(x-3*k/4,y,k/2);
fractal(x+3*k/4,y,k/2);
fractal(x,y-3*k/4,k/2);
fractal(x,y+3*k/4,k/2); } }
int main()
{ int cul,gd,gm;
gd=DETECT;
randomize();
initgraph(&gd,&gm,"c:\\bc\\bgi");
int x=300,y=250,k=150;
fractal(x,y,k);
getch();
closegraph(); } }
Anexa 8. Divide et impera
Ex. 1: Să se afișeze un vector în ordine inversă
int v[20],n,rez;
void dei(int st, int dr)
{ if(st==dr) cout<<v[st]<<" ";
else
{ int mij=(st+dr)/2;
dei(mij+1,dr); dei(st,mij); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"vectorul in ordine inversa: ";
dei(1,n);}
Ex. 2: Să se determine numărul de apariții ale unei valori x într-un vector
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr)
if(v[st]==xx) return 1;
else return 0;
else
{ int mij=(st+dr)/2;
return dei(st,mij)+dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; in>>v[i]; }
cout<<"da valoarea de cautat:"; cin>>xx;
cout<<"valoarea "<<xx<<" se gaseste de " <<dei(1,n)<<" ori"; }
Ex. 3: Să se calculeze cmmdc a n numere
int cmmdc(int a, int b)
{ while(a!=b)
if(a>b) a=a-b;
else b=b-a;
return a; }
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr) return v[st];
else
{ int mij=(st+dr)/2;
return cmmdc(dei(st,mij),dei(mij+1,dr)); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"cmmdc a celor "<<n<<" elemente “<<dei(1,n); }
Ex. 4: Să se calc suma 1+1*2+1*2*3+ … +1*2*3*…*n
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr)
{ rez=1;
for(int k=1;k<=st;k++)
rez=rez*k;
return rez; }
else
{ int mij=(st+dr)/2;
return dei(st,mij)+dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
cout<<"suma este "<<dei(1,n)<<endl; }
Ex. 5: Termenul n al sirului lui fibonacci
int dei(int n)
{ int rez1,rez2;
if(n==1 || n==2) return 1;
else return dei(n-1)+dei(n-2); }
int main()
{ cout<<"n="; cin>>n;
cout<<"termenul "<<n<<" al sirului lui
fibonacci este "<<dei(n); }
Ex. 6: Media aritmetică a elementelor dintr-un vector, divizibile cu 3
int dei_nr(int st, int dr)
{ if(st==dr)
if(v[st]%3==0) return 1;
else return 0;
else
{ int mij=(st+dr)/2;
return dei_nr(st,mij)+dei_nr(mij+1,dr); } }
int dei_suma(int st, int dr)
{ if(st==dr)
if(v[st]%3==0) return v[st];
else return 0;
else
{ int mij=(st+dr)/2;
return dei_suma(st,mij)+dei_suma(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"numarul elem diviz cu 3 este "<<dei_nr(1,n)<<endl;
cout<<"suma elem diviz cu 3 este "<<dei_suma(1,n)<<endl;
cout<<"ma="<<1.0*dei_suma(1,n)/dei_nr(1,n); }
Sau calcularea simultană a nr de elem și a sumei lor
void dei(int st, int dr, int &rez1, int &rez2)
{ int x1,x2,y1,y2;
if(st==dr)
if(v[st]%3==0)
{ rez1=1; rez2=v[st]; }
else rez1=rez2=0;
else
{ int mij=(st+dr)/2;
dei(st,mij,x1,x2);
dei(mij+1,dr,y1,y2);
rez1=x1+y1;
rez2=x2+y2; } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
dei(1,n,rez1,rez2);
cout<<"numarul elem diviz cu 3 este "<<rez1<<endl;
cout<<"suma elem diviz cu 3 este "<<rez2<<endl;
cout<<"ma="<<1.0*rez2/rez1; }
Ex. 7: Să se interschimbe linia k cu coloana q a unei matrici
void dei(int st, int dr)
{ int x1,x2,y1,y2;
if(st==dr)
{ int aux=a[st][q];
a[st][q]=a[k][st];
a[k][st]=aux;}
else
{ int mij=(st+dr)/2;
dei(st,mij);
dei(mij+1,dr); }}
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{ cout<<"v["<<i<<"]["<<j<<"]="; cin>>a[i][j]; }
cout<<"linia k=";cin>>k;
cout<<"coloana q=";cin>>q;
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; dei(1,n);
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; } }
Ex.8: Să se interschimbe coloana k cu coloana q
void dei(int st, int dr)
{ int x1,x2,y1,y2;
if(st==dr)
{ int aux=a[st][q];
a[st][q]=a[st][k];
a[st][k]=aux;}
else
{ int mij=(st+dr)/2;
dei(st,mij);
dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{ cout<<"v["<<i<<"]["<<j<<"]="; cin>>a[i][j]; }
cout<<"k=";cin>>k;
cout<<"q=";cin>>q;
for(int i=1;i<=n;i++)
{ for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; dei(1,n);
for(int i=1;i<=n;i++)
{ for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl; } }
Ex. 9 : Să se interschimbe elmentele de pe diagonala principală cu elemetele de pe diagonala secundară
void dei(int st, int dr)
{ int x1,x2,y1,y2;
if(st==dr)
{ int aux=a[st][st];
a[st][st]=a[st][n-st+1];
a[st][n-st+1]=aux; }
else
{ int mij=(st+dr)/2;
dei(st,mij);
dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{ cout<<"v["<<i<<"]["<<j<<"]=";
cin>>a[i][j]; }
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; dei(1,n);
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; } }
Ex. 10: Aflarea maximului pe fiecare linie în parte
void dei(int st, int dr, int i,int &max)
{ int max1,max2;
if(st==dr) max=a[i][st];
else
{ int mij=(st+dr)/2;
dei(st,mij,i,max1);
dei(mij+1,dr,i,max2);
if(max1>max2) max= max1;
else max=max2; } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{ cout<<"v["<<i<<"]["<<j<<"]=";
cin>>a[i][j]; }
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; max=0;
for(int i=1;i<=n;i++)
{ dei(1,n,i,max);
cout<<max<<endl;} }
Ex. 11: Aflarea maximului dintr-un vector
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr)
return v[st];
else
{ int mij=(st+dr)/2;
int max1=dei(st,mij);
int max2=dei(mij+1,dr);
if(max1>max2) return max1;
else return max2; } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"max celor"<<n<<"elemente este"<<dei(1,n); }
Ex. 12: Aflarea numărului de elemente pare dintr-un vector
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr)
if(v[st]%2==0) return 1;
else return 0;
else
{ int mij=(st+dr)/2;
return dei(st,mij)+dei(mij+1,dr); }}
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"exista "<<dei(1,n)<<" elem pare in vector"; }
Ex. 13: Să se afișze partițiile unui număr – pt n=4 se afișează 1+3 și 2+2
void dei(int st, int dr)
{ if(st==dr) cout<<st<<"+"<<n-st<<endl;
else
{ int mij=(st+dr)/2;
dei(st,mij); dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n; dei(1,n/2); }
Ex. 14: Să se afișeze val unui polinom într-un punct dat
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr) return pow(xx,st-1)*v[st];
else
{ int mij=(st+dr)/2;
return dei(st,mij)+dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"da valoarea: "; cin>>xx;
cout<<"valoarea polinomului: ";
for(int i=n;i>=1;i–)
cout<<v[i]<<"X^"<<i-1<<"+";
cout<<"\b"<<" ptr x="<<xx<<" este "<<dei(1,n); }
Ex. 15: Calcularea simultană a minimului și maximului dintr-un vector
void dei(int st, int dr, int &rez1, int &rez2)
{ int x1,x2,y1,y2;
if(st==dr) rez1=rez2=v[st];
else
{ int mij=(st+dr)/2;
dei(st,mij,x1,x2);
dei(mij+1,dr,y1,y2);
if(x1>y1) rez1=x1;
else rez1=y1;
if(x2<y2) rez2=x2;
else rez2=y2; } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
dei(1,n,rez1,rez2);
cout<<"max celor "<<n<<" elemente ale vectorului este "<<rez1<<endl;
cout<<"min celor "<<n<<" elemente ale vectorului este "<<rez2<<endl; }
Ex. 16: Să se calculeze suma 1*2+2*3+…+n*(n+1)
int dei(int st, int dr)
{ int rez1,rez2;
if(st==dr) return st*(st+1);
else
{ int mij=(st+dr)/2;
return dei(st,mij)+dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
cout<<"suma este "<<dei(1,n); }
Ex.17: Numărul elementelor pare
int dei(int st, int dr)
{ if(st==dr)
if(v[st]%2==0) return v[st];
else return 0;
else
{ int mij=(st+dr)/2;
return dei(st,mij)+dei(mij+1,dr); } }
int main()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]="; cin>>v[i]; }
cout<<"exista "<<n<<" elemente pare in vector "<<dei(1,n); }
Ex. 18: Să se verifice dacă un vector conține numai elemente pozitive sau numai negative
void dei(int st, int dr, int &rez1, int &rez2)
{ int x1,x2,y1,y2;
if(st==dr)
if(v[st]>=0)
{ rez1=1; rez2=0; }
else
{ rez1=0; rez2=1; }
else
{ int mij=(st+dr)/2;
dei(st,mij,x1,x2);
dei(mij+1,dr,y1,y2);
rez1=x1+y1;
rez2=x2+y2; } }
int main()
{ int n, v[100], rez1, rez2;
cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]=";
cin>>v[i]; }
dei(1,n,rez1,rez2);
if(rez1==n) cout<<"pozitive ";
else
if(rez2==n)
cout<<"negative ";
else
cout<<"amestecate"; }
Anexa 9. Backtracking
Ex. 1: Generarea elementelor unui produs cartezian
int st[10];
int n,k,ev,as,m[100];
void init()
{ st[k]=0; }
int succesor()
{ if(st[k]<m[k])
{ st[k]=st[k]+1;
return 1; }
else return 0; }
int valid()
{ return 1; }
int solutie()
{ return k==n; }
void tipar()
{ for(int i=1;i<=n;i++)
cout<<st[i]<<" ";
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k))
tipar();
else
bt(k+1); }
void main()
{ cout<<"n=";cin>>n;
for(int i=1;i<=n;i++)
{ cout<<"dati nr elem ale mult "<<i; cin>>m[i]; }
bt(); }
Ex2. Generarea aranjamentelor
int st[100],n,m;
void init(int k)
{ st[k]=0; }
int solutie(int k)
{ return k==m; }
int succesor(int k)
{ if(st[k]<n)
{ st[k]++; return 1; }
else return 0; }
int valid(int k)
{ for(int i=1;i<k;i++)
if(st[k]<=st[i]) return 0;
return 1; }
void tipar()
{ for(int i=1;i<=m;i++)
cout<<st[i]<<" ";
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k))
tipar();
else
bt(k+1); }
void main()
{ cout<<"n=";cin>>n;
cout<<"m=";cin>>m;
bt(1); }
Ex. 3: Generarea combinarilor
int st[100],n,m;
void init(int k)
{ if(k==1) st[k]=0;
else st[k]=st[k-1]; }
int solutie(int k)
{ return k==m; }
int succesor(int k)
{ if(st[k]<n-m+k)
{ st[k]++;
return 1; }
else return 0; }
int valid(int k)
{ return 1; }
void tipar()
{ for(int i=1;i<=m;i++)
cout<<st[i]<<” ";
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k))
tipar();
else
bt(k+1); }
void main()
{ cout<<"n=";cin>>n;
cout<<"m=";cin>>m;
bt(1); }
Ex. 4: Generarea tuturor posibilităților de a forma din n obiecte grupuri de m obiecte care să aibă anumite proprietăți (combinări)
int st[100],n,m,k,q;
void init(int k)
{ st[k]=0; }
int solutie(int k)
{ return k==m; }
int succesor(int k)
{ if(st[k]<n)
{ st[k]++; return 1; }
else return 0; }
int valid(int k)
{ if(st[k]==k||st[k]==q)
return 0;
for(int i=1;i<k;i++)
if(st[k]<=st[i])
return 0;
return 1; }
void tipar()
{ for(int i=1;i<=m;i++)
cout<<st[i]<<" ";
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k)) tipar();
else bt(k+1); }
void main()
{ cout<<"n=";cin>>n; cout<<"m=";cin>>m;
cout<<"k obligatoriu=";cin>>k;
cout<<"q lipsa=";cin>>q;
st[1]=k; bt(2); }
Ex. 5: Generarea partiților unui număr
int st[100],s=0,n,m,k,q,nr=0;
void init(int k)
{ if(k==1) st[k]=0;
else st[k]=st[k-1]-1;}
int solutie(int k)
{ return s==n;}
int succesor(int k)
{if(st[k]<n-s)
{ st[k]=st[k]+1; return 1; }
else
{ s=s-st[k-1]; return 0; }}
int valid(int k)
{ if(s+st[k]<=n)
{ s=s+st[k];
return 1; }
else return 0; }
void tipar(int k)
{ for(int i=1;i<=k;i++)
cout<<st[i]<<"+";
cout<<'\b';
cout<<" "<<endl;
s=s-st[k];}
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
void main()
{ cout<<"n="; cin>>n; bt(1); }
Ex. 6: Generarea partiților unei mulțimi
int st[100],s=0,n,m,k,q,nr=0;
void init(int k)
{ st[k]=0; }
int solutie(int k)
{ return k==n; }
int succesor(int k)
{ if(st[k]<st[k-1]+1)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ return 1; }
void tipar(int k)
{ int i,j,max=st[1];
for(i=2;i<=n;i++)
if(st[i]>max)
max=st[i];
for(i=1;i<=max;i++)
{ cout<<”{”;
for(j=1;j<=n;j++)
cout<<j<<",";
cout<<'\b'<<"} "; }
cout<<endl;}
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
void main()
{ cout<<"n=";cin>>n;
bt(1); }
Ex. 7: Problema celor n dame
int st[100],n,m,k,q;
void init(int k)
{ st[k]=0; }
int solutie(int k)
{ return k==n; }
int succesor(int k)
{ if(st[k]<n)
{ st[k]++;
return 1; }
else
return 0; }
int valid(int k)
{ for(int i=1;i<k;i++)
if(st[k]==st[i] || abs(st[k]-st[i])==k-i)
return 0;
return 1; }
void tipar()
{ for(int i=1;i<=n;i++)
cout<<st[i]<<" ";
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k))
tipar();
else
bt(k+1); }
void main()
{ cout<<"n=";cin>>n;
bt(1); }
Ex. 8: Să se aranjeze n persoane astfel încât fiecare persoană din șir să nu aibă în fața sa persoanele pe care le-a avut în șirul iniațial.
int n,x[10],a[10];
int continuare(int k)
{ for(i=1;i<k;i++)
if(x[i]<=x[k])
return 0;
return 1; }
void afisare(int k)
{ for(int i=1;i<=k;i++)
out<<b[x[i]]<<" ";
out<<endl; }
Ex. 9: Să se genereze toate posibilitățile de aranjare a n persoane într-un șir astfel încât fiecare persoană să nu aibă aceeași vecini ca în șirul inițial
char b[25][256];
int n,x[10],a[10];
int continuare(int k)
{ if(abs(x[k]-x[k-1])==1&&k>1)
return 0;
for(i=1;i<k;i++)
if(x[i]==x[k]) return 0;
return 1; }
void afisare(int k)
{ for(int i=1;i<=k;i++)
out<<b[x[i]]<<" ";
out<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k))
tipar();
else
bt(k+1); }
void main()
{ cin>>n;
for(int i=1;i<=n;i++)
{ cin.get(); cin.get(b[i],256); }
back(); }
Ex.10: Să se genereze permutăriile mulțimii 1,3,5….2*n+1
int n,x[10],a[10];
int continuare(int k)
{ for(i=1;i<k;i++)
if(x[i]==x[k])
return 0;
return 1; }
void afisare(int k)
{ for(int i=1;i<=k;i++)
out<<x[i]<<" ";
out<<endl; }
void back()
{ int k=1; x[k]=-1;
while(k!=0)
if(x[k]<2*n-1)
{ x[k]=x[k]+2;
if(continuare(k))
if(k==n) afisare(k);
else {k++; x[k]=-1; } }
else
k–; }
void main()
{ cin>>n; back(); }
Ex. 11: Să se genereze permutările mulțimii 1,2,3…n în care două nr vecine nu trebuie să fie ambele pare sau ambele impare
int n,x[10],a[10];
int continuare(int k)
{ if((x[k]%2==0&&x[k-1]%2==0)||(x[k]%2!=0&&x[k-1]%2!=0)) return 0;
for(i=1;i<k;i++)
if(x[i]==x[k]) return 0;
return 1; }
Ex. 12: Să se genereze toate permutările mulțimii 1,2…,n în care nu apar numere consecutive
int n,x[10],a[10];
int continuare(int k)
{ if(k>1&&abs(x[k]-x[k-1])==1) return 0;
for(i=1;i<k;i++)
if(x[i]==x[k]) return 0;
return 1; }
Ex. 13: Să se afișeze toate anagramele unui cuvânt citit de la tastatură
char a[255];
int n,x[10];
int continuare(int k)
{ for(i=1;i<k;i++)
if(x[i]==x[k])
return 0;
return 1; }
void afisare(int k)
{ for(int i=1;i<=k;i++)
out<<a[x[i]-1]<<" ";
out<<endl; }
void main()
{ cin.get(a,200); cin.get();
n=strlen(a);
back(); }
Ex. 14: Problema bilei
int dl[9]={0,-1,-1,-1,0,0,1,1,1};
int dc[9]={0,-1, 0, 1,-1,1,-1,0,1};
int a[10][10],k,b[10][10],x[100],lv,cv,y,n,l0,c0,l1;
int c1,nr,m,i,j,l,c;
void citire()
{ cout<<"poz initiala a bilei (i0,j0): "; cin>>l0>>c0;
in>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{ in>>a[i][j];
b[i][j]=a[i][j]; }
for(i=1;i<=n;i++)
{for(j=1;j<=m;j++)
cout<<setw(3)<<a[i][j]<<" ";
cout<<endl; }
cout<<endl<<endl;}
int continuare(int lv, int cv, int k)
{ if(a[lv][cv]<b[l][c]&&lv>=1&&lv<=n&&cv>=1&& cv<=n)
return 1;
else return 0; }
void afisare()
{ int i,j; nr++; a[l0][c0]=100;
cout<<"solutia "<<nr<<" este:"<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
{ if(a[i][j]!=100) cout<<setw(3)<<a[i][j]<<" ";
else cout<<setw(3)<<"* "; }
cout<<endl; }
cout<<endl; }
void back()
{ a[l0][c0]=100; k=1; x[k]=0; l=l0; c=c0;
while(k>0)
if(x[k]<8)
{ x[k]++; lv=l+dl[x[k]]; cv=c+dc[x[k]];
if(continuare(lv,cv,k))
{ l=lv; c=cv;
k++;
a[l][c]=100;
x[k]=0;
if((lv==1||lv==n||cv==1||cv==m)&&(lv!=0||cv!=c0)) afisare(); } }
else
{ x[k]=0;
a[l][c]=b[l][c];
k–;
l=l-dl[x[k]];
c=c-dc[x[k]]; } }
int main()
{ citire();
nr=0; back();
if(nr==0)
cout<<"nu exista sol"; }
Ex. 15: Problema cal-rege
int dl[9]={0,1,2,2,1,-1,-2,-2,-1};
int dc[9]={0,2,1,-1,-2,-2,-1,1,2};
int a[10][10],x[100],n,l0,c0,l1,c1,nr,l,c,lv,cv,m,i,j, k,k,ok;
void citire()
{ cout<<"dim tablei de sah: "; in>>n>>m;
cout<<"poz initiala a calului (i0,j0): "; in>>l0>>c0;
cout<<"poz regelui (i1,j1): "; in>>l1>>c1;
cout<<"nr poz arse:"; in>>k;
for(i=1;i<=k;i++)
{ cout<<"coord poz arsa: "; in>>l>>c;
a[l][c]=-1; } }
int continuare(int lv, int cv, int k)
{ if(a[lv][cv]==0&&lv>=1&&lv<=n &&cv>=1&&cv<=n)
return 1;
else
return 0; }
void afisare()
{ int i,j; nr++;
cout<<"solutia "<<nr<<" este:"<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
cout<<setw(3)<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; }
void back()
{ int lv,cv,c,l,k;
k=1; x[k]=0; l=l0; c=c0;
while(k>0)
if(x[k]<8)
{ x[k]++; lv=l+dl[x[k]]; cv=c+dc[x[k]];
if(continuare(lv,cv,k))
{ l=lv; c=cv;
k++;a[l][c]=k;x[k]=0;
if(lv==l1 &&cv==c1)
ok=1;
if(ok==1 && lv==l0 && cv==c0)
afisare(); } }
else
{ x[k]=0;
a[l][c]=0;k–;
l=l-dl[x[k]];c=c-dc[x[k]]; } }
int main()
{ citire(); nr=0; ok=0;
back();
if(nr==0)
cout<<"nu exista sol"; }
Ex. 16: Capcane
int dl[9]={0,-1,-1,1,1};
int dc[9]={0,-1,1,-1,1};
int a[10][10]={0},x[100],n,l0,c0,l1,c1,nr,m,i,j,y,z, ln,cn;
void citire()
{ in>>n>>m; //dimensiunea
in>>l0>>c0; //pornire
in>>ln>>cn; //final
while(in>>z>>y)
a[z][y]=-1; }
int continuare(int lv, int cv, int k)
{ if(a[lv][cv]==0 && lv>=1 &&lv<=n &&cv>=1 && cv<=n)
return 1;
else
return 0; }
void afisare()
{ int i,j; nr++;
cout<<"solutia "<<nr<<" este:"<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
cout<<setw(3)<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; }
void back()
{ int lv,cv,c,l,k;
a[l0][c0]=1;
k=1; x[k]=0;
l=l0; c=c0;
while(k>0)
if(x[k]<8)
{ x[k]++;
lv=l+dl[x[k]];
cv=c+dc[x[k]];
if(continuare(lv,cv,k))
{ l=lv; c=cv; k++; a[l][c]=k; x[k]=0;
if(lv==ln &&cv==cn)
afisare(); } }
else
{ x[k]=0; a[l][c]=0; k–;
l=l-dl[x[k]]; c=c-dc[x[k]]; } }
int main()
{ citire();
nr=0;
back();
if(nr==0)
cout<<"nu exista sol"; }
Ex. 17: Problema labirintului
int dl[9]={0,-1,0,1,0};int dc[9]={0,0,1,0,-1};
int a[20][20],x[100],n,l0,c0,l1,c1,nr,m,i,j,ln,cn;
void citire()
{ cout<<"poz initiala (i0,j0): "; cin>>l0>>c0;
ifstream in("labirint.txt"); in>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
in>>a[i][j];
cout<<"poz finala (in,jn): ";cin>>ln>>cn; }
int continuare(int lv, int cv, int k)
{ if(a[lv][cv]==1&&lv>=1 &&lv<=n &&cv>=1 && cv<=m)
return 1;
else
return 0; }
void afisare()
{ int i,j; nr++; a[l0][c0]=1;
cout<<"solutia "<<nr<<" este:"<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=m;j++)
cout<<setw(3)<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; }
void back()
{ int lv,cv,c,l,k; a[l0][c0]=1;
k=1; x[k]=0; l=l0; c=c0;
while(k>0)
if(x[k]<4)
{ x[k]++;
lv=l+dl[x[k]];
cv=c+dc[x[k]];
if(continuare(lv,cv,k))
{ l=lv; c=cv;
k++;
a[l][c]=k; x[k]=0;
if(lv==ln && cv==cn)
afisare();} }
else
{ x[k]=0; a[l][c]=0;
k–;
l=l-dl[x[k]];
c=c-dc[x[k]]; } }
int main()
{ citire(); nr=0;
back();
if(nr==0)
cout<<"nu exista sol"; }
Ex. 18: Ṣah
int dl[9]={0,1,2,2,1,-1,-2,-2,-1};
int dc[9]={0,2,1,-1,-2,-2,-1,1,2};
int a[10][10],x[100],n,l0,c0,l1,c1,nr;
void citire()
{ cout<<"dim tablei de sah: "; cin>>n;
cout<<"poz initiala a calului (i0,j0): ";
cin>>l0>>c0;
cout<<"poz interzisa (i1,j1): "; cin>>l1>>c1; }
int continuare(int lv, int cv, int k)
{ if(a[lv][cv]==0&& lv>=1 &&lv<=n &&cv>=1 && cv<=n)
return 1;
else
return 0; }
void afisare()
{ int i,j; nr++;
cout<<"solutia "<<nr<<" este:"<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; }
cout<<endl; }
void back()
{ int lv,cv,c,l,k;
a[l0][c0]=1; a[l1][c1]=-1;
k=1; x[k]=0; l=l0; c=c0;
while(k>0)
if(x[k]<8)
{ x[k]++;
lv=l+dl[x[k]];
cv=c+dc[x[k]];
if(continuare(lv,cv,k))
{ l=lv; c=cv;
k++;
a[l][c]=k;
x[k]=0;
if(k==n*n-1)
afisare(); } }
else
{ x[k]=0;
a[l][c]=0;
k–;
l=l-dl[x[k]];
c=c-dc[x[k]]; } }
int main()
{ citire();
nr=0;
back();
if(nr==0)
cout<<"nu exista sol"; }
Anexa 10. Grafuri
Ex. 1. Crearea și afișarea matricei de adiacență a unui graf. Se citesc muchiile/arcele unui graf apoi se creează matricea de adiacență a grafului.
void citire ()
{ int i,j;
cout<<”Numar de noduri”; cin>>n;
cout<<”Numar de muchii”; cin>>m;
for(int k=1;k<=m;k++)
{ cout<<”Primul nod al muchiei ”<<k<<”:”; cin>>i;
cout<<”Al doilea nod al muchiei “<<k<<”:”;
cin>>j;
a[i][j]=1; a[j][i]=1; } }//doar la graful neorientat
void afisare ()
{ for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
cout<<a[i][j] <<” ”;
cout<<endl; } }
Ex. 2. Nodurile izolate și cele terminale ale unui graf neorientat.
int grad(int i)
{ int j,g=0;
for(j=1;j<=n;j++)
g+=a[i][j];
return g; }
void noduri()
{ cout<<"Nodurile izolate sunt: ";
for(i=1;i<=n;i++)
if(grad(i)==0) cout<<i<<" ";
cout<<endl;
cout<<"Nodurile terminale sunt:";
for(i=1;i<=m;i++)
if(grad(i)==1)
cout<<i<<" "; }
Ex. 3. Nodurile izolate și cele terminale ale unui graf orientat.
int grad_int(int i) // Gradul intern al unui graf orientat
{ int j,g=0;
for(j=1;j<=n;j++)
g+=a[j][i];
return g; }
int grad_ext(int i) //Gradul extern al unui graf orientat
{ int j,g=0;
for(j=1;j<=n;j++)
g+=a[j][i];
return g; }
void afisare_nod()
{ cout<<"Nodurile izolate sunt:";
for(i=1;i<=n;i++)
if(grad_int(i)+grad_ext(i)==0)
cout<<i<<" ";
cout<<endl <<"Nodurile terminale sunt:";
for(i=1;i<=m;i++)
if(grad_int(i)+grad_ext(i)==1)
cout<<i<<" "; }
Ex. 4. Numărul de muchii al unui graf neorientat
int nr_m()
{ int i,j,m=0;
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
m+=a[i][j];
return m; }
Ex. 5. Numărul de arce al unui graf orientat
int nr_a()
{ int i,j,m=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
m+=a[i][j];
return m; }
Ex. 6. Numărul de vecini ai unui nod dintr-un graf neorientat
int vecini(int i)
{ int j,v=0;
for(j=1;j<=n;j++)
if(a[i][j]==1) v++;
return v; }
Ex. 7. Numărul de vecini ai unui nod dintr-un graf orientat
int vecini(int i)
{ int j,v=0;
for(j=1;j<=n;j++)
if(a[i][j]==1||a[j][i]==1) v++;
return v; }
Ex. 8. Crearea și afișarea matricei de incidență prin citirea muchilor/arcelor.
void citesteN () // Graful neorientat
{ int i,j;
cin>>n>>m;
for(k=1;k<=m;k++)
{ cin>>i>>j; a[i][k]=1; a[j][k]=1; } }
void citesteO() // Graful orientat
{ int k,i,j;
cin>>n>>m;
for(k=1;k<=m;k++)
{ cin>>i>>j; a[i][k]=-1; a[j][k]=1; } }
void afiseaza_mi ()
{ for (int i=1;i<=n;i++)
{ for (int j=1;j<=m;j++)
cout<<a[i][j]<<” “;
cout<<endl; } }
Ex. 9. Crearea matricei de incidență a unui graf neorientat prin citirea datelor din matricea de adiacență. Afișarea muchiilor și a nodurilor izolate.
void citeste_mi ()
{ int i,j; cin>>n;
for (i=1;i<=n;i++)
for(j=1;j<=n;j++)
{ cin>>a[i][j];
if (a[i][j]==1) m++; }
m=m/2; }
void transforma()
{ int i,j,k=1;
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
if (a[i][j]==1)
{ b[i][k]=1; b[j][k]=1; k++; } }
void afiseaza_muchii()
{ for(int k=1;k<=m;k++)
{ cout<<” muchia” <<k << “ : “ ;
for(int i=1;i<=n;i++)
if (b[i][k]==1) cout<<i<<” “;
cout<<endl; } }
void afiseaza_noduri_izolate ()
{ int i,k,x;
for(i=1;i<=n;i++)
{ for(k=1, x=0; k<=m && x==0; k++)
if(b[i][k]==1) x =1;
if (!x) cout<<i<<” “; } }
void vecini ()
{ int k,j;
for(k=1;k<=m;k++)
if(a[i][k]==1)
for(j=1;j<=n;j++)
if (j!=i && a[i][k]==1) cout<<j<<” “; }
Ex. 10. Crearea matricei de incidență a unui graf orientat prin citirea datelor din matricea de adiacență. Afișarea muchiilor și a nodurilor izolate
void citeste_ma ()
{ cin>>n;
for (int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{ cin>>a[i][j];
if (a[i][j]==1) m++; } }
void transforma_mi()
{ int I,j,k=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if (a[i][j]==1)
{ b[i][k]= -1; b[j][k]=1; k++; } }
void afiseaza_muchii()
{ for(int k=1;k<=m;k++)
{ cout<<” muchia” <<k << “ : “ ;
for(int i=1;i<=n;i++)
if (b[i][k]==1) cout<<i<<” “;
cout<<endl; } }
void afiseaza_arce ()
{ int I,k,x,y;
for(k=1;k<=m;k++)
{ cout<<”arcuri” <<k<<” :”;
for(i=1;i<=n;i++)
{ if(b[i][k]== -1) x=i;
if(b[i][k]==1) y=i; }
cout<<x<<” – “<<y<<endl; } }
void afiseaza_noduri_izolate ()
{ int i,k,x;
for(i=1;i<=n;i++)
{ for(k=1, x=0; k<=m && x==0; k++)
if(b[i][k]==1 || b[i][k]== -1) x=1;
if (!x) cout<<i<<” “; } }
void succ (int i)
{ for(int k=1;k<=m;k++)
if (a[i][k]==-1)
for(int j=1;j<=n;j++)
if (j!=i && a[j][k]==1)
s[j]=1; }
void pred (int i)
{ for(int k=1;k<=m;k++)
if (a[i][k]==1)
for(int j=1;j<=n;j++)
if (j!=i && a[j][k]== -1)
p[j]=1; }
void vecini (int i)
{ succ (i); pred (i);
for(j=1;j<=n;j++)
if (j!=i && (s[j]==1 || p[j]==1))
cout<<j<<” “; }
Ex. 11. Reprezentarea grafurilor prin lista muchiilor folosind matricea muchiilor de dimensiune mx2. Afișarea nodurilor izolate și terminale.
int a[10][2],n,m; // graful neorientat
int grad (int i)
{ int k,g=0;
for(k=1;k<=m;k++)
if(a[k][0]= =i || a[k][1]= =i) g++;
return g; }
void afis_nod()
{ int i,j,k;
cout<<”Numar de noduri”; cin>>n;
cout<<”Numar de muchii”; cin>>m;
for(k=1;k<=m;k++)
{ cout<<”Primul nod al muchiei” <<k <<”:”; cin>>i;
cout<<”Al doilea nod al muchiei“<<k<<”:”; cin>>j;
a[k][0]=i; a[k][1]=j; }
cout<<”Nodurile izolate sunt : “;
for(i=1;i<=n;i++)
if(grad(i)==0) cout<<i<<” “;
cout<<”Nodurile terminale sunt : “;
for(i=1;i<=n;i++)
if(grad(i)==1) cout<<i<<” “; }
int a[10][2],n,m; // garful orientat
int grad_int(int i)
{ int g=0,k;
for(k=1;k<=m;k++)
if(a[k][1] = = i) g++;
retrun g; }
int grad_extern(int i)
{ int g=0,k;
for(k=1;k<=m;k++)
if(a[k][0] = = i) g++;
return g; }
void afisa_nod()
{ int i,j,k;
cout<<”Numar de noduri”; cin>>n;
cout<<”Numar de arce”; cin>>m;
for(k=1;k<=m;k++)
{ cout<<”Nodul initial al arcului ” <<k<<”:”; cin>>i;
cout<<”nodul final al arcului “ <<k<<”:”; cin>>j;
a[k][0]=i; a[k][1]=j; }
cout<<”Nodurile izolate sunt: “;
for(i=1;i<=n;i++)
if(grad_int(i)+grad_extern(i) == 0)
cout<<i<<” “;
cout<<endl<<”Nodurile terminale sunt: “;
for(i=1;i<=n;i++)
if(grad_int(i)+grad_extern(i) == 1)
cout<<i<<” “; }
Ex. 12. Reprezentarea grafurilor prin lista muchiilor folosind un vector de muchii ale cărui elemente sunt înregistrări. Afișarea nodurilor izolate și terminale.
struct muchie { int x,y.d; }; // Graf neorientat
muchie u[20]; int n,m;
void citeste()
{ cin>>n>>m;
for(int k=1;k<=m;k++)
cin>>u[k].x >>u[k].y >>u[k].d; }
int izolat(int i)
{ int g=0;
for(int k=1;k<=m;k++)
if(u[k].x==i || u[k].y==i) g++;
return g==0; }
void afisari()
{ int k,p,min;
cout<<”nodul “;cin>>p;
if(izolat(p))
cout<<”nodul “<<p<<” nu are vecini”;
else
{ k=1;
while(u[k].x!=p && u[k].y!=p) k++;
min=u[k].d;
for(k=1;k<=m;k++)
if(u[k].x==p || u[k].y==p)
if(u[k].d<min) min=u[k].d;
cout<<” distanta minima este “<<min<<endl;
cout<<”nodurile aflate la distanta minima sunt:”;
for(k=1;k<=m;k++)
{ if(u[k].x==p && u[k].d==min)
cout<<u[k].y<<” “;
if(u[k].y==p && u[k].d==min)
cout<<u[k].x<<” “; } } }
struct arc{int x,y,d;}; // Graf orientat
arc u[20]; int n,m;
int succ(int i)
{ int k,g=0;
for(k=1;k<=m;k++)
if(u][k].x==i) g++;
return g!=0; }
void vecini_dist()
{ int k,p,min; citeste();
cout<<”nodul “;cin>>p;
if(!succ(p))
cout<<“nodul “<<p<<”nu are vecini la care poate ajunge”;
else { k=1;
while(u[k].x!=p) k++;
min=u[k].d;
for(k=1;k<=m;k++)
if(u[k].x==p && u[k].d<min)
min=u[k].d;
cout<<”distanta minima este: ”<<min<<endl;
cout<<”nodurile aflate la distanta minima sunt: ”;
for(k=1;k<=m;k++)
if(u[k].x==p && u[k].d==min)
cout<<u[k].y<<” “; } }
Ex. 13. Crearea matricii de adiacență din matricea de incidență
void matrice()
{ int l,c;
for(int i=1;i,=n;i++)
for(int j=1;j<=n;j++)
b[i][j]=0;
for(int j=1;j<=m;j++) { l=c=0;
for(int i=1;i<=n;i++)
{ if(l==0&&a[i][j]==1)
{ l=i; i++; }
if(a[i][j]==1) c=i; }
b[l][c]=1; b[c][l]=1; }
Ex. 14. Algoritm pentru a determina numărul minim de arce care trebuie adăugate la un graf orientat, pentru a obține un graf orientat complet.
void adaugate()
{ int i,j,m=0;
for(i=2;i<=n;i++)
for(j=1;j<i;j++)
if(a[i][j]==0&&a[j][i]==0) m++;
cout<<”nr de arce care trebuie adaugate este:”<<m; }
Ex. 15. Algoritm pentru a determina numărul maxim de noduri izolate pe care poate să le conțină un graf neorientat care are n noduri și m muchii
void maxin()
{ int n,m,n1;
cout<<”muchii=”;cin>>m;
cout<<”noduri=”;cin>>n;
n1=(int) ((1+sqrt(1+8*m))/2);
cout<<”nr max de noduri izolate este: ”<<n-n1-1; }
Ex. 16. Să se verifice dacă o matrice dată poate reprezenta matricea de adiacență a unui graf
int main()
{ int a[20][20],n,i,j, ok=1;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
in>>a[i][j];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{ if(a[i][j]!=1&&a[i][j]!=0) ok=0;
if(a[i][i]!=0) ok=0;
if(a[i][j]!=a[j][i]) ok=0; }
if(ok==0)
cout<<"matricea nu poate fi Ma a unui graf";
else cout<<"poate fi";
cout<<endl; }
Ex. 17. Să se afișeze lista de adiacență (muchii)
for(i=1;i<=n;i++)
{ cout<<"L"<<i<<"=";
for(j=1;j<=n;j++)
if(a[i][j]==1)
cout<<j<<" ";
cout<<endl; }
Ex. 18. Să se afișeze șirul grafic asociat unui graf.
for(i=1;i<=n;i++)
{ int nr=0;
for(j=1;j<=n;j++)
nr=nr+a[i][j];
cout<<nr<<" "; }
Ex. 19. Să se afișeze numărul de muchii și muchiile unui graf
int nr1=0;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
if(a[i][j]==1)
{ cout<<"["<<i<<";" <<j<<"] :"<<endl; nr1++;}
cout<<"nr de muchii = "<<nr1;
Ex. 20. Pentru un nod dat să se afișeze vecinii lui
int x; cin>>x;
for(j=1;j<=n;j++)
if(a[x][j]==1)
cout<<j<<" ";
Ex. 21. Se dă o muchie afișați muchiile cu care este incidentă aceasta
int y; cin>>x>>y;
cout<<endl<<"muchiile incidente cu muchia "<<x<<" "<<y<<" :"<<endl;
for(j=1;j<=n;j++)
{ if(a[x][j]==1&&j!=y) out<<x<<" "<<j<<" "<<endl;
if(a[y][j]==1&&x!=j) out<<y<<" "<<j<<" "<<endl; }
Ex. 22. Se dă un șir de numere. Să se afișeze un mesaj dacă șirul citit este sau nu șir grafic. Dacă este șir grafic să se afișeze numărul de noduri și de muchii (-fiecare nod are gradul <= n-1; -suma tuturor gradelor este numar par; -numarul de noduri cu grad impar este par)
int main()
{ int s=0,ok=1,v[25],n,i,j,nr=0; cin>>n;
for(i=1;i<=n;i++) cin>>v[i];
for(i=1;i<=n;i++)
{ s=s+v[i];
if(v[i]>n-1) ok=0;
if(v[i]%2!=0) nr++; }
if(nr%2==0&&s%2==0&&ok==1)
cout<<"este sir grafic cu "<<n<<
" noduri si "<<s/2<<" muchii"<<endl;
else cout<<"nu este sir grafic";}
Ex. 23. Să se verifice dacă o matrice dată poate reprezenta matricea de incidență a unui graf orientat
int ok=1;
for(j=1;j<=m;j++)
{ int nr1=0,nr2=0;
for(i=1;i<=n;i++)
{ if(u[i][j]!=0&&u[i][j]!=1&&u[i][j]!=-1) ok=0;
if(u[i][j]==1) nr1++;
if(u[i][j]==-1) nr2++; }
if(nr1!=1||nr2!=1) ok=0; }
if(ok==1) cout<<"da";
else cout<<"nu";
cout<<endl;
Ex. 24. Să se construiască matricea de adiacență pornind de la matricea de incidență.
int x,y;
for(j=1;j<=m;j++)
{ for(i=1;i<=n;i++)
{ if(u[i][j]==-1) x=i;
if(u[i][j]==1) y=i; }
a[x][y]=1; }
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
out<<a[i][j]<<" ";
out<<endl; }
Ex. 25. Să se afișeze gradele nodurilor și vecinii unui nod dat
for(i=1;i<=n;i++)
{ int nrp=0,nrm=0;
for(j=1;j<=m;j++)
{ if(u[i][j]==1) nrp++;
if(u[i][j]==-1) nrm++; }
cout<<"dm("<<i<<")="<<nrm;
cout<<" dp("<<i<<")="<<nrp<<endl; }
cin>>x;
for(j=1;j<=n;j++)
if(a[x][j]==1) out<<j<<" "; }
Ex. 26. Algoritm pentru reprezentarea grafurilor cu lista de adiacență în implementare statica prin citire listelor de vecini, implementare cu matrice.
void citeste()
{ int i,j,k,x; cin>>n>>m;
for(i=1;i<=n;i++) L[1][i]=i;
for(i=1;i<=n;i++)
{ if(x==0) L[2][i]=0;
else { L[2][i]=j;
for(k=1;k<=x;k++)
{ cin>>L[1][j];
if(k!=x)
L[2][j]=j+1;
else
L[2][j]=0;
j++; } } } }
int grad(int i)
{ int g,j=L[2][i];
if(L[2][i]=0) g=0;
else
{ g=1;
while(L[2][j]!=0)
{ g++; j++; } }
return g; }
int grad_max()
{ int i,max=0;
for(i=1;i<=n;i++)
if(grad(i)>max)
max=grad(i);
return max; }
void transpune()
{ int i,j;
for(i=1;i<=n;i++)
{ j=L[2][i];
if(L[2][i]!=0)
{ while(L[2][j]!=0)
{ a[i][L[1][j]]=1; j++; }
a[i]L[1][j]]=1; } } }
void scrie()
{ int i,j; cout<<n<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; } }
int main()
{ int i; citeste();
cout>>"gradul cel mai mare=";
cout<<grad_max()<<endl;
cout<<"nodurile cu gradul cel mai mare=";
for(i=1;i<=n;i++)
if(grad(i)==grad_max())
cout<<i<<" ";
transpune(); scrie(); }
Ex. 27. Algoritm pentru reprezentarea grafurilor cu lista de adiacență în implementare statica prin citire listelor de vecini, implementare cu vectori.
int n,m,L[50],a[10][10],cap[10];
void citeste()
{ int i,j=1,x,k; cin>>n>>m;
for(i=1;i<=n;i++)
{ cin>>x;
if(x==0)
cap[i]=0;
else
{ cap[i]=j;
for(k=1;k<=n;k++)
{ f1>>L[j]; j++; } } } }
int grad(int i)
{ int g, j;
if(cap[i]==0) g=0;
else
{ if(i<n)
{ j=i+1;
while(cap[j])==0&&j<n)
j++;
if(j==n+1)
g=2*m+1-cap[i]; }
return g; }
int grad_max()
{// este identica cu cea de la implementarea matrici}
void transpunere()
{ int i,j;
for(i=0;i<=n;i++)
for(j=0;j<grad[i];j++)
a[i][L[cap[i]+j]]=1; }
void scrie()
{ // este identica cu cea de la implem de la matrici}
void main()
{// este identica cu cea de la implem e la matrici}
Ex. 28. Algoritm pentru crearea listei de adiacență în implementare statică din matricea de adiacență, implementare cu matrice.
int n,m,L[3][50],a[10][10];
void citeste()
{ int i,j; f1>>n;
for(i=1;i<=n;i++)
for|(j=1;j<n;k++)
{ f1>>a[i][j];
if(a[i][j]==1) m++; }
m=m/2; }
// numai pt graf neorientat
void transpune()
{ int i,j,k,g;
for(i=1li<=n;i++) L[1][i]=i;
k=n+1;
for(i=1;i<=n;i++)
{ for(j=1,g=0;j<=n;j++)
if(a[i][j]==1)
{ L[1][k]=j; L[2][k]=k+1; k++;g++; }
if(g==0) L[2][i]=0;
else
{ L[2][i]=k-g; L[2][k-1]=0; } } }
int grad(int i )
{ // identica cu cea de la implementarea maticilor}
void scrie()
{ int i,j=1,k;
cout<<n<<" "<<m<<endl;
for(i=1;i<=n;i++)
if(L[2][i]==0) cout<<0<<endl;
else { cout<<grad(i)<<" ";
for(k=1;k<grad(i);k++,j++)
cout<<L[1][j]<<" ";
cout<<endl; } }
int main() { citeste(); trasnpune(); scrie();}
Ex. 29. Algoritm pentru crearea listei de adiacență în implementare statică din matricea de adiacență, implementare cu vectori.
int n,m,L[50],cap[10],a[10][20];
void citeste(){//identica cu cea de la implem cu matrice}
void transpune()
{ int i,j,k=1,g;
for(i=1;i<=n;i++)
{ for(j=1,g=0;j<=n;j++)
if(a[i][j]==1)
{ L[k]=j;k++;g++; }
if(g==0) cap[i]=0;
else cap[i]=k-g; } }
int grad(int i)
{ //identica cu cea de la implem cu matrice}
void scrie()
{ int i,j; cout<<n<<" "<<endl;
for(i=1;i<=n;i++)
{ f2<<grad(i)<<" ";
for(j=0;j<grad(i);j++)
cout<<L[cap[i]+j]<<" ";
cout<<endl; } }
void main()
{//identica cu cea de la implem cu matrice}
Ex. 30. Algoritm pentru determinarea ciclurilor elementare într-un graf neorientat
int a[20][20],n,k,as,ev,x,este=0,st[100];
void citeste() { //se citeste matricea de adiacenta din fisier }
void init(int k) { //este identica cu cea de la afisarea lanturilor elem }
int succesor(int k ){ //este indentica cu cea de la afisarea lanturilor elem }
int valid(int k) { //este identica cu cea de la afisarea lanturilor elem }
int solutie(int k) { return a[st[k]][x]==1 && k>2; }
//se obtine solutia atunci cand ultimul nod adaugat este adiacent nodului x si in stiva exista cel putin 3 noduri
void tipar(int k)
{ for(int i=1,este=1;i<=k;i++)
cout<<st[i]<<” “;
cout<<x<<endl; }
void bt(int k) { //partea fixa a algoritmului }
int main()
{ citeste();
for(x=1;x<=n;x++) { st[1]=x; bt(1); }
if(!este) cout<<”Nu exista nici un ciclu elementar”; }
Ex. 31. Algoritm pentru determinarea circuitelor elementare într-un graf orientat
int a[20][20],n,k,as,ev,x,este=0, st[100];
void citeste() { //se citeste matricea de adiacenta }
void init(int k) { //identica cu cea de la afisarea lanturilor elementare }
int succesor(int k) { //identica cu cea de la afisarea lanturilor elementare }
int valid(int k)
{ if(k>1)
if(a[st[k-1]][st[k]]==0) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1; }
int solutie(int k) { return a[st[k]][x]==1 && k>1; }
//se obtine solutia atunci cand ultimul nod adaugat este adiacent nodului x si in stiva exista cel putin doua noduri
void tipar(int k)
{ for(int i=1,este=1;i<=k;i++)
cout<<st[i]<<” “;
cout<<x<<endl; }
void bt(int k) {//partea fixa a algoritmului }
void main()
{ citeste();
for(x=1;x<=n;x++) { st[1]=x; bt(1); }
if(!este) cout<<”Nu exista circuite”; }
Ex. 32. Algoritmi pentru determinarea și afișarea drumurilor elementare dintr-un graf
void citeste() { //se citeste matricea de adiacenta din fisier }
void init(int k) { //identica cu cea de la afisarea lanturilor elementare }
int succesor(int k) { //ca cea de la afisarea lanturilor elementare }
int valid(int k)
{ if(k>1)
if(a[st[k-1]][st[k]]==0) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1; }
int solutie(int k)
{ return st[k]==y; }
void tipar(int k)
{ for(int i=1,este=1;i<=k;i++)
cout<<st[i]<<” “;
cout<<x<<endl; }
void bt(int k) { //partea fixa a algoritmului }
int main()
{ citeste();
for(x=1;x<=n;x++)
for(y=1;y<=n;y++)
if(x!=y)
{ st[1]=x; bt(1); }
if(!este) cout<<”Nu exista”; }
Ex. 33. Verificarea dacă două matrici de adiacențăpot reprezenta matricele de adiacență ale unui graf și ale unui subgraf al acestuia.
int n,k,a1[10][10],a2[10][10],b[10][10];
int v[10],nr,x,gasit, st[100];
void zero()
{ for(int i=1;i<=k;i++)
for(j=1;j<=k;j++)
b[i][j]=0; }
void init (int k) { st[k]=0; }
int succesor(int k)
{ if(st[k]<n)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ if (k>1 && st[k]<st[k-1]) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1; }
int solutie (int k) { return k==p; }
int tipar(int k)
{ int i,j; zero();
if (x==0)
{ for(i=1;i<=k;i++)
for(j=1;j<=k;j++)
if(a1[st[i]][st[j]] == 1) b[i][j]=1;
for(i=1;i<=k;i++)
for(j=1;j<=k;j++)
if(a2[i][j] != b[i][j]) return 0; }
else
{ for(i=1;i<=k;i++)
for(j=1;j<=k;j++)
if(a2[st[i]][st[j]] == 1) b[i][j]=1;
for(i=1;i<=k;i++)
for(j=1;j<=k;j++)
if(a1[i][j] != b[i][j]) return 0; }
return 1; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
int main()
{ int i,j,m,p;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cin>>a1[i][j];
cin>>p;
for(i=1; i<=p; i++)
for(j=1; j<=p; j++)
cin>>a2[i][j];
if(p>n) { m=n; n=p; n=m; x=1; }
else x=0; bt(1);
if(gasit)
if(x) cout<<"Prima matrice de adiacenta este a subgrafului";
else cout<<"A 2-a matrice de adiacenta este a subgrafului ";
else
cout<<"Nu este subgraf!";
Ex. 34. Verificarea dacă un graf Gp este graf parțial al unui graf G
int m,n,,a1[10][10],a2[10][10];
int grafp()
{ if(m!=n) return 0;
else
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a2[i][j]==1&&a1[i][j]==0) return 0;
return 1; }
void verific_partial()
{ int i,j; cin>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
cin>>a1[i][j];
for(i=1;i<=m;i++)
for(j=1;j<=m;j++)
cin>>a2[i][j];
if(grafp()) cout<<”este graf partial”;
else cout<<”nu este graf partial”; }
Ex. 35. Obținerea unui graf parțial Gp al unui graf G
int a[20][20],n,m,x,v[10];
int grad(int i)
{ int j,g=0;
for(j=1j<=n;j++)
g+=a[i][j];
return g; }
void graf_partial()
{ int i,k=0;
for(i=1;i<=n;i++)
if(grad(i)%2==0) v[++k]=i;
for(i=1;i<=k;i++)
if(a[v[i]][x]==1)
{ a[v[i]][x]=0; a[x][v[i]]=0; m–; } }
void scrie()
{ cout<<n<<” “<<m<<endl;
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
if(a[i][j]==1) cout<<i<<” “<<j<<endl; }
int main()
{ citeste(); graf_partial(); scrie(); }
Ex. 36. Generarea tuturor grafurilor parțiale ale unui graf neorientat
int n,m,k,k,ev,as,a[10][10],b[10][20],nr,st[100];
void citeste()
{ int i,j; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{ cin>>a[i][j];
if(a[i][j]==1) m++; }
m=m/2; }
void transformare()
{ int i,j,k=1;
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
if(a[i][j]==1)
{ b[i][k]=1; b[j][k]=1;
k++; } }
void init(int k) { st[k]=0; }
int successor(int k)
{ if(st[k]<m)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ if(k>1&&st[k]<st[k-1]) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1; }
int solutie(int k) { return k==p; }
void tipar(int k)
{ int i,j; nr++;
cout<<”graful partial “<<nr<<endl;
cout<<”muchiile:”;
for(i=1;i<=k;i++)
{ for(j=1;j<=n;j++)
if(b[j][st[i]]==1)
cout<<j<<” “;
cout<<”; “; }
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
int main()
{ citeste(); transformare();
for(k=m;k>=0;k–)
bt(1); }
Ex. 37. Verificarea dacă un graf Gs este subgraf al grafului G.
int m,n,a1[10][10],a2[10][10],v[10];
int subgraf()
{ if(m>n) return 0;
else
{ for(int i=1;i<=m;i++)
if(v[i]>n) return 0;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(a2[i][j] != a1[v[i]][v[j]]) return 0; }
return 1; }
void verificare()
{ cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a1[i][j];
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
cin>>a2[i][j];
for(i=1;i<=m;i++)
cin>>v[i];
if(subgraf()) cout<<" Este subgraf!";
else cout<<"Nu este subgraf! "; }
Ex. 38. Generarea tuturor subgrafurilor unui graf
int st[100],n,k,k,ev,as,a[10][10],nr;
void init(int k) { st[k]=0; }
int succesor(int k)
{ if(st[k]<n)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ if(k>1 && st[k]<st[k-1]) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1; }
int solutie(int k) { return k==p; }
void tipar(int k)
{ int i,j; nr++;
cout<<"subgraful "<<nr<<endl<<"nodurile: ";
for(i=1;i<=k;i++)
cout<<st[i]<<" ";
cout<<endl;
cout<<"muchiile: "; //cout<<"arcele: " – pt Gr orientat
for(i=1;i<=k;i++)
for(j=i+1;j<=k;j++) //for(j=1;j<=k;j++)-pt orientat
if(a[st[i]][st[j]]==1)
cout<<st[i]<<" – "<<st[j]<<" ";
cout<<endl; }
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
int main()
{ citeste();
for(p=n;p>=1;p–) bt(1); }
Ex. 39. Generarea tuturor grafurilor bipartite
void generare(int n)
{ int a[10]={0},i,j,k=0,posibil=1;
while(posibil)
{ j=n;
while(j>0 && a[j]==1)
{ a[j]=0; j–; }
if(j==0) posibil=0;
else
{ a[j]=1; k++;
if(k <= pow(2,n)-2)
{ cout<<"Graful "<<k<<endl<<"Multimea A: ";
for(i=1;i<=n;i++)
if(a[i]) cout<<i<<" ";
cout<<"Multimea B: ";
for(i=1;i<=n;i++)
if(!a[i]) cout<<i<<" ";
cout<<endl<<"Muchiile sunt: ";
for(i=1;i<=n;i++)
if(a[i]==1)
for(j=1;j<=n;j++)
if(a[j]==0 && i!=j)
cout<<"["<<i<<","<<j<<"] ";
cout<<endl; } } } }
int main()
{ int n; cout<<"Numarul de noduri: "; cin>>n;
generare(n); }
Ex. 40. Verificarea dacă un graf este graf bipartit.
int a[10][10],n;
int bipartit()
{ int x[10]={0},i,j,m,k=0,posibil=1,gasit=0;
while (posibil && !gasit)
{ m=n;
while(m>0 && x[m]==1)
{ x[m]=0; m–; }
if(m==0) posibil=0;
else { x[m]=1; k++;
if(k <= pow(2,n)-2)
for(i=1,gasit=1; i<=n &&gasit; i++ )
for(j=1; j<=n &&gasit ;j++)
if(a[i][j]==1)
if((x[i]==1 && x[j]==1) || (x[i]==0 && x[j]==0))
gasit=0; } }
return gasit; }
void main()
{ citeste();
if(bipartit()) cout<<"Este bipartit!";
else cout<<"Nu este bipartit!"; }
Ex. 41. Verificarea unui șir de etichete de noduri dacă formează un lanț simplu
#include<fstream.h>
struct muchie { int x,y; }; muchie z[10];
int k,n,m,a[10][10],v[10];
void citeste()
{ int i,x,y; f>>n>>m;
for (i=1;i<=m;i++)
{ f>>x>>y; a[x][y]=1; a[y][x]=1; } }
int lant()
{ for (int i=1;i<k;i++)
if (a[v[i]][v[i+1]]==0) return 0;
return 1; }
int simplu()
{ for (int i=1;i<k;i++)
for (int j=i+1;j<=k;j++)
if (z[i].x==z[j].x && z[i].y==z[j].y) return 0;
return 1; }
int main()
{ int i; citeste(); cout<<"k="; cin>>k;
for (i=1;i<=k;i++)
{ cout<<"Eticheta "<<i<<" = "; cin>>v[i]; }
for (i=1;i<k;i++)
if (v[i]<v[i+1]) { z[i].x=v[i]; z[i].y=v[i+1]; }
else { z[i].x=v[i+1]; z[i].y=v[i]; }
if (lant())
if (simplu()) cout<<"este lant simplu";
else cout<<"nu este lant simplu";
else cout<<"nu este lant"; }
Ex. 42. Algoritm pentru determinarea lanțurilor elementare dintre două noduri ale unui graf.
int a [20][20],n,k,as,ev,x,este=0,st[100];
void init(int k) { st[k]=0; }
int successor(int k)
{ if(st[k]<n)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ if(k>1)
if(a[st[k-1]][st[[k]]==0) return 0;
// pentru graful orientat
//if(a[st[k]][st[[k-1]]==0&&a[st[k-1]][st[[k]]==0) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
retrun 1; }
int solutie(int k) { return st[k]==y; }
//se obtin sol atunci cand ultimul nod adaugat in st e y
void tipar(int k)
{ for(int i=1,este=1;i<=k;i++)
cout<<st[i]<<” “;
cout<<endl; }
void bt(int k)
{ init(k);
while(k>1)
{ as=1; ev=0;
while (as && !ev)
{ as=succesor(k);
if(as) ev=valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
void main()
{ citeste();
cout<<”x= “; cin>>x; cout<<”y= “; cin>>y;
st[1]=x; bt(2);
if(!este) cout<<”Nu exista lant”;
//det tuturor lanturilor elementare din graf
for (x=1;x<=n;x++)
for (y=1;y<=n;y++)
if (x!=y) { st[1]=x; bt(1); }
if (!este) cout<<"Nu exista lanturi elementare."; }
Ex. 43. Algoritmui pentru determinarea conexitatii grafurilor
void citeste() { //se citeste matricea de adiacenta }
void init(int k) { st[k]=0; }
int successor(int k)
{ if(st[k]<n)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ if(k>1)
if(a[st[k-1]][st[[k]]==0) return 0;
// pentru graful orientat
//if(a[st[k]][st[[k-1]]==0&&a[st[k-1]][st[[k]]==0) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
retrun 1; }
void solutie (int k) { return st[k]==y; } //se obtine sol atunci cand ultimul nod este adaugat in stiva este y
void tipar(int k) { este=1;} //daca exista solutie (un lant intre nodurile x si y ),variabila este va avea valoarea 1
void bt(int k)
{ init(k);
while(k>1)
{ as=1; ev=0;
while (as && !ev)
{ as=succesor(k);
if(as) ev=valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
void componente()
{ int m=0;
for(x=1;x<=n;x++)
if(v[x] = = 0)
{ m++; st[1]=x; v[x]=1;
cout<<”Comp conexa”<<m<<”:”<<x<<” “;
for(y=1;y<=n;y++)
if(x!=y)
{ este=0; bt(1);
if(este)
{ v[y]=1; cout<<y<<” “; } }
cout<<endl;} }
void main() { citeste(); componente(); }
Ex. 44. Afișarea componentelor conexe dintr-un graf
void citeste () { //se citeste matricea de adiacenta }
void cauta ()
{ for(int i=1;i<=n;i++)
if (vizitat[i]==0) return i;
return 0; }
void init (int k)
{ vf=1; st[vf]=k; vizitat[k]=1; }
int este_vida () { return vf==0; }
void adaug (int i)
{ vf++; st[vf]=i; vizitat[i]=1; }
void elimin () { vf–; }
void prelucrare ()
{ int i=1, k=st[vf];
while (i<=n && (a[k][i]==0 || (a[i][k]==1&& vizitat[i]==1)))
i++;
if(i==n+1) elimin();
else { cout<<i<<” ; “; adaug (i); } }
int main ()
{ citeste(); k=cauta();
while (k)
{ m++; init (k);
cout<<endl<<”componenta conexa”<<” : “<<k<<” “;
while (!este_vida()) prelucrare ();
k=cauta (); } }
Ex. 45. Afișarea componentelor tare conexe dintr-un graf orientat
void citeste (){ //se citeste matricea de adiacenta}
void cauta ()
{ for(int i=1;i<=n;i++)
if (vizitat[i]==0) return i;
return 0; }
void zero (int x[])
{ for(int i=1;i<=n;i++) x[i]=0; }
void init (int k) { vf=1; st[vf]=k; }
int este_vida() { return vf==0; }
void adaug (int i, int x[])
{ vf++; st[vf]=i; x[i]=1; }
void elimin () { vf–; }
void prelucrare1 (int x[])
{ int i=1, k=st[vf]; x[k]=1;
while (i<=n && (a[i][k]==0 || (a[i][k]==1 && x[i]==1)))
i++;
if(i==n+1) elimin ();
else adaug (i,x); }
void prelucrare2 (int x[])
{ int i=1,k=st[vf]; x[k]=1;
while(i<=n&& (a[k][i]==0 || ( a[k][i]==1 && x[i]==1 )))
i++;
if (i==n+1) elimin ();
else adaug (i,x); }
void comp (int x[], int y[])
{ for(int i=1;i<=n;i++)
if(x[i]==1)&&y[i])
{ cout<<i<<” “; vizitat [i]=1; } }
int main ()
{ int k, pred[10], succ[10];
citeste (); k=cauta(); m++;
cout<<”componentele tare conexe: “<<endl;
while (k)
{ cout<<endl<<m<<” : “; init(k); zero (pred);
while (!este_vida())
prelucrare1 (pred);
init (k); zero(succ);
while (!este_vida())
prelucrare2 (succ);
comp (pred,succ);
k=cauta (); m++; } }
Ex. 46. Afișarea componentelor conexe ale unui graf orientat
int a[20][20],n,v[20], st[100];
void citeste() {//se citeste matricea de adiacenta }
void transforma()
{ for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j] = = 0&& i!=k)
a[i][j]=a[i][k]*a[k][j]; }
void componente ()
{ int i,j,m=0;
for(int i=1;i<=n;i++)
if(v[i] = = 0)
{ m++; v[i]=1;
cout<<”Comp conexa “<<m<<”:”<<i<<” “;
for(int j=1;j<=n;j++)
if(a[i][j] = =1 && i!=j)
{ v[j]=1; cout<<j<<” “; }
cout<<endl; } }
int main() { citeste(); transforma(); componente(); }
Ex. 47. Determinarea componentelor tare conexe într-un graf orientat
int a[20][20],n,k,ev,as,x,y,v[20],est1,este2,este=0,st[10];
void citeste(){//se citeste matricea de adiacenta}
void init(int k)
{ st[k]=0; }
int successor(int k)
{ if(st[k]<n)
{ st[k]=st[k]+1; return 1; }
else return 0; }
int valid(int k)
{ if(k>1)
if(a[st[k-1]][st[[k]]==0) return 0;
// pentru graful orientat
//if(a[st[k]][st[[k-1]]==0 && a[st[k-1]][st[[k]]==0) return 0;
for(int i=1;i<k;i++)
if(st[k]==st[i]) return 0;
retrun 1; }
int solutie(int k)
{ return st[k]==y; }
// se obtine sol cand ultimul nod adaugat in stiva este y
void tipar(int k)
{ este=1; }
//daca exista solutie (un drum intre nodurile x si y), //variabila este va avea valoarea 1
void bt(int k)
{ init(k);
while(succesor(k))
if(valid(k))
if(solutie(k))
tipar(k);
else
bt(k+1); }
void componente()
{ int i,j,m=0;
for(i=1;i<=n;i++)
if(v[i] = =0)
{ m++; v[i]=0;
cout<<”Componenta conexa”<< <<”:”<<i<<” “;
for(j=1;j<=n;j++)
if(j!=i)
{ x=i; y=j; st[1]=x; este=0; bt(1); este1=este;
x=j; y=I; st[1]=x, este=0; bt(1); este2=este;
if(este1 && este2 )
{ v[j]=i; cout<<j<<” “;} }
cout<<endl; } }
int main()
{ citeste(); componente(); }
Ex. 48. Algoritm pentru parcurgerea grafului turneu
int n,a[10][10],D[10];
void citeste(){//se citeste matricea de adiacenta}
void generare() { int i,j,k,m=2,gasit;
if (a[1][2]==1) { D[1]=1; D[2]=2; }
else { D[1]=2; D[2]=1; }
for (i=3;i<=n;i++)
{ if (a[1][D[1]]==1) k=1;
else { for (j=1, gasit=0; j<=n && !gasit; j++)
if (a[D[j]][i]==1 && a[i][D[j+1]]==1) gasit=1;
k=j+1; }
for (j=m+1;j>k;j–) D[j]=D[j-1]; D[k]=i; m++; } }
void afisare()
{ for (int i=1;i<=n;i++) cout<<D[i]<<" "; }
int main() { citeste(); generare(); afisare(); }
Ex. 49. Algoritm pentru parcurgerea unui graf hamiltonian
int a[20][20], n,k,as,ev,este=0, st[100];
void citeste(){//se citeste matricea de adiacenta}
void init(int k) { st[k]=0; }
int successor(int k)
{ if(st[k]<n) {st[k]=st[k]+1; return 1; }
else return 0;}
int valid(int k)
{ if(k>1 && a[st[k-1]][st[k]]==0) return 0;
for(inr i=1;i<k;i++) if(st[k]==st[i]) return 0;
return 1;}
int solutie(int k) { return a[st[k]][1]==1 && k==n; }
void tipar(int k)
{ for(int i=1,este=1;i<=n;i++)
cout<<st[i]<<” “;
cout<<st[1]<<endl; }
void bt(int k) { init(k);
while(k>1) { as=1; ev=0;
while (as && !ev)
{ as=succesor(k);
if(as) ev=valid(k))
if(solutie(k)) tipar(k);
else bt(k+1); }
int main()
{ citeste(); st[1]=1; bt(1);
if(!este) cout<<”graful nu este hamiltonian”; }
Ex. 50. Algoritm pentru parcurgerea unui graf eulerian
int n,a[20][20],vizitt[20],vf,k,m,g[20],k,c[20],c1[20],st[20];
void citeste(){//se citeste matricea de adiacenta}
void init(int k) { vf=1; st[vf]=k; vizitt[k]=1; }
int este_vida() { return vf==0; }
void adaug(int k) { vf++; st[vf]=k; vizitt[k]=1; }
void elimin() { vf–; }
void prelucrare()
{ int i=1; k=st[vf];
while(i<=n&&(a[i][k]==0 || (a[i][k]==1&&vizitt[i]==1)))
i++;
if(i==n+1) elimin();
else { k++; adaug(i); } }
int conex(){ k=1; init(k);
while(!este_vida()) prelucrare();
return (k==n); }
void grad()
{ for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]==1) { g[i]++; m++; }
m=m/2; }
int izolat()
{ for(int i=1;i<=n;i++)
if(g[i]==0) return 1;
return 0; }
int grad_par()
{ for(int i=1;i<=n;i++)
if(g[i]%2==1) return 0;
return 1; }
void ciclu()
{ int I,j,k=1,k,q,gasit;c[1]=1;
do{ for(j=1,gasit=0;j<=n && !gasit;j++)
if(a[c[k]][j]==1) { k=k+1; c[k]=j;
a[c[k-1]][j]=0; a[j][c[k-1]]=0; g[j]–;
g[c[k-1]]–; gasit=1; }
}while(c[k]!=1);
while(k-1<m)
{ for i=1,q=0;i<k=1 && q==0;i++)
if(g[c[i]]>0) { c[1]=c[i]; q=i; }
p=1;
do{ for(j=1, gasit=0; j<=n && !gasit; j++)
if(a[c1[p]][j]==1)
{ p=p+1; c1[p]=j; a[c1[p-1]][j]=0;
a[j][c1[p-1]]=0; g[j]–; g[c1[p-1]]–; gasit=1;}
}while(c1[p]!=c1[1]);
for(j=k;j>=q;j–) c[j+k-1]=c[j];
for(j=1;j<=k-1;j++) c[j+q]=c1[j+1];
k=k+p-1; } }
int main()
{ int eulerian; citeste(); grad();
eulerian=!(izolat()) && grad_par() && conex();
if(!eulerian) cout<<”graful nu este eulerian”<<endl;
else { cout<<”graful este eulerien”<<endl;
ciclu(); cout<<”ciclul eulerian este:”;
for(int i=1;i<=m+1;i++) cout<<c[i]<<” “; } }
Ex. 51. Algoritmul Roy-Warshall de determinare a matricei drumurilor
void citeste() { //se citeste matricea de adiacenta }
void transforma()
{ for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]==0&&i!=k&&j!=k) a[i][j]=a[i][k]*a[k][j]; }
void afiseaza()
{cout<<”Exista drum intre perechile de noduri “<<endl;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]==1&&i!=j) cout<<”(“<<i<<”,”<<j<<”)”<<” “; }
int main() { citeste(); transforma(); afiseaza(); }
Anexa 11. Arbori
Ex. 1. Se citeste un arbore cu n noduri dat prin vectorul de tați.
a) Să se afișeze gradele nodurilor.
b) Să se afișeze pentru fiecare vârf nivelul pe care se află (numerotarea nivelelor începe de la 0-rădăcina).
c) Să se afișeze frunzele arborelui.
d) Să se afișeze muchiile arborelui
e) Să se construiască și să se afișeze matricea de adiacență a arborelui.
Exemplu: Pentru vectorul de tați 2 0 2 1 3 se va afișa:
Gradele: 2 2 2 1 1
Nivelele: 1 0 1 2 2
Frunzele: 4 si 5.
Muchiile: [1,2] [2,3] [1,4] [3,5]
Matricea de adiacență:
0 1 0 1 0
1 0 1 0 0
0 1 0 0 1
1 0 0 0 0
0 0 1 0 0
int n,r,tata[100],grad[100]={0},f[100]={0},niv[100];
int ok[i]={0},a[10][10];
void citire()
{ cout<<"n="; cin>>n;
for(int i=1;i<=n;i++)
cin>>tata[i]; }
void gradul()
{ for(int i=1;i<=n;i++)
if(tata[i]!=0) //daca nu e radacina se socoteste
{ grad[i]++; //la grad si predecesorul
grad[tata[i]]++; } }
void afis_grad_niv()
{ for(int i=1;i<=n;i++)
cout<<grad[i]<<" ";
cout<<endl;
for(i=1;i<=n;i++)
cout<<niv[i]<<" "; }
void muchii()
{ for(int i=1;i<=n;i++)
if(tata[i]!=0) cout<<"["<<tata[i]<<","<<i<<"] "; }
void afis_matrice()
{ for(int i=1;i<=n;i++)
if(tata[i]!=0) a[i][tata[i]]=a[tata[i]][i]=1;
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl; } }
void frunze()
{ for(int i=1;i<=n;i++)
f[tata[i]]=1; // nodurile care apar in vectorul tata
for(int i=1;i<=n;i++)
if(f[i]==0) cout<<i<<" "; }
void df(int r)
{ for(int i=1;i<=n;i++)
if(tata[i]==r && ok[i]==0)
{ ok[i]=1; //s-a gasit nivelul nodului i
niv[i]=niv[r]+1;
df(i); } }
int main()
{ for(int i=1;i<=n;i++) //se cauta radacina arborelui
if(tata[i]==0) r=i; //in vectorul de tati
niv[r]=0;
df(r); gradul();
afis_grad_nivel();
cout<<endl;
afis_matrice();
frunze(); }
Ex. 2. Se dă o expresie aritmetică în forma poloneză prefixată. Expresia este formată din operatorii + – / * %, iar operanzii sunt litere mici. Afișați expresia în forma normală (infixată) și în forma postfixată.
char op[]="+-*/%";
struct nod{ char info;
nod *st, *dr; }*r;
void citire(nod* &r)
{ char x;
cin>>x;
if(strchr(op,x)==NULL)
{ r=new nod;
r->info=x;
r->st=NULL;
r->dr=NULL; }
else
{ r=new nod;
r->info=x;
read(r->st);
read(r->dr); } }
void SRD(nod *r)
{ if(strchr(op,r->info)) cout<<"(";
if(r->st!=NULL) SRD(r->st);
cout<<r->info;
if(r->dr!=NULL) SRD(r->dr);
if(strchr(op,r->info)) cout<<")"; }
void SDR(nod *r)
{ if(r->st!=NULL) SDR(r->st);
if(r->dr!=NULL) SDR(r->dr);
cout<<r->info; }
int main()
{ citire(r); SRD(r); cout<<endl; SDR(r); }
Ex.3. Se dă un arbore cu rădăcină cu n vârfuri (n<=100) prin vectorul de tați. Să se determine dacă este arbore binar și, în caz afirmativ, să se afișeze vectorii st și dr (considerăm fiul stâng < fiul drept), dacă raspunsul este negativ, să se determine dacă prin schimbarea rădăcinii, arborele poate deveni binar.
int n,tata[101],fii[101],st[101],dr[101],grad[101];
int main()
{ cin>>n;
for(int i=1;i<=n;i++)
{ cin>>tata[i];
fii[tata[i]]++;
int ok=1; // daca cel putin un nod are mai
for(int i=1;i<=n;i++) // mult de 2 fii, nu e arbore binar
if(fii[i]>2) ok=0;
if(ok)
{ cout<<"DA"<<endl;
for(int i=1;i<=n;i++)
if(tata[i]!=0)
{ if(st[tata[i]]==0) st[tata[i]]=i;
else dr[tata[i]]=i; }
for(int i=1;i<=n;i++)
cout<<st[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++)
cout<<dr[i]<< " "; }
else
{ cout<<"NU "<<endl;
ok=1; //daca orice alt nod in afara de
for(int i=1;i<=n;i++) //radacina are cel putin trei fii,
if(fii[i]>=3) ok=0; //atunci nu se poate
if(ok) cout<<"DA";
else cout<<"NU"; } }
Ex.4. Se dau numerele n, p și q unde n este numărul de noduri ale unui arbore, iar p și q sunt noduri din arbore. Apoi se citește vectorul de tați prin care este reprezentat arborele. Afișați lanțul elementar de la nodul p la nodul q.
int n, tata[101],p,q;
void schimba(int r)
{ if(tata[r]!=0)
{ schimba(tata[r]);
tata[tata[r]]=r; } }
void drum(int v)
{ if(v!=0)
{ drum(t[v]);
cout<<v<<" "; } }
int main()
{ cin>>n>>p>>q;
for(int i=1;i<=n;i++)
cin>>tata[i];
schimba(p);
tata[p]=0;
drum(q); }
Ex. 5. Se dă un arbore binar cu n noduri (cel mult 1000) prin vectorii st și dr (pentru fiecare nod se precizează fiul stâng și apoi cel drept). Să se calculeze și să se afișeze numărul de nivele ale arborelui și apoi câte noduri se află pe fiecare nivel.
int niv[1001],n, st[1001], dr[1001],pr[1001]={0},r=0;
void nivel(int k, int x)
{ if(k!=0)
{ niv[k]=x;
nivel(st[k],x+1);
nivel(dr[k],x+1); } }
int main()
{ cin>>n;
for(int i=1;i<=n;i++)
{ cin>>st[i]>>dr[i];
pr[st[i]]=1; pr[dr[i]]=1; } //pt radacina
for(int i=1;i<=n;i++)
if(pr[i]==0) r=i;
nivel(r,0);
int nivmax=0;
for(int i=1;i<=n;i++)
if(nivele[i]>nivmax) nivmax=nivele[i];
cout<<nivmax+1<<endl;
for(int niv=0;niv<=nivmax;niv++)
{ int k=0;
for(int j=1;j<=n;j++)
if(nivele[j]==niv) k++;
cout<<k<<" "; } }
Ex. 6. Se dăun arbore cu n vârfuri prin vectorul tata. Afișați care dintre vârfurile arborelui por fi alese ca rădăcină a acestuia astfel încât arborele să aibă înălțime minimă.
int n,t[100];
void citire()
{ cin>>n;
for(int i=1;i<=n;i++)
cin>>t[i]; }
void f(int k)
{ if(t[k]) f(t[k]);
t[t[k]]=k; }
int inaltime()
{ int i,j,h,maxx=0;
for(i=1;i<=n;i++)
{ h=0; j=i;
while(t[j])
{ h++; j=t[j]; }
if(h>maxx) maxx=h; }
return maxx; }
int main()
{ int h[100],k,minn=n;
citire();
for(k=1;k<=n;k++)
{ f(k); t[k]=0;
h[k]=inaltime();
if(h[k]<minn) minn=h[k]; }
for(k=1;k<=n;k++)
if(h[k]==minn) cout<<k<<" "; }
Ex. 7. Se dă un arbore cu n vnoduri având muchiile etichetate cu costuri numere naturale. Calculați costul între oricare două noduri ale arborelui.
int c[100][100],n;
void citire()
{ int i,j,x,y,cost;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j) c[i][j]=0;
else c[i][j]=1000;
for(i=1;i<n;i++)
{ cin>>x>>y>>cost;
c[y][x]=c[x][y]=cost; } }
void rf()
{ for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(c[i][j]>c[i][k]+c[k][j])
c[i][j]=c[i][k]+c[k][j]; }
void afis()
{ for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
cout<<c[i][j]<<" ";
cout<<endl; } }
int main()
{ citire(); rf(); afis(); }
Ex. 8. Arborele parțial de cost minim (cu algoritmul lui Prim).
const int inf=-1000;
int n,m,A[100][100],P[100];
void citire()
{ int i,j,k,c;
cin>>n>>m;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
A[i][j]=A[j][i]=inf;
for(int k=1;k<=m;k++)
{ cin>>i>>j>>c;
A[i][j]=A[j][i]=c; } }
int main()
{ int i,j,k,minn,x,y;
citire(); P[1]=1;
for(k=1;k<n;k++)
{ minn=inf;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(P[i]&&!P[j]&& a[i][j]<minn)
{ minn=A[i][j];
x=i;y=j; }
cout<<x<<""<<y<<" ";
cout<<A[x][y]<<endl;
P[y]=1; } }
Ex.9. Arbore parțial de cost minim (cu algoritmul lui Kruskal).
struct muchie
{ int x,y,c; } v[100];
int n,m,a[100][100],p[100],k;
void citire()
{ cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>v[i].x>>v[i].y>>v[i].c; }
void colorare(int r,int cul)
{ int s,d,i,x[100];
s=d=1; x[1]=r; p[r]=1;
while(s<=d)
{ for(int i=1;i<=n;i++)
if(p[i]!=cul && a[x[s]][i])
{ d++; x[d]=i; p[i]=cul; }
s++; } }
void ordonare()
{ muchie aux;
for(int i=1;i<m;i++)
for(int j=i+1;j<=m;j++)
if(v[i].c>v[j].c)
{ aux=v[i];
v[i]=v[j];
v[j]=aux; } }
int main()
{ citire();
for(int i=1;i<=n;i++)
p[i]=i;
ordonare();
k=0; int i=1;
while(k<n-1)
{ if(p[v[i].x]!=p[v[i].y])
{ cout<<v[i].x<<" "<<v[i].y<<" "<<v[i].c<<endl;
a[v[i].x][v[i].y]=a[v[i].y][v[i].x]=1;
if(p[v[i].x]<p[v[i].y]) colorare(v[i].y,p[V[i].x]);
else colorare(v[i].x,p[v[i].y]);
k++; }
i++; } }
Ex.10. Crearea unui arbore binar. Se verifică dacă este identic în oglindă, dacă doi arbori sunt identici ca structura, se afișează numărul de frunze, suma numerelor din frunze, suma nodurilor de pe același nivel, se verifică dacă există un număr în arbore sau dacă este descendent direct de stânga sau dreapta.
#include <iostream>
#include <fstream>
using namespace std;
struct nod { int info;
nod *st, *dr; };
ifstream f("date.in");
int inf, ct, sem;
nod *r, *r1;
void creare(nod *&q)
{ f >> inf;
if(inf!=0)
{ q=new nod();
q->info=inf;
q->st=q->dr=0;
creare(q->st);
creare(q->dr); } }
void RSD(nod *r)
{ cout << r->info << " ";
if(r->st) RSD(r->st);
if(r->dr) RSD(r->dr); }
void creare_oglinda(nod *p, nod *&q)
{ if(p)
{ q=new nod();
q->info=p->info;
q->st=q->dr=0;
creare_oglinda(p->st, q->dr);
creare_oglinda(p->dr, q->st); } }
//identici ca structura, ca schelet
int identici(nod *p, nod*q)
{ if(!p) return q==0;
if(!q) return p==0;
return identici(p->st, q->st)*identici(p->dr, q->dr); }
void RSD_gasire(nod *r, int k)
{ ct++;
if(ct!=k)
{ if(r->st) RSD_gasire(r->st, k);
if(r->dr) RSD_gasire(r->dr, k); }
else cout << r->info; }
void nod_nivel(nod *r, int nivel, int i)
{ if(i==nivel)
cout << r->info << " ";
else
{ if(r->st) nod_nivel(r->st, nivel, i+1);
if(r->dr) nod_nivel(r->dr, nivel, i+1); } }
//numarul de frunze
int nr_frunze(nod *r)
{ if(r==0) return 0;
else
if(r->st==0 && r->dr==0) return 1;
else return nr_frunze(r->st)+nr_frunze(r->dr); }
//suma numerelor din frunze
int s_frunze(nod *r)
{ if(r==0) return 0;
else
if(r->st==0 && r->dr==0) return r->info;
else return s_frunze(r->st)+s_frunze(r->dr); }
//suma nodurilor de pe acelasi nivel
int suma_nod_nivel(nod *r, int nivel, int i)
{ if(r==0) return 0;
else
if(i==nivel) return r->info;
else return suma_nod_nivel(r->st, nivel, i+1)+ suma_nod_nivel(r->dr, nivel, i+1); }
//daca exista un numar in arbore
int exista(nod *r, int x)
{ if(r==0) return 0;
else
if(r->info==x) return 1;
else return exista(r->st,x) || exista(r->dr,x); }
void descendent_direct(nod *r, int v, int w)
{ if(r)
{ if(r->info==v)
{ sem=1;
if(r->st && r->st->info==w)
{ cout << "Este descendent pe stanga ";
return; }
else
if(r->dr && r->dr->info==w)
{ cout << "Este descendent pe dreapta ";
return; }
else
{ cout << "Nu este descendent direct";
return; } }
else
{ if(r->st) descendent_direct(r->st, v, w);
if(r->dr) descendent_direct(r->dr, v, w); } } }
int main()
{ creare(r);
RSD(r); cout << endl;
creare_oglinda(r, r1);
RSD(r1); cout << endl;
if(identici(r, r1)==1)
cout << "Arborele este identic cu oglindirea sa";
else
cout << "Arborii nu este identic cu oglindirea sa ";
cout << endl;
int k; cout << "k= "; cin >> k;
RSD_gasire(r, k); cout << endl;
int niv; cout << "Nivelul= "; cin >> niv;
nod_nivel(r, niv, 0); cout << endl;
cout<<"suma: "<<suma_nod_nivel(r, niv, 0);
int v, w,x;
cout << "v= "; cin >> v;
cout << "w= "; cin >> w;
descendent_direct(r, v, w);
if(!sem) cout << "Nodul v nu exista in arbore ";
cout<<endl;
cout<<"nr de frunze"<<nr_frunze(r)<<endl;
cout<<"suma frunze"<<s_frunze(r)<<endl;
cout<<"x="; cin>>x;
if(exista(r,x)) cout<<"exista nodul x";
else cout<<"nu exista nodul x ";
return 0; }
Anexa 12. Documentație proiect recursivitate
Liceul Teoretic „Stephan Ludwig Roth”
Mediaș
Proiect
Recursivitatea
algoritmi elementari
Mediaș
2017Cuprins
Introducere 213
Motivarea lucrării 213
Definirea recursivității Error! Bookmark not defined.
Principiul de execuție al recursivității Error! Bookmark not defined.
Parametrii-valoare și parametrii-variabilă Error! Bookmark not defined.
Tehnica eliminării recursivității Error! Bookmark not defined.
Funcții recursive Error! Bookmark not defined.
Agoritmi recursivi elementari. Sume și produse. Funcții speciale Error! Bookmark not defined.
Lucrul cu divizorii unui număr Error! Bookmark not defined.
Lucrul cu cifrele unui număr Error! Bookmark not defined.
Algoritmi recursivi cu vectori Error! Bookmark not defined.
Algoritmi recursivi cu matrici Error! Bookmark not defined.
Explicarea programului Error! Bookmark not defined.
Concluzie Error! Bookmark not defined.
Anexă: Cod Sursă Error! Bookmark not defined.
Bibliografie Error! Bookmark not defined.
Introducere
Motivarea lucrării
Lucrarea are rol de material didactic pentru generațiile viitoare de elevi care vor studia informatica. Aplicația realizată poate fi folosită de către elevi pentru a înțelege mult mai bine noțiunea de recursivitate. Având în față teoria recursivitații precum si aplicația realizată în limbajul C/C++ elevii au șansa de a învăța și utiliza mai ușor aceasta noțiune. În lucrare este prezentat atât conceptul de recursivitate cât și câteva clase de algoritmi recursivi, pentru întelegerea si rutinarea acestei tehnici puternice de programare, ce permite scrierea unor soluții clare, concise și rapide, care pot fi usor înțelese și verificate.
Limbajul folosit
C este un limbaj de programare elaborat de Dennis M. Ritchie în 1972. A primit acest nume deoarece a urmat unui limbaj de programare numit B. Deși mulți îl consideră mai mult un limbaj de asamblare independent de mașină decît un limbaj de nivel înalt, legătura sa strânsă cu sistemul de operare UNIX, răspândirea de care se bucură și standardizarea sa de către ANSI (American National Standards Institute) au făcut ca el să se apropie cel mai mult, probabil, de obiectivul unui limbaj de programare standard pe piața microcalculatoarelor și a stațiilor de lucru. C este un limbaj compilat care conține un mic set de funcții încorporate, dependente de mașină. Celelalte funcții sunt independente de mașină și sunt incluse în librării accesibile din programe. Programele scrise în C sunt alcătuite din una sau mai multe funcții definite de programator; astfel, C este un limbaj de programare structurat.
C este un limbaj de programare popular, utilizat de multe ori pentru a scrie compilatoare și sisteme de operare. Aproape toate aplicațiile proiectate pentru a ușura comunicațiile pe Internet sunt scrise în C. Într-adevăr, atât sistemul de operare UNIX (care este structura de bază a Internetului) cât și TCP/IP (suita de protocoale folosită pentru transportul datelor pe Internet)au fost dezvoltate în C. Nu este nici o exagerare să spunem că, dacă limbajul C nu ar fi apărut, nu ar fi apărut nici Internetul, asa cum îl știm acum.Limbajul C are o legătură directă cu dezvoltarea Internetului.
Anexa 13. Figuri
Figura 1. Apelurile pentru calcularea termenului 10 al șirului lui Fibonacci 15
Figura 2. Mecanismul de funcționare al stivei 17
Figura 3. Mecanismul de funcționare al stivei pentru calcularea lui n! 18
Figura 4. Aplicație geometrică a șirului lui Fibonacci [45] 19
Figura 5. Mecanismul de funcționare a metodei Divide et Impera 26
Figura 6. Problema turnurilor din Hanoi 31
Figura 7. Transferul pentru 4 discuri [41] 32
Figura 8. Triunghiul lui Sierpinski [30] și curba lui Koch [47] 35
Figura 9. Reprezentarea pe stivă a celor șase soluții 38
Figura 10. Reprezentarea configurațiilor stivei 40
Figura 11. Exemplu de arbore 56
Figura 12. Exemplu de arbore binar 58
Figura 13. Medota ciorchinelui pentru reprezentarea noțiunilor privitoare la recursivitate 71
Figura 14. Documentație proiect recursivitate (Anexa 12) 74
Figura 15. Afișarea zilei și 101
Figura 16. Afișarea orei și a formulei de salut corespunzătoare 104
Figura 17. Exemplu de folosire a instrucțiunii FOR 104
Figura 18. Cronometrarea răspunsului elevilor 105
Figura 19. Exemplu de fereastră WEB 107
Figura 20. Adăugare link film youtube 108
Figura 21. Exemplu de obiect BUTTON 111
Figura 22. Butoane modificate 111
Figura 23. Căsuțe de informații 112
Figura 24. Evidențierea selecției căsuțelor de validare, utilizând JavaScript 113
Figura 25. Căsuțe de validare care folosesc atributul checked 113
Figura 26. Butoane radio 114
Figura 27. Mărire imagine când se trece cu mouse-ul pe deasupra ei 116
Figura 28. Animație 116
Figura 29. Organigrama site-ului 117
Figura 30. Pagina principală 118
Figura 31. ”Antetul” site-ului 119
Figura 32. Cadrul din stânga al site-ului 120
Figura 33. Cadrul din dreapta 121
Figura 34. Prezentare generală – pagina despre recursivitate 122
Figura 35. Meniu ascuns 123
Figura 36. Link pentru recapitularea noțiunilor despre funcții 123
Figura 37. Pagina pentru recapitulare 124
Figura 38. Declanșatorul și fereastra cu fișa noțiuni teoretice 124
Figura 39. Intrebări cu variante de răspuns – răspuns corect 125
Figura 40. Intrebări cu variante de răspuns – răspuns greșit 126
Figura 41. Fișa cu rezolvări ale problemelor 126
Figura 42. Fereste independente 127
Figura 43. Exemplu: parcurgerea pas cu pas pentru apelul suma(5). 128
Figura 44. Imagini care se derulează când mouse-ul este deaspura lor 129
Figura 45. Legătura spre pagina de test 129
Figura 46. Mesaj pentru introducere parolă greșită 130
Figura 47. Pagina de test 130
Figura 48. Prezentare generală – Divide et Impera 131
Figura 49. Parte a paginii cu exerciții 132
Figura 50. Meniu lateral și link pentru ”poveste” 133
Figura 51. Pagina cu ”povestea” 133
Figura 52. Continuarea paginii de lectură 134
Figura 53. Legătura spre pagina de test 135
Figura 54. Pagina de test de la metoda Divide et Impera 135
Figura 55. Prezentare generală – Metoda Backtracking 136
Figura 56. Partea de exerciții a paginii 137
Figura 57. Pagina cu testul pentru metoda backtracking 137
Figura 58. Prezentarea paginii – Fractali 138
Figura 59. Prezentare generală – Grafuri 139
Figura 60. Noțiuni teoretice 139
Figura 61. Exerciții 140
Figura 62. Mărire imagine, cronometru, 140
Figura 63. Butoane cu întrebări 141
Figura 64. Exerciții 143
Figura 65. Răspunsuri prin butoane radio 143
Figura 66. Răspunsuri prin casete de validare 144
Figura 67. Răspunsuri prin completarea 144
Figura 68. Răspunsuri date 145
Figura 69. Formular 145
Figura 70. Pagina de lucru 146
Figura 71. Pagina anunțuri 146
Figura 72. Pagina Logare 147
Figura 73. Pagina cu link-uri 147
Anexa 14. Tabele
Tabelul 1. Generalități ale metodelor tradiționale și a celor moderne 90
Tabelul 2. Învățarea, prezentată din prisma celor două tipuri de metode 91
Tabelul 3. Rolul și responsabilitățile elevilor 91
Tabelul 4. Rolul și responsabilitățile profesorului 92
Tabelul 5. Evaluarea elevilor, între tradițional și modern 95
Tabelul 6. Criterii de evaluare proiect [17] 75
Anexa 15. Exemple
Exemplul 1: Exemplu de recursivitate directă: Să se calculeze suma primelor n numere naturale. S=1+2+3+…+n, definită prin relațiile: S0=0; Sn= Sn-1 + n, pentru n>=1. 12
Exemplul 2: Exemplu de recursivitate indirectă: Să se calculeze termenii șirurilor (a) și (b) definite prin: a0=a, b0=b, (a,b>0), 13
Exemplul 3: Șirul lui Fibonacci. a) Aflarea termenului n. b) Aflarea primilor n termeni ai șirului lui Fibonacci. 14
Exemplul 4: Pentru un n dat, citit de la tastatură, să se calculeze n! 17
Exemplul 5: Să se calculeze suma numerelor impare mai mici sau egale cu n, folosind un subprogram recursiv. Dacă n=10, se va afișa 25 = 1+3+5+7+9. 20
Exemplul 6: Să se calculeze produsul K=1*4*7*10*…*3n-2, folosind un subprogram recursiv. Dacă n=4 se va afișa 280 = 1*4*7*10. 20
Exemplul 7: Dându-se două variabile n și k scrieți programul care calculează recursiv combinări de n luate câte k. Dacă n=4 și k=2 se va afișa 6, iar dacă n=7 și k=2 rezultatul este 21. 20
Exemplul 8: Funcția lui Ackermann este o funcție cu două argumente, definită prin următoarele 3 ecuații: 21
Exemplul 9: Pentru un număr dat x să se calculeze recursiv suma divizorilor lui. Pentru n=10 se va afișa 18 = 1+2+5+10 21
Exemplul 10: Pentru un număr dat x să se afișeze recursiv divizorii proprii. Pentru n=20 se va afișa 2 4 5 10. 21
Exemplul 11: Folosind o funcție recursivă să se verifice dacă un număr este prim. De exemplu pentru n 13 sau 23 se va afișa ”e prim”, iar dacă pentru n se citește valoarea 20 sau 135 se va afișa ”nu e prim”. 22
Exemplul 12: Să se creeze un număr cu cifre date de la tastatură. 22
Exemplul 13: Să se afle inversul unui număr dat. Dacă se citește pentru n valoarea 1234 se va afișa valoarea 4321. 23
Exemplul 14: Pentru un număr x citit de la tastaură, să se afle suma cifrelor lui. Dacă pentru x se citește valoarea 345 se va afișa 12. 23
Exemplul 15: Se citește o valoare n și apoi n elemente. Se cere să se afișeze aceste valori. Citirea și afișarea vectorului se vor face folosind funcții recursive. Dacă se citește un număr X, să se calculeze nr de apariții ale lui X în vector. 23
Exemplul 16: Se citesc două numere n și m, apoi n*m elemente. Se cere să se afișeze aceste valori sub formă de matrice, câte m elemente pe n linii. Citirea și afișarea matricii se vor face folosind funcții recursive. Să se calculeze apoi suma elementelor din matrice. 24
Exemplul 17: Să se determine suma elementelor unui vector de întregi utilizând metoda Divide et Impera. 25
Exemplul 18: Să se calculeze simultan suma și produs elementelor dintr-un vector 27
Exemplul 19: Să se caute, într-un șir de numere ordonate strict crescător poziția în care se găsește o valoare dată x. Dacă valoarea nu se găsește să se afișeze un mesaj. 27
Exemplul 20: Sortarea prin interclasare (MergeSort) 28
Exemplul 21: Sortarea rapida (QuickSort) 30
Exemplul 22: Problema turnurilor din Hanoi: se mută n discuri de pe tija a pe tija b folosind tija c ca și tijă intermediară. 33
Exemplul 23: Modele fractale, curba lui Koch 35
Exemplul 24: Să se genereze permutările de n elemente. 36
Exemplul 25: Implementarea algoritmului Roy-Floyd 51
Exemplul 26: Implementarea algoritmului Dijkstra 52
Exemplul 27: Parcurgerea în lățime (BF – Breadth First): se vizitează mai întâi un nod inițial, apoi vecinii acestuia, apoi vecinii nevizitați ai acestora etc. 54
Exemplul 28: Parcurgerea în adâncime (DF – Depth First): se vizitează mai întâi un nod i după care se trece la primul vecin nevizitat j al lui i, apoi se trece la primul vecin nevizitat al lui j etc până când se parcurge în adâncime ramura apoi se revine la nodul de la care s-a plecat ultima dată și se trece la următorul vecin. 54
Exemplul 29: Se citește un număr natural n. Construiți un arbore cu proprietatea că fiecare nod are numărul de descendenți direcți cu 1 mai mare decât nivelul pe care se află. Excepție fac frunzele și nodul pentru care se termină cele n noduri. Afișați vectorul de tați. 57
Exemplul 30: Se dă un arbore binar cu n noduri prin vectorii de descendenți st și dr. Afișați frunzele arborelui, nodurile cu un singur descendent direct, nodurile cu doi descendenți direcți. 58
Exemplul 31: Se dă un arbore binar cu n noduri prin vectorii T și P (reprezentarea cu legături ascendente de tip tată și respectiv poziția fiilor: -1 pentru stânga, 1 pentru dreapta). Afișați vectorii de descendenți st și dr. 59
Exemplul 32. Implementarea dinamică a arborilor și parcurgerea lor în inordine, preordine și postordine 60
BIBLIOGRAFIE
[01] Acu C. I. (2003) Optimizarea paginilor Web, Iași: Polirom
[02] Buraga S. (2007) Programare în Web 2.0, Iași: Polirom
[03] Cerchez, E., Șerban, M. (2005) Programarea în limbajul C/C++ pentru liceu: metode și tehnici de programare, Iași: Polirom
[04] Cerghit, I. (2002) Sisteme de instruire alternative și complementare. Structuri, stiluri și strategii. București: Aramis
[05] Crețu D. (2015) Metodologia cercetării educaționale, Sibiu: Univ “Lucian Blaga”
[06] Cucoș C. (2006) Pedagogie. Ediția a II-a. – Iași: Polirom
[07] Cucoș, C, (2008) Teoria și metodologia evaluării, Iași: Polirom
[08] Eurocor – Institutul European de Cursuri prin Corespondență,Web Design, București
[09] Ionescu, M., Chis, V. (2001) Pedagogie. Suporturi pentru formarea profesorilor, Cluj Napoca: Presa Universității Clujeana
[10] Iordan V. (2007) Algoritmi și programare în C, Timișoara: Eurostampa
[11] Livovschi L., Georgescu H. (1986) Sinteza și analiza algoritmilor, București: Științifică și Enciclopedică
[12] Masalagiu C., Asiminoaei I., Maxim I. (2001) Metodica predării informaticii, București: Matrix Rom
[13] Mateescu G. D., Moraru, K. F. (2006) Informatica pentru liceu și bacalaureat, Sibiu: Donaris
[14] Miloșescu M. (2006) Manual informatică pentru clasa a XI-a, București: Didactică și Pedagogică
[15] Miloșescu M. (2015) Manual informatică pentru clasa a X-a, București: Didactică și Pedagogică
[16] Niculescu F. R. (2007) Proiectarea Paginilor Web – HTML, CSS, JavaScript, București: România de Mâine
[17] Păcurari, O., Târcă, A., Sarivan, L. (2003) Strategii didactice inovative. Suport de curs, București: Sigma
[18] Pop I. (2006) Tehnologii WEB, Sibiu: Univ, ”Lucian Blaga”
[19] Radu, I.T. (2000) Evaluarea în procesul didactic, București: DK
[20] Scheau I. (2014) Filosofia educației, Cluj Napoca: Eikon
[21] Scheau,I. (2004.) Gândirea critică-metode active de predare-invățare Cluj-Napoca: Dacia Educational
[22] Simian D. (2004) Algoritmi fundamentali și tehnici de programare, Sibiu: Universitatea “Lucian Blaga”
[23] Simian D., Bercea C., (2015) Tendințe noi în predarea informaticii la nivel liceal: metoda diagonalei, Sibiu: Universitatea “Lucian Blaga”
[24] Sorin T. (2009) Manual de informatica clasa aX-a (Tehnici de programare) – PASCAL si C++, București: L&S INFO-MAT
[25] Steele J.L., Meredith K.S., Temple C., (1998) Lectura și scrierea pentru dezvoltarea gândirii critice, vol. I. ClujNapoca: Casa de Editură și Tipografia Gloria
[26] Stoica, A. (2001) Evaluarea curentă și examenele. Ghid pentru profesori. București: ProGnosis
[27] Fibonacci, http://software.ucv.ro/~cstoica/ISP/Lucrarea%201%20-%20recursivi-tate.pdf, accesat la 29.04.2018
[28] Arbori, Nitchi S. (2014) http://www.cs.ubbcluj.ro/~gabitr/Cursul8.pdf, accesat la 6.05.2018
[29] Avramescu Ana Nicoleta, Platforma e-learning, http://www.elearning.ro/platforma-educationala-moodle-un-succes-in-e-learning, accesat la 29.04.2018
[30] Curba lui Kock, http://www.oxfordmathcenter.com/drupal7/node/417, accesat la 6.05.2018
[31] Divide et impera https://ro.wikipedia.org/wiki/Divide_et_impera, accesat la 29.04.2018
[32] Divide et impera, http://divideetimp.blogspot.ro/, accesat la 6.05.2018
[33] e-Learning, http://www.competente-it.ro/content/despre-e-learning-general%E2% 80%A6, accesat la 03.01. 2017
[34] Fractali http://ro.math.wikia.com/wiki/Fractal, accesat la 28.12. 2017
[35] Fractali, http://www.artacunoasterii.ro/curiozitati/fractali, accesat la 03.01.2018
[36] HTML pe înțelesul tuturor, Iordache L, 2011, http://www.ecursuri.ro/cursuri/html-pe-intelesul-tuturor.php, accesat la 28.12. 2017
[37] Ghid didactic pentru scrierea lucrării de gradul I, http://dppd.ulbsibiu.ro/obj/documents/Ghid_gradul_didactic_I.pdf, accesat la 6.05.2018
[38] Butoane, http://www.w3im.com/ro/css/tryit.php?filename=trycss_buttons_color, accesat 12.04.2018
[39] Despre platforme e-learning, https://www.moodle.ro/preparandia/images/docs/ DrugCrina.pdf, accesat la 28.12. 2017
[40] Informatica în viața noastră, Slavu M., 2015, http://informaticaazi.blogspot.ro/, accesat la 03.01.2017
[41] Problema turnurilor din Hanoi, http://www.anulmatematicii.ro/ articol/turnul-din-hanoi, accesat la 28.12. 2017
[42] Problema turnurilor din Hanoi, https://infoalgoritmi.wikispaces.com/Turnurile+ din+Hanoi, accesat la 28.12.2017
[43] Recursivitate, https://ro.wikipedia.org/wiki/Recursivitate, accesat la 3.01.2018
[44] Recursivitatea în fizică, muzică, literatură, http://nemiram.ro/recursivitate/, accesat la 3.01. 2018
[45] Religie, plante, planete https://matematicasiteologie.wordpress.com/2012/09/19/ sirul-lui-fibonacci-una-din-cheile-de-acces-la-codul-sursa-al-creatiei-lui-dumnezeu/, accesat la 29.04.2018
[46] Studiu comparativ între metodele tradiționale și moderne utilizate în procesul de predare-învățare, https://edict.ro/studiu-comparativ-intre-metodele-traditionale-si-moderne-utilizate-in-procesul-de-predare-invatare/, accesat la 6.05.2018
[47] Triunghiul lui Sierpinski, http://www.cplusplus.com/articles/LyTbqMoL/, accesat la 6.05.2018
[48] Variabile tablou http://www.marplo.net/javascript/obiectejs1.html, accesat la 28.12. 2017
CUPRINS
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Calculatorul, considerat de mulți cea mai mare invenție a secolului al XX-lea, influențează într-un mod sau altul viețile noastre. Este folosit… [308711] (ID: 308711)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
