Sunteți pe pagina 1din 28

Algoritmi si structuri de date

II. Tablouri
1. Elemente de memorare a informatiei
2. Definire tablouri
3. Tablouri unidimensionale
1. Implementare statica
2. Implementare dinamica
4. Tablouri multidimensionale
1. Implementare statica
2. Implementare dinamica
5. Matrici particulare
1. Triunghiulara
2. Simetrica
3. Banda
6. Implementarea dinamica semicompacta a matricelor

Bibliografie: S. Barza, L. M. Morogan, Structuri de date, EFRM, 2007,


Cap I.5, p. 17-18, Cap II, p.19-42
1. Elemente de memorare a informatiei
Program de calculator - colectie de date si procese de prelucrare ale acestora.
Segment de date – partea de program ce contine informatia memorata si supusa
procesului de prelucrare.
Segment de cod (de instructiuni) – partea de program formata din descrierea
proceselor de prelucrare.
Date statice - datele care se definesc odata cu instructiunile de prelucrare a lor si
care sunt memorate in spatiul program.
Date dinamice – datele care nu se definesc odata cu instructiunile de prelucrare a
lor si care sunt memorate intern in afara spatiului programului.
Structura dinamica compacta – structura dinamica de date care ocupa un spatiu
continuu.
Structura dinamica divizata - structura dinamica de date memorata pe
componente, fara ca acestea sa ocupe un spatiu continuu.
2. Definire
Tablou = multime de date de acelasi tip la care se face referire globala prin numele
tabloului si la fiecare data din multime prin indicii corespunzatori elementului.
f : A 1× A 2× × A t A
A1 ,A 2 , ,A t - multimi finite, valorile indicilor
A – multimea valorilor elementelor tabloului
t – nr. natural, dimensiunea tabloului
t = 1 – tablou unidimensional, vector
t = 2 – tablou bidimensional, matrice
3. Tablouri unidimensionale
3.1. Implementare statica
B= {b1 ,b 2 , ,bn }multime finita si ordonata de numere, f : B A - vector
• Numelui vectorului i se asociaza o adresa unica de memorie = prima locatie in
care se face memorarea corespunzatoare primului element al vectoruluiloc = f
• Elementele vectorului se memoreaza intr-un spatiu continuu, incepand cu
primul element, rezervat integral in spatiul programului.
• Dimensiune spatiu de memorare vector = nr. elemente vector * dimensiunea
unui element.
Rangul unui element al unui vector = nr. natural ce indica pozitia relativa a
elementului in cadrul vectorului. Rangul primului element este 0.
- adresa fizica asociata primului element al vectorului
rang f bi =i− 1 - formula de rang
loc f b = loc f +l⋅ rang f b - pozitia fizica in memorie a elementului
de indice b
dim f =∣B∣⋅ l - spatiul ocupat de vector
l – spatiul ocupat de fiecare element din A
3. Tablouri unidimensionale
3.2. Implementare dinamica
a – adresa fizica de inceput a elementelor vectorului (in gen. 4 bytes)
t – definirea notiunii de vector (tipul elementelor vectorului)
s – spatiul de memorare al vectorului
Vectorul este accesibil doar pe perioada de executie.
Faze de lucru:
1. Alocarea spatiului de memorie al vectorului: inainte de primul acces la vector se
obtine spatiul de memorie s necesar memorarii elementelor acestuia.
2. Prelucrarea vectorului.
3. Eliberarea spatiului de memorie alocat vectorului.

1-3 fac apel la mecanismele de gestionare a memoriei ale sistemului de operare.

Obs. In limbajele de programare, definirea generica a unui tip nu produce alocare


de memorie. Alocarea memoriei se realizeaza lafiecare definire de variabila de
acel tip sau la cererea de alocare dinamica pentru tipul respectiv.
3. Tablouri unidimensionale
3.2.1. Vectori dinamici cu implementare fixa
t – predefinit in cadrul programului (asociat cu informatia de adresa a; variabila de
adresa cu tip asociat)
s- nedefinit; poate fi alocat oriunde in memoria interna.
Extindere notiune: dimensiunea unui vector la dimensiunea unui tip vector:
Fie v vector definit static de tip t. Spunem ca tipul vector t are aceeasi
dimensiune cu dim(v). Not. dim(t).

