Sunteți pe pagina 1din 40

Curs 6 - agenda

• Tipuri de date de nivel înalt

– Liste liniare

– Liste liniare ordonate

– Stiva

– Coada

• Tipul abstract (LLin, LLinOrd, Stiva, Coada)

– Implementarea cu tablouri

– Implementarea cu liste simplu înlănţuite

• Aplicaţie la conversii de expresii

Liste liniare: tipul abstract LLin

• obiecte

L = (e 0 ,…, e n-1 ), n 0, e i al elementelor)

• operaţii

– listaVida()

• intrare: nimic

• ieşire

– ()

(lista cu zero elemente)

– insereaza()

• intrare:

Elt (tipul abstract

L = (e 0 ,…, e n-1 ), k

Nat, e Elt

• ieşire

L = (…e k-1 , e, e k, …) daca 0

– eroare în caz contrar

k

n

LLin (continuare 1)

– elimina()

• intrare:

L = (e 0 ,…, e n-1 ), k

• ieşire

Nat

L = (…e k-1 , e k+1 …) daca 0

– eroare în caz contrar

– alKlea()

• intrare:

L = (e 0 ,…, e n-1 ), k

Nat

• ieşire

e k daca 0

– eroare în caz contrar

k

n-1

k

n-1

LLin (continuare 2)

– elimTotE()

• intrare:

L = (e 0 ,…, e n-1 ), e

• ieşire:

Elt

– lista L din care s-au eliminat toate elementele egale cu e

– parcurge()

• intrare:

L = (e 0 ,…, e n-1 ), o procedură (funcţie) viziteaza()

• ieşire:

– lista L în care toate elementele au fost procesate aplicând viziteaza()

LLin (continuare 3)

– poz()

• intrare:

L = (e 0 ,…, e n-1 ), e

• ieşire:

Elt

– prima poziţie pe care apare e în L sau -1 dacă e nu apare în L

– lung()

• intrare:

L = (e 0 ,…, e n-1 )

• ieşire:

– n – lungimea listei L

–…

LLin: implementare cu tablouri

reprezentarea obiectelor L = (e 0 ,…, e n-1 )

L.tab Elt[MAX]
L.tab
Elt[MAX]

e 0

e

n-1

0 L.ultim Nat
0
L.ultim
Nat

MAX-1

L este o structură care conţine

– un câmp de tip tablou L.tab pentru memorarea elementelor – un câmp L.ultim pentru memorarea poziţiei ultimului element

LLin: implementare cu tablouri:

• insereaza()

operaţii

– deplasează elementele de pe poziţiile k, k+1, … la dreapta cu o poziţie – inserează e pe poziţia k – excepţii:

• k < 0, k > L.ultim+1 (n) • L.ultim = MAX-1

LLin: implementare cu tablouri:

operaţii

void insereaza(LLin &L, int k, Elt e){

if (k < 0 || k > L.ultim+1){ printf(“eroare-pozitie incorecta”); return;

}

if (L.ultim >= MAX-1){ printf(“eroare-spatiu insuficient”); return;

}

int j; for (j = L.ultim; j >= k; j--) L.tab[j+1] = L.tab[j]; L.tab[k] = e; L.ultim = L.ultim + 1;

};

– timpul de execuţie: O(n)

LLin: implementare cu tablouri:

• parcurge()

operaţii

void parcurge(LLin L, void viziteaza(Elt)){ int i = 0; for(; i <= L.ultim; i++) viziteaza(L.tab[i]);

}

• daca viziteaza() procesează un element în O(1), atunci parcurge() procesează lista în O(n), unde n este numărul elementelor listei

LLin: implementare cu liste înlănţuite

reprezentarea obiectelor L = (e 0 ,…, e n-1 )

L.prim
L.prim
L.ultim
L.ultim

e

0

e 0 e 1
e 0 e 1

e

1

e 0 e 1
e 0 e 1
,…, e n - 1 ) L.prim L.ultim e 0 e 1 e n-1 … •
e n-1
e n-1

