Documente Academic
Documente Profesional
Documente Cultură
i februarie 2014
Specializarea Matematic-Informatic
Tematica general:
Algoritmic i programare.
1
Cuprins
ALGORITMIC I PROGRAMARE..................................................................................3
1. CUTRI I SORTRI..................................................................................................... 3
1.1. CUTRI............................................................................................................................ 3
1.1.1. Cutare secvenial................................................................................................ 3
1.1.2. Cutare binar........................................................................................................4
1.2. SORTRI.............................................................................................................................5
1.2.1. Sortare prin selecie................................................................................................6
1.2.2. Bubble sort..............................................................................................................6
1.2.3. Quicksort.................................................................................................................7
2. METODELE BACKTRACKING I DIVIDE ET IMPERA.......................................... 8
2.1. METODA BACKTRACKING.......................................................................................................8
2.2. METODA "DIVIDE ET IMPERA"..............................................................................................12
3. ALGORITMI I SPECIFICRI......................................................................................13
3.1. SCRIEREA UNUI ALGORITM PORNIND DE LA O SPECIFICAIE DAT................................................13
4. CONCEPTE OOP N LIMBAJE DE PROGRAMARE................................................ 17
4.1. NOIUNEA DE CLAS.......................................................................................................... 17
4.1.1. Realizarea proteciei datelor prin metoda programrii modulare.......................17
4.1.2. Tipuri abstracte de date........................................................................................18
4.1.3. Declararea claselor.............................................................................................. 19
4.1.4. Membrii unei clase. Pointerul this........................................................................21
4.1.5. Constructorul........................................................................................................ 21
4.1.6. Destructorul.......................................................................................................... 25
5. PROBLEME PROPUSE................................................................................................... 26
6. BIBLIOGRAFIE GENERAL........................................................................................ 27
2
Algoritmic i programare
1. Cutri i sortri
1.1. Cutri
Datele se afl n memoria intern, ntr-un ir de articole. Vom cuta un articol dup un
cmp al acestuia pe care l vom considera cheie de cutare. n urma procesului de cutare va
rezulta poziia elementului cutat (dac acesta exist).
Notnd cu k1, k2, ...., kn cheile corespunztoare articolelor i cu a cheia pe care o cutm,
problema revine la a gsi (dac exist) poziia p cu proprietatea a = kp.
De obicei articolele sunt pstrate n ordinea cresctoare a cheilor, deci vom presupune c
Uneori este util s aflm nu numai dac exist un articol cu cheia dorit ci i s gsim n caz
contrar locul n care ar trebui inserat un nou articol avnd cheia specificat, astfel nct s se
pstreze ordinea existent.
Deci problema cutrii are urmtoarea specificare:
O prim metod este cutarea secvenial, n care sunt examinate succesiv toate cheile.
Sunt deosebite trei cazuri: ak1, a>kn, respectiv k1 < a kn, cutarea avnd loc n al treilea caz.
3
sfdac
sf-CautSecv
Se observ c prin aceast metod se vor executa n cel mai nefavorabil caz n-1
comparri, ntruct contorul i va lua toate valorile de la 2 la n. Cele n chei mpart axa real n
n+1 intervale. Tot attea comparri se vor efectua n n-1 din cele n+1 intervale n care se poate
afla cheia cutat, deci complexitatea medie are acelai ordin de mrime ca i complexitatea n
cel mai ru caz.
Evident c n multe situaii acest algoritm face calcule inutile. Atunci cnd a fost deja
gsit cheia dorit este inutil a parcurge ciclul pentru celelalte valori ale lui i. Cu alte cuvinte
este posibil s nlocuim ciclul PENTRU cu un ciclu CTTIMP. Ajungem la un al doilea
algoritm, dat n continuare.
n cel mai ru caz i acest algoritm face acelai numr de operaii ca i subalgoritmul
Cautsecv. n medie numrul operaiilor este jumtate din numrul mediu de operaii efecuat de
subalgoritmul Cautsecv deci complexitatea este aceeai.
O alt metod, numit cutare binar, care este mult mai eficient, utilizeaz tehnica
"divide et impera" privitor la date. Se determin n ce relaie se afl cheia articolului aflat n
mijlocul coleciei cu cheia de cutare. n urma acestei verificri cutarea se continu doar ntr-o
jumtate a coleciei. n acest mod, prin njumtiri succesive se micoreaz volumul coleciei
rmase pentru cutare. Cutarea binar se poate realiza practic prin apelul funciei
BinarySearch(a, n, K, 1, n), descris mai jos, folosit n subalgoritmul dat n continuare.
4
Funcia BinarySearch(a, n, K, St, Dr) este:
Dac St Dr - 1
atunci BinarySearch := Dr
altfel m := (St+Dr) Div 2;
Dac a km
atunci BinarySearch := BinarySearch(a, n, K, St, m)
altfel BinarySearch := BinarySearch(a, n, K, m, Dr)
sfdac
sfdac
sf-BinarySearch
1.2. Sortri
Prin sortare intern vom nelege o rearanjare a unei colecii aflate n memoria intern
astfel nct cheile articolelor s fie ordonate cresctor (eventual descresctor).
Din punct de vedere al complexitii algoritmilor problema revine la ordonarea cheilor.
Deci specificarea problemei de sortare intern este urmtoarea:
5
1.2.1. Sortare prin selecie
Metoda "BubbleSort", compar dou cte dou elemente consecutive iar n cazul n care
acestea nu se afl n relaia dorit, ele vor fi interschimbate. Procesul de comparare se va ncheia
n momentul n care toate perechile de elemente consecutive sunt n relaia de ordine dorit.
Acest algoritm execut n cel mai nefavorabil caz (n-1)+(n-2)+ ... +2+1 = n(n-1)/2
comparri, deci complexitatea lui este O(n2).
O variant optimizat a algoritmului "BubbleSort" este :
6
Subalgoritmul BubbleSort(n, K) este:
Fie s := 0
Repet
Fie kod := 0; {Ipoteza "este ordine"}
Pentru i := 2; n-s execut
Dac ki-1 > ki atunci
t := ki-1;
ki-1 := ki;
ki := t;
kod := 1 {N-a fost ordine!}
sfdac
sfpentru
s := s + 1
pncnd kod = 0 sfrep {Ordonare}
sf-BubbleSort
1.2.3. Quicksort
Procedura QuickSort(n, K, St, Dr) va realiza ordonarea subirului kSt, kSt+1, ...,
kDr. Acest subir va fi rearanjat astfel nct kSt s ocupe poziia lui final (cnd irul este
ordonat). Dac i este aceast poziie, irul va fi rearanjat astfel nct urmtoarea condiie s fie
ndeplinit:
Odat realizat acest lucru, n continuare va trebui doar s ordonm subirul kSt,
kSt+1, ... ,ki-1 prin apelul recursiv al procedurii QuickSort(n, K, St, i-1) i apoi
subirul ki+1, ...,kDr prin apelul QuickSort(n, K, i+1, Dr). Desigur ordonarea acestor
dou subiruri (prin apelul recursiv al procedurii) mai este necesar doar dac acestea conin cel
puin dou elemente.
Procedura QuickSort este prezentat n continuare :
7
Subalgoritmul QuickSort (n, K, St, Dr) este:
Fie i := St; j := Dr; a := ki;
Repet
Cttimp kj a i (i < j) execut j := j - 1 sfct
ki := kj;
Cttimp ki a i (i < j) execut i := i + 1 sfct
kj := ki ;
pncnd i = j sfrep
Fie ki := a;
Dac St < i-1 atunci Cheam QuickSort(n, K, St, i - 1) sfdac
Dac i+1 < Dr atunci Cheam QuickSort(n, K, i + 1, Dr) sfdac
sf-QuickSort
Complexitatea algoritmului prezentat este O(n2) n cel mai nefavorabil caz, dar
complexitatea medie este de ordinul O(nlog2n).
8
x1 1 2 3
x2 1 2 3 1 2 3 1 2 3
x3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
9
Start
x1 1 x1 n
... ...
...
xk+1 Cautare pe nivel Cautare cu succes:
pas in fata 1 n
...
xn
Figura 1.2. Spaiul soluiilor posibile pentru generarea permutrilor
Pentru a finisa acest algoritm trebuie s precizm elementele nestandard prezente. Astfel,
avem nevoie de funcia boolean
condiii-continuare(k, posibil, v)
funcie care verific dac vectorul promitor posibil[1..k-1] completat cu valoarea v conduce la
un vector promitor.
Apoi, pentru a iniializa cutarea la nivelul j avem nevoie de a alege un element fictiv din
mulimea Sj, activitate realizat de funcia
10
init(j)
care returneaz acest element fictiv, care are rolul de a indica faptul c din mulimea S nc nu s-
a ales nici un element, deci dup el urmeaz primul element propriu din aceast mulime. Pentru
a cuta o valoare pe nivelul j, n ipoteza c valoarea curent nu e bun, avem nevoie de funcia
boolean
urmtor(j, v, nou)
care este True dac poate alege o valoare din Sj care urmeaz dup valoarea v, valoare notat
prin nou i False n cazul n care nu mai exist alte valori n Sj, deci nu mai poate fi fcut
alegerea. Cu aceste notaii algoritmul devine:
11
sfct
conditii-continuare:=kod
sf-conditii
Observaii:
o mprirea se face pn cnd se obine o problem rezolvabil imediat.
o Subproblemele n care se descompune problema iniial trebuie s fie
independente. Dac subproblemele nu sunt independente, se aplic alte
metode de rezolvare.
o Tehnica admite i o implementare recursiv.
12
Metoda poate fi descris n felul urmtor:
mparte: Dac dimensiunea datelor este prea mare pentru a fi rezolvabil imediat,
mparte problema n una sau mai multe subprobleme independente (similare
problemei iniiale).
Stpnete: Folosete recursive aceeai metod pentru a rezolva subproblemele.
Combin: Combin soluiile subproblemelor pentru a obine soluia problemei
iniiale.
3. Algoritmi i specificri
Algoritmi i specificri. Scrierea unui algoritm pornind de la o specificaie dat. Se d un
algoritm; se cere rezultatul execuiei lui
Problema 1
Date nr;
Precondiia: nr, nr1
Rezultate l1,l2,...,ln;
nr
Postcondiia: n *, li = nr 1 i n, li l j i j ,1 i, j n , n este
li
maximal
13
Problema 2
Date n,L=(l1,l2,...,ln);
Precondiia: liR, i=1,n
Rezultate R=(r1,r2,...,rn);
Postcondiia: R este o permutare a lui L, r1 r2 ... rn.
Problema 3
Problema 4
Problema 5
Function Prim(p:Integer):Boolean;
Var d:Integer;
Begin
d:=2;
While (d<=Sqrt(p)) And (p Mod d>0) Do Inc(d);
Prim:= d> Sqrt(p)
End;
Var n,p1,p2:Integer;
Begin
14
Repeat
Write(' Dati n : '); Readln(n);
If n>0 Then
If Desc(n,p1,p2) Then Writeln(n:5,p1:7,p2:5)
Else Writeln(' Nu ex. desc.');
Until n=0;
End.
Problema 6
Function Acc(a,b:Integer):Boolean;
Var Ma, Mb:MultimeC;
Begin
Mc(a,Ma);
Mc(b,Mb);
15
Acc:= Ma=Mb
End;
Var X:Sir;
n:Byte;
Begin
ClrScr;
C__S__(X,n);
M__S__(X,n);
T__S__(X,n);
Readln
End.
Problema 7
Precizai ce realizeaz urmtorul program, apoi scriei programul Pascal pentru funcia
invers.
Program Str_Lit_Urm;
Uses Crt;
Function UrmL(l:Char):Char;
Begin
Case l Of
'Z': UrmL:='A';
'z': UrmL:='a';
Else UrmL:=Succ(l)
End
End;
Function ModC(c:Char):Char;
Begin
If UpCase(c) In ['A'..'Z'] Then ModC:=UrmL(c)
Else ModC:=c
End;
Function Modif(s:String):String;
Var i:Byte;
16
Begin
For i:=1 To Length(s) Do s[i]:=ModC(s[i]);
Modif:=s
End;
Var s:String;
Begin
ClrScr;
Writeln(' Dati randurile de codif.:');
Repeat
Readln(s);
Writeln(Modif(s))
Until s=''
End.
Obs. Presupunnd c acest program realizeaz o codificare a unui text, scriei programul care
realizeaz decodificarea!
#include <iostream>
17
d = d1;
e = new int[d];
for(int i = 0; i < d; i++)
e[i] = e1[i];
}
Observm c dei n programul principal se lucreaz cu doi vectori nu putem s-i folosim
mpreun, deci de exemplu modulul vector1.cpp nu poate fi extins astfel nct s realizeze i
adunarea a doi vectori. n vederea nlturrii acestui neajuns s-au introdus tipurile abstracte
de date.
18
Tipurile abstracte de date realizeaz o legtur mai strns ntre datele problemei i operaiile
(funciile) care se refer la aceste date. Declararea unui tip abstract de date este asemntoare
cu declararea unei structuri, care n afar de date mai cuprinde i declararea sau definirea
funciilor referitoare la acestea.
De exemplu n cazul vectorilor cu elemente numere ntregi putem declara tipul abstract:
struct vect {
int* e;
int d;
void init(int* e1, int d1);
void distr() { delete [] e; }
void lapatrat();
void afiseaza();
};
Funciile declarate sau definite n interiorul structurii vor fi numite funcii membru iar datele
date membru. Dac o funcie membru este definit n interiorul structurii (ca i funcia distr
din exemplul de mai sus), atunci ea se consider funcie inline. Dac o funcie membru se
definete n afara structurii, atunci numele funciei se va nlocui cu numele tipului abstract
urmat de operatorul de rezoluie (::) i numele funciei membru. Astfel funciile init, lapatrat
i afiseaza vor fi definite n modul urmtor:
void vect::lapatrat()
{
for(int i = 0; i < d; i++)
e[i] *= e[i];
}
void vect::afiseaza()
{
for(int i = 0; i < d; i++)
cout << e[i] << ' ';
cout << endl;
}
Dei prin metoda de mai sus s-a realizat o legtur ntre datele problemei i funciile
referitoare la aceste date, ele nu sunt protejate, deci pot fi accesate de orice funcie utilizator,
nu numai de funciile membru. Acest neajuns se poate nltura cu ajutorul claselor.
Un tip abstract de date clas se declar ca i o structur, dar cuvntul cheie struct se
nlocuiete cu class. Ca i n cazul structurilor referirea la tipul de dat clas se face cu
numele dup cuvntul cheie class (numele clasei). Protecia datelor se realizeaz cu
19
modificatorii de protecie: private, protected i public. Dup modificatorul de protecie se
pune caracterul :. Modificatorul private i protected reprezint date protejate, iar public date
neprotejate. Domeniul de valabilitate a modificatorilor de protecie este pn la urmtorul
modificator din interiorul clasei, modificatorul implicit fiind private. Menionm c i n
cazul structurilor putem s folosim modificatori de protecie, dar n acest caz modificatorul
implicit este public.
De exemplu clasa vector se poate declara n modul urmtor:
class vector {
int* e; //elementele vectorului
int d; //dimensiunea vectorului
public:
vector(int* e1, int d1);
~vector() { delete [] e; }
void lapatrat();
void afiseaza();
};
Se observ c datele membru e i d au fost declarate ca date de tip private (protejate), iar
funciile membru au fost declarate publice (neprotejate). Bineneles, o parte din datele
membru pot fi declarate publice, i unele funcii membru pot fi declarate protejate, dac
natura problemei cere acest lucru. n general, datele membru protejate pot fi accesate numai
de funciile membru ale clasei respective i eventual de alte funcii numite funcii prietene
(sau funcii friend).
O alt observaie important referitoare la exemplul de mai sus este c iniializarea datelor
membru i eliberarea zonei de memorie ocupat s-a fcut prin funcii membru specifice.
Datele declarate cu ajutorul tipului de dat clas se numesc obiectele clasei, sau simplu
obiecte. Ele se declar n mod obinuit n forma:
nume_clas list_de_obiecte;
vector v;
~vector() { delete [] e; }
este un destructor.
Tipurile abstracte de date de tip struct pot fi i ele considerate clase cu toate elementele
neprotejate. Constructorul de mai sus este declarat n interiorul clasei, dar nu este definit, iar
destructorul este definit n interiorul clasei. Rezult c destructorul este o funcie inline.
20
Definirea funciilor membru care sunt declarate, dar nu sunt definite n interiorul clasei se
face ca i n cazul tipurilor abstracte de date de tip struct, folosind operatorul de rezoluie.
Referirea la datele respectiv funciile membru ale claselor se face cu ajutorul operatorilor .
sau -> ca i n cazul referirii la elementele unei structuri. De exemplu, dac se declar:
vector v;
vector* p;
n interiorul funciilor membru ns referirea la datele respectiv funciile membru ale clasei se
face simplu prin numele acestora fr a fi nevoie de operatorul punct ( . ) sau sgeat ( -> ).
De fapt compilatorul genereaz automat un pointer special, pointerul this, la fiecare apel de
funcie membru, i folosete acest pointer pentru identificarea datelor i funciilor membru.
Pointerul this va fi declarat automat ca pointer ctre obiectul curent. n cazul exemplului de
mai sus pointerul this este adresa vectorului v respectiv adresa referit de pointerul p.
Dac n interiorul corpului funciei membru afiseaza se utilizeaz de exemplu data membru d,
atunci ea este interpretat de ctre compilator ca i this->d.
Pointerul this poate fi folosit i n mod explicit de ctre programator, dac natura problemei
necesit acest lucru.
4.1.5. Constructorul
21
class persoana {
char* nume;
char* prenume;
public:
persoana(); //constructor implicit
persoana(char* n, char* p); //constructor
persoana(const persoana& p1); //constructor de copiere
~persoana(); //destructor
void afiseaza();
};
Fiierul persoana.cpp:
#include <iostream>
#include <cstring>
#include "persoana.h"
persoana::persoana()
{
nume = new char[1];
*nume = 0;
prenume = new char[1];
*prenume = 0;
cout << "Apelarea constructorului implicit." << endl;
}
persoana::persoana(char* n, char* p)
{
nume = new char[strlen(n)+1];
prenume = new char[strlen(p)+1];
strcpy(nume, n);
strcpy(prenume, p);
cout << "Apelare constructor (nume, prenume).\n";
}
persoana::~persoana()
{
delete[] nume;
delete[] prenume;
}
void persoana::afiseaza()
{
cout << prenume << ' ' << nume << endl;
}
Fiierul persoanaTest.cpp:
22
#include "persoana.h"
int main() {
persoana A; //se apeleaza constructorul implicit
A.afiseaza();
persoana B("Stroustrup", "Bjarne");
B.afiseaza();
persoana *C = new persoana("Kernighan","Brian");
C->afiseaza();
delete C;
persoana D(B); //echivalent cu persoana D = B;
//se apeleaza constructorul de copire
D.afiseaza();
return 0;
}
class nume_clasa {
nume_clasa_1 ob_1;
nume_clasa_2 ob_2;
...
nume_clasa_n ob_n;
...
};
nume_clasa(lista_de_argumente):
ob_1(l_arg_1), ob_2(l_arg_2), ..., ob_n(l_arg_n)
Dac clasa conine date membru de tip obiect atunci se vor apela mai nti constructorii
datelor membru, iar dup aceea corpul de instruciuni al constructorului clasei respective.
23
Fiierul pereche.cpp:
#include <iostream>
#include "persoana.h"
class pereche {
persoana sot;
persoana sotie;
public:
pereche() //definitia constructorului implicit
{ //se vor apela constructorii impliciti
} //pentru obiectele sot si sotie
pereche(persoana& sotul, persoana& sotia);
pereche(char* nume_sot, char* prenume_sot,
char* nume_sotie, char* prenume_sotie):
sot(nume_sot, prenume_sot),
sotie(nume_sotie, prenume_sotie)
{
}
void afiseaza();
};
void pereche::afiseaza()
{
cout << "Sot: ";
sot.afiseaza();
cout << "Sotie: ";
sotie.afiseaza();
}
int main() {
persoana A("Pop", "Ion");
persoana B("Popa", "Ioana");
pereche AB(A, B);
AB.afiseaza();
pereche CD("C","C","D","D");
CD.afiseaza();
pereche EF;
EF.afiseaza();
return 0;
}
Observm c n cazul celui de al doilea constructor, parametrii formali sot i sotie au fost
declarai ca i referine la tipul persoana. Dac ar fi fost declarai ca parametri formali de tip
persoana, atunci n cazul declaraiei:
constructorul de copiere s-ar fi apelat de patru ori. n astfel de situaii se creeaz mai nti
obiecte temporale folosind constructorul de copiere (dou apeluri n cazul de fa), dup care
se execut constructorii datelor membru de tip obiect (nc dou apeluri).
24
4.1.6. Destructorul
Destructorul este funcia membru care se apeleaz n cazul distrugerii obiectului. Destructorul
obiectelor globale se apeleaz automat la sfritul funciei main ca parte a funciei exit. Deci,
nu este indicat folosirea funciei exit ntr-un destructor, pentru c acest lucru duce la un ciclu
infinit. Destructorul obiectelor locale se execut automat la terminarea blocului n care s-au
definit. n cazul obiectelor alocate dinamic, de obicei destructorul se apeleaz indirect prin
operatorul delete (obiectul trebuie s fi fost creat cu operatorul new). Exist i un mod
explicit de apelare a destructorului, n acest caz numele destructorului trebuie precedat de
numele clasei i operatorul de rezoluie.
Numele destructorului ncepe cu caracterul ~ dup care urmeaz numele clasei. Ca i n cazul
constructorului, destructorul nu returneaz o valoare i nu este permis nici folosirea
cuvntului cheie void. Apelarea destructorului n diferite situaii este ilustrat de urmtorul
exemplu. Fiierul destruct.cpp:
#include <iostream>
#include <cstring>
scrie::scrie(char* n)
{
nume = new char[strlen(n)+1];
strcpy(nume, n);
cout << "Am creat obiectul: " << nume << '\n';
}
scrie::~scrie()
{
cout << "Am distrus obiectul: " << nume << '\n';
delete nume;
}
void functie()
{
cout << "Apelare functie" << '\n';
scrie local("Local");
}
scrie global("Global");
int main() {
scrie* dinamic = new scrie("Dinamic");
functie();
cout << "Se continua programul principal" << '\n';
delete dinamic;
25
return 0;
}
5. Probleme propuse
1. Scriei un program ntr-unul din limbajele de programare C++, Java, C# care:
a. Definete o clas Student avnd:
un atribut nume de tip ir de caractere;
un atribut note coninnd un ir de note (numere ntregi),
constructori, accesori i o metod care calculeaz media notelor studentului.
b. Definete o funcie care primind un obiect de tip Student returneaz adevrat dac
toate notele elevului sunt >4.
c. Scriei specificaiile metodelor definite n clasa Student precum i a funciei de la
punctul b.
26
6. Bibliografie general
27