Alocarea vectorului: apel in care se specifica informatia de adresa.


Prelucrarea vectorului: aceleasi reguli ca la prelucrarea statica.

Ex.: a1, …, an – vectori dinamici in implementare fixa, de tipuri t1,…,tn


c bytes – dimensiune segment de cod; p bytes – alte date statice;
4 bytes – spatiu memorie pt informatie de adresa;
p + 4n – dimensiune segment de date al programului
ds = c + p + 4n bytes - dimensiunea statica a programului (spatiul de memorie
necesar pt lansarea in executie a programului)
3. Tablouri unidimensionale
3.2.1. Vectori dinamici cu implementare fixa
α – moment al executiei programului
ai1, …,aim – vectorii dinamici folositi la momentul α
Dimensiune spatiu de memorie (nu neaparat continuu) utilizat de program la
momentul α: m
dd α =c+p+4n ∑ dim t ik
k=1

Dimensiunea maxima a spatiului de memorie utilizat de program:


∑ dim t ik
k= 1
3. Tablouri unidimensionale
3.2.2. Vectori dinamici cu implementare variabila
T – tipul asociat unui vector maximal pentru datele considerate
dim(T) – spatiul maximal definit generic
t – se defineste pe parcursul executiei si este o restrictie a lui T
a - adresa asociata vectorului, singura componenta definita in program
Ex.: V : {i1,…,in} → A din care sunt definite efectiv doar primele p ≤ n componente
t = T |p ; t – tipul vectorului v : {i1,…,ip} → A , vi = Vi, i din {i1,…,ip}
s = dim(t) – spatiul alocat la implementare = buffer
- de regula nu este un spatiu accesibil direct elementelor vectorului;
- spatiu cu aceeasi dimensiune cu a vectorului si peste care acesta se
suprapune.
Accesul la un element al vectorului – procese de acces:
- In scriere: trecerea valorii in spatiul unei componente se face cu
descompunerea reprezentarii in bytes componenti;
- In citire: valoarea din spatiul unei componente se obtine prin recompunerea
reprezentarii plecand de la bytes componenti.
4. Tablouri multidimensionale
4.1. Implementare statica
Implementare prin linearizare linie (Pascal, Delphi, C++, Java) sau coloana
(FORTRAN) => se bazeaza pe implementarea statica a vectorilor.

f : B1 x … x Bp → A - tablou p – dimensional: | Bi | = ni
∣B ∣=ni nr. de elemente ale tabloului = nr. de elemente ale vectorului v
peste care se face suprapunerea tabloului; v : {1, …, n} → A
∣B ∣ i spatiul alocat tabloului multidimensional f
Rangul unui element al unui tablou multidimensional f = nr care indica pozitia
elementului in vectorul de liniarizare.

Formula de rang:
- Linearizare prin linii:
p = 2: rang b 1 ,b 2 = ∣B ∣rang b1 +rang b2
2 2 1 1
rang 2 a[ i,j ] =n 2⋅ i− 1 j− 1
4. Tablouri multidimensionale
4.1. Implementare statica
p – oarecare: gi : B2 x … x Bp → A, gi (i2, …, ip) = f (i, i2, …, ip )
m : B1 x C → A, unde C = B2 x … x Bp.
rang 2 b 1 ,c =∣C∣rang 1 b1 +rang1 c
rang p b1 , . .. ,b p =n 2 .. . n p rang 1 b 1 +rang p− 1 b2 ,. .. ,b p
rang p b1 ,...,b p =n 2 ...n p rang 1 b 1 +n 3 ...n p rang 1 b 2 ...+rang1 b p
p p
rang lp b1 , . .. ,b p = ∑ ∏ n j rang 1 b i
i=1 j=i+1

l – linearizare linie; x – spatiul ocupat de un element din tablou


