Fișiere text

Fișiere text și algoritmul eficient de la III.3

Cum citești dintr-un fișier până la capăt, cum scrii într-unul și ce înseamnă algoritm eficient la barem. III.3 rezolvat pe patru lucrări, cu descrierea în cuvinte pentru a) și programul pentru b).

  • 30 min
  • La BAC: Subiectul al III-lea, 3 a (2p) · Subiectul al III-lea, 3 b (8p)
  • De revizuit
Ilustrație: Fișiere text și algoritmul eficient de la III.3
Ilustrație generată pentru ZECE (artistică, nu o planșă științifică: pentru detalii exacte vezi schemele din lecție).

ții minte doar fișa asta și ești acoperit

Fișa de aur

  1. 01

    Citirea: ifstream f("bac.txt"); apoi while(f>>x) citește până la capăt.

  2. 02

    Scrierea: ofstream g("bac.txt"); apoi g<<x<<" "; exact ca la cout.

    Truc: f>> ca cin, g<< ca cout.

  3. 03

    III.3 b = 8 p: operații cu fișiere 1, valori determinate 5, eficiență 1, declarări și afișare 1.

  4. 04

    III.3 a = 2 p: descriere coerentă 1 și justificarea eficienței 1.

  5. 05

    Eficient, la barem: algoritm liniar. Dacă enunțul cere și memorie, nu memorezi tot șirul când n-ai nevoie.

  6. 06

    Fără tablou mare: păstrezi doar ultima valoare sau ultimele două. Dacă valorile sunt mici, vector de frecvență.

1 din 9

Pe scurt

1 minesențialul, de recitit oricând

Culorile din lecție:termenidee-cheie

  • Fișierele text se citesc și se scriu cu aceleași operatori ca tastatura și ecranul.
  • La III.3, cerința are două părți: a) descrii algoritmul și justifici eficiența; b) scrii programul.
  • „Eficient”, pentru barem, înseamnă algoritm liniar, iar când enunțul cere și memorie, folosire eficientă a memoriei.
  • Tema apare la ambele specializări, de cele mai multe ori cu o cerință mai simplă la științele naturii.

Fișierul, ca o tastatură care nu obosește

3 min o întrebare la final

Programul citește dintr-un fișier la fel cum citește de la tastatură. Îi spui o dată de unde citește, apoi folosești >> ca la cin.

#include <iostream>
#include <fstream>
using namespace std;

int main()
{ ifstream f("bac.txt");
  int x,s=0;
  while(f>>x)
    s=s+x;
  f.close();
  cout<<s;
  return 0;
}

Oficial: fișierele text au acces secvențial: se parcurg de la început spre sfârșit. ifstream deschide pentru citire, ofstream pentru scriere. while(f>>x) se oprește când nu mai sunt valori de citit. Pentru scriere:

ofstream g("bac.txt");
g<<1<<" "<<2;
g.close();
Deschidere pentru citire
C++
ifstream f("bac.txt");
C
FILE *f=fopen("bac.txt","r");
Pascal
assign(f,'bac.txt'); reset(f);
Deschidere pentru scriere
C++
ofstream g("bac.txt");
C
FILE *g=fopen("bac.txt","w");
Pascal
assign(g,'bac.txt'); rewrite(g);
Citire
C++
f>>x
C
fscanf(f,"%d",&x)
Pascal
read(f,x)
Până la sfârșit
C++
while(f>>x)
C
while(fscanf(f,"%d",&x)==1)
Pascal
while not eof(f) do
Scriere
C++
g<<x
C
fprintf(g,"%d",x)
Pascal
write(g,x)
Închidere
C++
f.close();
C
fclose(f);
Pascal
close(f)
1 / 6

Ce bibliotecă incluzi pentru ifstream?

Ce înseamnă „eficient” la barem

5 min

Când enunțul zice „proiectați un algoritm eficient”, se referă la două criterii din programă: durata de executare și spațiul de memorie. Citește care dintre ele e cerut.

Enunțul spuneBaremul cere

eficient din punctul de vedere al timpului
algoritm liniar (model 2027)
eficient din punctul de vedere al timpului și al memoriei
algoritm liniar, care utilizează eficient memoria (iunie 2026, sesiunea specială 2026)

Oficial, un algoritm liniar face un număr de operații proporțional cu numărul de valori. Baremul din rezerva 2026 îl numește „de complexitate O(n)”. Două bucle imbricate pe tot șirul nu sunt liniare.

Oficial: cum arată baremul pentru III.3 (iunie 2026, varianta 3)

a) descriere coerentă a algoritmului — 1p (chiar dacă algoritmul nu este eficient)

a) elemente de eficiență justificate — 1p

b) operații cu fișiere: declarare, pregătire în vederea citirii, citire — 1p