L structură cu două câmpuri

L.prim - pointer la primul element

L.ultim - pointer la ultimul element

• un nod *p (aflat la adresa din p) are două câmpuri:

unul pentru memorarea informaţiei: p->elt = e i

– unul pentru nodul succesor: p->succ

LLin: implementare cu liste înlănţuite

• insereaza()

– parcurge elementele 0, 1,…, k-1 – inserează un nou element după k-1

• creează nodul

• memorează informaţiile

• reface legăturile

– excepţii

• lista vidă •k = 0 •k = n

• k < 0, k > n

LLin: implementare cu liste înlănţuite

e k-1 e
e
k-1
e
LLin : implementare cu liste înlănţuite e k-1 e e k L.prim L.ultim e L.prim e

e k

LLin : implementare cu liste înlănţuite e k-1 e e k L.prim L.ultim e L.prim e
LLin : implementare cu liste înlănţuite e k-1 e e k L.prim L.ultim e L.prim e
L.prim L.ultim
L.prim
L.ultim
e
e
L.prim e e 0
L.prim
e
e 0

LLin: implementare cu liste înlănţuite

void insereaza(LLin &L, int k, Elt e)}{ if (k < 0) { printf(“eroare-pozitie incorecta”); return;} Nod* q = new Nod; q->elt = e; if (k == 0 || L.prim == NULL){ q->succ = L.prim; L.prim = q; if (L.ultim == NULL) L.ultim = q;

}

else { Nod * p = L.prim; int j = 0; while (j < k-1 && p != L.ultim ){ p = p->succ; j++;

}

if (j < k-1) { printf(“eroare-poz. incorecta”); return;} q->succ = p->succ; p->succ = q; if (p == L.ultim) L.ultim = q;

}

}

Algoritmi şi programare

13

LLin: aplicaţie

• linie poligonală de puncte

Punct: structură cu două câmpuri x şi y

– crearea unei liste

void creeazaLista(LLin &L) L = listaVida();

/*

for (int i = 0; i < n-1; i++){

citeste n

*/

/* citeste p.x, p.y insereaza(L, 0, p);

*/

}

– atenţie: timpul de execuţie depinde de implementare

LLin: aplicaţie (continuare 1)

– multiplică cu 2 coordonatele unui punct void ori2Punct(Punct &p){ p.x *= 2; p.y *= 2;

}

– multiplică cu 2 coordonatele unei linii poligonale

void ori2Linie(L){ parcurge(L, ori2Punct);

}

LLin: aplicaţie (continuare 2)

– translatează punct void trPunct(Punct &p, int dx, int dy){ p.x = p.x + dx; p.y = p.y + dy;

}

– translatează linie poligonală void trLinie(LLin L, int dx, int dy){ parcurge(L, trPunct, dx, dy);

}

- … totuşi presupune modificare procedurii parcurge

Liste liniare ordonate: LLinOrd

• obiecte

L = (e 0 ,…, e n-1 ), n 0, e i

Elt, e 0 <…< e n-1

• operaţii

– listaVida()

• intrare: nimic

• ieşire

– () (lista cu zero elemente)

– insereaza()

• intrare:

L = (e 0 ,…, e n-1 ), e

Elt

• ieşire

L = (…e k-1 , e, e k, …) daca e k-1

(e -1 = -

, e n = +

)

e

e k

LLinOrd: (continuare)

– elimina()

• intrare:

L = (e 0 ,…, e n-1 ), e

• ieşire

Elt

L = (…e k-1 , e k+1 …) daca e = e k

– eroare în caz contrar

– alKlea()

– parcurge()

– poz()

LLinOrd: implementare cu tablouri

căutare binară