Adresa de memorie l a1unui element
p din tablou:
l 1 p
loc f b , . .. ,b =a+x⋅ rang p b ,. .. ,b p
dim f =x ∏ n i
Spatiul ocupat de un tablou multidimensional definit static: i= 1
4. Tablouri multidimensionale
4.2. Implementare dinamica
(a, t, s, rang); v. caracteristicile implementarii dinamice a vectorilor
4.2.1. Tablouri dinamice cu implementare fixa
Caz I: t – predefinita; asociere directa a tipului la componenta a
Lucrul pe un limbaj de programare permite utilizarea directa a unei formule de rang
implicite, conforme cu modul de linearizare adoptat pt implementarea statica a
tablourilor.
s – singura componenta cu caracter dinamic
Caz II: Exista posibilitatea ca definirea tipului sa corespunda definitiei unui vector
= > alegerea linearizarii nu mai tine de limbaj, e la alegerea programatorului =>
necesitatea specificarii explicite a formulei de rang aplicate la regasirea
informatiei din tablou.
Avantaj: posibilitatea gruparii spatiului neutilizat la sfarsitul tabloului.
Dezavantaj: specificarea explicita a formulei de rang => etape acces element
tablou:
– Calculul explicit al formulei de rang.
– Accesul efectiv la element.
=> Procese de prelucrare laborioase.
4. Tablouri multidimensionale
4.2.2. Tablouri dinamice cu implementare variabila
Implementarea prin vectori de linearizare =>
=> restrictionarea vectorului de implementare la dimensiunea strict necesara
memorarii tabloului =>
=> tablou dinamic cu implementare variabila.

Scrierea in memorie a valorii unui element:


– se descompune in bytes componenti,
– Se aplica formula de rang
– Se calculeaza locatia primului byte al zonei de memorie afectate elementului
– Se depun bytes componenti in memorie incepand cu locatia calculata.

Citirea din memorie a valorii unui element:


– Se aplica formula de rang
– Se calculeaza locatia primului byte al zonei de memorie afectate elementului
– Se transfera de la aceasta adresa un nr de bytes corespunzatori tipului de informatie si se
recompun pt formarea valorii dorite.
5. Implementarea matricilor triunghiulare
Ex.: A - matrice patrata n x n
A s.n. matrice superior triunghiulara  pt orice i > j, 1 ≤ i, j ≤ n, aij = 0.
A s.n. matrice inferior triunghiulara  pt orice i < j, 1 ≤ i, j ≤ n, aij = 0.
Intr-o matrice triunghiulara sunt cel putin n(n - 1) / 2 elementele egale cu 0.
O matrice triunghiulara se poate defini numai prin elementele diferite de 0.
f : {1, …,n} x {1,…,n} → A, f(i,j) = f ij pt i ≥ j, si f(i,j) = 0 pt i < j, pt. matr. sup. tr.
Implementare cu vector de linearizare de dimensiune m = n2 – n(n-1)/2 = n(n+1)/2.
Linearizare linie: (f11,…,f1n,f22,…,f2n,…,fn-1,n-1,fn-1,n,fnn)
i− 1 2n 2− i
Pentru f ij, cu 1 ≤ i ≤ j ≤ n, formula de rang este: rang sup
l i,j =
2
+j− 1

j j− 1 j− 1 2n 2− j
rang sup
c i,j = +i− 1 rang inf
2 c i,j = +i− 1
2
i i− 1
rang inf
l i,j = +j− 1
2
6. Implementarea matricilor simetrice
Ex.: A, B - matrici patrate n x n
A s.n. matrice simetrica  pt orice i ≠ j, aij = aji.
B s.n. componenta superior triunghiulara a matricei A  bij = aij, pt i ≤ j,
respectiv bij = 0, pt i > j.
Implementarea matricelor simetrice se realizeaza ca implementarea matricelor
inferior triunghiulare, printr-un vector cu m = n(n+1)/2 elemente.
Formula de rang pentru
i i− 1
- Linearizare linie rang sim
l i,j = +j− 1, i≥ j
2
j j− 1
rang sim
l i,j = +i− 1,i<j
2
i− 1 2n 2− i
- Linearizare coloana rang sim
c i,j =
2
+j− 1,i>j