b) valori determinate — 5p (numai 3p dacă parcurge pașii necesari, dar cu detalii care nu duc la rezultat)

b) eficiență a algoritmului — 1p (numai pentru algoritm liniar, care utilizează eficient memoria)

b) variabile declarate, afișare, corectitudine globală — 1p

Oficial: iunie 2026, varianta 3, III.3

5 min o întrebare la final

Fișierul bac.txt are cel mult 10⁴ numere, câte o pereche pe linie: poziția într-un clasament și tipul concursului (1 șah, 2 go), în ordine cronologică. Un rezultat e motivant dacă poziția e mai bună (mai mică) decât la concursul anterior de același tip. Afișează numărul de rezultate motivante la șah și la go. Pentru exemplul din enunț se afișează 3 2. (La SN se cere doar numărul de la șah.)

Ideea: nu ai nevoie de toate pozițiile. Pentru fiecare tip, ține minte doar ultima poziție.

Ce se întâmplă la fiecare pereche citită

  1. Citești p și c

  2. Compari p cu ultima poziție

    de același tip; dacă e mai mică, contorul crește

  3. Actualizezi ultima poziție

#include <iostream>
#include <fstream>
using namespace std;

int main()
{ ifstream f("bac.txt");
  int p,c,ups=-1,upg=-1,ns=0,ng=0;
  while(f>>p>>c)
    if(c==1)
    { if(p<ups) ns++;
      ups=p;
    }
    else
    { if(p<upg) ng++;
      upg=p;
    }
  f.close();
  cout<<ns<<" "<<ng;
  return 0;
}

Inițializarea cu -1 face ca primul rezultat de fiecare tip să nu se numere: poziția e cel puțin 1, deci nu e mai mică decât -1.

Răspuns-model pentru a) (formulare proprie)

Citesc din fișier, pe rând, câte o pereche (p, c). Pentru fiecare tip de concurs păstrez ultima poziție obținută, în ups și upg, inițializate cu -1, și câte un contor, ns și ng. Dacă poziția curentă este mai mică decât ultima de același tip, măresc contorul acelui tip. Apoi actualizez ultima poziție.

Algoritmul este eficient din punctul de vedere al timpului de executare, pentru că parcurge fișierul o singură dată, deci este liniar. Este eficient și din punctul de vedere al memoriei, pentru că folosește doar câteva variabile simple, fără să memoreze șirul.

Soluția din barem este chiar aceasta: ns, ng, ups, upg.

Cum reții ultimul rezultat pentru două tipuri de concurs?

Oficial: sesiunea specială 2026, varianta 4, III.3

4 min o întrebare la final

Șirul lunar de pachete livrate e 0 3 9 21 45 93 189 381...: fiecare termen este termenul precedent plus dublul diferenței dintre ultimii doi. Se citesc de la tastatură ultimul și penultimul termen. Se scriu în bac.txt, în ordine descrescătoare, toți termenii până la 0. Pentru 189 și 93, fișierul conține 189 93 45 21 9 3 0.

Ideea: mergi înapoi. Dacă x e termenul dinainte, z penultimul, y ultimul, relația dă y=z+2(z-x), adică y=3z-2x. Deci x=(3z-y)/2. Nu memorezi nimic în tablou.

#include <iostream>
#include <fstream>
using namespace std;

int main()
{ ofstream g("bac.txt");
  int x,y,z;
  cin>>y>>z;
  g<<y<<" "<<z;
  while(z>0)
  { x=(3*z-y)/2;
    g<<" "<<x;
    y=z;
    z=x;
  }
  g.close();
  return 0;
}

Barem: operații cu fișiere (declarare, pregătire pentru scriere, scriere) 1 p; valori determinate 5 p; algoritm eficient 1 p; declarări, citire și corectitudine globală 1 p. Baremul scrie x=[(3∙y-z)/2]: acolo y e ultima valoare afișată, iar z e cea dinaintea ei, adică invers decât aici.

La științele naturii, aceeași sesiune dă un șir mai simplu, 0 3 7 15 31 63 127 255..., în care fiecare termen e dublul precedentului plus 1, și se dă doar ultimul. Termenul anterior se obține cu x=(y-1)/2. Baremul adaugă: se oprește după ce s-a afișat 3, apoi se afișează 0, pentru că 3 nu se obține din 0 după aceeași regulă.

La curierat, cum afli termenul de dinaintea ultimilor doi?

Oficial: iunie 2025, varianta 1, III.3

2 min

Pe prima linie din bac.in este intervalul orar disponibil, apoi, pe câte o linie, intervalul fiecărui muzeu, în ordine. Un muzeu e convenabil dacă se poate vizita cel puțin o oră în timpul disponibil. Se afișează numărul de muzee convenabile și numărul de ordine al ultimului. Pentru exemplul din enunț, 3 4.