int Poz(LLinOrd L, Elt e){ int p = 0, q = L.ultim; int m = (p+q)/2; while (L.tab[m] != e && p < q){ if (e < L.tab[m]) q = m–1; else p = m+1; m = (p+q)/2;

}

}

if (L.tab[m] == else return -1;

e) return m;

LLinOrd: complexitatea căutării

• implementare cu tablouri

– timpul de execuţie O(log n)

• implementare cu liste înlănţuite

– căutarea binară -> căutare liniară

– timpul de execuţie O(n), dar mai mic decât în cazul neordonat

Tipul abstract Stiva

• obiecte

– liste în care se cunoaşte vechimea elementelor introduse (liste LIFO)

• operaţii

– stivaVida()

• intrare: nimic

• ieşire

– lista vidă

– push()

• intrare

– S

• ieşire

Stiva, e

Elt

– S la care s-a adaugat e ca ultimul element introdus (cel cu vechimea cea mai mică)

Stiva (continuare 1)

– pop()

• intrare

– S Stiva

• ieşire

– S din care s-a eliminat ultimul element introdus (cel cu vechimea cea mai mică)

– eroare dacă S este vidă

– esteVida()

• intrare

– S Stiva

• ieşire

true dacă S este vidă false dacă S nu este vidă

Stiva (continuare 2)

– top()

• intrare

– S Stiva

• ieşire

– ultimul element introdus (cel cu vechimea cea mai mică)

– eroare dacă S este vidă

Stiva (continuare 3)

push(S, e) = insereaza(S, 0, e) pop(S) = elimina(S, 0) top(S) = alKlea(S, 0)

sau

push(S, e) = insereaza(S, lung(S), e) pop(S) = elimina(S, lung(S)-1) top(S) = alKlea(S, lung(S)-1)

Stiva: implementare cu tablouri

• reprezentarea obiectelor

S.tab Elt[MAX]
S.tab
Elt[MAX]

e 0

e

n-1

0 S.varf n-1
0
S.varf
n-1

MAX-1

• implementarea operaţiilor

– push()

void push(Stiva &S, Elt e){

if (S.virf == MAX-1) { printf(“eroare”); return; } S.virf = S.virf+1; S.tab[virf] = e;

}

Stiva: implementare cu liste înlănţuite

• reprezentarea obiectelor

S
S
e n-1 e n-2 .
e n-1
e n-2
.

.

. e 0
.
e 0

Stiva: implementare cu liste înlănţuite

• implementarea operaţiilor

– push()

void push(Nod* S, Elt e){

Nod* q = new Nod; q->elt = e; q->succ = S;

S = q;

}

– pop()

void pop(Nod* S){

if (S == NULL) { printf(“eroare”); return; }

q

= S;

S

= S->succ;

delete q;

}

Tipul abstract Coada

• obiecte

– liste în care se cunoaşte vechimea elementelor introduse (liste FIFO)

• operaţii

– coadaVida()

• intrare: nimic

• ieşire

– lista vidă

– insereaza()

• intrare – C Coada, e Elt

• ieşire

– C la care s-a adăugat e ca ultimul element introdus (cel cu vechimea cea mai mică)

Coada (continuare 1)

– elimina()

• intrare

– C Coada

• ieşire

– C din care s-a eliminat primul element introdus (cel cu vechimea cea mai mare)

– eroare dacă C este vidă

– esteVida()

• intrare

– C Coada

• ieşire

true dacă C este vidă false dacă C nu este vidă

Coada (continuare 2)

– citeste()

• intrare

– C Coada

• ieşire

– primul element introdus (cel cu vechimea cea mai mare)

– eroare dacă C este vidă

Coada (continuare 3)

insereaza(C, e) = insereaza(C, lung(C), e)

elimina(C) = elimina(C, 0)

citeste(C) = alKlea(C, 0)

Coada: implementare cu tablouri

• reprezentarea obiectelor

C Elt[nMax]
C
Elt[nMax]
… e 0 … e n-1 …

e

0

e

n-1

