Sunteți pe pagina 1din 9

LISTE SIMPLU NLNUITE ORDONATE......................................................................................................................

2
CND FOLOSIM O LIST SIMPLU NLNUIT ORDONAT?....................................................................................................2
ADUGAREA NTR-O LIST SIMPLU NLNUIT ORDONAT.................................................................................................3
TERGEREA DINTR-O LIST SIMPLU NLNUIT ORDONAT.................................................................................................4
EXEMPLU CU LIST SIMPLU NLNUIT ORDONAT.............................................................................................................5
LISTE SIMPLU NLNUITE CIRCULARE.....................................................................................................................9

APLICAII CU LISTE SIMPLU NLNUITE.................................................................................................................9

PROBLEME PROPUSE........................................................................................................................................................10
PROBLEMA 1: RULAREA EXEMPLULUI..................................................................................................................................10
PROBLEMA 2: IMPLEMETAREA UNEI COZI CU LIST SIMPLU NLNUIT CIRCULAR.........................................................10
PROBLEMA 3: FUNCII RECURSIVE PENTRU LISTE................................................................................................................10
PROBLEME EXTRA:................................................................................................................................................................10
Liste simplu nlnuite ordonate.

Cnd folosim o list simplu nlnuit ordonat?


Folosim o list nlnuit ordonat atunci cnd avem definit o relaie de ordine pe mulimea
elementelor listei; cu alte cuvinte atunci cnd nodurile trebuiesc nlnuite dup un anumit criteriu de
ordine (de exemplu cresctor sau descresctor dup un anumit cmp).

Vom lua cazul unui dicionar implementat cu list simplu nlnuit. Structura unui nod va fi:
typedef struct elem{
char *cuvant;
char *explicatie;
struct elem *urm;
}nod;
void main(){
nod *radacina; /* radacina listei = adresa de inceput a listei = adr primului
element, daca exista */
radacina=NULL; // radacina o initializam cu NULL obligatoriu!!!!!
}

Crearea unui nou nod o vom face cel mai probabil ntr-o funcie separat, urmnd ca apoi s
introducem nodul creat la locul su n list. Sunt exemplificate n imagine operaiile efectuate; urmrii
codul i n paralel reprezentarea grafic corespunztore (bucata de cod are aceeai culoare cu
reprezentarea grafic a efectului produs)

nod *creare_nod(char *cuv, char *expl){


nod *nou;

(1) nou=(nod *)malloc(sizeof(nod));


// se aloca memorie pentru nod; adresa de inceput a zonei respective de meorie se
stocheaza in pointerul nou

(2) nou->cuvant=(char *)malloc( (strlen(cuv)+1) * sizeof(char) );


strcpy(nou->cuvant, cuv);
// se aloca memorie pentru cuvant, adresa ei se stocheaza in nou->cuvant si se
copiaza in ea cuvantul memorat in cuv

(3) nou->explicatie=(char *)malloc( (strlen(expl)+1) * sizeof(char) );


strcpy(nou->explicatie, expl);

(4) nou->urm=NULL;

}
Adugarea ntr-o list simplu nlnuit ordonat

Dac dorim ca nodurile listei s fie parcurse dup un anumit criteriu (de exemplu cresctor dup
cmpul cuvant), trebuie ca introducerea unui nou nod n list s se fac astfel nct s nu se strice
ordinea listei (altfel spus, l vom introduce la locul lui); pentru exemplul considerat, vom introduce
noul nod naintea primului nod cu cmpul cuvant mai mare dect cmpul su cuvant.

Adugarea la nceputul listei

Dac nodul nou are cmpul cuvant mai mic dect cmpul cuvant al primului nod

nod *adaug_incep(nod *nou){


nou->urm=prim; // nou->urm pointeaza spre primul nod din lista
prim=nou; // prim pointeaza acum spre nou, care a devenit primul nod al listei
}

Adugarea la sfritul listei

void adaug_sfs(nod *nou, nod *p){


// anterior s-a parcurs lista pna la ultimul nod p
nou->urm=NULL; //se poate scrie si nou->urm=p->urm, deoarece p->urm == NULL
p->urm=nou; // p->urm pointeaza spre nou, care este acum ultimul nod al listei
}

Adugarea dup nodul p al listei

void adaug_mijl(nod *nou, nod *p){


// anterior s-a parcurs lista pna la nodul p
nou->urm=p->urm ; // nou va pointa spre nodul de dupa pe, p->urm
p->urm=nou; // p->urm pointeaza spre nou
}

Observaie: cele 2 funcii, adaug_sfs i adaug_mijl difer doar la legtura 1, care am vzut c se
poate scrie la fel (urmrii comentariile din adaug_sfs). Rezult c putem scrie o singur funcie
pentru adugarea la sfrit i n interiorul listei; mai exact, funcia pentru adugare dup nodul p din
interiorul listei acoper i cazul cnd nodul p este ultimul.

tergerea dintr-o list simplu nlnuit ordonat


Dac dorim s eliminm un nod din list, memoria pe care acesta o ocupa va trebui eliberat, pentru a
fi folosit la adugarea de alte noduri; dac nu o eliberm explicit cu funcia free, ea va rmne marcat
ca fiind ocupat pe durata execuiei programului i nu va putea fi folosit. De aceea, nainte de a reface
legturile pentru ca nodul de ters s fie eliminat din list, adresa lui va fi memorat ntr-o varialbil
pentru a fi eliberat ulterior zona de memorie dedicat lui.