#include <iostream>
#include <fstream>
using namespace std;

int main()
{ ifstream f("bac.in");
  int h1,h2,c1,c2,v1,v2,nr=0,nv=0,ult=0;
  f>>h1>>h2;
  while(f>>c1>>c2)
  { nr++;
    if(c1>h1) v1=c1; else v1=h1;
    if(c2<h2) v2=c2; else v2=h2;
    if(v1<v2)
    { nv++;
      ult=nr;
    }
  }
  f.close();
  cout<<nv<<" "<<ult;
  return 0;
}

Două intervale au o parte comună de la maximul începuturilor până la minimul sfârșiturilor. Dacă această parte are cel puțin o oră, muzeul e bun. Soluția din barem e exact aceasta.

Oficial: model 2027, III.3, vector de frecvență

4 min

Numerele din bac.txt sunt rezultate: numărul problemei (1, 2 sau 3), punctajul (0–99) și indicativul echipei (10–99), lipite. De exemplu 19912: problema 1, 99 de puncte, echipa 12. Câștigă echipa cu cel mai mare total; la egalitate, cea cu mai multe probleme de 99 de puncte; apoi cea înscrisă mai devreme. La SN nu există criteriul cu 99.

Ideea: valorile posibile pentru echipă sunt puține, de la 10 la 99. Deci poți ține câte o valoare pentru fiecare echipă, oricât de lung ar fi fișierul.

#include <iostream>
#include <fstream>
using namespace std;

int main()
{ ifstream f("bac.txt");
  int p[100]={0},nr[100]={0},x,i,pct,em=10;
  while(f>>x)
  { i=x%100;
    x=x/100;
    if(x>99) pct=x%100;
    else pct=x%10;
    p[i]=p[i]+pct;
    if(pct==99) nr[i]++;
  }
  f.close();
  for(i=11;i<=99;i++)
    if(p[i]>p[em] || (p[i]==p[em] && nr[i]>nr[em]))
      em=i;
  cout<<em;
  return 0;
}

De ce două cazuri la pct? Un număr ca 3010 înseamnă problema 3, 0 puncte, echipa 10. După x/100 rămâne 30, deci punctajul e 30%10. Baremul scrie exact această distincție.

Parcurgând de la 10 la 99 și schimbând doar la strict mai bun, la egalitate totală rămâne echipa înscrisă mai devreme.

Ce se cere la BAC

4 mincum apare la examen

Citești o valoare și o compari cu ultima
Unde a apărut
iunie 2026 var. 3
Ce ții în memorie
ultima valoare, contor
Secvențe (scară, mesaj, perioadă)
Unde a apărut
iulie 2024 var. 3, august 2026 var. 1, august 2025 var. 4
Ce ții în memorie
lungimea curentă, lungimea maximă
Valori puține, într-un interval mic
Unde a apărut
model 2027
Ce ții în memorie
vector de frecvență
Scrii un șir înapoi în fișier
Unde a apărut
sesiunea specială 2026, rezervă 2026 var. 5
Ce ții în memorie
ultima valoare sau ultimele două
1 / 4

Citește atent ce se citește din fișier și ce se afișează pe ecran: la sesiunea specială 2026, datele vin de la tastatură, iar fișierul e pentru scriere.

Greșeli care costă puncte

1 mincapcanele de evitat

  • while(!f.eof()), cu prelucrarea ultimei valori de două ori.
  • Lipsește justificarea eficienței la a).
  • Spui „eficient” fără cei doi termeni: dacă enunțul cere timp și memorie, justifică-i pe amândoi.
  • Tablou imens pentru tot șirul, când ai nevoie doar de ultimele valori.
  • Dublă buclă pe tot fișierul, deci algoritm care nu mai e liniar.
  • Fișierul pus greșit: numele este în enunț, bac.txt sau bac.in, și trebuie scris exact.

Termeni-cheie

Fișier text
Un fișier cu numere și litere, ca un text obișnuit. Se parcurge de la început spre sfârșit (acces secvențial).
ifstream
Fluxul din fstream pentru citire dintr-un fișier: ifstream f("bac.txt");
ofstream
Fluxul din fstream pentru scriere într-un fișier: ofstream g("bac.txt");
while(f>>x)
Citește cât timp mai sunt valori. Se oprește singur la sfârșitul fișierului.
Algoritm liniar
Numărul de operații crește proporțional cu numărul de valori; O(n). Baremul îl cere la III.3.
Eficiență de memorie
Folosești doar ce e necesar: la cele mai multe III.3 asta înseamnă să nu memorezi tot șirul într-un tablou.
Vector de frecvență
Tablou în care poziția e o valoare, iar elementul e ce știm despre ea: f[x] este de câte ori a apărut x.

Notițele mele

Salvat local

Surse