… e 0 … e n-1 …
prim p
prim
p
q ultim
q ultim

nMax-1

C Elt[nMax]
C
Elt[nMax]
… e n-1 … e 0 … e i

e

n-1

e

0

e

i

ultim q
ultim
q
p prim
p prim

nMax-1

Coada: implementare cu tablouri

• implementarea operaţiilor

– insereaza()

void insereaza(Coada &C, Elt e){ if ((C.ultim + 1) % nMax == C.prim){ printf(“error”); return;

}

C.ultim = (C.ultim + 1) % nMax;

C.elemente[ultim] = e;

}

Coada: implementare cu liste înlănţuite

• reprezentarea obiectelor

prim
prim

e 0

cu liste înlănţuite • reprezentarea obiectelor prim e 0 e 1 ultim … e n-1 Algoritmi
cu liste înlănţuite • reprezentarea obiectelor prim e 0 e 1 ultim … e n-1 Algoritmi

e 1

cu liste înlănţuite • reprezentarea obiectelor prim e 0 e 1 ultim … e n-1 Algoritmi
cu liste înlănţuite • reprezentarea obiectelor prim e 0 e 1 ultim … e n-1 Algoritmi
ultim … e n-1
ultim
e n-1

Coada: implementare cu liste înlănţuite

• implementarea operaţiilor

– insereaza()

void insereaza(Coada &C, Elt e){ Nod* q = new Nod; q->elt = e; q->succ = NULL; if (C.ultim == NULL){ C.prim = q; C.ultim = q;

}

else { C.ultim->succ = q; C.ultim = q;

}

}

Aplicaţie: notaţia postfixată a expresiilor

• notaţia infixată

a + b

a + (b * 2)

• notaţia postfixată

a

b +

a

b 2 * +

• reguli de precedenţă

a + b * 2

• reguli de asociere

7 / 3 * 2

– la stânga (7 / 3) * 2

– la dreapta 7 / (3 * 2)

Translatarea infix -> postfix

void convInfix2Postfix(Coada &infix, Coada &postfix) { /* infix si postfix sunt cozi */ Stiva S = stivaVida(); while (!esteVida(infix)) { citeste(infix, x); elimina(infix); if (esteOperand(x)) insereaza(postfix, x) else if (x == ‘)’) { while (top(s)!=‘(’) {insereaza(postfix, top(S)); pop(S)} pop(S);

}

else { while( !estevida(S) && top(S) != ‘(’ && \ priorit(top(S))>= priorit(x)) { insereaza(postfix, top(S)); pop(S);

}

}

push(S,x);

}

while (not estevida(S)) {insereaza(postfix, top(S)); pop(S);}

}

Translatarea infix -> postfix

Exemplu: a+b*(c+d)+e x x inf.tab Elt[MAX] a + b ( d c + ) +
Exemplu: a+b*(c+d)+e
x
x
inf.tab
Elt[MAX]
a +
b
( d
c
+ )
+
e
*
postf.tab
Elt[MAX]
a b
c
d
+ e
*
+ +

S (stiva)

+ ( * + +

+

(

*

+ +

Evaluarea expresiilor postfixate

int valPostfix(Coada postfix){ Stiva S = stivaVida(); char x; while (!esteVida(postfix)){ citeste(postfix, x); elimina(postfix); if (esteOperand(x))push(S, x); else {

char drp = top(S); pop(S); char stg = top(S); pop(S); int val = op(stg, x, drp); push(S, val);

}

}

val = top(S); pop(S);

return val;

}

Translatarea infix -> postfix

Exemplu: abcd+*+e+ x x postf.tab Elt[MAX] a b c d + * + e +
Exemplu: abcd+*+e+
x
x
postf.tab
Elt[MAX]
a
b
c
d
+
*
+
e
+

S (stiva)

d

c+d

c

b*(c+d) b e

a

a+b*(c+d)+e

a+b*(c+d)