j− 1 2n 2− j
rang sim
c i,j = +i− 1, i≤ j
2
7. Implementarea matricilor banda
7.1. Matrice p – diagonala
f : {1, …,n} x {1,…,n} → A, 1 ≤ k << n. f – matrice (2k – 1) – diagonala  toate
elementele pentru care |i – j| > k – 1 sunt nule.
Nr. elemente pe cele p “diagonale”:
m = n + 2(n - 1) + … + 2(n – k + 1) = n(2k – 1) – k(k – 1)
Implementarea matricelor diagonale prin memorarea doar a elementelor de pe
“diagonale” este eficienta daca reducere spatiului este semnificativa. (>50%)
3− diag
Formule de rang: k = 2; m = 3n – 2; linearizare linie rang l i,j = 2i +j− 3

7.2. Matrice triunghiulara k – diagonala


f : {1, …,n} x {1,…,n} → A, 1 ≤ k << n. f – matrice superior k – diagonala  f –
superior triunghiulara si (2k – 1) diagonala.
Nr. elemente pe cele k“diagonale”: m = k(2n – k + 1) / 2.
7. Implementarea matricilor banda
7.2. Matrice triunghiulara k – diagonala
Formula de rang pt linearizare linie de matrice superior k-diagonala:

{ }
k− 1 i− 1 +j− 1 1≤ i<n− k+ 1
rang sup−
l
k− diag
i,j = i+k − n− 1 n+k − i
+k n− k +j− i n− k+1≤ i≤ n
2

Formula de rang pt linearizare diagonala de matrice superior k-diagonala:


j− i j− i− 1
rang sup−
d
k− diag
i,j = j− i n+1− j+i +i− 1
2
8. Implementarea tablourilor in C. Exemplificare
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 0;

while ((c = getchar()) != EOF)


if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;

printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n", nwhite, nother);
}
8. Implementarea tablourilor in C. Siruri de caractere
while (there's another line)
if (it's longer than the previous longest)
(save it)
(save its length)
print longest line

#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */

int getline(char line[], int maxline);


void copy(char to[], char from[]);

/* print the longest input line */


main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
8. Implementarea tablourilor in C. Siruri de caractere
while (there's another line)
if (it's longer than the previous longest)
(save it)
(save its length)
print longest line

#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */

int getline(char line[], int maxline);


void copy(char to[], char from[]);

/* print the longest input line */


main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
8. Implementarea tablourilor in C. Siruri de caractere
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
return 0;
}

/* getline: read a line into s, return length */


int getline(char s[],int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
8. Implementarea tablourilor in C. Siruri de caractere
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
8. Implementarea tablourilor in C. Pointeri si tablouri
8.1. Pointeri si adrese
Pointer = variabila ce contine adresa unei variabile.
Un calculator tipic are un sir de celule de memorie numarate (adresate) consecutiv, ce pot fi
manipulate in mod individual sau in grupuri continue.
Pointer = grup de celule (adesea doua sau patru) ce pot sa contina o adresa.
Fie c de tip char si p un pointer ce pointeaza spre c.
Operatorul unar & da adresa unui obiect => instructiunea:
p = &c;
atribuie adresa lui c variabilei p. Se spune ca p pointeaza spre c.
Obs. Operatorul unar & se aplica numai obiectelor din memorie: variabile si elemente de
tablouri. Nu se poate aplica expresiilor, constantelor sau variabilelor registru.
Operatorul unar * este operatorul de indirectare (dereferentiere). Se aplica unui pointer si
acceseaza obiectul catre care pointerul pointeaza.
Fie x si y intregi si ip un pointer catre int.

int x = 1, y = 2, z[10];
int *ip; /* ip is a pointer to int */

ip = &x; /* ip now points to x */


y = *ip; /* y is now 1 */
*ip = 0; /* x is now 0 */
ip = &z[0]; /* ip now points to z[0] */
8. Implementarea tablourilor in C. Pointeri si tablouri
8.1. Pointeri si adrese
Daca ip pointeaza spre intregul x, atunci *ip poate sa apara in orice context in care ar putea
sa apara x:
*ip = *ip + 10;
incrementeaza *ip cu 10.

Operatorii unari * si & sunt prioritari operatorilor aritmetici:


y = *ip + 1;
valorii variabilei catre care pointeaza ip I se adauga 1 si rezultatul se atribuie lui y.
*ip += 1;
incrementeaza catre ceea ce ip pointeaza, ca si
++*ip;
precum si
(*ip)++;

Obs. Parantezele sunt necesare in ultimul exemplu. Fara paranteze s-ar incrementa ip.
Operatorii unari precum * si ++ se asociaza de la dreapta la stanga.

Obs. Deoarece pointerii sunt variabile, pot fi folositi fara dereferentiere. Ex. Fie iq un alt
pointer spre int:
iq = ip
copiaza continutul lui ip in iq, facand iq sa pointeze catre ceea ce pointa si ip.
8. Implementarea tablourilor in C. Pointeri si tablouri
8.2. Pointeri si tablouri
Declaratia
int a[10];
defineste un tablou de dimensiune 10, adica un bloc de 10 obiecte consecutive a[0], a[1],
...,a[9].
Daca pa este un pointer catre un intreg:
int *pa;
atunci atribuirea:
pa = &a[0];
seteaza pa sa pointeze catre elementul 0 al lui a => pa contine adresa lui a[0].
Atribuirea
x = *pa;
copiaza continutul lui a[0] in x.
Daca pa pointeaza catre un element particular al unui tablou, atunci pa+1 pointeaza catre
urmatorul element, pa+i pointeaza al i-lea element dupa pa, iar pa-i pointeaza al i-lea
element de dinaintea lui pa.
Astfel, daca pa pointeaza spre a[0], *(pa+1) face referire la continutul lui a[1], pa+i este
adresa lui a[i] si *(pa+i) este continutul lui a[i].

Aceste observatii sunt adevarate indiferent de tipul sau de dimensiunea variabilelor din
tablou.
8. Implementarea tablourilor in C. Pointeri si tablouri
8.2. Pointeri si tablouri
Prin definitie, valoarea unei variabile sau expresii de tip array este adresa elementului 0 al
array-ului. Astfel, dupa atribuirea
pa = &a[0];
pa si a au valori identice.
Deoarece numele array-ului este sinonim cu cu locatia elementului initial, atribuirea
pa=&a[0];
se mai poate scrie
pa = a;
De asemenea, referire catre a[i] se mai poate scrie *(a+i). Pentru evaluarea lui a[i], C face
imediat conversia sa in *(a+i). Putem spune ca cele doua forme sunt echivalente.
Aplicand operatorul & ambelor parti ale echivalentei => &a[i] si a+i sunt identice: a+i este
adresa celui de-al i-lea element de dupa a.
Cum pa este un pointer, poate sa apara in expresii cu indexare; pa[i] este identic cu *(pa+i).

Diferenta dintre numele array-ului si pointer:


pointerul este o variabila => pa=a si pa++ sunt legale.
Numele unui array nu este o variabila => constructiile a=pa si a++ sunt ilegale.

Cand numele unui array este transmis unei functii, ceea ce se transmite este locatia
elementului initial. In cadrul functiei apelate, acest argument este o variabila locala
8. Implementarea tablourilor in C. Pointeri si tablouri
8.2. Pointeri si tablouri
/* strlen: return length of string s */
int strlen(char *s)
{
int n;
for (n = 0; *s != '\0', s++)
n++;
return n;
}
Deoarece s este un pointer, incrementarea sa este legala; s++ nu are efect asupra sirului de
caractere din functia care apeleaza strlen, ci incrementeaza copia pointerului.

Sunt legale:
strlen("hello, world"); /* sir de constante */
strlen(array); /* char array[100]; */
strlen(ptr); /* char *ptr; */
8. Implementarea tablourilor in C. Pointeri si tablouri
8.2. Pointeri si tablouri
Este posibil sa se transmita o parte a unui tablou unei functii, transmitand un pointer catre
inceputul subsirului corespunzator. De exemplu, daca a este un sir,
f(&a[2])
si
f(a+2)
transmit, ambele, functiei f, adresa subsirului care incepe la a[2]. In cadrul lui f, declararea
parametrului este
f(int arr[]) { ... }
or
f(int *arr) { ... }

Daca este sigur ca elementele exista, se pot face indexari in sens invers in sir. P[-1], p[-2],...
sunt legale dpv sintactic si se refera la elementele imediat precedente lui p[0]. Este ilegal sa
se faca referire la obiecte care nu se afla intre extremitatile sirului.

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