tergerea primului nod

nod *sterg_incep(nod *p){


nod *q
q=prim; // q retine adresa primului element al listei
prim=q->urm; // prim pointeaza acum spre al 2-lea nod din lista, devenit primul
free(q); // eliberam memoria ocupata de fostul prim element
}

tergerea ultimului nod

Dac nu avem un pointer care s ne rein 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)
}

tergerea nodului de dup nodul p

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
}

Observaie: cele 2 funcii, sterg_sfs i sterg_mijl difer doar la legtura 2, care am vzut c se
poate scrie la fel (urmrii comentariile din sterg_sfs). Rezult c putem scrie o singur funcie
pentru tergerea la sfrit i n interiorul listei; mai exact, funcia pentru tergere a nodului de dup
nodul p din interioru listei acoper i cazul cnd acesta este ultimul.

Exemplu cu list simplu nlnuit ordonat


Problema rezolvat efectueaz operaiile de adugare, tergere i cutare ntr-o list simplu nlnuit
ordonat. Adugarea se va face astfel nct lista s rmn 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;

/* cauta in lista indicata de p nodul cu campul info = inf si


returneaza pointerul catre acel nod, daca nodul cautat nu exista returneaza NULL
*/
nod *caut(nod *p, float inf)
{
for ( ; p!=NULL && p->info<inf; p=p->urm);
/* cautam doar pana la primul element mai mare decat inf (daca el nu exista),
deoarece lista e ordonata, deci nu mai are sens sa parcurgem mai departe*/
if (p!=NULL && inf==p->info)
return p; /* daca info a fost gasit in lista */
return NULL; /* daca nu a fost gasita */
}

/* Functia listez parcurge lista si pentru fiecare nod


afiseaza informatia memorata. */
void listez(nod *p)
{
printf("Un nod ocupa %d octeti, pointerul catre nod ocupa %d octeti\n",
sizeof(*p), sizeof(p));
for ( ; p!=NULL; p=p->urm)
printf("(adr=%p) |%6g| %p | \n",p,p->info, p->urm);
}

/* Functia sterg elimina din lista (indicata de pointerul


p) nodul ce are campul info egal cu argumentul inf */
nod *sterg(nod *radacina, float inf)
{
nod *aux, *p;
if (radacina==NULL){ // lista vida
printf("Eroare: lista e vida\n");
return NULL;
}
else
if (radacina->info==inf){ // sterg primul element
aux=radacina;
radacina=radacina->urm;
free(aux);
return radacina;
}
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;
}
}
/*Functia introduc insereaza un nod in lista ordonata,
Functia returneaza pointerul catre inceputul listei modificate */
nod * introduc(nod *radacina, float infonou)
{
nod *nou, *p;
if ((nou=(nod *)malloc(sizeof(nod)))==NULL)
{
/* daca nu e memorie suficienta pentru a crea un nod nou,se da un mesaj
de eroare dupa care se termina functia sise returneaza NULL */
printf("Eroare: memorie insuficienta\n");
return NULL;
}
nou->info=infonou; /* se salveaza infonou in nodul nou */
nou->urm=NULL;
/* nodul nou este inserat in lista ordonata astfel incat ea ramane ordonata
si dupa inserare. Lista este parcursa cautandu-se primul nod avand
campul info mai mare sau egal cu info */
if (radacina==NULL) // lista vida
radacina=nou;
else
if (p->info>infonou){ // iintroduc la inceput
nou->urm=radacina;
radacina=nou;
}
else{ // inserare in int listei sau la sfarsit
for(p=radacina; p->urm!=NULL && p->urm->info<infonou; p=p->urm);
nou->urm=p->urm;
p->urm=nou;
}
return radacina;
}

/* Functia main afiseaza meniul programului,citeste comanda */


/* si apeleaza functia corespunzatoare */
void main(void)
{
char o;
float val;
nod *radacina=NULL, *p; /* pastreaza inceputul listei */
puts("");
while(1)
{
puts("");
/* se afiseaza meniul programului */
puts("a : adauga un nod");
puts("c : cauta si tipareste un nod");
puts("s : sterge un nod");
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");
}
}

}
Liste simplu nlnuite circulare

O list simplu nlanuit va fi circular dac ultimul ei nod (cmpul su urm mai exact) va pointa spre
primul su nod. Putem s ne reprezentm astfel acest tip particular de list:

Lista fiind circular, nu mai are un prim nod i un ultim nod (de regul, dar nu neaprat, noi hotrm
cum implementm); vom avea un nod curent (l vom boteza crt). Acest nod poate s aib diverse
semnificaii, n funcie de problema.

Aplicaii cu liste simplu nlnuite

Coada (FIFO)

Coada este o list simplu nlnuit (poate s fie i circular) n care tergerea se face la nceput i
adugare se face doar la sfrit (se zice c este de tip FIFO = First In Firs Out).
Pentru implementarea cu list simplu nlnuit vom folosi 2 pointeri, unul pentru primul nod (de
aici vom terge) i unul pentru ultimul nod (aici vom face adugarea).
Dac implemetm coada circular, n pointerul crt vom stoca adresa ultimului element introdus;
astfel, adugarea unui nod nou se va face dup nodul (*crt) (crt pointnd apoi spre nodul nou
introdus). De ters vom terge nodul de dup crt, deoarece acesta este nodul introdus cel mai
devreme.

S-ar putea să vă placă și