Cursuri ATP
Cursuri ATP
5 1
2 9
3
16
2
5 5
4
P3: selectează u1=3, L(3)=1, cea mai mică dintre w-distanţele calculate la P2
P4: S1={1,3}
P5: i=i+1=1 ≠ 4, reia P2
Pagină 1 din 77
calculată w-distanţa
D(1,v), eticheta lui v 0, -1 5, 1 1, 1 7, 2 21,2
P3: selectează u3=4, L(4)=7, cea mai mică dintre w-distanţele calculate la P2
P4: S3={1,3,2,4}
P5: i=i+1=3 ≠ 4, reia P2
P3: selectează u4=5, L(5)=12, cea mai mică dintre w-distanţele calculate la P2
P4: S3={1,3,2,4,5}
P5: i=i+1=4, stop.
Algoritmul calculează următoarele rezultate:
Drumurile de cost minim de la vârful 1 la fiecare dintre vârfurile grafului se stabilesc pe baza sistemului de
etichete astfel: drumul de la 1 la un vârf v este dat de: v1, eticheta lui v, v2 eticheta lui v1 …, până se ajunge la
eticheta 1. Astfel, v0 -drumurile de cost minim sunt:
până la 2: 2,1;
până la 3: 3,1;
până la 4: 4,2,1;
până la 5: 5,4,2,1.
//subprogram
//preia datele unui graf in forma tabelara din fisierul nume si obtine
//matricea ponderilor, unde MAX este valoarea cu semnificatie de infinit
//ultima linie a fisierului contine virful initial din algoritmul Dijkstra
Pagină 2 din 77
//subprogram
//functia pentru implementarea algoritmului Dijkstra - returneaza
//vectorul de etichete
//subprogram
//functia principala
void preia_graf(char *nume, float ***w, int *n, int *v0, float MAX)
{ int i,j,m,u,v; float p;
FILE *f=fopen(nume,"rt");
fscanf(f,"%i",n);
float **mw=(float **)malloc(*n*sizeof(float*));
for(i=0;i<*n;i++)
mw[i]=(float *)malloc(*n*sizeof(float));
fscanf(f,"%i",&m);
for(i=0;i<*n;i++)
for(j=0;j<*n;j++)
mw[i][j]=MAX;
for(i=0;i<m;i++)
{ fscanf(f,"%i",&u);
fscanf(f,"%i",&v);
fscanf(f,"%f",&p);
mw[u-1][v-1]=mw[v-1][u-1]=p; }
fscanf(f,"%i",v0);
fclose(f);
*w=mw;}
for(i=0;i<n;i++)
v_et[i].l=MAX;
v_et[v0-1].l=0;
prel=(int*)malloc(n*sizeof(int));
//vector cu proprietatea prel[i]=1 daca pentru virful i+1 a
Pagină 3 din 77
//fost deja determinat un drum de cost minim
//prel[i]=0 in caz contrar
for(i=0;i<n;i++)
prel[i]=0;
prel[v0-1]=1;
ui=v0;
for(nrit=0;nrit<n-1;nrit++)
{ lmin=MAX;
//sunt recalculate w-distantele de la virfurile v cu prel[v-1]=0 si este determinat vmin, //urmatorul virf cu
proprietatea ca pentru acesta a fost determinat un drum de cost minim,
// lmin
for(v=1;v<=n;v++)
{ if((prel[v-1]==0)&&(v_et[v-1].l>v_et[ui-1].l+w[v-1][ui-1]))
{ v_et[v-1].l=v_et[ui-1].l+w[v-1][ui-1];
v_et[v-1].vf=ui;
}
if((prel[v-1]==0)&&v_et[v-1].l<lmin)
{ lmin=v_et[v-1].l; vmin=v;
}
}
ui=vmin; prel[ui-1]=1;
}
free(prel); return v_et;
}
void main()
{ float **w,MAX=1000000; int n,v0,v,u,i;
char numef[20];
printf("Introduceti numele fisierului care contine graful:");
scanf("%s", numef);
preia_graf(numef,&w, &n, &v0, MAX);
eticheta *rez=Dijkstra(w,n,v0,MAX);
for(v=1;v<=n;v++)
if(v!=v0)
{ printf("Costul unui cel mai ieftin drum de la %i la %i este %8.3f",v,v0,rez[v-1].l);
printf("\n Un drum de cost minim: %i ",v);
u=v;
Pagină 4 din 77
while(rez[u-1].vf!=v0)
{ printf("%i ",rez[u-1].vf);
u=rez[u-1].vf;
}
printf("%i \n\n",v0);
}
free(rez);
for(i=0;i<n;i++) free(w[i]);
free(w);
}
Exemplu de execuție
În anumite aplicaţii este necesară exclusiv determinarea w-distanţelor D(v0,v), pentru toţi vV. În acest caz
algoritmul Roy-Floyd permite o rezolvare a acestei probleme mai simplu de implementat decât algoritmul
Dijkstra.
Pagină 5 din 77
Teste de autoevaluare
2. Fie graful ponderat,
1
2 1
2 9
3
1
12
1 5
4
Drumurile de cost minim de la vîrful 1 la fiecare dintre vîrfurile grafului se stabilesc pe baza sistemului de
etichete. Astfel, v0 -drumurile de cost minim sînt:
pînă la 2: 2,1;
pînă la 3: 3,1;
pînă la 4: 4,5,2,1;
pînă la 5: 5,2,1.
Fisierul [Link] trebuie sa se regaseasca in directorul proiectului.
Pagină 6 din 77
3. Fie graful,
1
5 1
2 9
3
16
2
5 5
4
Pagină 7 din 77
Arbori parțiali de cost minim: Kruskal, Prim
Atât în algoritmul lui Prim cât și în algoritmul lui Kruskal putem identifica elementele generale
specifice metodei Greedy astfel:
există o mulțime inițială 𝐴 din care se aleg elementele care vor compune soluția (𝐴 este
mulțimea muchiilor grafului);
fiecărui element al mulțimii 𝐴 îi este asociată o valoare numerică (ponderea muchiei);
mulțimea inițială se sortează crescător, în ordinea ponderilor asociate muchiilor;
din mulțimea 𝐴 se aleg, în ordine, primele 𝑚 ― 1 elemente care nu formează cicluri
(criteriul de alegere).
Pentru implementarea algoritmului Kruskal, graful conex ponderat este reprezentat sub formă
tabelară, muchiile fiind ordonate crescător după ponderi. Muchiile selectate de algoritm pot fi
8
menţinute de asemenea într-o structură tabelară, sau doar marcate ca fiind incluse în mulţimea de
muchii din arborele parţial minim a cărui construcţie este dorită. În varianta prezentată în
continuare muchiile selectate sunt afişate.
Calculul care realizează adăugarea unei noi muchii poate fi descris astfel:
- Este determinată o muchie de cost minim e=v1v2 care nu a fost selectată anterior;
- Dacă vârfurile v1 şi v2 nu aparţin aceluiaşi arbore, atunci proprietatea de aciclicitate este
îndeplinită şi muchia e este adăugată la structura curentă.
- Adăugarea muchiei e selectate este realizată prin reunirea arborilor din care fac parte v1 şi v2
de rădăcini r1, respectiv r2, astfel: dacă TATA[r1]<TATA[r2], atunci arborele rezultat prin
reunirea celor doi arbori are ca rădăcină vârful r1, iar vârful r2 devine fiu al lui r1. Altfel,
rădăcina arborelui rezultat prin reunire fiind r2, iar r1 devenind fiu al rădăcinii.
- Calculul se încheie după ce a fost adăugată şi cea de-a (n-1)-a muchie.
#include<stdio.h>
#include<conio.h>
void main()
{ int cost,i,j,nv,nm, a[100][3];
//graful este preluat de la tastatura
//datele citite:numarul de virfuri, numarul de muchii si tabela
//muchiilor in ordinea crescatoare a costurilor
printf("Numarul de virfuri:");scanf("%i",&nv);
printf("Numarul de muchii:");scanf("%i",&nm);
printf("Matricea de reprezentare\n");
for(i=0;i<nm;i++)
{ printf("Muchia %i si ponderea:",i+1);
for(j=0;j<3;j++)
scanf("%i",&a[i][j]);
}
for(i=0;i<nm;i++)
for(j=0;j<2;j++)a[i][j]--;
printf("Arborele de cost minim: \n");
cost=kruskall(a,nm,nv);
printf("\ncu costul %i",cost);
getch();
}
Exemplu de executie:
10
2. Algoritmul lui Prim: exemplu, explicații, implementare și exemplu de execuție
Exemplu:v0=4
Funcția care implementează algoritmul lui Prim primește matricea ponderilor (w), numărul de
vârfuri ale grafului (n), un vârf inițial (v0), adresa unde depune tabela muchiilor selectate (arb), o
valoare folosită pentru inițializare la căutarea muchiei cu cost minim (MAX). Prin numele
funcției se întoarce costul arborelui construit.
#include<stdio.h>
#include<conio.h>
11
#include<malloc.h>
void main()
{ int i,j,nv,nm,v,u, v0, **arb; float **w, MAX=1000000, cost,p;
//graful este preluat de la tastatura
//datele citite:numarul de virfuri, numarul de muchii si matricea ponderilor
printf("Numarul de virfuri:");scanf("%i",&nv);
printf("Numarul de muchii:");scanf("%i",&nm);
printf("Matricea ponderilor\n");
12
for(i=0;i<nv;i++)
for(j=0;j<nv;j++)
w[i][j]=MAX;
for(i=0;i<nm;i++)
{ printf("Muchia %i si ponderea:",i+1);
scanf("%i %i %f",&v, &u, &p);
w[u-1][v-1]=w[v-1][u-1]=p;
}
printf("Introduceti varful de pornire:");
scanf("%i", &v0);
cost=Prim(w,nv,v0,&arb,MAX);
printf("\nArborele partial de cost minim este:\n");
for(i=0;i<nv-1;i++)
printf("%i -> %i\n", arb[i][0],arb[i][1]);
printf(" cu costul %4.2f\n",cost);
getch();
}
13
Subprograme recursive. Metoda Divide et Impera - exemple
1. Să se scrie subprogramul recursiv care determină numărul de elemente negative dintr-un vector.
Se va scrie și programul apelator.
a) Metoda reducerii unei probleme de grad n la o problema de grad n-1 și o problema primitiva
(verificarea unui element din vector)
#include<stdio.h>
int numara(float v[], int n)
{ int nr;
if( n == 0) nr = 0;
else {
nr=numara(v,n-1);nr+=(v[n-1]<0)?1:0;
}
return nr;
}
void main()
{ int n,i, rez; float x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%f", &x[i]);}
rez=numara(x,n);
printf("numarul de elemente negative este %d ", rez);
}
b) Metoda descompunerii unei probleme în două subprobleme (doi vectori) cu rezolvare similară (până la
probleme primitive – cu rezolvare imediată, anume vectori cu un singur element)
#include<stdio.h>
int numara(float v[], int ls, int ld)
{ int nr;
if( ls==ld) nr = (v[ls]<0)?1:0;
else {
nr=numara(v,ls, (ls+ld)/2)+numara(v,(ls+ld)/2+1, ld);
}
return nr;
}
void main()
{ int n,i, rez; float x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%f", &x[i]);}
rez=numara(x,0, n-1);
14
printf("numarul de elemente negative este %d ", rez);
}
2. Să se scrie subprogramul recursiv care determină produsul scalar dintre doi vectori. Se va scrie și
programul apelator.
#include<stdio.h>
//metoda reducerii
float ps(float *x, float *y, int n)
{ float s;
if (n==0) s=0;
else s= ps(x,y,n-1)+x[n-1]*y[n-1];
return s;
}
//metoda de descompunere
float ps1(float *x, float *y, int ls, int ld)
{ float s;
if( ls==ld) s= x[ls]*y[ls];
else {
s=ps1(x,y,ls, (ls+ld)/2)+ps1(x,y,(ls+ld)/2+1, ld);
}
return s;
}
void main()
{ int n,i; float x[100], y[100], rez;
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%f", &x[i]);}
for(i=0;i<n;i++)
{printf("y[%d]=", i);scanf("%f", &y[i]);}
rez=ps(x,y,n);
printf("produsul scalar este %5.2f \n", rez);
rez=ps1(x,y,0, n-1);
printf("produsul scalar in varianta doi este %5.2f ", rez);
}
3. Să se scrie subprogramul recursiv care determină cmmdc dintre două numere naturale. Se va oferi
și un exemplu de apel.
#include<stdio.h>
15
int cmmdc_2(int a, int b)
{
int rez;
if (a%b==0) rez= b;
else rez= cmmdc_2(b,a%b);
return rez;
}
void main()
{
int a,b, cmmdc;
printf("a="); scanf("%d", &a);
printf("b="); scanf("%d", &b);
cmmdc=cmmdc_2(a,b);
printf("cmmdc=%d", cmmdc);
}
4. Să se scrie subprogramul recursiv care determină CMMDC dintr-un sir de numere naturale. Se va
oferi și un exemplu de apel.
#include<stdio.h>
unsigned int cmmdc_2(unsigned int a, unsigned int b)
{
unsigned int rez;
if (a%b==0) rez= b;
else rez= cmmdc_2(b,a%b);
return rez;
}
void main()
{
unsigned int x[100], cmmdc;
int n,i;
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%u", &x[i]);}
cmmdc=cmmdc_n(x,n);
printf("cmmdc=%u", cmmdc);
}
16
5. Să se scrie subprogramul recursiv care determină suma elementelor impare dintr-un vector. Se va
oferi un exemplu de apel.
#include<stdio.h>
//metoda reducerii
int suma(int *v, int n)
{ int s;
if (n==0) s=0;
else s= suma(v,n-1) + (v[n-1]%2==1)*v[n-1];
return s;
}
//metoda descompunerii
int suma2(int *v, int ls, int ld)
{ int s;
if (ls==ld) s=(v[ls]%2==1)*v[ls];
else s= suma2(v,ls, (ls+ld)/2) + suma2(v, (ls+ld)/2+1, ld);
return s;
}
void main()
{
int x[100], s;
int n,i;
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%d", &x[i]);}
s=suma(x,n);
printf("suma numerelor impare este=%d\n", s);
s=suma2(x,0,n-1);
printf("suma numerelor impare in varianta doi este=%d", s);
}
#include<stdio.h>
int produs(int n)
{
int rez;
if(n==1) rez=1;
else
rez=(2*n-1)*produs(n-1);
return rez;
}
void main()
{
17
int n;
printf("n="); scanf("%d", &n);
printf("produsul primelor %d numere impare=%d", n, produs(n));
}
7. Să se scrie subprogramul recursiv care determină suma cifrelor unui numar intreg.
#include<stdio.h>
int suma(int n)
{ int rez;
if(!n) rez=0;
else rez= n%10+suma(n/10);
return rez;
}
void main()
{
int n;
printf("n="); scanf("%d", &n);
printf("suma cifrelor este=%d", suma(n));
}
Problema turnurilor din Hanoi este următoarea: se dau trei tije verticale (fie ele 1, 2, 3), și un n discuri de
diametre diferite, cu o gaură în centru, prin care poate trece o tijă. În situația inițială toate discurile sînt
introduse pe tija 1. Regulile sînt următoarele: a) un disc mai mare nu poate fi pus peste un disc mai mic; la
o mutare se poate muta un singur disc de pe o tijă pe alta. Situația inițială respectă regula a), discurile fiind
așezate în ordine descrescătoare a diametrelor, de la bază spre vîrf. Se cere să se găsească o serie de
mutări, prin care toate discurile să fie mutate pe tija 3.
Subprogramul următor memorează mutările necesare într-o matrice cu două coloane, în care fiecare linie
descrie o mutare, elementul de pe prima coloană fiind tija sursă, cel de pe a doua coloană este tija
destinație. Această matrice și numărul de mutări (numărul de linii) constituie parametri de intrare/ieșire la
fiecare apel.
void main()
{
int i,n,mutari[100][2],nrm;
printf("numarul de discuri=");scanf("%d", &n);
nrm=0;
turnuri_hanoi(n,1,3,2,mutari,&nrm);
for(i=0;i<nrm;i++)
printf("%d, %d\n", mutari[i][0], mutari[i][1]);
}
9. Metoda bisectiei
Funcţia are ca parametri de intrare capetele intervalului în care se caută
soluţia (x0 şi x1), numărul maxim de iteraţii (n), precizia dorită (eps),
funcţia asociată ecuaţiei (f) şi adresa unde se va înscrie soluţia. Prin
numele funcţiei se returnează un cod de eroare cu următoarea semnificaţie: 0 –
nu s-a găsit soluţie datorită numărului prea mic de iteraţii sau preciziei
prea mari cerute; 1 – s-a obţinut soluţia exactă; 2 – s-a obţinut o soluţia
aproximativă; 3 – intervalul dat nu conţine nici o soluţie.
#include <stdio.h>
#include<math.h>
float f(float x)
{ return (pow(x,2)-5*pow(x,1)+6);
}
19
int bisectie(float x0,float x1,unsigned n,float eps,float (*f)(float),float
*sol)
{ int cod;
if ((*f)(x0)*(*f)(x1)>0) cod=3;
else if (n==0) cod=0;
else {*sol=(x0+x1)/2;
if((*f)(*sol)==0) cod=1;
else if(fabs(x0-x1)<=eps) cod=2;
else if((*f)(*sol)*(*f)(x0)<0)
cod=bisectie(x0,*sol,n-1,eps,f,sol);
else cod=bisectie(*sol,x1,n-1,eps,f,sol);
}
return cod;
}
int main()
{ float eps,x0,x1,x2;
int n;
printf("x0= ");
scanf("%f",&x0);
printf("x1= ");
scanf("%f",&x1);
printf("n= ");
scanf("%d",&n);
printf("epsilon= ");
scanf("%f",&eps);
int cod=bisectie(x0,x1,n,eps,f,&x2);
switch (cod)
{case 0:printf("Nu s-a gasit nici o solutie !"); break;
case 1:printf("Solutia exacta: %f",x2); break;
case 2:printf("Solutia aproximativa: %f",x2); break;
case 3:printf("Nu exista solutie in intervalul dat"); break;
}
return 0;
}
Temă:
1. Să se scrie subprogramul recursiv care determină un număr la o putere (xn), precum și programul
apelator.
2. Să se scrie subprogramul recursiv care calculează valoarea unui polinom într-un punct dat, precum
și programul apelator.
3. Scrieți un subprogram recursiv care calculează (aranjamente de n luate cîte k), precum
și programul apelator.
4. Să se scrie subprogramul recursiv care determină rezultatul ridicării unei matrice la o putere data,
precum și programul apelator.
Se vor studia ambele metode de scriere a unui subprogram recursiv (metoda reducerii și metoda
descompunerii).
20
Complexitatea algoritmilor. Algoritmi de sortare
1. Complexitatea algoritmilor
- Calcul timp de execuție pentru sortarea prin inserție
2. Algoritmi de sortare
1. Sortarea Shell
2. Sortarea prin interclasare
3. Sortarea Heap
4. Sortarea rapidă
5. Sortarea prin numărare
1. Complexitatea algoritmilor
- Exemplu - Calcul timp de execuție pentru sortarea prin inserție
Obs:
Timpul total de execuție este egal cu numărul prelucrărilor elementare executate.
Termenul dominant este termenul care devine semnificativ mai mare decât ceilalți atunci
când dimensiunea problemei crește (dictează comportarea algoritmului când dimensiunea
problemei crește).
Ordinul de creștere caracterizează creșterea termenului dominant al timpului de execuție
în raport cu dimensiunea problemei.
Pseudocod:
do-for j=2,n,1
{ aux=x[j];
i=j-1;
{ x[i+1]=x[i];
i=i-1
}endwhile
X[i+1]=aux
}enddo
21
Operație Cost Nr. repetări Caz favorabil Caz nefavorabil
1 C1 n n n
2 C2 n-1 n-1 n-1
3 C3 n-1 n-1 n-1
𝑛 𝑛 𝑛
4 C4 𝑛(𝑛 + 1)
1=n-1
𝑡𝑗 𝑗=2 𝑗= ―1
𝑗=2
2
𝑗=2
𝑛 𝑛
5 C5 0 𝑛(𝑛 ― 1)
(𝑡𝑗 ― 1) 𝑗=
𝑗=2
2
𝑗=2
𝑛 𝑛
6 C6 0 𝑛(𝑛 ― 1)
(𝑡𝑗 ― 1) 𝑗=
𝑗=2
2
𝑗=2
7 C7 n-1 n-1 n-1
T(n) (c1+c2+c3+c4+c7)n- ( c4/2 + c5/2 + c6/2 )n2
(c2+c3-c4-c7) +(c1+c2+c3+ c4/2 − c5/2
− c6/2
+c7)n−(c2+c3+c4+c7)
O(n) O(n2)
tj = 1, j = 2, . . . , n
tj = j, j = 2, . . . , n
T(n) = c1n+c2(n-1)+c3(n-1)+c4(n(n+1)/2-1)+c5n(n-1)/2+c6n(n-1)/2+c7(n-1)=
2. Algoritmi de sortare
2.1. Sortarea Shell (cu micsorarea incrementului)
#include<stdio.h>
void sort_shell(double v[], int l)
{ int i,j,inc;
double a;
for(inc=l/2;inc>0;inc=inc/2)
22
for(i=inc;i<l;i++)
for(j=i-inc;(j>=0)&&(v[j]>v[j+inc]);j=j-inc)
{ a=v[j];
v[j]=v[j+inc];
v[j+inc]=a;
}
}
void main()
{ int n,i; double v[1000];
printf("n="); scanf("%i",&n);
for(i=0;i<n;i++)
{
printf("v[%d]=",i);
scanf("%lf",&v[i]);
}
sort_shell(v,n);
printf("Vectorul sortat\n");
for(i=0;i<n;i++) printf("%8.4lf ",v[i]);
}
#include<stdio.h>
void interclasare(float v[], int ls, int m, int ld)
{ int i, j, k; float v1[100];
for(i=ls, j=m+1, k=0; i<=m && j<=ld;k++)
v1[k]= (v[i]<v[j])?v[i++]:v[j++];
while(i<=m)v1[k++]=v[i++];
while(j<=ld)v1[k++]=v[j++];
for(i=0;i<k;i++)v[ls+i]=v1[i]; //for(i=ls;i<=ld;i++) v[i]=v1[i-ls];
}
23
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%f", &x[i]);}
sortare(x, 0, n-1);
for (i=0;i<n;i++) printf("%3.1f ", x[i]);
}
24
aranjeaza_heap(H,i,n);
}
void main()
{ int n,i; double x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%lf", &x[i]);}
heap_sort(x,n);
for (i=0;i<n;i++) printf("%3.1lf ", x[i]);
}
#include<stdio.h>
25
int poz(float *x,int p,int u)
{ int i,j,l,di,dj;
float v;
//di, dj: pasii de incrementare pentru i si j; ei indica sensul parcurgerii
i=p;j=u;di=0;dj=-1;
while(i<j)
if (x[i]>x[j])
{ v=x[i];x[i]=x[j];x[j]=v;
l=di;di=-dj;dj=-l;
i+=di;j+=dj;
}
else
{ i+=di;j+=dj;
}
return i;
}
void main()
{ int n,i; float v[1000];
printf("Dimensiunea vectorului:"); scanf("%i",&n);
printf("Elementele vectorului\n");
for(i=0;i<n;i++)
{
printf("v[%d]=",i);
scanf("%f",&v[i]);
}
quick(v,0,n-1);
printf("Vectorul sortat\n");
for(i=0;i<n;i++) printf("%8.4f ",v[i]);
}
#include<stdio.h>
#include<malloc.h>
void sort_numarare(double v[], int l)
26
{ int i,j, *num; double *temp;
temp=(double*)malloc(l*sizeof(double));
num=(int*)malloc(l*sizeof(int));
for(i=0;i<l;i++) num[i]=0;
for(i=0;i<l-1;i++)
for(j=i+1;j<l;j++)
if(v[j]<v[i]) num[i]++;
else num[j]++;
for(i=0;i<l;i++) temp[num[i]]=v[i];
for(i=0;i<l;i++) v[i]=temp[i];
free(temp); free(num);
}
void main()
{ int n,i; double x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%lf", &x[i]);}
sort_numarare(x,n);
for (i=0;i<n;i++) printf("%3.1lf ", x[i]);
}
27
Exemple la metoda backtracking
Probleme propuse:
Rezolvări:
Problema generării permutărilor unei mulțimi se exprimă foarte ușor în termenii metodei backtracking,
dacă se reprezintă mulțimea liniar și se asociază fiecărui element o valoare numerică, în funcție de
poziția ocupată. În continuare fiecare element va fi reprezentat de o valoare numerică 𝑥𝑖, 𝑖 = 1,𝑛 cu
semnificația următoare: 𝑥𝑖 este poziția elementului 𝑖 în permutare; pentru mulțimea inițială 𝑥𝑖 = 𝑖. Cu
aceste considerații, spațiul soluțiilor este definit prin intermediul mulțimilor identice 𝑆𝑖, 𝑥𝑖 ∈ 𝑆𝑖 =
{1, 2,…, 𝑛}, 𝑖 = 1,𝑛 . Aceste mulțimi pot fi exprimate ca progresii aritmetice cu elementul inițial 𝑎𝑖 = 1,
rația 𝑟𝑖 = 1 și ultimul element 𝑠𝑖 = 𝑛.
Deoarece într-o permutare nu pot fi două elemente pe aceeași poziție, valoarea atribuită unui element
𝑥𝑖 este acceptabilă dacă este diferită de valorile atribuite elementelor anteriore din soluția parțială
construită: 𝑥𝑖 ≠ 𝑥𝑗, 𝑗 = 1,𝑖 ― 1. Condiția este suficientă, astfel încît nu e necesară verificarea vreunei
condiții suplimentare după construirea unei soluții. La găsirea unei soluții (permutări) aceasta este
numărată (și afișată pe ecran, în exemplul următor de implementare).
#include <stdio.h>
#include<malloc.h>
{ int j, r; r=1;
if(v[i]==v[j]) r=0;
28
return r;
{ int i;
// I: n
// E: numar permutari
int permutari(int n)
{ int* p,i,am,nr;
i=0;
{ am=0;
while( p[i]<n && !am) //alege urmatoarea valoare acceptabila pentru x[i]
i--;
else
retine_solutia(++nr,n,p);
29
else
//Permutari recursiv
//I: dimensiune (n), pas curent (i), sol. partiala curenta (x), nr. crt. sol. (nr)
{ int j;
if( i==n)
retine_solutia(++nr,n,x);
else
{ x[i]=j;
if( posibil(x,i) )
nr=permutari_r(n,i+1,x,nr);
return nr;
void main(){
int n,nr;
free(x);
30
2. Să se genereze toate aranjamentele dintr-o mulțime cu 𝒏 elemente, luate cîte 𝒌.
#include <stdio.h>
#include<malloc.h>
{ int j, r;
r=1;
j=0;
if(j<i)r=0;
else r=1;
return r;
{ int i;
printf("%2d ",v[i]);
31
}
{ int j;
if( i==k)
retine_solutia(++nr,k,x);
else
{ x[i]=j;
if( posibil(x,i) )
nr=aranjamente(n,k, i+1,x,nr);
return nr;
void main()
{ int n, k, nr;
int* x=(int*)malloc(n*sizeof(int));
free(x); }
32
3. Să se genereze toate combinările dintr-o mulțime cu 𝒏 elemente, luate cîte 𝒌.
#include <stdio.h>
#include<malloc.h>
for(int i=0;i<*n;i++)
*(*x+i)=0;
//afiseaza solutia
{for(int i=0;i<k;i++)
printf("\n");
{ int r=1;
r=0;
return r;
33
}
{ int pval;
for(pval=1;pval<=n;pval++)
{x[p]=pval;
if(posibil(p,x))
{if(p==k-1)
afiseaza(k,x);
else
combinari(p+1, n,k,x);
void main()
{ int n, k, *x;
init(&n,&k,&x);
free(x);
4. Problema celor 8 (n) regine. Se cere să se așeze 8 regine pe o tablă de șah astfel încît să nu existe două
regine care să se atace. Trebuie găsite toate posibilitățile de așezare a celor 8 regine pe tabla de șah.
34
Problema se poate extinde la 𝑛 regine, pe o tablă de dimensiuni 𝑛 × 𝑛, 𝑛 > 2, de aceea în continuare se
va folosi 𝑛 ca dimensiune a problemei.
Considerând liniile și coloanele tablei de șah numerotate de la 1 la 𝑛 (8), începînd din colțul din stînga
sus, poziția unei regine pe tabla de șah este determinată de o pereche de coordonate de forma 𝑃𝑖 = (
𝑙𝑖𝑛𝑖𝑎𝑖, 𝑐𝑜𝑙𝑜𝑎𝑛𝑎𝑖), 𝑖 = 1,𝑛, deci soluția problemei este o mulțime cu 𝑛 astfel de poziții. Ținînd cont că
reginele nu trebuie să se atace, rezultă că pe fiecare linie trebuie să se afle o singură regină și numai una.
Ca urmare, în mulțimea soluție va exista câte un element și numai unul cu linia 1, respectiv linia 2 etc.
adică 𝑙𝑖𝑛𝑖𝑎𝑖 = 𝑖, 𝑖 = 1,𝑛 . Putem considera mulțimea soluție ca o mulțime ordonată, cu 𝑛 elemente de
forma (𝑖,𝑐𝑜𝑙𝑜𝑎𝑛𝑎𝑖), 𝑖 = 1,𝑛. Pentru reprezentarea acestei mulțimi este necesară doar reținerea
coordonatei coloană. În aceste condiții, putem exprima soluția problemei ca o mulțime 𝑋 = {𝑥𝑖| 𝑖 = 1,𝑛},
unde 𝑥𝑖 este coloana pe care se află regina de pe linia 𝑖. Altfel spus, poziția reginei 𝑖 este (𝑖,𝑥𝑖), 𝑖 = 1,𝑛.
Deoarece o regină se poate afla pe una din cele 𝑛 coloane ale tablei de șah, rezultă că elementele 𝑥𝑖 pot
lua valori din mulțimea 𝑆𝑖 = {1, 2, …, 𝑛}, 𝑖 = 1,𝑛. Mulțimile 𝑆𝑖 se pot exprima ca progresii aritmetice cu
elementul inițial 𝑎𝑖 = 1, rația 𝑟𝑖 = 1 și ultimul element 𝑠𝑖 = 𝑛.
Pentru a evita confuziile legate de utilizarea indicilor masivelor în C, se poate folosi un vector cu un
element în plus (lungime 𝑛 + 1), în care elementul cu indicele 0 rămîne nefolosit (risipa de resurse este
insignifiantă în acest caz).
posibil – poziția aleasă pentru regina curentă, (𝑖,𝑥𝑖), este acceptabilă dacă nu este atacată de nici una
din reginele anterior plasate pe tablă. Această poziție nu trebuie să se afle pe aceeași linie sau coloană
cu una din reginele anterioare și nici pe diagonală cu vreuna din ele. Deoarece fiecare regină e plasată
pe o linie nouă, cu siguranță prima parte a condiției este îndeplinită. Pentru a verifica dacă nu se află
pe aceeași coloană cu o regină plasată anterior, se compară coloana curentă 𝑥𝑖 cu coloanele atribuite
reginelor anterioare 𝑥𝑗, 𝑗 = 1,𝑖 ― 1. Se acceptă valoarea curentă dacă 𝑥𝑖 ≠ 𝑥𝑗, 𝑗 = 1,𝑖 ― 1. Două regine
se află pe diagonală dacă distanțele pe verticală și orizontală între ele sînt egale; se acceptă valoarea
curentă dacă |𝑖 ― 𝑗| ≠ |𝑥𝑖 ― 𝑥𝑗|, 𝑗 = 1,𝑖 ― 1.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<malloc.h>
35
int posibil(int *x, int i)
{ int j, p;
p=1;
p=0;
return p;
// E: -
{ int i,j;
printf("%c ",j==x[i]?'R':'x');
printf("\n");
// E: numar solutii
int regine(int n)
36
i=1;
{ am=0;
while( x[i]<n && !am) //alege urmatoarea valoare acceptabila pentru x[i]
if(!am) i--;
else
else
} free(x);
return nr;
// E: nr. solutii
{ int j;
if( i==n+1)
retine_solutia(++nr,n,x);
else
{ x[i]=j;
if( posibil(x,i) )
nr=regine_r(n,i+1,x,nr); }
return nr; }
37
void main(){
int n;
int nr=0;
free(x);
5. Plata unei sume (cu/fără bancnotă unitate). Fie 𝒏 tipuri de bancnote, cu valorile nominale 𝒕𝒊, 𝒊 = 𝟏,𝒏.
Din fiecare tip este disponibilă cantitatea 𝒏𝒓𝒊, 𝒊 = 𝟏,𝒏. Să se determine toate modalitățile în care se
poate plăti o sumă 𝑺 folosind aceste bancnote.
Pentru rezolvare, se reprezintă tipurile de bancnote disponibile într-un vector (prin valorile lor nominale)
iar în alt vector cantitățile disponibile din tipurile respective (asigurând corespondența tip-cantitate prin
folosirea aceleiași poziții în cei doi vectori). Soluția problemei poate fi exprimată sub forma unui vector
𝑋 în care elementul 𝑥𝑖 indică numărul de bancnote de tipul 𝑡𝑖 utilizate: 𝑥𝑖 ∈ 𝑆𝑖 = {0,1,2,…,𝑛𝑟𝑖}, 𝑖 = 1,𝑛.
Mulțimile 𝑆𝑖 se pot exprima ca progresii aritmetice cu elementul inițial 𝑎𝑖 = 0, rația 𝑟𝑖 = 1 și ultimul
element 𝑠𝑖 = 𝑛𝑟𝑖.
38
O valoare atribuită elementului 𝑥𝑖 este acceptabilă dacă prin adăugarea bancnotelor respective (cu
valoarea 𝑥𝑖 ∗ 𝑡𝑖) la bancnotele anterior alese nu se depășește suma de plată. Această condiție nu este
suficientă; după ce se aleg și acceptă valori pentru toate elementele 𝑥𝑖, valoarea tuturor bancnotelor
𝑛
selectate (∑𝑖=1 𝑥𝑖 ∗ 𝑡𝑖) trebuie să fie egală cu suma de plată.
Pentru a evita calcularea acestei sume la fiecare pas, se poate păstra într-o variabilă suma curentă
plătită, care se ajustează de fiecare dată când se atribuie o valoare nouă unui element al soluției. Inițial
aceasta este zero. Algoritmul funcționează și dacă între tipurile de bancnote disponibile nu se află și
bancnota unitate.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<malloc.h>
//I: solutia (x), pasul curent (i), numarul de tipuri (n), suma de plata (s)
{ int rez;
if(i==n-1)
rez=(s==c)?1:0;
else
rez=(s>=c)?1:0;
return rez;
//I: tipuri (t), solutia (x), numarul de tipuri (n), numarul de solutii (ns)
39
printf("\n\nSolutia numarul %d", ns);
//I: suma, suma curenta (crt), tipuri (t), cantitati (nr), numar de tipuri (n)
int plata(int suma, int crt, int* t, int* nr, int n, int ns, int i, int* x)
{ int j;
if(i==n )
retine(t, x, n, ++ns);
else
{ x[i]=j;
crt+=t[i]*j;
crt-=t[i]*j;
return ns;
void main(){
//n=7;
40
int t[20],nr[20];
for(i=0;i<n;i++)
41
Lucru cu fișiere text: exemple
Enunțuri:
1. Să se scrie un subprogram pentru crearea unui fișier text care să conțină elemente reale (în fișier sunt memorate
elementele unui vector – un element pe fiecare linie). Se va oferi și un exemplu de utilizare.
2. Să se scrie un subprogram pentru preluarea vectorului în memorie. Se va scrie și programul apelator.
3. Să se scrie programul care memorează într-un fişier text date despre studenţii unei facultăţi. Pe fiecare linie se
memorează: numărul matricol, numele, prenumele, anul, grupa, cele 10 note obţinute la examene. Datele sunt separate
prin cîte un spaţiu.
4. Să se scrie programul care calculează media studenţilor integralişti şi cea mai mare dintre mediile studenţilor
integralişti din fişierul creat anterior.
Rezolvări:
1. Să se scrie un subprogram pentru crearea unui fișier text care să conțină elemente reale (în fișier sunt memorate
elementele unui vector – un element pe fiecare linie). Se va oferi și un exemplu de utilizare.
void main()
{
char numef[20];
printf("Introduceti numele fisierului:");
scanf("%s", numef);
scriere_vector(numef);
}
42
2. Să se scrie un subprogram pentru preluarea vectorului în memorie. Se va scrie și programul apelator.
void main()
{
float a[100]; int n;
char numef[20];
printf("Introduceti numele fisierului:");
scanf("%s",numef);
preluare_vector_1(numef, a, &n); //fișierul [Link] de la exemplul 1
for (int i=0;i<n;i++) printf("%4.1f ,", a[i]);
_getch();
}
3. Să se scrie programul care memorează într-un fişier text date despre studenţii unei facultăţi. Pe fiecare linie se
memorează: numărul matricol, numele, prenumele, anul, grupa, cele 10 note obţinute la examene. Datele sunt
separate prin câte un spaţiu. Acolo unde nu se cunoaşte încă nota se va introduce valoarea 0.
43
f=fopen(s,"w");
printf("Nr. matricol: "); scanf("%d",&nr);
while(!feof(stdin))
{fflush(stdin); //getchar();
printf("Nume si prenume: ");gets(nume);
printf("An: ");scanf("%d",&an);
printf("Grupa: ");scanf("%d",&gr);
fprintf(f,"%4d %30s %2d %2d ",nr,nume,an,gr);
for(i=0;i<10;i++)
{printf("nota %d: ",i+1); scanf("%d",&n[i]);
fprintf(f,"%2d ",n[i]);}
fprintf(f,"\n");
printf("Nr. matricol: "); scanf("%d",&nr);}
fclose(f);}
4. Să se scrie programul care calculează media studenţilor integralişti şi cea mai mare dintre mediile studenţilor
integralişti din fişierul creat anterior.
#include<stdio.h>
void main()
{FILE *f;
char nume[30],s[200]; int nr,an,gr,n[10],i,e,p; float m,max,m1;
printf("Nume fisier: "); gets(s);
if(!(f=fopen(s,"r")))printf("Nu se poate deschide fisierul.");
else {p=0;max=0;m1=0;
fscanf(f,"%d",&nr);
while(!feof(f))
{fscanf(f,"%s %d %d",nume,&an,&gr);
e=1;m=0;
for(i=0;i<10;i++)
{fscanf(f,"%d",&n[i]);
if(n[i]<5)e=0; m+=n[i];}
if(e){m/=10; p++; m1+=m;
if(m>max)max=m;}
44
fscanf(f,"%d",&nr);}
if (p==0) printf ("Nu exista niciun student integralist");
else
{printf("\nmedia: %5.2f",m1/p); printf("\nmedia maxima: %5.2f", max);}
}
fclose(f);}
45
Lucrul cu fişiere organizate secvenţial: exemple
(inclusiv problema cu grade de total)
Enunțuri:
1. Să se scrie programul care creează un fişier secvenţial cu date despre studenţii unei facultăţi. Articolele au
următoarea structură: număr matricol, nume, anul, grupa, numărul de note, notele (maxim 15). Datele se preiau
de la tastatură, sfârşitul introducerii fiind marcat standard. (expl. de creare)
2. Să se scrie programul care afişează datele despre studenţii ale căror numere matricole se introduc de la tastatură.
Sfârşitul introducerii este marcat standard. ([Link] consultare un articol)
3. Să se scrie programul care listează, în fişiere text, situaţia studenţilor din grupele ale căror numere se introduc de
la tastatură. Sfârşitul introducerii este marcat standard. (expl. de consultare cu selecție)
4. Să se scrie programul care listează, într-un fişier text, sub formă de tabel, conţinutul fişierului creat la problema
anterioara. (expl. de consultare integrală)
5. Să se scrie programul pentru adăugarea notei la disciplina algoritmi și tehnici de programare pentru studenul al
cărui număr matricol este introdus de la tastatură. (expl. de modificare articol unic)
6. Să se scrie programul pentru adăugarea punctului din oficiu la nota la ATP pentru studenţii din grupa al cărei
număr este introdus de la tastatură. (expl. de modificare cu selecție)
7. Să se scrie programul care listează, într-un fişier text, studenţii integralişti, pe ani şi grupe, calculând media
fiecărei grupe şi a fiecărui an. (expl. de problemă cu grade de total)
46
Rezolvări:
1. Să se scrie programul care creează un fişier secvenţial cu date despre studenţii unei facultăţi. Articolele au
următoarea structură: număr matricol, nume, anul, grupa, numărul de note, notele (maxim 15). Datele se preiau
de la tastatură, sfârşitul introducerii fiind marcat standard. Acolo unde nu se cunoaşte încă nota se va introduce
valoarea 0. (Numele fisierului binar [Link])
Observație: Pentru recunoașterea funcției gets în Visual Studio versiunile mai noi -> se va schimba extensia
fișierului sursă. Noua extensie va fi .c (in loc de .cpp)
void main()
{FILE *f;
char s1[20];
Student s;
int i;
printf("\nFisier: ");gets(s1);
f=fopen(s1,"wb");
printf("[Link]: ");scanf("%d",&[Link]);
while(!feof(stdin))
{printf("Nume: ");
getchar();
gets([Link]);
printf("An: ");scanf("%d",&[Link]);
printf("Grupa: ");scanf("%d",&[Link]);
printf("[Link]:(<15)");scanf("%d",&s.n);
for(i=0;i<s.n;i++)
{printf("Nota %d: ",i+1);
scanf("%d",&[Link][i]);}
fwrite(&s,sizeof(Student),1,f);
printf("[Link]: ");scanf("%d",&[Link]);
}
fclose(f);}
2. Să se scrie programul care afişează datele despre studenţii ale căror numere matricole se introduc de la
tastatură. Sfârşitul introducerii este marcat standard.
void main()
{FILE *f;
char s1[20];
Student s;
int i,n,j;
printf("\nFisier: ");gets(s1);
f=fopen(s1,"rb");
if(!f)printf("\nFisierul %s nu poate fi deschis", s1);
else{printf("\nNr. matricol: ");
scanf("%d",&n);
while(!feof(stdin))
{rewind(f);
fread(&s,sizeof(Student),1,f);
i=0;
while((!feof(f))&&(!i))
{if(n==[Link])
{i=1;
printf("\[Link]:%3d Nume: %-30s An: %2d Grupa: %4d\nNote: ",[Link],[Link],[Link],[Link]);
for(j=0;j<s.n;j++)
printf("%2d ",[Link][j]);}
fread(&s,sizeof(Student),1,f);}
if(!i)printf("\nNu a fost gasit.");
printf("\nNr. matricol: ");
scanf("%d",&n);}
fclose(f);}
}
3. Să se scrie programul care listează, în fişiere text, situaţia studenţilor din grupele ale căror numere se introduc
de la tastatură. Sfârşitul introducerii este marcat standard.
void main()
{FILE *f,*g;
char s1[20];
Student s;
int i,n,j;
48
printf("\nFisier: ");gets(s1);
f=fopen(s1,"rb");
if(!f)printf("\nFisierul %s nu poate fi deschis",s1);
else{printf("\nNr. grupei: ");
scanf("%d",&n); //grupa
while(!feof(stdin))
{rewind(f);
getchar();
printf("\nFisier rezultat: ");gets(s1);
g=fopen(s1,"w");
fread(&s,sizeof(Student),1,f);
i=0;
while(!feof(f))
{if(n==[Link])
{i=1;
fprintf(g,"\[Link]:%3d Nume: %-30s An: %2d Grupa: %4d\nNote: ",[Link],[Link],[Link],[Link]);
for(j=0;j<s.n;j++)
fprintf(g,"%2d ",[Link][j]);}
fread(&s,sizeof(Student),1,f);}
if(!i)printf("\nNu a fost gasita.");
printf("\nNr. grupei: ");
scanf("%d",&n);
fclose(g);}
fclose(f);}
}
4. Să se scrie programul care listează, într-un fişier text, sub formă de tabel, conţinutul fişierului creat la problema
1.
void main()
{FILE *f,*g;
char s1[20];
Student s;
int i,n;
printf("\nNumele fisierului binar: ");gets(s1);
f=fopen(s1,"rb");
if(!f)printf("\nFisierul %s nu poate fi deschis",s1);
else{printf("\nFisier rezultat (text): ");gets(s1);
g=fopen(s1,"w");
49
fprintf(g,"\nNr. Nume %25s An Grupa Note"," ");
fread(&s,sizeof(Student),1,f);
n=0;
while(!feof(f))
{fprintf(g,"\n%3d %-30s %2d %4d ",++n,[Link],[Link],[Link]);
for(i=0;i<s.n;i++)
fprintf(g,"%2d ",[Link][i]);
fread(&s,sizeof(Student),1,f);
}
fclose(g);
fclose(f);}
}
5. Să se scrie programul pentru adăugarea notei la disciplina algoritmi și tehnici de programare pentru studenul al
cărui număr matricol este introdus de la tastatură. Nota la disciplina ATP se găseste pe poziția zero în vectorul de
note.
void main()
{FILE *f;
char s1[20];
Student s;
int i,n,j;
printf("\nFisier: ");gets(s1);
f=fopen(s1,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", s1);
else{printf("\nNr. matricol: ");
scanf("%d",&n);
while(!feof(stdin))
{rewind(f);
fread(&s,sizeof(Student),1,f);
i=0;
while((!feof(f))&&(!i))
{if(n==[Link])
{i=1;
printf("\[Link]:%3d Nume: %-30s An: %2d Grupa: %4d\nNote: ",
[Link],[Link],[Link],[Link]);
for(j=0;j<s.n;j++)
printf("%2d ",[Link][j]);
printf("Introduceti nota la ATP");
50
scanf ("%d", &[Link][0]);
fseek(f, ftell(f)-sizeof(Student),0);
fwrite(&s, sizeof(Student), 1, f);
}else
fread(&s,sizeof(Student),1,f);
}
if(!i)printf("\nNu a fost gasit.");
printf("\nNr. matricol: ");
scanf("%d",&n);}
fclose(f);}
}
6. Să se scrie programul pentru adăugarea punctului din oficiu la nota la ATP pentru studenţii din grupa al cărei
număr este introdus de la tastatură. Nota la ATP se regăsește pe poziția zero în vectorul de note.
void main()
{FILE *f;
char s1[20];
Student s;
int n,i;
printf("\nFisier: ");gets(s1);
f=fopen(s1,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis",s1);
else{
printf("\nNr. grupei: ");
scanf("%d",&n);
while(!feof(stdin))
{rewind(f);
fread(&s, sizeof(Student), 1, f);
i=0;
while(!feof(f))
{if(n==[Link])
{i=1;
[Link][0]=([Link][0]==10)? [Link][0]: [Link][0]+1;
fseek(f, ftell(f)-sizeof(Student), 0);
fwrite(&s, sizeof(Student), 1, f);
fseek(f, 0, 1); //folosit la trecerea de la scriere la citire
}
fread(&s, sizeof(Student), 1, f);
}
if(!i) printf("\n Nu a fost gasit nici un student");
51
printf("\nNr grupei: ");scanf("%d",&n);}
fclose(f);}
}
7. Pentru problema cu grade de total, fisierul trebuie să fie ordonat după caracteristicile de control
a) Să se scrie programul care sortează studenţii după anii de studiu şi grupe. (se va apela apoi problema 4).
Se vor verifica datele daca sunt sortate)
#include<stdio.h>
void main()
{FILE *f,*g;
char s[20];
Student s1,s2;
int ok,n,i;
printf("\nFisier: ");gets(s);
f=fopen(s,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis",s);
else{n=nrart(f,sizeof(Student));
ok=1;
while(ok)
{ok=0;
for(i=0;i<n-1;i++)
{fseek(f, i*sizeof(Student), 0);
fread(&s1, sizeof(Student), 1, f);
fread(&s2, sizeof(Student), 1, f);
if (([Link]>[Link])|| (([Link]==[Link]) && ([Link]>[Link])))
{ok=1;
fseek(f,i*sizeof(Student),0);
fwrite(&s2, sizeof(Student), 1, f);
fwrite(&s1, sizeof(Student), 1, f);
}
}
}
fclose(f);}
}
52
b) Să se scrie programul care listează, într-un fişier text, studenţii integralişti, pe ani şi grupe, calculând
media fiecărei grupe şi a fiecărui an. (fisierul rezultat se va numi [Link] si se va verifica rezultatul
comparand cu datele din [Link])
#include<stdio.h>
void main()
{FILE *f,*g;
char s1[20];
Student s;
int i,na,j,e,ng,ca,cg;
float ma,mg,ms;
printf("\nFisier: ");gets(s1);
f=fopen(s1,"rb");
if(!f)printf("\nFisierul %s nu poate fi deschis",s1);
else {printf("\nFisier text: ");gets(s1);
g=fopen(s1,"w");
fread(&s,sizeof(Student),1,f);
while(!feof(f))
{// operatii initiale pentru an
ca=[Link];
fprintf(g,"\n\nAnul %d",ca);
ma=0; na=0;
while((!feof(f))&& ([Link]==ca))
{// operatii initiale pentru grupa
mg=0; ng=0;
cg=[Link];
fprintf(g,"\n\tGrupa %d",cg);
while((!feof(f))&&(ca==[Link])&&(cg==[Link]))
{e=1;ms=0;
for(j=0;j<s.n;j++)
if([Link][j]<5)e=0;
else ms+=[Link][j];
if(e){mg+=ms/s.n;
ng++;
fprintf(g,"\n\t\t%4d %-30s Media %5.2f Note: ",[Link],[Link],ms/s.n);
for(j=0;j<s.n;j++)fprintf(g,"%2d ",[Link][j]);}
fread(&s,sizeof(Student),1,f);
}
//operatii finale grupa
if(ng){fprintf(g,"\n\tGrupa %d, media: %5.2f",cg,mg/ng);ma+=mg;na+=ng;}
else fprintf(g,"\n\Grupa nu are integralisti");}
//operatii finale an
if(na)fprintf(g,"\nMedia anului %d este: %5.2f",ca,ma/na);
else fprintf(g,"\nAnul nu are integralisti");}
fclose(f);
fclose(g);}
}
53
Algoritmi și tehnici de programare 145
Se observă că un calculator mai slab are nevoie de mult mai puțin timp pentru a
realiza aceeași prelucrare, dacă utilizează un algoritm cu o complexitate mai redusă
(„mai bun”).
Observație. În practică s-a constatat că algoritmul de sortare prin inserare, deși are
o complexitate mai mare, este mai rapid decît cel de sortare prin interclasare în
cazul masivelor de dimensiuni reduse. Ca urmare, cei doi algoritmi pot fi combinați
astfel: în algoritmul de sortare prin interclasare (cel cu complexitate mai mică),
atunci cînd în urma divizării masivului de sortat rezultă masive de dimensiuni mici,
acestea se sortează folosind algoritmul de sortare prin inserare, în loc să se utilizeze
recursiv sortarea prin interclasare.
dimensiunea utilizată poate fi numărul de biți care descriu datele de intrare (de
exemplu operații aritmetice cu numere).
1. Fie funcția 𝑓(𝑛) = 3𝑛2 ―2𝑛 (fără termen de rang zero, deoarece este irelevant
în discuția despre timpul asimptotic de execuție). Conform simplificărilor
menționate, ea aparține mulțimii Θ(𝑛2) – am păstrat doar termenul cu cel mai mare
grad și am eliminat coeficientul lui. Conform definiției, trebuie găsite constantele
𝑐1, 𝑐2 și pragul 𝑛0 astfel încît
𝑐1 ∙ 𝑛2 ≤ 3𝑛2 ― 2𝑛 ≤ 𝑐2 ∙ 𝑛2, ∀𝑛 ≥ 𝑛0
2 2
Împărțind la 𝑛2 obținem 𝑐1 ≤ 3 ― 𝑛 ≤ 𝑐2, unde 3 ― 𝑛 ∈ [1,3), ∀𝑛 ≥ 1. Rezultă că
putem alege 𝑐1 = 1 (sau orice valoare mai mică decît 1), 𝑐2 = 3 (sau orice valoare
mai mare decît 3) și 𝑛0 = 1. Ca urmare, într-adevăr funcția dată 𝑓(𝑛) ∈ Θ(𝑛2)
(uneori în literatură se folosește notația 𝑓(𝑛) = Θ(𝑛2), cu aceeași semnificație).
𝑐1 ∙ 𝑛2 ≤ 2𝑛3 ≤ 𝑐2 ∙ 𝑛2, ∀𝑛 ≥ 𝑛0
rang inferior poate fi compensată prin utilizarea unor valori mai mici (pentru 𝑐1),
respectiv mai mari (pentru 𝑐2).
cc22*g(n)
*g(n)
f(n)
f(n)
cc11*g(n)
*g(n)
n
n00 n
n
Fig. 1. 𝚯(𝒈(𝒏))
c*g(n)
f(n)
n00 n
Fig. 2. 𝑶(𝒈(𝒏))
Algoritmi și tehnici de programare 151
f(n)
c*g(n)
n00 n
Fig. 3. 𝛀(𝒈(𝒏))
ocupînd un spațiu de memorie separat (în acest caz masivul original nu este
modificat).
L1 pentru k=1:n-1
L2 aux=v[k]
L3 j=k-1
L4 cât timp j>=0 și v[j]>aux
L5 v[j+1]=v[j]
L6 j=j-1
L7 v[j+1]=aux
Notând cu 𝑡𝑘 numărul de repetări “cât timp” pentru 𝑘 = 1,…,𝑛, rezultă că, în cel
mai favorabil caz, 𝑡𝑘 = 1, în timp ce, în situația cea mai defavorabilă, 𝑡𝑘 = 𝑘 + 1.
În următorul table sunt prezentate costurile la nivel de linie a algoritmului.
L1 C1 n n n
L2 C2 n-1 n-1 n-1
L3 C3 n-1 n-1 n-1
L4 C4 𝒏―𝟏 n-1 𝒏(𝒏 + 𝟏)
―𝟏
𝒕𝒌 𝟐
𝒌=𝟏
L5 C5 𝒏―𝟏 0 𝒏(𝒏 ― 𝟏)
(𝒕 𝒌 ― 𝟏 ) 𝟐
𝒌=𝟏
L6 C6 𝒏―𝟏 0 𝒏(𝒏 ― 𝟏)
(𝒕 𝒌 ― 𝟏 ) 𝟐
𝒌=𝟏
L7 C7 n-1 n-1 n-1
𝑇𝑅(𝑛)
(𝑛(𝑛2+ 1) ― 1) + 𝑐 𝑛(𝑛2― 1) + 𝑐
= 𝑐1𝑛 + 𝑐2(𝑛 ― 1) + 𝑐3(𝑛 ― 1) + 𝑐4 5 6
𝑐 𝑐 𝑐
+ 𝑐 (𝑛 ― 1) = ( + + )𝑛
𝑛(𝑛 ― 1) 4 5 6
2
7
2 2 2 2
𝑐 𝑐 𝑐
+ (𝑐 + 𝑐 + 𝑐 + ― ― + 𝑐 ) 𝑛 ― (𝑐 + 𝑐 + 𝑐 + 𝑐 ) = 𝑎
4 5 6
1 2 3 7 2 3 4 7
2 2 2
∙ 𝑛2 + 𝑏 ∙ 𝑛 + 𝑐
Algoritmi și tehnici de programare 154
Grafuri. Reprezentări. Metode de parcurgere.
2. Fie D=(V,E) digraf, V={1,…,5}, E={(1,2), (1,3), (2,5), (3,5), (4,1), (5,1), (5,3), (5,4)}. Care este
matricea de adiacenţă a digrafului?
0 1 1 0 0
0 0 0 0 1
Raspuns: A 0 0 0 0 1
1 0 0 0 0
1 0 1 1 0
3. Fie D=(V,E) digraf, V={1,…,5}, E={(1,2), (1,3), (1,5), (2,5), (3,5), (4,1), (5,4)}. Digraful poate fi
reprezentat grafic astfel,
1
4
2
3
5
4. Fie G=(V,E,W) graf ponderat, V={1,2,3,4,5}, E={(1,2), (1,4), (2,3), (2,4), (3,4)}, W((1,2))=5,
W((1,4))=7, W((2,3))=4, W((2,4))=2, W((3,4))=1. Specificaţi matricea ponderilor.
2 3
6
4
7
5
şi v0=1. Realizați parcurgerea în lățime a grafului pornind din vârful 1 (tabelul distanțelor).
Observaţie Deoarece graful este conex, traversarea BF realizează vizitarea tuturor vârfurilor grafului.
Aplicarea metodei BF unui graf neconex nu determină vizitarea tuturor vârfurilor. Cu alte cuvinte,
metoda BF aplicată unui graf determină vizitarea tuturor vârfurilor care sunt conectate cu vârful iniţial
selectat.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include<malloc.h>
void main()
{ int n,v0,**a,m,i,j,vf1,vf2;
printf("Numarul de virfuri:");
scanf("%i",&n);
//se va aloca memorie pentru matricea a
a=(int **)malloc(n*sizeof(int*));
for(i=0;i<n;i++)
a[i]=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
a[j][i]=a[i][j]=0;
printf("\nNumarul de muchii:");
Ordinea de vizitare a vârfurilor este 1,2,3,4,7,5,6 care poate fi văzută atât din exemplul numeric, cât și
prin execuția programului pentru același graf și vârf de pornire.
6. Pentru graful,
2 3
6
4
7
5
O variantă de implementare a metodei DF rezultă prin gestionarea stivei S în modul următor. Iniţial
vîrful v0 este unicul component al lui S. La fiecare etapă se preia, fără ştergere, ca vîrf curent vârful
stivei. Se introduce în stivă unul dintre vecinii vârfului curent încă nevizitat. Vizitarea unui vârf revine
la introducerea lui în S. Dacă vârful curent nu are vecini încă nevizitaţi, atunci el este eliminat din stivă
şi este efectuat un nou acces de preluare a noului vârf al stivei ca vârf curent. Calculul se încheie în
momentul în care este efectuat un acces de preluare a vârfului stivei ca vârf curent şi se constată că S
este vidă. Evident, nici în cazul acestei variante nu vor fi vizitate vârfurile care nu sunt conectate cu
vârful iniţial ales.
c S
1 2 3 4 5 6 7
t T
t=1 1 0 0 0 0 0 0 t=1 1
t=2 1 1 0 0 0 0 0 t=2 2 1
t=3 1 1 0 0 1 0 0 t=3 5 2 1
t=4 1 1 0 1 1 0 0 t=4 4 5 2 1
t=5 1 1 1 1 1 0 0 t=5 3 4 5 2 1
t=6 1 1 1 1 1 1 0 t=6 6 3 4 5 2 1
t=7 1 1 1 1 1 1 1 t=7 7 6 3 4 5 2 1
t=8 1 1 1 1 1 1 1 t=8 6 3 4 5 2 1
t=9 1 1 1 1 1 1 1 t=9 3 4 5 2 1
t=10 1 1 1 1 1 1 1 t=10 4 5 2 1
t=11 1 1 1 1 1 1 1 t=11 5 2 1
t=12 1 1 1 1 1 1 1 t=12 2 1
t=13 1 1 1 1 1 1 1 t=13 1
Ordinea în care sunt vizitate vârfurile corespunzător acestei variante este: 1,2,5,4,3,6,7
Implementarea metodei DF
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include<malloc.h>
int insereaza_stiva(int *stiva,int n, int vf)
{ int i;
for (i=n-1;i>=0;i--)
stiva[i+1]=stiva[i];
stiva[0]=vf;
n++;
return n;
}
int sterge_stiva(int *stiva,int n)
{ int i;
for (i=0;i<n-1;i++)
stiva[i]=stiva[i+1];
n--;
return n;
}
int citeste_stiva(int *stiva, int n)
{ return stiva[0];
}
void main()
{ int n,v0,**a,m,i,j,vf1,vf2;;
printf("Numarul de virfuri:");
scanf("%i",&n);
a=(int **)malloc(n*sizeof(int*));
for(i=0;i<n;i++)
a[i]=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
a[j][i]=a[i][j]=0;
printf("\nNumarul de muchii:");
scanf("%i",&m);
for(i=0;i<m;i++)
{ printf("Virf initial:");scanf("%i",&vf1);
printf("Virf final:");scanf("%i",&vf2);
a[vf1-1][vf2-1]=a[vf2-1][vf1-1]=1;
}
printf("\nVirful initial pentru parcurgerea DF ");
scanf("%i",&v0);
printf("\nOrdinea de vizitare a virfurilor grafului este:");
1. Pentru graful,
v2
v4
v5
v1 v3
1: v1, v2, v3, v2, v5, v3, v4 este un v1- v4 drum care nu este proces;
2: v1, v2, v5, v1, v3, v4 este un v1- v4 proces care nu este drum elementar;
3: v1, v3, v4 este un v1- v4 drum elementar.
2. În graful,
v2 v6 v7
v1 v4 v5 v8 v10
v3 v9
dacă : v1, v2, v4, v5, v3, v1, v2, v5, v6, v7, v8, v9, v5, v9, v8, v10, atunci
1: v1, v2, v5, v9, v8, v10,
2: v1, v2, v4, v5, v9, v8, v10 sunt v1-v10 subdrumuri elementare.
3. Pentru graful,
4
Determinați matricea existenței drumurilor.
Răspuns:
Pagină 163 din 77
Algoritmi și tehnici de programare 164
Matricea existenţei drumurilor; algoritmul Roy-Warshal
(1) (2) ( n 1 )
Matricea M A A A se numeşte matricea existenţei drumurilor în graful G.
Semnificaţia componentelor matricei M este:
0 , dacă nu există vi v j drum în G
1 i , j n , mij
1, altfel
0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
1 0 0 0 0
2 1 1 1 1
3 0 1 1 1 1 1 1
A , A , A , M
1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1
Observaţie Calculul matricei existenţei drumurilor permite verificarea dacă un graf dat este conex.
Graful este conex dacă şi numai dacă toate componentele matricei M sunt egale cu 1.
2
6
4
3
Observaţii
Un graf este conex dacă şi numai dacă numărul componentelor sale conexe este 1.
5. Pentru graful,
1 7 3
2
4 5 8 9 6
Determinați componenta conexă care conține vârful 1.
Răspuns:
Determinarea componentei conexe care conţine un vârf v0 dat poate fi realizată pe baza următorului
algoritm.
6. Fie graful,
1 8
3
2
6
4 9 10
11
5 7
7. Pentru graful de mai sus, determinaţi componenta conexă care conţine vârful 5.
Răspuns:
Aplicarea algoritmului descris pentru v0=5, determină următoarea evoluţie:
I Vi Ei
i=0 {5} Ø
i=1 {1,4,5} {(1,5),(4,5)}
i=2 {1,2,3,4,5,7} {(1,5),(4,5),(1,2),(1,3),(2,4),(3,4),(1,7),(4,7)}
i=3 {1,2,3,4,5,6,7} {(1,5),(4,5),(1,2),(1,3),(2,4),(3,4),(1,7),(4,7),(3,6),(3,7)}
8. Fie graful,
Pagină 165 din 77
Algoritmi și tehnici de programare 166
1
2
4
6
5
3
Răspuns:
1 1 1 10 1
1 1 1 10 1
1 1 1 10 1
Matricea existenţei drumurilor este A
0 0 0 00 0
1 1 1 1
0 1
1 1 1 0 1 1
9. Scrieți un subprogram care calculează matricea existenței drumurilor într-un graf neponderat
(algoritmul Roy-Warshall), precum și programul apelator.
#include <stdio.h>
#include <malloc.h>
*dim=n;
m=(int**)malloc(n*sizeof(int*));
for(i=0;i<n;i++)
m[i]=(int*)malloc(n*sizeof(int));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
m[i][j]=a[i][j];
for(i=0;i<n;i++)
void main()
{ int **a,**m_dr,l;
int n,i,j;
char numef[20];
printf("Introduceti numele fisierului care contine graful:");
scanf("%s", numef);
preia_graf(numef,&a, &n);
m_dr=Roy_Warshall(a,n,&l);
for(i=0;i<l;i++)
{ for(j=0;j<l;j++) printf("%3i ", m_dr[i][j]);
Pentru graful preluat din fișierul [Link] (fisierul text va fi adaugat in directorul proiectului), anume:
11 11
1 2
1 3
2 4
2 6
3 4
3 5
4 5
5 6
7 8
7 9
8 9
matricea existenței drumurilor este:
1 1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 0 0 0 0 0
1 1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
Probleme propuse:
5. Fiind dat numărul natural k>1 să se scrie programul care determină cel mai mic număr natural
n având exact k divizori naturali proprii (diferiți de 1 și de n).
Probleme rezolvate
Dacă obiectele transportate pot fi fracționate, problema este numită continuă. În acest caz se va utiliza
întotdeauna întreaga capacitate de transport.
Dacă obiectele nu pot fi fracționate, problema este numită întreagă. În acest caz e posibil ca soluția
obținută să nu utilizeze întreaga capacitate de transport. De asemenea, soluția obținută poate să nu fie
optimă. În plus, e posibil să existe o soluție de utilizare a întregii capacități de transport, dar aceasta să nu
fie găsită prin algoritmul de tip Greedy.
Cea mai bună soluție se obține dacă se folosește o valoare derivată: câștigul unitar (𝑐𝑖/𝑣𝑖). La fiecare pas
se ia în considerare următorul element al mulțimii sortate descrescător (alegere). Dacă acesta încape în
mijlocul de transport (verificare), e adăugat la soluție (adăugare) și se diminuează capacitatea de transport
rămasă disponibilă. Dacă nu încape, atunci:
dacă problema e continuă, se ia din obiectul curent atât cât încape (adăugare);
dacă problema e întreagă, se respinge obiectul curent.
Pentru reprezentarea soluției se poate folosi un vector 𝐵 în care fiecare element are valoarea 1 (obiect
acceptat) sau 0 (obiect respins). În cazul în care se acceptă fracționarea obiectelor, unul singur va fi
fracționat iar elementul din vectorul soluție corespunzător lui va avea o valoare în intervalul (0,1).
Elementul 𝑏𝑖 arată dacă obiectul 𝑎𝑖 este acceptat sau respins (sau acceptat fracționat).
Exemplu de apel.
Se va modifica programul principal astfel incat datele de intrare sa fie citite de la tastatura.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<conio.h>
#define N 10
void main()
{ //exemplu de apel
float CT=33; //capacitate totala de transport
float c[N]={1,2,3,4,5,6,7,8,9,10}; //capacitati
float v[N]={3,2,1,4,5,3,2,7,1,8}; //venituri
//pentru cazul general datele de intrare se vor citi de la tastatura
//prelucrare preliminara
//sortarea obiectelor
for(i=0;i<N-1;i++)
for(j=i+1;j<N;j++)
if(v[i]/c[i] < v[j]/c[j]) //cistig unitar
{ a=v[i]; v[i]=v[j]; v[j]=a;
a=c[i]; c[i]=c[j]; c[j]=a;
}
//apel functie
Rucsac_c(CT, N, c, sol);
//afisare rezultate
cistig=0;
for(i=0;i<N;i++)
{ printf("\n%2d: c=%5.2f v=%5.2f %2f, cistig=%5.2f",i+1, c[i], v[i], sol[i],
cistig+=v[i]*sol[i]);
}
_getch();
}
2. Problema rucsacului, varianta întreagă
Se va modifica programul principal astfel incat datele de intrare sa fie citite de la tastatura.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<conio.h>
#define N 10
void main()
{ //exemplu de apel
float CT=33; //capacitate totala de transport
float c[N]={1,2,3,4,5,6,7,8,9,10}; //capacitati
float v[N]={3,2,1,4,5,3,2,7,1,8}; //venituri
//pentru cazul general datele de intrare se vor citi de la tastatura
//prelucrare preliminara
//sortarea obiectelor
for(i=0;i<N-1;i++)
for(j=i+1;j<N;j++)
if(v[i]/c[i] < v[j]/c[j]) //cistig unitar
{ a=v[i]; v[i]=v[j]; v[j]=a;
a=c[i]; c[i]=c[j]; c[j]=a;
}
//apel functie
Rucsac_i(CT, N, c, sol);
//afisare rezultate
cistig=0;
for(i=0;i<N;i++)
{ printf("\n%2d: c=%5.2f v=%5.2f %2d, cistig=%5.2f",i+1, c[i], v[i], sol[i],
cistig+=v[i]*sol[i]);
}
_getch();
Se dă o mulțime de elemente reale 𝑨 = {𝒂𝟏, 𝒂𝟐, …, 𝒂𝒏,}. Se cere să se scrie funcția care determină o
submulțime 𝑺 ⊆ 𝑨 astfel încât suma elementelor submulțimii 𝑺 să fie cea mai mare posibilă (problema
sumei maxime).
O sortare inițială descrescătoare a mulțimii date asigură un număr mai mic de pași la aplicarea algoritmului
Greedy (oprire la primul element nul/negativ), dar crește complexitatea la nivel general, de aceea e
preferabil (în acest caz) să nu se facă prelucrarea inițială și să se analizeze toate elementele mulțimii
inițiale. Funcția următoare rezolvă problema sumei maxime, fără sortare prealabilă a mulțimii inițiale,
fiind astfel necesară parcurgerea întregii mulțimi.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<conio.h>
{ int i;
*nr=0;
for(i=0;i<n;i++)
b[(*nr)++]=a[i];
void main()
int n, i, nr;
for(i=0;i<n;i++)
suma_maxima(a,n,b,&nr);
else {
printf("Solutia este:");
for(i=0;i<nr;i++)
}
4. Plata unei sume cu bacnota unitate
Să se scrie subprogramul C care permite plata unei sume 𝑺 ∈ ℕ folosind cît mai puține bancnote din
tipurile (valorile) 𝒂𝒊, 𝒊 = 𝟏,𝒏, știind că printre acestea se află și bancnota cu valoare unitate. Sunt
disponibile cantități nelimitate din fiecare tip de bancnotă.
Pentru a folosi cât mai puține bancnote, trebuie utilizate bancnote cu valori cât mai mare, ceea ce duce la
sortarea mulțimii date în ordine descrescătoare. Astfel, bancnotele cu valorile cele mai mari vor fi primele
luate în considerare. Soluția poate fi reprezentată ca un vector 𝐵 = {𝑏𝑖 ∈ ℕ| 𝑖 = 1,𝑛}, în care fiecare
element 𝑏𝑖 arată câte bancnote de tipul 𝑎𝑖 trebuie utilizate.
Pornind de la valoarea inițială 𝑆, se acoperă cît se poate de mult cu cel mai mare tip de bancnotă, apoi se
ajustează suma rămasă de plată. Se continuă cu fiecare tip de bancnotă, pînă cînd suma rămasă este zero.
Dacă mai rămîn tipuri de bancnote neinvestigate, ele rămân nefolosite.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<conio.h>
{ int i, sr;
sr=s;
for(i=0;i<n;i++)
{ sol[i]=sr/t[i];
sr=sr%t[i];
for (i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i]<x[j])
aux=x[i];x[i]=x[j];x[j]=aux;
void main()
for(i=0;i<n;i++)
plata_unitate(s,t,n,sol);
for(i=0;i<n;i++)
5. Fiind dat numărul natural k>1 să se scrie programul care determină cel mai mic număr natural n
având exact k divizori naturali proprii (diferiți de 1 și de n).
Verificările vor începe de la k+2, dacă are k divizori proprii. Verificările vor continua până la determinarea
primului număr natural care are exact k divizori proprii, care va reprezenta și cel mai mic număr natural
cu proprietatea cerută.
#include <stdio.h>
int verificare (int n, int k)
{ int i, d=0;
if(n%i==0)d++;
int r=(d==k)?1:0;
return r;
int divizori(int k)
{ int i, n;
n=k+2;
while (verificare(n,k)==0)n++;
return n;
void main()
{ int k;
scanf("%d", &k);
printf("Cel mai mic nr. natural cu %d divizori proprii este %d\n", k,divizori(k));
}
Seminar 5
Lucrul cu fișiere text și fișiere binare – probleme economice
Probleme propuse:
1. Fie un fişier organizat secvențial, cu date referitoare la punctele obținute de studenți la disciplina Algoritmi și
tehnici de programare. Articolele au următoarea structură:
Puncte proba practică Puncte teme (0-1)
Nr. matricol Nume şi prenume Grupa Puncte examen (0-50)
(0-30) 1 2 … 10
cha cha cha cha
int char[30] int char char
r r r r
Scrieți programul care înregistrează în fișier punctajul obținut de un student la examen. Studentul este identificat
prin numărul matricol. Programul trebuie să ofere posibilitatea repetării, pentru înregistrarea punctajelor mai
multor studenți.
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
2. Fie un fişier organizat secvențial, cu date referitoare la punctele obținute de studenți la disciplina Algoritmi și
tehnici de programare. Articolele au următoarea structură:
Puncte proba practică Puncte teme (0-1)
Nr. matricol Nume şi prenume Grupa Puncte examen (0-50)
(0-30) 1 2 … 10
cha cha cha cha
int char[30] int char char
r r r r
Scrieți programul care înregistrează înmatricularea unui nou student (punctajele vor avea valori nule).
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
3. Fie un fişier organizat relativ, cu date referitoare la absențele studenților de la cursuri și seminarii/laboratoare
pentru fiecare dintre cele 15 discipline specifice fiecărui an de studiu. Cheia relativă este numărul matricol al
studentului (domeniul de valori pentru numerele matricole începe de la 0). Articolele au următoarea structură:
An Absențe (0-14)
Indicator de stare (0/1) Nr. matricol Nume şi prenume Grupa
(1-5) 1 2 … 15
C S C S C S
char int char[25] int char
char char char char char char
Numărul de activități la fiecare disciplină este 14.
Scrieţi un program care înregistrează exmatricularea unui student. Studentul este identificat prin numărul matricol.
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
4. Fie un fişier organizat relativ, cu date referitoare la absențele studenților de la cursuri și seminarii/laboratoare
pentru fiecare dintre cele 15 discipline specifice fiecărui an de studiu. Cheia relativă este numărul matricol al
studentului (domeniul de valori pentru numerele matricole începe de la 0). Articolele au următoarea structură:
An Absențe (0-14)
Indicator de stare (0/1) Nr. matricol Nume şi prenume Grupa
(1-5) 1 2 … 15
C S C S C S
char int char[25] int char
char char char char char char
Numărul de activități la fiecare disciplină este 14.
11
Scrieţi un program care înregistrează o nouă absență a unui student la o activitate. Studentul este identificat prin
numărul matricol, activitatea este identificată prin poziția în vector (1-15) și tip (Curs/Seminar).
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
Exemple de rezolvare:
Observatii:
Fisierul binar trebuie sa se regaseasca in directorul proiectului
În Visual Studio versiuni mai noi extensia fișierului sursă trebuie să fie .c (nu .cpp) – (dacă aveți eroare
legată de funcția gets)
#define _CRT_SECURE_NO_WARNINGS //în cazul în care apar avertismente legate de securitate
1. Problema 1
//Fisierul binar se numeste [Link]
#include<stdio.h>
void main()
{FILE *f;
12
char nume[30];
STUDENT s;
int gasit,n,j;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", nume);
else
{
lista_studenti(f);
printf("\nNr. matricol: ");scanf("%d",&n);
while(!feof(stdin))
{rewind(f);
fread(&s,sizeof(STUDENT),1,f);
gasit=0;
while((!feof(f))&&(gasit==0))
{
if(n==[Link])
{gasit=1;
printf("\[Link]:%3d Nume: %-30s Grupa: %4d Punctaj pp: %2d\n: ",[Link],[Link],[Link], [Link]);
for(j=0;j<10;j++)
printf("%2d ",[Link][j]);
printf("Punctaj examen: %2d ",[Link]);
printf("Introduceti punctajul la examen:");
scanf ("%d", &[Link]);
fseek(f, ftell(f)-sizeof(STUDENT),0);
fwrite(&s, sizeof(STUDENT), 1, f);
}else
fread(&s,sizeof(STUDENT),1,f);
}
if(gasit==0)printf("\nNu a fost gasit.");
printf("\nNr. matricol: ");scanf("%d",&n);
}
fclose(f);}
}
13
Va fi creat fișierul text cu studenții din fișierul binar
2. Problema 2
14
for(i=0;i<10;i++)
fprintf(g,"%2d ",[Link][i]);
fprintf(g,"%6d ",[Link]);
fread(&s,sizeof(STUDENT),1,f);
}
fclose(g);
}
void main()
{FILE *f;
char nume[30];
STUDENT s;
int i;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", nume);
else
{
lista_studenti(f);
fseek(f,0,2);//pozitionare la sfarsitul fisierului
printf("[Link]: ");scanf("%d",&[Link]);
while(!feof(stdin))
{
printf("Nume: ");getchar(); gets([Link]);
printf("Grupa: ");scanf("%d",&[Link]);
[Link]=0;
for(i=0;i<10;i++)[Link][i]=0;
[Link]=0;
fwrite(&s,sizeof(STUDENT),1,f);
printf("[Link]: ");scanf("%d",&[Link]);
}
fclose(f);}
}
La urmatoarea listare in fișier text se poate observa că cei doi studenți au fost adaugați la sfârșitul fișierului
15
3. Problema 3
void main()
{FILE *f;
char nume[30];
STUDENT s;
int n;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", nume);
else
{
lista_studenti(f);
printf("\n Numarul matricol:"); scanf("%d",&n);
while(!feof(stdin))
{
if(n>=nrart(f,sizeof(STUDENT)))
printf("Studentul nu exista!");
else{
fseek(f,n*sizeof(STUDENT),0);
fread(&s,sizeof(STUDENT), 1, f);
if([Link]==0) printf("Studentul nu exista!");
else{
fseek(f,n*sizeof(STUDENT),0);
printf("Studentul %s va fi exmatriculat: ",[Link]);
[Link]=0;
fwrite(&s,sizeof(STUDENT), 1, f);
}
}
printf("\nNumar matricol: "); scanf("%d",&n);
}
fclose(f);}
}
După încă o apelare se poate observa că în fișierul text rezultat nu mai apare studentul cu numarul matricol
respectiv
17
4. Problema 4 – tema
Obs. Este tot o modificare (ca si la problema anterioara), dar a altui câmp din structura articolului
Important: se va avea în vedere lucrul cu fișiere binare organizate secvențial și relativ (a se vedea toate operațiile
discutate la curs), precum și rapoarte în fișiere text
18
Seminar 7
Complexitatea algoritmilor. Algoritmi de sortare
1. Complexitatea algoritmilor
- Calcul timp de execuție pentru sortarea prin inserție
2. Algoritmi de sortare
1. Sortarea Shell
2. Sortarea prin interclasare
3. Sortarea Heap
4. Sortarea rapidă
5. Sortarea prin numărare
1. Complexitatea algoritmilor
- Exemplu - Calcul timp de execuție pentru sortarea prin inserție
Obs:
Timpul total de execuție este egal cu numărul prelucrărilor elementare executate.
Termenul dominant este termenul care devine semnificativ mai mare decât ceilalți atunci
când dimensiunea problemei crește (dictează comportarea algoritmului când dimensiunea
problemei crește).
Ordinul de creștere caracterizează creșterea termenului dominant al timpului de execuție
în raport cu dimensiunea problemei.
Pseudocod:
do-for j=2,n,1
{ aux=x[j];
i=j-1;
{ x[i+1]=x[i];
i=i-1
}endwhile
X[i+1]=aux
}enddo
19
Operație Cost Nr. repetări Caz favorabil Caz nefavorabil
1 C1 n n n
2 C2 n-1 n-1 n-1
3 C3 n-1 n-1 n-1
𝑛 𝑛 𝑛
4 C4 𝑛(𝑛 + 1)
1=n-1
𝑡𝑗 𝑗=2 𝑗= ―1
𝑗=2
2
𝑗=2
𝑛 𝑛
5 C5 0 𝑛(𝑛 ― 1)
(𝑡𝑗 ― 1) 𝑗=
𝑗=2
2
𝑗=2
𝑛 𝑛
6 C6 0 𝑛(𝑛 ― 1)
(𝑡𝑗 ― 1) 𝑗=
𝑗=2
2
𝑗=2
7 C7 n-1 n-1 n-1
T(n) (c1+c2+c3+c4+c7)n- ( c4/2 + c5/2 + c6/2 )n2
(c2+c3-c4-c7) +(c1+c2+c3+ c4/2 − c5/2
− c6/2
+c7)n−(c2+c3+c4+c7)
O(n) O(n2)
tj = 1, j = 2, . . . , n
tj = j, j = 2, . . . , n
T(n) = c1n+c2(n-1)+c3(n-1)+c4(n(n+1)/2-1)+c5n(n-1)/2+c6n(n-1)/2+c7(n-1)=
2. Algoritmi de sortare
2.1. Sortarea Shell (cu micsorarea incrementului)
#include<stdio.h>
void sort_shell(double v[], int l)
{ int i,j,inc;
double a;
20
for(inc=l/2;inc>0;inc=inc/2)
for(i=inc;i<l;i++)
for(j=i-inc;(j>=0)&&(v[j]>v[j+inc]);j=j-inc)
{ a=v[j];
v[j]=v[j+inc];
v[j+inc]=a;
}
}
void main()
{ int n,i; double v[1000];
printf("n="); scanf("%i",&n);
for(i=0;i<n;i++)
{
printf("v[%d]=",i);
scanf("%lf",&v[i]);
}
sort_shell(v,n);
printf("Vectorul sortat\n");
for(i=0;i<n;i++) printf("%8.4lf ",v[i]);
}
#include<stdio.h>
void interclasare(float v[], int ls, int m, int ld)
{ int i, j, k; float v1[100];
for(i=ls, j=m+1, k=0; i<=m && j<=ld;k++)
v1[k]= (v[i]<v[j])?v[i++]:v[j++];
while(i<=m)v1[k++]=v[i++];
while(j<=ld)v1[k++]=v[j++];
for(i=0;i<k;i++)v[ls+i]=v1[i]; //for(i=ls;i<=ld;i++) v[i]=v1[i-ls];
}
21
{ int n,i; float x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%f", &x[i]);}
sortare(x, 0, n-1);
for (i=0;i<n;i++) printf("%3.1f ", x[i]);
}
22
for (i=n/2;i>=0;i--)
aranjeaza_heap(H,i,n);
}
void main()
{ int n,i; double x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%lf", &x[i]);}
heap_sort(x,n);
for (i=0;i<n;i++) printf("%3.1lf ", x[i]);
}
23
#include<stdio.h>
int poz(float *x,int p,int u)
{ int i,j,l,di,dj;
float v;
//di, dj: pasii de incrementare pentru i si j; ei indica sensul parcurgerii
i=p;j=u;di=0;dj=-1;
while(i<j)
if (x[i]>x[j])
{ v=x[i];x[i]=x[j];x[j]=v;
l=di;di=-dj;dj=-l;
i+=di;j+=dj;
}
else
{ i+=di;j+=dj;
}
return i;
}
void main()
{ int n,i; float v[1000];
printf("Dimensiunea vectorului:"); scanf("%i",&n);
printf("Elementele vectorului\n");
for(i=0;i<n;i++)
{
printf("v[%d]=",i);
scanf("%f",&v[i]);
}
quick(v,0,n-1);
printf("Vectorul sortat\n");
for(i=0;i<n;i++) printf("%8.4f ",v[i]);
}
#include<stdio.h>
#include<malloc.h>
24
void sort_numarare(double v[], int l)
{ int i,j, *num; double *temp;
temp=(double*)malloc(l*sizeof(double));
num=(int*)malloc(l*sizeof(int));
for(i=0;i<l;i++) num[i]=0;
for(i=0;i<l-1;i++)
for(j=i+1;j<l;j++)
if(v[j]<v[i]) num[i]++;
else num[j]++;
for(i=0;i<l;i++) temp[num[i]]=v[i];
for(i=0;i<l;i++) v[i]=temp[i];
free(temp); free(num);
}
void main()
{ int n,i; double x[100];
printf("n="); scanf("%d", &n);
for(i=0;i<n;i++)
{printf("x[%d]=", i);scanf("%lf", &x[i]);}
sort_numarare(x,n);
for (i=0;i<n;i++) printf("%3.1lf ", x[i]);
}
25
Sortarea HEAP (Heapsort)
Contents
1. Heap-uri ............................................................................................................................................1
2. Reconstituirea proprietații de heap..................................................................................................3
3. Construirea unui heap ......................................................................................................................6
4. Algoritmul heapsort..........................................................................................................................9
5. Cozi de prioritați .............................................................................................................................11
Timpul de execuție al agoritmului heapsort este O(n lg n), asemănător sortării prin
interclasare. Heapsort ordonează elementele în spațiul alocat vectorului, asemănător sortării prin
inserție: la un moment dat doar un număr constant de elemente ale vectorului sunt păstrate în afara
spațiului alocat vectorului de intrare. Astfel, algoritmul heapsort combină calitațile celor doi
algoritmi de sortare menționați mai sus.
Heapsort introduce o tehnică nouă de proiectare a algoritmilor bazată pe utilizarea unei
structuri de date. Structura de date heap este utilă nu doar pentru algoritmul heapsort, ea poate fi
la fel de utilă și în tratarea eficientă a unei cozi de prioritate. Termenul heap a fost introdus și
utilizat inițial în contextul algoritmului heapsort, dar acesta se foloseste și în legatură cu alocarea
dinamică.
1. Heap-uri
Structura de date heap (binar) este un vector care poate fi vizualizat sub forma unui arbore
binar aproape complet, conform figurii 1. Fiecare nod al arborelui corespunde unui element al
vectorului care conține valorile atasate nodurilor. Arborele este plin, exceptând eventual nivelul
inferior, care este plin de la stânga la dreapta doar pâna la un anumit loc. Un vector A care
reprezintă un heap are două atribute: lungime[A], reprezintă numărul elementelor din vector și
dimensiune-heap[A] reprezintă numărul elementelor heap-ului memorat în vectorul A. Astfel,
Pag 26 din 57
chiar dacă A[1..lungime[A]] conține în fiecare element al său date valide, este posibil ca
elementele urmatoare elementului A[dimensiune-heap[A]], unde dimensiune-heap[A] ≤
lungime[A], să nu aparțină heap-ului. Radacina arborelui este A[1]. Dat fiind un indice i,
corespunzator unui nod, se pot determina ușor indicii părintelui acestuia Parinte(i), al fiului
Stânga(i) și al fiului Dreapta(i).
Parinte(i)
returneaza [i/2]
Stânga(i)
returneaza 2i
Dreapta(i)
returneaza 2i + 1
1
16
2 3
14 10
4 5 6 7
8 7 9 3
8 9 10
2 4 1
Figura 1. a)
1 2 3 4 5 6 7 8 9 10
16 14 10 8 7 9 3 2 4 1
Figura 1. b)
Figura 1. Un heap reprezentat sub forma unui arbore binar (a) și sub forma unui vector (b)
Pag 27 din 57
implementare eficientă a algoritmului heapsort, aceste proceduri sunt adeseori codificate sub
forma unor “macro-uri” sau a unor proceduri “in-line”.
Pentru orice nod i, diferit de rădăcină, este adevarată urmatoarea proprietate de heap:
A[Parinte(i)] ≥A[i], (1)
adică valoarea atașată nodului este mai mică sau egală cu valoarea asociată părintelui său. Astfel
cel mai mare element din heap este păstrat în rădăcină, iar valorile nodurilor oricărui subarbore al
unui nod sunt mai mici sau egale cu valoarea nodului respectiv.
Definim înalțimea unui nod al arborelui ca fiind numărul muchiilor aparținând celui mai
lung drum care leagă nodul respectiv cu o frunză, iar înălțimea arborelui ca fiind înălțimea
rădăcinii. Deoarece un heap cu n elemente corespunde unui arbore binar complet, înălțimea
acestuia este Θ(lg n). Timpul de execuție al operațiilor de bază, care se efectuează pe un heap, este
proporțional cu înălțimea arborelui și este O(lg n). În cele ce urmează, sunt prezentate cinci
proceduri și modul lor de utilizare în algoritmul de sortare, respectiv într-o structură de tip coadă
de prioritate.
Procedura Reconstituie-Heap are timpul de execuție O(lg n) și este de primă importanță în
întreținerea proprietații de heap (1);
Procedura Construieste-Heap are un timp de execuție liniar și generează un heap dintr-un
vector neordonat, furnizat la intrare;
Procedura Heapsort se execută în timpul O(n lg n) și ordonează un vector în spațiul alocat
acestuia;
Procedurile Extrage-Max și Insereaza se execută în timpul O(lg n), iar cu ajutorul lor se
poate utiliza un heap în realizarea unei cozi de prioritate.
Pag 28 din 57
dacă l ≤ dimesiune-heap[A] și A[l] > A[i] atunci
maxim ← l
altfel
maxim ← i
dacă r ≤ dimesiune-heap[A] și A[r] > A[maxim] atunci
maxim ← r
dacă maxim ≠ i atunci
schimbă A[i] ↔ A[maxim]
Reconstituie-Heap(A, maxim)
1
16
2 3
i 4 10
4 5 6 7
14 7 9 3
8 9 10
2 8 1
Figura 2. a)
Pag 29 din 57
1
16
2 3
14 10
4 5 6 7
i 4 7 9 3
8 9 10
2 8 1
Figura 2. b)
1
16
2 3
14 10
4 5 6 7
8 7 9 3
8 9 10
2 4 1
Figura 2. c)
Pag 30 din 57
Soluția acestei recurențe se obține pe baza celui de-al doilea caz al teoremei master: T(n)
= O(lg n). Timpul de execuție al procedurii Reconstituie-Heap pentru un nod de înalțime h poate
fi exprimat alternativ ca fiind egal cu O(h).
Construieste-Heap(A)
dimesiune-heap[A] ← lungime[A]
pentru i ← [lungime[A]/2],1 execută
Reconstituie-Heap(A, i)
1 2 3 4 5 6 7 8 9 10
A 4 1 3 2 16 9 10 14 8 7
1
4
2 3
1 3
4 5 6 7
2 i 16 9 10
8 9 10
14 8 7
Pag 31 din 57
Figura 3. a)
1
4
2 3
1 3
4 5 6 7
i 2 16 9 10
8 9 10
14 8 7
Figura 3. b)
1
4
2 3
1 3 i
4 5 6 7
14 16 9 10
8 9 10
2 8 7
Figura 3. c)
1
4
2 3
i 1 10
4 5 6 7
14 16 9 3
8 9 10
2 8 7
Figura 3. d)
Pag 32 din 57
1
i 4
2 3
16 10
4 5 6 7
14 7 9 3
8 9 10
2 8 1
Figura 3. e)
1
16
2 3
14 10
4 5 6 7
8 7 9 3
8 9 10
2 4 1
Figura 3. f)
Timpul de execuție a procedurii Reconstituie-Heap pentru un nod de înalțime h fiind O(h), obținem
pentru timpul de execuție a procedurii Construieste-Heap:
lg 𝑛] 𝑛
∑[ℎ=0 [𝑙𝑔𝑛] ℎ
[2ℎ+1]𝑂(ℎ) = 𝑂 𝑛 ∑ℎ=0 2ℎ (2)( )
Ultima însumare poate fi evaluată prin înlocuirea x:
1
ℎ 2
∑∞
ℎ=0 2ℎ ― 1 2
= 2 (3)
(1 ― ) 2
Pag 33 din 57
Astfel, timpul de execuµie al procedurii Construieste-Heap poate fi estimat ca fiind:
( [lg〖𝑛]〗 ℎ
) ∞
(ℎ
𝑂 𝑛 ∑ℎ=0 ℎ = 𝑂 𝑛 ∑ℎ=0 ℎ = 𝑂(𝑛) (4)
2 2 )
De aici rezultă că se poate construi un heap dintr-un vector într-un timp liniar.
4. Algoritmul heapsort
Heapsort(A)
Construieste-Heap(A)
pentru i ← lungime[A], 2 execută
schimbă A[1] ↔ A[i]
dimesiune-heap[A] ← dimesiune-heap[A] - 1
Reconstituie-Heap(A,1)
16 14
14 10 8 10
8 7 9 3 4 7 9 3
2 4 1 2 1 16 i
Figura 4. a) Figura 4. b)
Pag 34 din 57
10 9
8 9 8 3
4 7 1 3 4 7 1 2
i i
2 14 16 10 14 16
Figura 4. c) Figura 4. d)
8 7
7 3 4 3
4 2 1 i 9 1 2 8 i 9
10 14 16 10 14 16
Figura 4. e) Figura 4. f)
4 3
2 3 2 1
1 7 i 8 9 4 i 7 8 9
10 14 16 10 14 16
Figura 4. g) Figura 4. h)
2 1
1 3 i 2 i 3
4 7 8 9 4 7 8 9
10 14 16 10 14 16
Figura 4. i) Figura 4. j)
1 2 3 4 5 6 7 8 9 10
A 1 2 3 4 7 8 9 10 14 16
Figura 4. Modul de funcționare a algoritmului Heapsort. (a) Structura de date heap, imediat după
construirea sa de către procedura Construieste-Heap. (b)-(j) Heap-ul, imediat după câte un apel al
procedurii Reconstituie-Heap (linia 5 în algoritm). Figura reprezintă valoarea curenta a variabilei
i. Din heap fac parte doar nodurile din cercurile nehașurate. (k) Vectorul A ordonat, obținut ca
rezultat.
Pag 35 din 57
5. Cozi de prioritați
Extrage-Max-Din-Heap(A)
dacă dimesiune-heap[A] < 1 atunci
eroare “depășire inferioară heap”
max ←A[1]
A[1] ← A[dimesiune-heap[A]]
dimesiune-heap[A] ← dimesiune-heap[A] - 1
Reconstituie-Heap(A,1)
returnează maxim
Pag 36 din 57
Procedura Insereaza-În-Heap inserează un nod în heap-ul A. La prima expandare a heap-
ului se adaugă o frunză arborelui. Apoi, se traversează un drum pornind de la această frunză către
rădăcină, în scopul găsirii locului definitiv al noului element.
Insereaza-În-Heap(A,cheie)
dimesiune-heap[A] ← dimesiune-heap[A] + 1
i ←dimesiune-heap[A]
cât timp i > 1 și A[Parinte(i)] < cheie execută
A[i] ←A[Parinte(i)]
i ←Parinte(i)
A[i] ← cheie
16 16
14 10 14 10
8 7 9 3 8 7 9 3
2 4 1 2 4 1
Figura 5. a) Figura 5. b)
16 16
10 15 10
8 14 9 3 8 14 9 3
2 4 1 7 2 4 1 7
Figura 5. c) Figura 5. d)
Figura 5. Operația Insereaza-În-Heap. (a) Heap-ul din figura 4(a) înainte de inserarea nodului
având cheia 15. (b) Se adaugă arborelui o frunză nouă. (c) Se “scufundă” valorile de pe drumul
dintre frunză și rădăcină până la găsirea nodului corespunzator cheii 15. (d) Se inserează cheia 15.
Pag 37 din 57
Sortări în timp liniar
Cuprins
1. Sortarea prin numărare (Counting Sort)...........................................................................................1
2. Sortare pe baza cifrelor (Radix Sort).................................................................................................3
3. Sortarea pe grupe (Bucket Sort) .......................................................................................................3
In cadrul sortării prin numărare se presupune că fiecare dintre cele n elemente ale datelor de
intrare este un număr întreg între 1 şi k, pentru un număr întreg k oarecare. Când k = O(n), sortarea
se execută în timpul O(n).
Ideea de bază în sortarea prin numărare este de a determina numărul de elemente mai mici
decât x, pentru fiecare element x din datele de intrare. Această informaţie poate fi utilizată pentru
a poziţiona elementul x direct pe poziţia sa din tabloul de ieşire. De exemplu, dacă există 10
elemente mai mici decât x, atunci x va fi pe poziţia 11 în tabloul de ieşire.
Un caz particular apare atunci când în datele de intrare există mai multe elemente care au
aceeași valoare și acestea nu trebuie așezate toate pe aceeași poziție. In acest caz, schema de
rezolvare trebuie puțin modificată.
Pag 38 din 57
În algoritmul pentru sortarea prin numărare presupunem că datele de intrare formează un tablou
A[1..n], şi deci lungime [A] = n (figura 1). Sunt necesare alte două tablouri suplimentare:
- tabloul B [1..n] care cuprinde datele de ieşire sortate
- tabloul C [1..k] pentru stocarea temporară în timpul lucrului.
Pag 39 din 57
Algoritmul de sortare prin numărare conform algoritmului descris presupune:
- iniţializarea din liniile 1–2
- în liniile 3–4 se contorizează fiecare element de intrare. Dacă valoarea unui element
de intrare este i, se incrementează valoarea lui C [i]. Astfel, după liniile 3–4, C[i]
păstrează un număr de elemente de intrare egal cu i pentru fiecare număr întreg i =
1, 2, … , k.
- în liniile 6–7 se determină, pentru fiecare i = 1, 2,…, k, numărul elementelor de
intrare mai mici sau egale decât i; aceasta se realizează prin păstrarea în C[k] a
sumei primelor k elemente din tabloul iniţial.
- în liniile 9–11, fiecare element A[j] se plasează pe poziţia sa corect determinată din
tabloul de ieşire B, astfel încât acesta este ordonat. Dacă toate cele n elemente sunt
distincte, la prima execuţie a liniei 9, pentru fiecare A[j], valoarea C[A[j]] este
poziţia finală corectă a lui A[j] în tabloul de ieşire, întrucât există C[A[j]] elemente
mai mici sau egale cu A[j]. Deoarece elementele ar putea să nu fie distincte,
decrementăm valoarea C[A[j]] de fiecare dată când plasăm o valoare A[j] în tabloul
B; aceasta face ca următorul element de intrare cu o valoare egală cu A[j], dacă
există vreunul, să meargă în poziţia imediat dinaintea lui A[j] în tabloul de ieşire.
Pag 40 din 57
Ordonarea pe baza cifrelor este algoritmul folosit de către maşinile de sortare a cartelelor,
care se mai găsesc la ora actuală numai în muzeele de calculatoare.
Modalitate de organizare a cartelelor. Cartelele sunt organizate în 80 de coloane, şi fiecare
coloană poate fi perforată în 12 poziţii. Sortatorul poate fi “programat” mecanic să examineze o
coloană dată a fiecărei cartele dintr-un pachet şi să distribuie fiecare cartelă într-una dintre cele 12
cutii, în funcţie de poziţia perforată. Un operator poate apoi să strângă cartelele cutie cu cutie,
astfel încât cartelele care au prima poziţie perforată să fie deasupra cartelelor care au a doua poziţie
perforată ş.a.m.d.
Pentru cifre zecimale sunt folosite numai 10 poziţii în fiecare coloană. (Celelalte două poziţii
sunt folosite pentru codificarea caracterelor nenumerice). Un număr având d cifre ar ocupa un
câmp format din d coloane. Întrucât sortatorul de cartele poate analiza numai o singură coloană la
un moment dat, problema sortării a n cartele în funcţie de un număr având d cifre necesită un
algoritm de sortare.
Intuitiv, s-ar putea sorta numerele în funcţie de cea mai semnificativă cifră, să se sorteze recursiv
fiecare dintre cutiile ce se obţin, şi apoi să se combine pachetele în ordine. Un dezavantaj al acestei
abordări ar fi că acele cartele din 9 dintre cele 10 cutii trebuie să fie păstrate pentru a putea sorta
fiecare dintre cutii, această procedură generând teancuri intermediare de cartele care trebuie
urmărite.
Ordonarea pe baza cifrelor rezolvă problema sortării cartelelor într-un mod care contrazice
intuiţia, sortând întâi în funcţie de cea mai puţin semnificativă cifră. Cartelele sunt apoi combinate
într-un singur pachet, cele din cutia 0 precedând cartelele din cutia 1, iar acestea din urmă
precedând pe cele din cutia 2 şi aşa mai departe. Apoi întregul pachet este sortat din nou în funcţie
de a doua cifră cea mai puţin semnificativă şi recombinat apoi într-o manieră asemănătoare.
Procesul continuă până când cartelele au fost sortate pe baza tuturor celor d cifre.
De remarcat că în acel moment cartelele sunt complet sortate în funcţie de numărul având d
cifre. Astfel, pentru sortare sunt necesare numai d treceri prin lista de numere. În figura 3 este
ilustrat modul de operare al algoritmului de ordonare pe baza cifrelor pe un “pachet” de şapte
numere de câte trei cifre.
Pag 41 din 57
Modul de funcţionare al algoritmului de ordonare pe baza cifrelor pe o listă de şapte numere a
câte 3 cifre (figura 3):
- prima coloană este intrarea
- celelalte coloane prezintă lista după sortări succesive în funcţie de poziţiile cifrelor în
ordinea crescătoare a semnificaţiei.
- săgeţile verticale indică poziţia cifrei după care s-a sortat pentru a produce fiecare listă din
cea precedentă.
Este important ca sortarea cifrelor în acest algoritm să fie stabilă. Sortarea realizată de către un
sortator de cartele este stabilă, dar operatorul trebuie să fie atent să nu schimbe ordinea cartelelelor
pe măsură ce acestea ies dintr-o cutie, chiar dacă toate cartelele dintr-o cutie au aceeaşi cifră în
coloana aleasă.
Într-un calculator care funcţionează pe bază de acces secvenţial aleator, ordonarea pe baza cifrelor
este uneori utilizată pentru a sorta înregistrările de informaţii care sunt indexate cu chei având
câmpuri multiple.
De exemplu, am putea dori să sortăm date în funcţie de trei parametri: an, lună, zi.
Am putea executa un algoritm de sortare cu o funcţie de comparare care, considerând două date
calendaristice, compară anii, şi dacă există o legătură, compară lunile, iar dacă apare din nou o
legătură, compară zilele. Alternativ, am putea sorta informaţia de trei ori cu o sortare stabilă: prima
după zi, următoarea după lună, şi ultima după an.
Pseudocodul pentru algoritmul de ordonare pe baza cifrelor este intuitiv (figura 4). Următoarea
procedură presupune:
- că într-un tablou A având n elemente, fiecare element are d cifre
- cifra 1 este cifra cu ordinul cel mai mic
- cifra d este cifra cu ordinul cel mai mare.
Timp de execuție. Analiza timpului de execuţie depinde de sortarea stabilă folosită ca algoritm
intermediar de sortare. Când fiecare cifră este în intervalul [1; k], iar k nu este prea mare, sortarea
prin numărare este opţiunea evidentă. Fiecare trecere printr-o mulţime de n numere a câte d cifre
se face în timpul ʘ(n + k). Se fac d treceri, astfel încât timpul total necesar pentru algoritmul de
ordonare pe baza cifrelor este ʘ(dn + kd). Când d este constant şi k = O(n), algoritmul de ordonare
pe baza cifrelor se execută în timp liniar.
Unii informaticieni consideră că numărul biţilor într-un cuvânt calculator este ʘ(lg n). Pentru
exemplificare, să presupunem că d lg n este numărul de biţi, unde d este o constantă pozitivă.
Pag 42 din 57
Atunci, dacă fiecare număr care va fi sortat încape într-un cuvânt al calculatorului, îl vom putea
trata ca pe un număr având d cifre reprezentat în baza n.
De exemplu, să considerăm sortarea a 1 milion de numere având 64 de biţi. Tratând aceste numere
ca numere de patru cifre în baza 216, putem să le sortăm pe baza cifrelor doar prin patru treceri,
comparativ cu o sortare clasică prin comparaţii de timp ʘ(n lg n) care necesită aproximativ lg n =
20 de operaţii pentru fiecare număr sortat.
Din păcate, versiunea algoritmului de ordonare pe baza cifrelor care foloseşte sortarea prin
numărare ca sortare intermediară stabilă nu sortează pe loc, lucru care se întâmplă în cazul multora
din sortările prin comparaţii de timp ʘ(n lg n). Astfel, dacă se doreşte ca necesarul de memorie să
fie mic, atunci este preferabil algoritmul de sortare rapidă.
Sortarea pe grupe se execută, în medie, în timp liniar. Ca şi sortarea prin numărare, cea pe
grupe este rapidă pentru că face anumite presupuneri despre datele de intrare. În timp ce sortarea
prin numărare presupune că intrarea constă din întregi dintr-un domeniu mic, ordonarea pe grupe
presupune că intrarea este generată de un proces aleator care distribuie elementele în mod uniform
în intervalul [0; 1).
Principiul algoritmului de ordonare pe grupe este de a împărţi intervalul [0; 1) în n
subintervale egale, numite grupe (engl. buckets) şi apoi să distribuie cele n numere de intrare în
aceste grupe. Întrucât datele de intrare sunt uniform distribuite în intervalul [0; 1), nu ne aşteptăm
să fie prea multe numere în fiecare grupă. Pentru a obţine rezultatul dorit, sortăm numerele din
fiecare grupă, apoi trecem prin fiecare grupă în ordine, listând elementele din fiecare.
Pseudocodul pentru ordonarea pe grupe presupune că datele de intrare formează un tablou
A având n elemente şi că fiecare element A[i] satisface relaţia 0 <= A[i] < 1.
Codul necesită un tablou auxiliar B[0..n-1] de liste înlănţuite (reprezentând grupele) şi
presupune că există un mecanism pentru menţinerea acestor liste.
Pentru a demonstra că acest algoritm funcţionează corect, se consideră două elemente A[i] şi A[j].
Dacă aceste elemente sunt distribuie în aceeaşi grupă, ele apar în ordinea relativă adecvată în
secvenţa de ieşire, deoarece grupa lor este sortată de sortarea prin inserţie. Să presupunem, totuşi,
că ele sunt distribuite în grupe diferite. Fie aceste grupe B[i’] şi respectiv B[j’], şi să presupunem,
fără a pierde din generalitate, că i’ < j’ . Când listele lui B sunt concatenate în linia 6, elementele
grupei B[i’] apar înaintea elementelor lui B [j’], şi astfel A[i] precede A[j] în secvenţa de ieşire.
Pag 43 din 57
Timp de execuție. Pentru a analiza timpul de execuţie, să observăm mai întâi că toate liniile, cu
excepţia liniei 5, necesită, în cel mai defavorabil caz, timpul O(n). Timpul total pentru a examina
în linia 5 toate grupele este O(n) şi, astfel, singura parte interesantă a analizei este timpul consumat
de sortările prin inserţie din linia 5.
Pentru a analiza costul sortărilor prin inserţie, fie ni o variabilă aleatoare desemnând numărul de
elemente din grupa B[i]. Întrucât sortarea prin inserţie se execută în timp pătratic (timpul de
execuţie în cazul cel mai defavorabil poate fi exprimat sub forma a*n2 + b*n + c, unde constantele
a, b şi c depind, din nou, de costurile ci ale instrucţiunilor, fiind astfel o funcţie pătratică de n),
timpul necesar sortării elementelor în grupele B [i] este:
În consecinţă, timpul mediu total necesar sortării tuturor elementelor în toate grupele va fi:
In concluzie, timpul mediu pentru sortarea prin inserţie este O(n). Astfel, întregul algoritm de
ordonare pe grupe se execută în timp mediu liniar.
Pag 44 din 57
Lucrul cu fişiere organizate relativ: exemple
Enunțuri:
1. Să se scrie programul care creează un fişier organizat relativ cu date despre produsele unei societăţi
comerciale. Datele care se reţin despre produse sunt: denumirea, pret, cantitate (maxim 12). Cheia relativă
a fişierului este codul produsului. Datele se preiau de la tastatură, sfârşitul introducerii fiind marcat
standard. (exemplu de creare). Să se modifice programul pentru a realiza și operația de adăugare.
2. Să se scrie programul care listează, într-un fişier text, produsele cu cea mai mare valoare pe an. (exemplu
de consultare cu selecție)
3. Să se scrie programul pentru stergerea produselor care au inregistrat productie zero în cel puţin trei luni.
(exemplu de ștergere cu selecție)
Temă:
4. Să se scrie programul care modifică o cantitate pentru produsele ale căror coduri se introduc de la
tastatură. De la tastatură se va introduce luna (1-12) pentru care se modifica cantitatea. (exemplu de
modificare cod unic) Să se modifice programul astfel încât să se realizeze operațiile de consultare și
ștergere articol unic.
5. Să se scrie programul care listează într-un fişier text toate produsele realizate de societatea comercială.
(exemplu de consultare integrală)
Pag 45 din 57
Rezolvări:
1. Să se scrie programul care creează un fişier organizat relativ cu date despre produsele unei societăţi
comerciale. Datele care se reţin despre produse sunt: denumirea, pret, cantitate (maxim 12). Cheia relativă
a fişierului este codul produsului. Datele se preiau de la tastatură, sfârşitul introducerii fiind marcat
standard.
#define _CRT_SECURE_NO_WARNINGS //în cazul în care apar avertismente de securitate
#include<stdio.h>
typedef struct{
char denumire[20];
float pret;
int cant[12];
char is;
}PRODUS;
int nrart(FILE *f, int l)
{long p; int n;
p=ftell(f); fseek(f,0,2); n=ftell(f)/l;
fseek(f,p,0);return n;}
void main()
{FILE *f;
char nume[20]; PRODUS p; int i, cod;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"wb+");
printf("\n Cod produs"); scanf("%d",&cod);
while(!feof(stdin))
{if(cod>=nrart(f,sizeof(PRODUS)))
{[Link]=0; fseek(f,0,2);
for(i=nrart(f,sizeof(PRODUS));i<=cod;i++)
fwrite(&p,sizeof(PRODUS), 1, f);
}
fseek(f,cod*sizeof(PRODUS),0); fread(&p,sizeof(PRODUS), 1, f);
if([Link]) printf("\nExista deja un produs cu acest cod");
else{fseek(f,cod*sizeof(PRODUS),0);
printf("Denumire: "); getchar();gets([Link]);
printf("pret:"); scanf("%f",&[Link]);
for(i=0;i<12;i++) {printf("Cant %d: ",i+1); scanf("%d",&[Link][i]);}
[Link]=1; fwrite(&p,sizeof(PRODUS), 1, f);}
printf("\nCod: "); scanf("%d",&cod);}
fclose(f);}
Pag 46 din 57
2. Să se scrie programul care listează, într-un fişier text, produsele cu cea mai mare valoare pe an.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef struct{
char denumire[20];
float pret;
int cant[12];
char is;
}PRODUS;
void main()
{FILE *f, *g; char nume[20];
PRODUS p; float max, val; int i, cod;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb");
if(!f)printf("\nFisierul %s nu poate fi deschis",nume);
else{printf("\nFisier text: "); gets(nume); g=fopen(nume,"w");
max=0; cod=0;
fprintf(g,"\n Produsele sunt:");
fread(&p,sizeof(PRODUS), 1, f);
while(!feof(f))
Pag 47 din 57
{if([Link])
{val=0;
for(i=0;i<12;i++)val+=[Link][i]*[Link];
if(val>max)
{fclose(g);
g=fopen(nume,"w");
max=val;
fprintf(g,"\n Produsele cu valoarea %5.2f sunt:", max);
}
if(val==max)
fprintf(g,"\n%4d %-30s",cod, [Link]);}
cod++;
fread(&p,sizeof(PRODUS), 1, f);}
fclose(g);
fclose(f);}
}
3. Să se scrie programul pentru stergerea produselor care au inregistrat productie zero în cel puţin trei luni.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
typedef struct{
char denumire[20];
float pret;
int cant[12];
char is;
}PRODUS;
void main()
{FILE *f; char nume[20]; PRODUS p; int i, e, n;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis",nume);
else{n=0;
fread(&p,sizeof(PRODUS), 1, f);
Pag 48 din 57
while(!feof(f))
{if([Link])
{e=0;
for(i=0;i<12 && e<3;i++) if([Link][i]==0) e++;
if(e>=3)
{printf("\n%-30s",[Link]);
fseek(f,ftell(f)-sizeof(PRODUS),SEEK_SET);
[Link]=0; fwrite(&p,sizeof(PRODUS), 1, f);
fseek(f,0,1);
n++;}
}
fread(&p,sizeof(PRODUS), 1, f);}
fclose(f); printf("\nAu fost sterse %d produse",n);}
}
Pag 49 din 57
Lucrul cu fișiere text și fișiere binare – probleme economice
Probleme propuse:
1. Fie un fişier organizat secvențial, cu date referitoare la punctele obținute de studenți la disciplina Algoritmi și
tehnici de programare. Articolele au următoarea structură:
Puncte proba practică Puncte teme (0-1)
Nr. matricol Nume şi prenume Grupa Puncte examen (0-50)
(0-30) 1 2 … 10
cha cha cha cha
int char[30] int char char
r r r r
Scrieți programul care înregistrează în fișier punctajul obținut de un student la examen. Studentul este identificat
prin numărul matricol. Programul trebuie să ofere posibilitatea repetării, pentru înregistrarea punctajelor mai
multor studenți.
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
2. Fie un fişier organizat secvențial, cu date referitoare la punctele obținute de studenți la disciplina Algoritmi și
tehnici de programare. Articolele au următoarea structură:
Puncte proba practică Puncte teme (0-1)
Nr. matricol Nume şi prenume Grupa Puncte examen (0-50)
(0-30) 1 2 … 10
cha cha cha cha
int char[30] int char char
r r r r
Scrieți programul care înregistrează înmatricularea unui nou student (punctajele vor avea valori nule).
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
3. Fie un fişier organizat relativ, cu date referitoare la absențele studenților de la cursuri și seminarii/laboratoare
pentru fiecare dintre cele 15 discipline specifice fiecărui an de studiu. Cheia relativă este numărul matricol al
studentului (domeniul de valori pentru numerele matricole începe de la 0). Articolele au următoarea structură:
An Absențe (0-14)
Indicator de stare (0/1) Nr. matricol Nume şi prenume Grupa
(1-5) 1 2 … 15
C S C S C S
char int char[25] int char
char char char char char char
Numărul de activități la fiecare disciplină este 14.
Scrieţi un program care înregistrează exmatricularea unui student. Studentul este identificat prin numărul matricol.
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
4. Fie un fişier organizat relativ, cu date referitoare la absențele studenților de la cursuri și seminarii/laboratoare
pentru fiecare dintre cele 15 discipline specifice fiecărui an de studiu. Cheia relativă este numărul matricol al
studentului (domeniul de valori pentru numerele matricole începe de la 0). Articolele au următoarea structură:
An Absențe (0-14)
Indicator de stare (0/1) Nr. matricol Nume şi prenume Grupa
(1-5) 1 2 … 15
C S C S C S
char int char[25] int char
char char char char char char
Numărul de activități la fiecare disciplină este 14.
Scrieţi un program care înregistrează o nouă absență a unui student la o activitate. Studentul este identificat prin
numărul matricol, activitatea este identificată prin poziția în vector (1-15) și tip (Curs/Seminar).
50
Includeți în program un subprogram care generează, într-un fișier text, o listă cu toate datele din fișierul binar.
Lista trebuie să apară ca tabel, cu coloanele corect aliniate.
Exemple de rezolvare:
Observatii:
Fisierul binar trebuie sa se regaseasca in directorul proiectului
În Visual Studio versiuni mai noi extensia fișierului sursă trebuie să fie .c (nu .cpp) – (dacă aveți eroare
legată de funcția gets)
#define _CRT_SECURE_NO_WARNINGS //în cazul în care apar avertismente legate de securitate
1. Problema 1
//Fisierul binar se numeste [Link]
#include<stdio.h>
void main()
{FILE *f;
char nume[30];
51
STUDENT s;
int gasit,n,j;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", nume);
else
{
lista_studenti(f);
printf("\nNr. matricol: ");scanf("%d",&n);
while(!feof(stdin))
{rewind(f);
fread(&s,sizeof(STUDENT),1,f);
gasit=0;
while((!feof(f))&&(gasit==0))
{
if(n==[Link])
{gasit=1;
printf("\[Link]:%3d Nume: %-30s Grupa: %4d Punctaj pp: %2d\n: ",[Link],[Link],[Link], [Link]);
for(j=0;j<10;j++)
printf("%2d ",[Link][j]);
printf("Punctaj examen: %2d ",[Link]);
printf("Introduceti punctajul la examen:");
scanf ("%d", &[Link]);
fseek(f, ftell(f)-sizeof(STUDENT),0);
fwrite(&s, sizeof(STUDENT), 1, f);
}else
fread(&s,sizeof(STUDENT),1,f);
}
if(gasit==0)printf("\nNu a fost gasit.");
printf("\nNr. matricol: ");scanf("%d",&n);
}
fclose(f);}
}
52
Va fi creat fișierul text cu studenții din fișierul binar
2. Problema 2
53
fprintf(g,"%2d ",[Link][i]);
fprintf(g,"%6d ",[Link]);
fread(&s,sizeof(STUDENT),1,f);
}
fclose(g);
}
void main()
{FILE *f;
char nume[30];
STUDENT s;
int i;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", nume);
else
{
lista_studenti(f);
fseek(f,0,2);//pozitionare la sfarsitul fisierului
printf("[Link]: ");scanf("%d",&[Link]);
while(!feof(stdin))
{
printf("Nume: ");getchar(); gets([Link]);
printf("Grupa: ");scanf("%d",&[Link]);
[Link]=0;
for(i=0;i<10;i++)[Link][i]=0;
[Link]=0;
fwrite(&s,sizeof(STUDENT),1,f);
printf("[Link]: ");scanf("%d",&[Link]);
}
fclose(f);}
}
La urmatoarea listare in fișier text se poate observa că cei doi studenți au fost adaugați la sfârșitul fișierului
54
3. Problema 3
void main()
{FILE *f;
char nume[30];
STUDENT s;
int n;
printf("\nFisier: ");gets(nume);
f=fopen(nume,"rb+");
if(!f)printf("\nFisierul %s nu poate fi deschis", nume);
else
{
lista_studenti(f);
printf("\n Numarul matricol:"); scanf("%d",&n);
while(!feof(stdin))
{
if(n>=nrart(f,sizeof(STUDENT)))
printf("Studentul nu exista!");
else{
fseek(f,n*sizeof(STUDENT),0);
fread(&s,sizeof(STUDENT), 1, f);
if([Link]==0) printf("Studentul nu exista!");
else{
fseek(f,n*sizeof(STUDENT),0);
printf("Studentul %s va fi exmatriculat: ",[Link]);
[Link]=0;
fwrite(&s,sizeof(STUDENT), 1, f);
}
}
printf("\nNumar matricol: "); scanf("%d",&n);
}
fclose(f);}
}
După încă o apelare se poate observa că în fișierul text rezultat nu mai apare studentul cu numarul matricol
respectiv
56
4. Problema 4 – tema
Obs. Este tot o modificare (ca si la problema anterioara), dar a altui câmp din structura articolului
Important: se va avea în vedere lucrul cu fișiere binare organizate secvențial și relativ (a se vedea toate operațiile
discutate la curs), precum și rapoarte în fișiere text
57