Professional Documents
Culture Documents
Matematică-Informatică
Proiect de practica:
1
Subiectul 3
2
Structurile dinamice de date reprezinta date structurate ale caror componente se aloca in mod dinamic.
Alocarea dinamica a componentelor structurii impune un mecanism prin care o noua componenta aparuta este
legata in succesiunea logica de corpul structurii deja format pana atunci. Rezulta ca fiecare componenta, pe
langa informatia propriu-zisa pe care o detine, contine si o informatie de legatura cu componenta de care se
leaga logic in succesiune. Informatia de legatura va fi adresa componentei spre care se realizeaza succesiunea
logica, iar mecanismul se mai numeste alocare inlantuita dupa adrese.
In functie de tipul inlantuirii realizate intre componente exista urmatoarele tipuri de organizari:
- structuri liniare/ liste (deschise sau inchise – circulare );
- structuri arborescendente;
- structuri retea.
Structura liniara se mai numeste si lista. Lista este o multime finita si ordonata de elemente de acelasi tip.
Elementele listei se numesc noduri.
Modul de inlantuire prin adrese a componentelor se poate face:
- intr-un singur sens, generandu-se lista simplu-inlantuita;
- in ambele sensuri, generandu-se lista dublu-inlantuita.
Folosim o listă înlănţuită ordonată atunci când nodurile trebuiesc înlănţuite după un anumit criteriu de
ordine (de exemplu crescător sau descrescător după un anumit câmp).
O componenta a unei liste simplu-inlantuite se declara ca o data structurata de tip articol, formata din doua
campuri : informatia propriu-zisa si informatia de legatura. Informatia propriu-zisa poate fi, la randul ei
structurata sau nu.
Variabila adresa necesara a fi definita pentru alocarea dinamica a unei componente va avea ca tip de baza
tipul structurii componentei (tipul articol).
Sunt posibile mai multe forme de declarare si definire a variabilei adresa a unei componente:
a) se poate defini un tip general de date de tip adresa, numit adr:
typdef struct componenta {tip_informatie info;
componenta *leg;}*adr;
b) se poate defini numai structura unei componente si apoi se pot declara variabile de referinta
Constructori:
Pentru crearea, initializarea, copierea si distrugerea obiectelor, in C++ se folosesc functii membre speciale,
numite constructori si destructori.
Constructorul este apelat automat la eliminarea unui obiect al clasei, la incheierea timpului de viata sau, in
cazul variabilelor dinamice, este solicitat prin program (cu operatorul delete), inclusiv pentru obiecte
temporare. Aceste functii efectueaza operatii prealabile utilizarii obiectului creat, respectiv eliminarii lui.
Alocare si eliminarea memoriei necesare datelor membre ramane in sarcina compilatorului. Astfel
constructurul este apelat dupa alocarea memoriei necesare pentru datele membre ale obiectului (in faza finala
a crearii obiectului).
Constructorii se declara si se definesc similar cu celelalte functii membre, dar se disting de acestea prin
unele caracteristici:
- numele functiilor constructor coincide cu numele clasei careia ii apartin;
- in declaratie si in definitie nu se specifica nici un tip de rezultat (nici macar void);
- nu se pot utiliza pointeri catre constructori;
- costructorii pot avea parametri si pot fi supradefiniti. Un constructor fara parametri se numeste costructor
implicit.
Daca o clasa nu dispune de constructori compilatorul va genera automat un constructor implicit.
Operatiile care se pot executa asupra listelor sunt foarte variate: adaugari, inserari, extrageri, cautari,
concatenari, divizari, sortari.
3
spus, îl vom introduce la locul lui); pentru exemplul considerat, vom introduce noul nod înaintea primului nod
cu câmpul cuvant mai mare decât câmpul său cuvant.
Dacă nodul nou are câmpul cuvant mai mic decât câmpul cuvant al primului nod
nod*adaug_incep (nod*nou){
nou->urm; (nou->urm pointeaza spre primul nod din lista)
prim=nou; (prim pointeaza acum spre nou, care a devenit primul nod al listei)
}.
Adăugarea la sfârşitul listei
}.
4
O funcţie de căutare a unui nod de cheie “key” va conţine secvenţa de program de mai jos; ea returnează
adresa nodului respectiv în caz de găsire sau pointerul NULL în caz contrar:
TIP_NOD *p;
p=prim;
while( p != 0 ) if (p->cheie == key)
{
/* s-a găsit nodul de cheie dată */
/* el are adresa p */
return p;
}
else p=p->urm;
return 0; /* nu există nod de cheie = key */
5
Ştergerea ultimului nod
Dacă nu avem un pointer care să ne reţină adresa ultimului nod, parcurgem lista şi ne oprim înaintea
ultimului nod
nod *sterg_sfs(nod *p){
nod *q;
q=p->urm; // q retine adresa ultimului element al listei
p->urm=NULL; // sau p->urm=q->urm , deoarece q->urm==NULL
// nodul(*q)este sters dpdv al listei, deoarece nu se mai poate ajunge la el
free(q); // eliberam memoria ocupata de ultimul element (de la adresa stocata in q)
}
Parcurgem lista şi ne oprim înaintea nodului pe care vrem să îl ştergem, adică la nodul p
nod *sterg_incep(nod *p){
nod *q;
q=p->urm; // q retine adresa ultimului element al listei
p->urm=q->urm; // nodul (*q) este sters dpdv al listei, deoarece nu se mai poate
ajunge la el
free(q); //eliberam memoria ocupata de ultimul element
}
Parcurgerea unei liste simplu inlantuite:
Consideram: cap- contine adresa primului element din lista.
O parcurgere inseamna prelucrarea pe rand a tuturor elementelor listei, in ordinea in care acestea apar in lista.
Vom avea o variabila pointer p care va indica pe rand fiecare element al listei:
p=cap;
while (p!=0){
(prelucreaza p-> data)
p=p->leg;
}
for {p=cap; p!=0; p=p->leg{
(prelucreaza p->data)
}
6
Problema rezolvată efectuează operaţiile de adăugare, ştergere şi căutare într-o listă simplu înlănţuită
ordonată. Adăugarea se va face astfel încât lista să rămână ordonată.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* tipul pentru nodul lista */
typedef struct elem
{
float info;
struct elem *urm;
} nod;
7
else{
// parcurgem lista pana gasim nodul cu info=infonou sau pana la sfarsit
for(p=radacina; p->urm!=NULL && p->urm->info<inf; p=p->urm);
if (p->urm != NULL && p->urm->info==inf) // nodul cautat exista
{
aux=p->urm;
p->urm=aux->urm; // adica p->urm=p->urm->urm;
free(aux);
}
else // nodul cautat nu exista
printf("Eroare: identificatorul %f nu apare in lista\n", inf);
return radacina;
}
}
8
puts("l : listeaza tot");
puts("t : termina programul");
printf("\nOptiunea: ");
while(isspace(o=getchar()) );
puts("");
switch (tolower(o))
{
case 'a': { printf("adauga nr=");
scanf("%f", &val);
radacina=introduc(radacina, val);
break;}
case 'c': { puts("cauta si tipareste un nod");
printf("nr=");
scanf("%f", &val);
if ((p=caut(radacina, val))!=NULL) /* cauta nodul in lista */
printf(" Valoare:%f\n", p->info);
else
printf("Eroare: Identificator nedefinit\n");
break;
}
case 's':{ printf("stergere nr=");
scanf("%f", &val);
radacina=sterg(radacina, val); /* sterge nodul din lista */
break;}
case 'l':{ puts("listare");
listez(radacina);
break;}
case 't':
return;
default:
printf("Eroare : Comanda inexistenta\n");
}
}