dinamică
Declarările de date în cadrul programului folosesc
alocarea statică a memoriei, care se face în timpul
compilării, în funcţie de modul în care a fost declarată
variabila de memorie sau structura de date, iar în
timpul execuţiei programului nu mai poate fi modificată.
Reamintire:
Aplicație
Se citeşte dintr-un fişier text un şir de numere separate prin spaţiu cu care se creează o listă simplu înlănţuită în
ordinea în care sunt citite numerele din fişier.
Să se verifice dacă lista conţine numai numere distincte şi apoi să se adauge după fiecare număr impar din listă
valoarea 100 şi să se afişeze numerele din listă.
Pentru testarea programului se vor folosi două seturi de numere: {2, 5, 10, 3, 8} şi {2, 5, 10, 5, 8, 7}.
4. Eliminarea unui nod din lista
Paşii executaţi în acest algoritm sunt:
Pentru eliminarea unui nod din listă, în funcţie de PAS1. Se salvează adresa nodului prim în
situaţie, se poate întâlni una dintre următoarele pointerul q.
situații: PAS2. Succesorul nodului prim devine nodul
1. eliminarea primului nod; prim.
2. eliminarea ultimului nod; PAS3. Se cere eliberarea zonei de memorie de la
3. eliminarea unui nod din interiorul listei. adresa memorată în pointerul q.
După eiminare se va elibera zona de memorie
ocupată de nod. Se foloseşte o funcţie procedurală elimina_prim()
al cărei parametru prim de tip nod se transmite
4.1. Eliminarea primului nod din prin referinţă, deoarece este parametru de intrare-
lista ieşire.
void elimina_prim(nod *&prim)
{ nod *q=prim;
info urm info urm info urm info NULL prim=prim->urm;
delete q;
}
prim succesorul nodului prim ultim
devine nodul prim
4.2. Eliminarea ultimului nod din PAS3. Predecesorul nodului ultim devine nod
lista terminal (adresa de legătură este NULL).
PAS4. Predecesorul nodului ultim devine nodul
info urm info urm info NULL info NULL ultim.
PAS3. Se cere eliberarea zonei de memorie de la
adresa memorată în pointerul q.
prim predeccesorul nodului ultim ultim
devine nodul ultim
Se foloseşte o funcţie procedurală elimina_ultim()
al cărei parametru prim de tip nod se transmite prin
referinţă, deoarece este parametru de intrare-
Paşii executaţi în acest algoritm sunt: ieşire.
void elimina_ultim(nod *prim,nod *&ultim)
PAS1. Se salvează adresa nodului ultim în pointerul q.
PAS2. Se caută predecesorul ultimului nod, prin
{nod *p,*q=ultim;
parcurgerea listei începând de la primul nod, până la for (p=prim; p->urm->urm!=NULL; p=p->urm);
predecesorul nodului terminal (nodul care nu se leagă p->urm=NULL;
de nimic – adresa de legătură are valoarea NULL). ultim=p;
delete q;}
4.3. Eliminarea unui nod din
interiorul listei
Pentru a elimina nodul p aflat în interiorul listei, trebuie Se foloseşte funcţia procedurală elimina() ai cărei
să legăm predecesorul nodului de succesorul lui. Dar, parametri sunt de tip nod:
predecesorul unui nod nu este cunoscut. Eliminarea unui • p (adresa nodului care se elimină), care se transmite
nod din listă înseamnă de fapt eliminarea din listă a prin valoare, deoarece este parametru de intrare,
informaţiei pe care o conţine. Astfel, din listă nu se va • ultim, care se transmite prin referinţă, deoarece este
elimina nodul p, ci succesorul său (care este cunoscut), parametru de intrare-ieşire.
după ce informaţia din el a fost copiată în nodul p. Paşii
executaţi în acest algoritm sunt: void elimina( nod *p, nod *&ultim)
PAS1. Se salvează adresa succesorului nodului p în { nod *q=p->urm;
pointerul q. p->info=p->urm->info;
PAS2. Se copiază în nodul p toată informaţia din p->urm=p->urm->urm;
succesorul lui (informaţia propriu-zisă şi informaţia de delete q;
legătură). if (p->urm==NULL) ultim=p;
PAS3. Se cere eliberarea zonei de memorie de la }
adresa memorată în pointerul q.
PAS4. Dacă succesorul nodului p era nodul ultim, atunci
nodul p devine nodul ultim.
Se foloseşte o funcţie operand cu tipul pointer către tipul
5. Căutarea unui nod în listă nod. În ambele variante:
o parametrul funcţiei este prim de tip nod şi se transmite
Într-o listă se poate căuta: prin valoare, deoarece este parametru de intrare;
1. Nodul care îndeplineşte o anumită condiţie, pe care o variabila locală p de tip pointer către nod se foloseşte
o notăm cu conditie şi care este exprimată printr-o pentru parcurgerea listei – este iniţializată cu adresa
expresie logică ce conţine cel puţin un câmp cu primului nod;
informaţie din nod; valoarea condiţiei este dependentă o adresa nodului găsit se memorează în pointerul p care va
de informaţia stocată în nod. Algoritmul utilizat: se fi returnată de funcţie
parcurge lista începând de la primul nod, în ordinea de 1.
înlănţuire a nodurilor, până se găseşte nodul care nod *caut(nod *prim)
îndeplineşte condiţia sau până s-a ajuns la sfârşitul {nod *p;
listei. for (p=prim; p!=NULL && !conditie; p=p->urm);
2. Nodul care se găseşte într-o anumită poziţie în listă return p;
pe care o notăm cu poz. }
Algoritmul utilizat: se parcurge lista începând de la 2. Variabila locală nr de tip int se foloseşte pentru a număra
primul nod, în ordinea de înlănţuire a nodurilor, până poziţiile parcurse – este iniţializată cu valoarea 1.
când s-au parcurs poz noduri sau până s-a ajuns la nod *caut(nod *prim, int poz)
sfârşitull listei {nod *p;
int nr=1;
for (p=prim; p!=NULL && nr<poz; p=p->urm,nr++);
return p;
}
Aplicații
1. Se citeşte dintr-un fişier text un şir de numere separate prin spaţiu cu care se creează o listă
simplu înlănţuită în ordinea în care sunt citite numerele din fişier.
Se mai citeşte de la tastatură un număr x. Să se caute şi să se şteargă din listă nodul care conţine
acest număr.
2. Se citeşte dintr-un fişier text un şir de numere separate prin spaţiu cu care se creează o listă
simplu înlănţuită în ordinea în care sunt citite numerele din fişier.
Să se elimine din listă valorile care se repetă, în afară de prima lor apariţie.
3. Se citesc dintr-un fişier text de pe prima linie un număr n1, care reprezintă numărul de elemente
ale primei mulţimi, apoi de pe următoarea linie elementele mulţimii, de pe linia următoare un număr
n2 – numărul de elemente ale celei de a doua mulţimi, apoi de pe următoarea linie elementele
mulţimii. Să se determine reuniunea şi intersecţia celor două mulţimi.
Aplicație – Liste ordonate – algoritmul de sortare
prin inserție
Acest algoritm este similar cu cel învățat în clasa a 9-a
și se foloseşte pentru întreţinerea unei liste ordonate. Vom face două variante:
Se porneşte de la lista care conţine un singur nod
V1: Se porneşte de la lista care conţine primul nod cu
(considerată o listă ordonată) şi orice adăugare a unui informaţie. Paşii executaţi în acest algoritm sunt:
nod la listă se face într-o poziţie prin care se păstrează PAS1. Se adaugă primul nod cu informaţie la listă.
ordonarea în listă. În implementarea algoritmului s-a PAS2. Cât timp mai există informaţie de adăugat execută:
folosit o listă pentru care câmpul cheie (după care se PAS3. Se caută nodul înaintea căruia trebuie adăugat
face ordonarea) este de tip numeric întreg, iar noul nod.
ordonarea este crescătoare după valoarea acestuia. PAS4. Dacă s-a ajuns la sfârşitul listei, atunci se adaugă
noul nod ca ultimul nod din listă; altfel, se adaugă noul nod în
Numerele care trebuie memorate în nodurile listei se
faţa nodului găsit.
citesc de la tastatură până se citeşte valoarea 0 (are
semnificaţia că nu mai există informaţie de adăugat).
Obs:
În algoritm nu este necesară adresa ultimului nod, din
această cauză pot fi eliminate prelucrările care se referă
la acesta din subprograme.
struct nod {int info;
nod *urm;};
int n; int main()
void adauga nod(nod *&prim) {nod *prim,*q;
{prim=new nod; cout<<"numar "; cin>>n;
prim->info=n; prim->urm=NULL;} adauga_nod(prim); //Se adaugă primul nod
cout<<"numar "; cin>>n;
void adauga_in_fata(nod *q) while(n!=0) //Cât timp mai există informaţie de adăugat
{nod *p=new nod; {q=cauta(prim);
p->urm=q->urm; p->info=q->info; //Se caută nodul q înaintea căruia trebuie adăugat nodul p
q->info=n; q->urm=p;} if (q->info<n) //Dacă s-a ajuns la sfârşitul listei
adauga_ultim(q); //nodul p se adaugă ca ultim nod
void adauga_ultim(nod *q) else adauga_in_fata(q); //nodul p se adaugă în faţa nodului q
{nod *p=new nod; cout<<"numar "; cin>>n;}
p->info=n; q->urm=p; p->urm=NULL;} afisare(prim);
return 0;}
nod * cauta(nod *prim)
{nod *q=prim;
while(q->info<n && q->urm!=NULL) q=q->urm;
return q;}
Sunt valabile aceleași funcșii de adăugare prim nod void creare(nod *&prim)
și adugare după utimul nod pe care le știm. {nod *ultim; cin>>n; adauga_nod(prim,ultim);
Folosindu-le, crearea unei astfel de liste implică, while(n!=0)
doar la final, realizarea legăturii de la ultimul nod {cin>>n; adauga_ultim(ultim);}
către primul. ultim->urm=prim;
Paşii algoritmului de creare sunt: }
PAS1. Se adaugă primul nod la listă (nodul prim).
PAS2. Cât timp mai există informaţie execută: se
adaugă un nod la listă după ultimul nod.
PAS3. Se leagă ultimul nod de primul nod.
Eliminarea unui nod din lista
Dacă se dorește eliminarea din listă a nodului care
urmează după nodul curent p trebuie să se verifice Se foloseşte o funcţie procedurală elimina_urm()
dacă acest nod nu este nodul prim, ca să nu se al cărei parametri de tip nod sunt: prim care se
piardă adresa primului element din listă. transmite prin referinţă, deoarece este parametru
Paşii algoritmului de eliminare a nodului următor de intrare-ieşire și p nodul curent, care este cel
nodului curent sunt: precedent celui eliminat, transmis prin valoare.
PAS1. Se salvează adresa succesorului nodului p în void elimina_urm(nod *p, nod *&prim)
pointerul q. { nod *q=p->urm;
PAS2. Se leagă nodul p de succesorul succesorului p->urm=p->urm->urm;
lui. if(q==prim) prim=prim->urm;
PAS3. Dacă succesorul nodului p era nodul prim, delete q;
atunci succesorul nodului prim devine nodul prim. }
PAS4. Se cere eliberarea zonei de memorie de la
adresa memorată în pointerul q.
Parcurgerea listei
Deoarece lista circulară nu are un ultim nod care să marcheze finalul ei, se va lucra cu
nodul prim ca marcator de final. Din această cauză se prelucrează acesta primul și apoi
lista se parcurge plecând de la succesorul lui pentru a prelucra informaţia stocată în
noduri, până la primul nod
Se foloseşte funcţia procedurală parcurge() al cărei parametru prim de tip nod se
transmite prin valoare, deoarece este parametru de intrare.
2. Să se insereze, după fiecare număr divizibil cu cea mai mare cifră a sa, valoarea
cifrei, şi să se elimine numerele care au ultimele două cifre consecutive.
Algoritmi pentru prelucrarea
listelor dublu înlănțuite Algoritmii de la listele simplu înlănţuite se modifică
prin adăugarea instrucţiunilor care întreţin şi
adresa de legătură cu predecesorul nodului.
prim Algoritmul de adăugare a unui nod p în interiorul
listei înaintea unui nod q se simplifică deoarece
NULL info urm ant info urm se cunoaşte adresa atât a succesorului, cât şi a
predecesorului.
ultim
ant info urm ant info NULL 1. Adăugarea primului nod la lista
În cazul listelor dublu înlănţuite informaţia de legătură void prim_nod (nod *&prim, nod *&ultim)
trebuie să conţină şi adresa predecesorului nodului {prim = new nod;
(pointerul *ant către tipul nod): prim->info=x;
struct nod prim->ant=NULL; prim->urm=NULL;
{int info; //informaţia propriu-zisă ultim=prim;}
nod *ant ,*urm;}; //informaţia pentru legătură
nod *prim, *ultim, *p;
2. Adăugarea unui nod 2.3. Adăugare în interiorul listei
2.1. Adăugare în faţa primului nod
void adauga_prim(nod *&prim)
{nod *p=new nod;
a. După nodul de adresă q
p->info=x;
p->ant=NULL; void adauga_dupa (nod *q, nod *&ultim)
p->urm=prim; {nod *p=new nod;
prim=p;} p->info=x;
p->urm=q->urm;
p->ant=q;
2.2. Adăugare după ultimul nod if (q==ultim) ultim=p;
void adauga_ultim(nod *&ultim) else q->urm->ant=p;
{nod *p=new nod; q->urm=p;}
p->info=x;
b. Înaintea nodului de adresă q
p->ant=ultim;
p->urm=NULL; void adauga_in_fata (nod *q)
ultim->urm=p; {nod *p=new nod;
ultim=p;} p->info=x;
p->urm=q; p->ant=q->ant;
q->ant->urm=p; q->ant=p;}
3. Parcurgerea listei 4. Eliminarea unui nod din
listă
Vizitarea fiecărui nod al listei se poate face în două 4.1. Eliminarea primului nod
moduri:
void elimina_prim(nod *&prim)
• pornind de la primul nod, până la ultimul nod,
{nod *q=prim;
în ordinea de înlănţuire a nodurilor – furnizată de
prim->urm->ant=NULL;
adresa urm din nodul vizitat;
prim=prim->urm;
• pornind de la ultimul nod, până la primul nod,
delete q;}
în ordinea de înlănţuire a nodurilor – furnizată de
adresa ant din nodul vizitat 4.2. Eliminarea ultimului nod
void elimina_ultim(nod *&ultim)
void parcuge_inainte (nod *prim) {nod *q=ultim;
{for (nod *p=prim; p!=NULL; p=p->urm) ultim->ant->urm=NULL;
//se prelucrează p->info} ultim=ultim->ant;
delete q;}
void parcuge_inapoi (nod *ultim)
4.3. Eliminarea unui nod din interiorul listei
{for (nod *p=ultim; p!=NULL; p=p->ant)
//se prelucrează p->info} void elimina(nod *p)
{nod *q=p;
p->ant->urm=p->urm; p->urm->ant=p->ant;
delete q;}
Aplicații
Datele se transmit între subprograme cu ajutorul parametrilor de comunicaţie şi nu al variabilelor globale. Se
creează liste dublu înlănţuite în nodurile cărora se memorează numere întregi. Şirul de numere se citeşte dintr-un
fişier text în care sunt memorate pe acelaşi rând, separate prin spaţiu. După executarea unei operaţii de prelucrare
a listei, se vor afişa numerele din noduri pentru a verifica dacă operaţia s-a executat corect. Se vor alege seturi de
date de intrare astfel încât să se verifice algoritmul pe toate traseele lui. Listele se creează astfel încât ordinea de
acces să fie cea în care sunt citite numerele din fişier
1. Să se adauge valoarea 1 după fiecare număr par şi să se şteargă apoi numerele pare din listă. Să se afişeze
numerele din listă după fiecare operaţie de prelucrare, în ambele moduri (de la primul la ultimul, şi de la ultimul la
primul).
2. Să se calculeze cifra de control a fiecărui număr şi, dacă numărul este divizibil cu cifra de control, cifra este
adăugată după număr; altfel, numărul este eliminat din listă. Cifra de control a unui număr este suma repetată a
cifrelor numărului până când se obţine o sumă mai mică decât 10.
3. Se citesc dintr-un fişier două numere foarte mari. Să se scrie următoarele subprograme pentru prelucrarea
numerelor:
● determinarea numărului de cifre ale unui număr;
● verificarea numărului dacă este palindrom.
● calcularea sumei, a diferenţei şi produsului numerelor;
Algoritmi pentru prelucrarea Altfel spus, prelucrarea unei stive se face de la
stivelor vârf spre bază şi se prelucrează întotdeauna
Cele două extremităţi ale stivei se numesc vârf şi nodul din vârful stivei. Accesul la informaţia din
bază. Accesul la nodurile stivei (adăugarea, acest nod se face doar cu varf->info.
extragerea sau consultarea unui nod) este permis Stiva vidă – se verifică vârful:
numai printr-o singură extremitate numită vârf şi int stiva_vida(nod *varf)
ultimul nod inserat este primul nod extras (se {return varf==NULL;}
extrage cea mai nouă informaţie adăugată). La o
operaţie de adăugare a unui nod, vârful stivei stivei 1. Inițializarea stivei:
urcă, iar la o operaţie de extragere a unui nod,
vârful stivei coboară. void init(nod *&varf)
Implementarea dinamică a stivei se face la fel ca a {varf = NULL;}
unei liste liniare, cu deosebirea că:
• vârful stivei va fi indicat de pointerul varf către 2. Adăugarea unui nod în stivă
tipul nod;
• pentru adăugarea unui nod, se poate folosi void adauga(nod *&varf)
numai algoritmul de adăugare în faţa primului {nod *p=new nod;
nod; p->info=x;
• pentru extragerea unui nod se poate folosi p->urm=varf;
numai algoritmul pentru eliminarea primului varf=p;}
nod.
3. Extragerea unui nod din
stivă
4. Prelucrarea stivei
Nodurile se extrag din stivă pentru a putea consulta
informaţia care există în nodurile următoare. Un
nod se poate extrage numai în cazul în care stiva Se consultă informaţia din fiecare nod al stivei.
nu este vidă. Se poate extrage numai nodul din Deoarece nu poate fi consultată decât informaţia
vârful stivei (se eliberează spaţiul care a fost din vârful stivei, pentru a ajunge la un nod trebuie
ocupat de nod). În vârful stivei va ajunge să se extragă toate nodurile până la el.
succesorul nodului extras.
void prelucrare(nod *&varf)
{while (varf!=NULL)
void extrage (nod *&varf) {//se prelucrează varf->info
{nod *p =varf; extrage(varf);)}
varf=varf->urm;
delete p;}
Algoritmi pentru prelucrarea Coada vidă – se verifică vârful:
cozilor int coada_vida(nod *cap)
Cele două extremităţi ale cozii se numesc cap şi {return cap==NULL;}
baza. Adăugarea de noduri la coadă se face prin
nodul baza, iar extragerea şi consultarea unui nod 1. Inițializarea cozii:
este permisă numai prin extremitatea cap (se void init(nod *&cap, nod *&baza)
extrage cea mai veche informaţie adăugată). {cap=baza= NULL;}
Implementarea dinamică a cozii se face la fel ca a
unei liste liniare, cu deosebirea că: 2. Adăugarea primului nod în coadă
• primul nod al cozii va fi indicat de pointerul cap void un_nod(nod *&cap, nod *&baza, int x)
către tipul nod, iar ultimul nod al cozii va fi {cap=new nod;
indicat de pointerul baza către tipul nod; cap->info=x;
• pentru adăugarea unui nod, se poate folosi cap->urm=NULL;
numai algoritmul de adăugare după ultimul nod; baza=cap;}
• pentru extragerea unui nod se poate folosi
numai algoritmul pentru eliminarea primului nod. 3. Adăugarea unui nod în coadă
Altfel spus, prelucrarea unei cozi se face de la cap
void adauga(nod *&baza, int x)
spre bază şi se prelucrează întotdeauna nodul din
{nod *p=new nod; p->info=x; p->urm=NULL;
capul cozii. Accesul la informaţia din acest nod se
baza->urm=p; baza=p;}
face cu cap->info.
3. Extragerea unui nod din
coadă
4. Prelucrarea cozii
Nodurile se extrag din coadă pentru a putea
consulta informaţia care există în nodurile
următoare. Un nod se poate extrage numai în cazul Se consultă informaţia din fiecare nod al cozii.
în care coada nu este vidă. Se poate extrage Deoarece nu poate fi consultată decât informaţia
numai nodul din capul cozii (se eliberează spaţiul din capul cozii, pentru a ajunge la un nod trebuie să
care a fost ocupat de nod). În capul cozii va ajunge se extragă toate nodurile până la el.
succesorul nodului extras.
void prelucrare(nod *&cap)
{while (cap!=NULL)
void extrage (nod *&cap) {//se prelucrează cap->info
{nod *p =cap; extrage(cap);)}
cap=cap->urm;
delete p;}
Aplicații
STIVE
1. Se citeşte dintr-un fişier text un şir de numere separate prin spaţiu care se depun într-o stivă în ordinea în care sunt
citite numerele din fişier. Să se elimine numărul de la baza stivei şi numerele rămase în stivă să se scrie într-un fişier
text.
2. Într-o stivă sunt memorate numere din intervalul [1,10], ordonate crescător, iar într-o altă stivă, numere din intervalul
[20,30], ordonate crescător. Să se concateneze cele două şiruri de numere, păstrând ordonarea crescătoare.
3. Se memorează într-o stivă un şir de litere mici. Se citeşte de la tastatură o literă mică a alfabetului – lit. Să se creeze
două stive: una va conţine literele din stiva iniţială care preced în alfabet litera lit şi alta va conţine literele din stiva
iniţială care succed în alfabet litera lit
COZI
1. Se citeşte dintr-un fişier text un şir de numere separate prin spaţiu care se depun într-o coadă în ordinea în care sunt
citite din fişier. Să se elimine numărul din mijlocul cozii, dacă numărul de noduri este impar, şi cele două numere din
mijloc, dacă numărul de noduri este par, iar numerele rămase în coadă să se scrie într-un fişier text.
2. Se concatenează două cozi, adăugând a doua coadă la sfârşitul primei cozi.
3. Se inversează ordinea numerelor dintr-o coadă cu ajutorul unei stive.